diff --git a/DEPS b/DEPS index 9f33d05..df441687 100644 --- a/DEPS +++ b/DEPS
@@ -105,11 +105,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': 'b965fcb47296870643d001acb4a43cec3d88579a', + 'skia_revision': 'c45a5c559365b2e04c89a3ef09752e5c1bb24aa2', # 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': '4fb310a1d7c008cf6b5772ab02c06f6f62bc4d6e', + 'v8_revision': '66a2db59c17dfef7405a3ad13b47d28d815d7584', # 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. @@ -117,7 +117,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '419acc8f4f3b238e714cbaaddeeea1bedd366bf8', + 'angle_revision': 'e076a2327f0d082d46683f32614c495e049a4bb2', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling build tools # and whatever else without interference from each other. @@ -550,7 +550,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '70331946770e5d627ce0be4648102ce357b614f3', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '9a962fc1e6e5de1a1881292cb7575fc0bfd4b1a9', 'condition': 'checkout_linux', }, @@ -575,7 +575,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '8d3925b164822e2660d3b985402a5681432b0285', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'fb734036f4b5ae6d5afc63cbfc41d3a5d1c29a82', 'src/third_party/devtools-node-modules': Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'), @@ -1045,7 +1045,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'a5c263cc63ffc2cc189b5214074c8792067c1853', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '3643aef89c785c6f1af625495023b64f5ffdbefe', + Var('webrtc_git') + '/src.git' + '@' + '056d811b6a044cd7e02da1133a520bc2d489836f', 'src/third_party/xdg-utils': { 'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d', @@ -1079,7 +1079,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@5e752946b94c956c3def0ad2dd65e00705b8d4e6', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@ed1bf6ade3398bd2b6580d62343c1037fe6aee6c', 'condition': 'checkout_src_internal', },
diff --git a/android_webview/browser/parent_output_surface.cc b/android_webview/browser/parent_output_surface.cc index c109e0c..67b4f127 100644 --- a/android_webview/browser/parent_output_surface.cc +++ b/android_webview/browser/parent_output_surface.cc
@@ -43,10 +43,12 @@ context_provider_->ContextGL()->ShallowFlushCHROMIUM(); } +#if BUILDFLAG(ENABLE_VULKAN) gpu::VulkanSurface* ParentOutputSurface::GetVulkanSurface() { NOTIMPLEMENTED(); return nullptr; } +#endif bool ParentOutputSurface::HasExternalStencilTest() const { return ScopedAppGLStateRestore::Current()
diff --git a/android_webview/browser/parent_output_surface.h b/android_webview/browser/parent_output_surface.h index 1e86919..973e2c8 100644 --- a/android_webview/browser/parent_output_surface.h +++ b/android_webview/browser/parent_output_surface.h
@@ -29,7 +29,9 @@ bool has_alpha, bool use_stencil) override; void SwapBuffers(viz::OutputSurfaceFrame frame) override; +#if BUILDFLAG(ENABLE_VULKAN) gpu::VulkanSurface* GetVulkanSurface() override; +#endif bool HasExternalStencilTest() const override; void ApplyExternalStencil() override; uint32_t GetFramebufferCopyTextureFormat() override;
diff --git a/ash/assistant/assistant_notification_controller.cc b/ash/assistant/assistant_notification_controller.cc index 534d40f..1dac8e0 100644 --- a/ash/assistant/assistant_notification_controller.cc +++ b/ash/assistant/assistant_notification_controller.cc
@@ -76,12 +76,22 @@ DISALLOW_COPY_AND_ASSIGN(AssistantNotificationDelegate); }; +std::string GetNotificationId(const std::string& grouping_key) { + return kNotificationId + grouping_key; +} + +message_center::NotifierId GetNotifierId() { + return message_center::NotifierId( + message_center::NotifierId::SYSTEM_COMPONENT, kNotifierAssistant); +} + } // namespace AssistantNotificationController::AssistantNotificationController( AssistantController* assistant_controller) : assistant_controller_(assistant_controller), assistant_notification_subscriber_binding_(this), + notifier_id_(GetNotifierId()), weak_factory_(this) {} AssistantNotificationController::~AssistantNotificationController() = default; @@ -113,9 +123,8 @@ // Create the specified |notification| that should be rendered in the // |message_center| for the interaction. - notification_ = std::move(notification); - const base::string16 title = base::UTF8ToUTF16(notification_->title); - const base::string16 message = base::UTF8ToUTF16(notification_->message); + const base::string16 title = base::UTF8ToUTF16(notification->title); + const base::string16 message = base::UTF8ToUTF16(notification->message); const base::string16 display_source = l10n_util::GetStringUTF16(IDS_ASH_ASSISTANT_NOTIFICATION_DISPLAY_SOURCE); @@ -125,14 +134,12 @@ std::unique_ptr<message_center::Notification> system_notification = message_center::Notification::CreateSystemNotification( - message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId, title, - message, gfx::Image(), display_source, GURL(), - message_center::NotifierId( - message_center::NotifierId::SYSTEM_COMPONENT, kNotifierAssistant), - optional_field, + message_center::NOTIFICATION_TYPE_SIMPLE, + GetNotificationId(notification->grouping_key), title, message, + gfx::Image(), display_source, GURL(), notifier_id_, optional_field, new AssistantNotificationDelegate(weak_factory_.GetWeakPtr(), assistant_controller_->GetWeakPtr(), - notification_.Clone()), + notification.Clone()), kAssistantIcon, message_center::SystemNotificationWarningLevel::NORMAL); system_notification->set_priority(message_center::DEFAULT_PRIORITY); @@ -141,17 +148,17 @@ void AssistantNotificationController::OnRemoveNotification( const std::string& grouping_key) { - if (!grouping_key.empty() && - (!notification_ || notification_->grouping_key != grouping_key)) { - return; - } - - // message_center has only one Assistant notification, so there is no - // difference between removing all and removing one Assistant notification. - notification_.reset(); message_center::MessageCenter* message_center = message_center::MessageCenter::Get(); - message_center->RemoveNotification(kNotificationId, /*by_user=*/false); + if (grouping_key.empty()) { + // Remove all assistant notifications by NotifierId. + message_center->RemoveNotificationsForNotifierId(notifier_id_); + } else { + // Remove the notification with |grouping_key|. It is no-op if no + // corresponding notification is found in |message_center|. + message_center->RemoveNotification(GetNotificationId(grouping_key), + /*by_user=*/false); + } } } // namespace ash
diff --git a/ash/assistant/assistant_notification_controller.h b/ash/assistant/assistant_notification_controller.h index 9188871..e332918 100644 --- a/ash/assistant/assistant_notification_controller.h +++ b/ash/assistant/assistant_notification_controller.h
@@ -12,6 +12,7 @@ #include "base/memory/weak_ptr.h" #include "chromeos/services/assistant/public/mojom/assistant.mojom.h" #include "mojo/public/cpp/bindings/binding.h" +#include "ui/message_center/public/cpp/notifier_id.h" namespace ash { @@ -48,8 +49,7 @@ // Owned by AssistantController. chromeos::assistant::mojom::Assistant* assistant_ = nullptr; - // Save the latest notification for future retrieval or dismiss operations. - AssistantNotificationPtr notification_; + const message_center::NotifierId notifier_id_; base::WeakPtrFactory<AssistantNotificationController> weak_factory_;
diff --git a/ash/content/keyboard_overlay/DEPS b/ash/content/keyboard_overlay/DEPS index 0bffc37f..275939a 100644 --- a/ash/content/keyboard_overlay/DEPS +++ b/ash/content/keyboard_overlay/DEPS
@@ -3,6 +3,6 @@ ] specific_include_rules = { ".*test\.cc": [ - "+content/public/test/test_browser_context.h", + "+content/public/test", ], }
diff --git a/ash/public/cpp/ash_layout_constants.cc b/ash/public/cpp/ash_layout_constants.cc index 5129f56..5401f98 100644 --- a/ash/public/cpp/ash_layout_constants.cc +++ b/ash/public/cpp/ash_layout_constants.cc
@@ -11,28 +11,19 @@ gfx::Size GetAshLayoutSize(AshLayoutSize size) { constexpr int kButtonWidth = 32; - const int mode = ui::MaterialDesignController::GetMode(); - switch (size) { - case AshLayoutSize::kBrowserCaptionMaximized: { - // These constants should be kept in sync with those for TAB_HEIGHT in - // chrome/browser/ui/layout_constants.cc. - // TODO: Ideally these values should be obtained from a common location. - constexpr int kBrowserMaximizedCaptionButtonHeight[] = {29, 33, 41, 34, - 41}; - return gfx::Size(kButtonWidth, - kBrowserMaximizedCaptionButtonHeight[mode]); - } - case AshLayoutSize::kBrowserCaptionRestored: { - constexpr int kBrowserRestoredCaptionButtonHeight[] = {36, 40, 48, 41, - 48}; - return gfx::Size(kButtonWidth, kBrowserRestoredCaptionButtonHeight[mode]); - } - case AshLayoutSize::kNonBrowserCaption: - return gfx::Size(kButtonWidth, 32); - } - NOTREACHED(); - return gfx::Size(); + if (size == AshLayoutSize::kNonBrowserCaption) + return gfx::Size(kButtonWidth, 32); + + // |kBrowserMaximizedCaptionButtonHeight| should be kept in sync with those + // for TAB_HEIGHT in // chrome/browser/ui/layout_constants.cc. + // TODO: Ideally these values should be obtained from a common location. + constexpr int kBrowserMaximizedCaptionButtonHeight[] = {29, 33, 41, 34, 41}; + const int mode = ui::MaterialDesignController::GetMode(); + int height = kBrowserMaximizedCaptionButtonHeight[mode]; + if (size == AshLayoutSize::kBrowserCaptionRestored) + height += 8; // Restored window titlebars are 8 DIP taller than maximized. + return gfx::Size(kButtonWidth, height); } } // namespace ash
diff --git a/ash/wm/overview/scoped_transform_overview_window.cc b/ash/wm/overview/scoped_transform_overview_window.cc index 864ab2aee..7f2456a 100644 --- a/ash/wm/overview/scoped_transform_overview_window.cc +++ b/ash/wm/overview/scoped_transform_overview_window.cc
@@ -278,9 +278,8 @@ return true; } -void ScopedTransformOverviewWindow::OnCompositingStarted( - ui::Compositor* compositor, - base::TimeTicks start_time) { +void ScopedTransformOverviewWindow::OnCompositingDidCommit( + ui::Compositor* compositor) { views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window_); DCHECK(widget); DCHECK_EQ(compositor, widget->GetCompositor());
diff --git a/ash/wm/overview/scoped_transform_overview_window.h b/ash/wm/overview/scoped_transform_overview_window.h index 3c0e085..f70003e 100644 --- a/ash/wm/overview/scoped_transform_overview_window.h +++ b/ash/wm/overview/scoped_transform_overview_window.h
@@ -200,9 +200,9 @@ void OnImplicitAnimationsCompleted() override; // ui::CompositorObserver: - void OnCompositingDidCommit(ui::Compositor* compositor) override {} + void OnCompositingDidCommit(ui::Compositor* compositor) override; void OnCompositingStarted(ui::Compositor* compositor, - base::TimeTicks start_time) override; + base::TimeTicks start_time) override {} void OnCompositingEnded(ui::Compositor* compositor) override {} void OnCompositingLockStateChanged(ui::Compositor* compositor) override {} void OnCompositingChildResizing(ui::Compositor* compositor) override {}
diff --git a/cc/layers/heads_up_display_layer_impl.cc b/cc/layers/heads_up_display_layer_impl.cc index cd16765..c45a685 100644 --- a/cc/layers/heads_up_display_layer_impl.cc +++ b/cc/layers/heads_up_display_layer_impl.cc
@@ -137,8 +137,10 @@ bool HeadsUpDisplayLayerImpl::WillDraw( DrawMode draw_mode, viz::ClientResourceProvider* resource_provider) { - if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE) + if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE && + !LayerImpl::WillDraw(draw_mode, resource_provider)) { return false; + } int max_texture_size = layer_tree_impl()->max_texture_size(); internal_contents_scale_ = GetIdealContentsScale(); @@ -147,7 +149,7 @@ internal_content_bounds_.SetToMin( gfx::Size(max_texture_size, max_texture_size)); - return LayerImpl::WillDraw(draw_mode, resource_provider); + return true; } void HeadsUpDisplayLayerImpl::AppendQuads(viz::RenderPass* render_pass,
diff --git a/cc/layers/heads_up_display_layer_impl_unittest.cc b/cc/layers/heads_up_display_layer_impl_unittest.cc index 1ffb91f9..f5dc43ee 100644 --- a/cc/layers/heads_up_display_layer_impl_unittest.cc +++ b/cc/layers/heads_up_display_layer_impl_unittest.cc
@@ -51,6 +51,7 @@ std::unique_ptr<HeadsUpDisplayLayerImpl> layer_ptr = HeadsUpDisplayLayerImpl::Create(host_impl.pending_tree(), 1); layer_ptr->SetBounds(gfx::Size(100, 100)); + layer_ptr->set_visible_layer_rect(gfx::Rect(100, 100)); HeadsUpDisplayLayerImpl* layer = layer_ptr.get(); @@ -84,6 +85,7 @@ std::unique_ptr<HeadsUpDisplayLayerImpl> layer_ptr = HeadsUpDisplayLayerImpl::Create(host_impl.pending_tree(), 1); layer_ptr->SetBounds(gfx::Size(100, 100)); + layer_ptr->set_visible_layer_rect(gfx::Rect(100, 100)); HeadsUpDisplayLayerImpl* layer = layer_ptr.get();
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc index 389e630..f0ae0f4b 100644 --- a/cc/layers/layer_impl.cc +++ b/cc/layers/layer_impl.cc
@@ -71,7 +71,6 @@ effect_tree_index_(EffectTree::kInvalidNodeId), clip_tree_index_(ClipTree::kInvalidNodeId), scroll_tree_index_(ScrollTree::kInvalidNodeId), - current_draw_mode_(DRAW_MODE_NONE), debug_info_(nullptr), has_will_change_transform_hint_(false), needs_push_properties_(false), @@ -89,7 +88,6 @@ } LayerImpl::~LayerImpl() { - DCHECK_EQ(DRAW_MODE_NONE, current_draw_mode_); layer_tree_impl_->UnregisterLayer(this); layer_tree_impl_->RemoveFromElementLayerList(element_id_); TRACE_EVENT_OBJECT_DELETED_WITH_ID( @@ -167,17 +165,17 @@ bool LayerImpl::WillDraw(DrawMode draw_mode, viz::ClientResourceProvider* resource_provider) { - // WillDraw/DidDraw must be matched. - DCHECK_NE(DRAW_MODE_NONE, draw_mode); - DCHECK_EQ(DRAW_MODE_NONE, current_draw_mode_); + if (visible_layer_rect().IsEmpty() || + draw_properties().occlusion_in_content_space.IsOccluded( + visible_layer_rect())) { + return false; + } + current_draw_mode_ = draw_mode; return true; } -void LayerImpl::DidDraw(viz::ClientResourceProvider* resource_provider) { - DCHECK_NE(DRAW_MODE_NONE, current_draw_mode_); - current_draw_mode_ = DRAW_MODE_NONE; -} +void LayerImpl::DidDraw(viz::ClientResourceProvider* resource_provider) {} bool LayerImpl::ShowDebugBorders(DebugBorderType type) const { return layer_tree_impl()->debug_state().show_debug_borders.test(type);
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h index 9555515..dcbd0fb 100644 --- a/cc/layers/layer_impl.h +++ b/cc/layers/layer_impl.h
@@ -133,9 +133,7 @@ // WillDraw must be called before AppendQuads. If WillDraw returns false, // AppendQuads and DidDraw will not be called. If WillDraw returns true, // DidDraw is guaranteed to be called before another WillDraw or before - // the layer is destroyed. To enforce this, any class that overrides - // WillDraw/DidDraw must call the base class version only if WillDraw - // returns true. + // the layer is destroyed. virtual bool WillDraw(DrawMode draw_mode, viz::ClientResourceProvider* resource_provider); virtual void AppendQuads(viz::RenderPass* render_pass,
diff --git a/cc/layers/surface_layer.cc b/cc/layers/surface_layer.cc index 5b099a3..3f457b5 100644 --- a/cc/layers/surface_layer.cc +++ b/cc/layers/surface_layer.cc
@@ -17,8 +17,19 @@ return base::WrapRefCounted(new SurfaceLayer()); } +scoped_refptr<SurfaceLayer> SurfaceLayer::Create( + UpdateSubmissionStateCB update_submission_state_callback) { + return base::WrapRefCounted( + new SurfaceLayer(std::move(update_submission_state_callback))); +} + SurfaceLayer::SurfaceLayer() = default; +SurfaceLayer::SurfaceLayer( + UpdateSubmissionStateCB update_submission_state_callback) + : update_submission_state_callback_( + std::move(update_submission_state_callback)) {} + SurfaceLayer::~SurfaceLayer() { DCHECK(!layer_tree_host()); } @@ -97,9 +108,16 @@ SetNeedsPushProperties(); } +void SurfaceLayer::SetMayContainVideo(bool may_contain_video) { + may_contain_video_ = may_contain_video; +} + std::unique_ptr<LayerImpl> SurfaceLayer::CreateLayerImpl( LayerTreeImpl* tree_impl) { - return SurfaceLayerImpl::Create(tree_impl, id()); + auto layer_impl = SurfaceLayerImpl::Create(tree_impl, id(), + update_submission_state_callback_); + layer_impl->set_may_contain_video(may_contain_video_); + return layer_impl; } bool SurfaceLayer::HasDrawableContent() const {
diff --git a/cc/layers/surface_layer.h b/cc/layers/surface_layer.h index fcc684c..cee2367 100644 --- a/cc/layers/surface_layer.h +++ b/cc/layers/surface_layer.h
@@ -16,11 +16,16 @@ namespace cc { +// If given true, we should submit frames, as we are unoccluded on screen. +// If given false, we should not submit compositor frames. +using UpdateSubmissionStateCB = base::RepeatingCallback<void(bool)>; + // A layer that renders a surface referencing the output of another compositor // instance or client. class CC_EXPORT SurfaceLayer : public Layer { public: static scoped_refptr<SurfaceLayer> Create(); + static scoped_refptr<SurfaceLayer> Create(UpdateSubmissionStateCB); void SetPrimarySurfaceId(const viz::SurfaceId& surface_id, const DeadlinePolicy& deadline_policy); @@ -36,6 +41,8 @@ void SetSurfaceHitTestable(bool surface_hit_testable); bool surface_hit_testable() const { return surface_hit_testable_; } + void SetMayContainVideo(bool); + // Layer overrides. std::unique_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override; void SetLayerTreeHost(LayerTreeHost* host) override; @@ -55,6 +62,7 @@ protected: SurfaceLayer(); + explicit SurfaceLayer(UpdateSubmissionStateCB); bool HasDrawableContent() const override; private: @@ -63,6 +71,9 @@ // Returns a SurfaceRange corresponding to the surface layer. viz::SurfaceRange GetSurfaceRange() const; + UpdateSubmissionStateCB update_submission_state_callback_; + + bool may_contain_video_ = false; viz::SurfaceId primary_surface_id_; viz::SurfaceId fallback_surface_id_; base::Optional<uint32_t> deadline_in_frames_ = 0u;
diff --git a/cc/layers/surface_layer_impl.cc b/cc/layers/surface_layer_impl.cc index 8e383af..3577afa 100644 --- a/cc/layers/surface_layer_impl.cc +++ b/cc/layers/surface_layer_impl.cc
@@ -16,14 +16,20 @@ namespace cc { -SurfaceLayerImpl::SurfaceLayerImpl(LayerTreeImpl* tree_impl, int id) - : LayerImpl(tree_impl, id) {} +SurfaceLayerImpl::SurfaceLayerImpl( + LayerTreeImpl* tree_impl, + int id, + UpdateSubmissionStateCB update_submission_state_callback) + : LayerImpl(tree_impl, id), + update_submission_state_callback_( + std::move(update_submission_state_callback)) {} SurfaceLayerImpl::~SurfaceLayerImpl() = default; std::unique_ptr<LayerImpl> SurfaceLayerImpl::CreateLayerImpl( LayerTreeImpl* tree_impl) { - return SurfaceLayerImpl::Create(tree_impl, id()); + return SurfaceLayerImpl::Create(tree_impl, id(), + std::move(update_submission_state_callback_)); } void SurfaceLayerImpl::SetPrimarySurfaceId( @@ -89,6 +95,22 @@ layer_impl->SetSurfaceHitTestable(surface_hit_testable_); } +bool SurfaceLayerImpl::WillDraw( + DrawMode draw_mode, + viz::ClientResourceProvider* resource_provider) { + bool will_draw = LayerImpl::WillDraw(draw_mode, resource_provider); + // If we have a change in WillDraw (meaning that visibility has changed), we + // want to inform the VideoFrameSubmitter to start or stop submitting + // compositor frames. + if (will_draw_ != will_draw) { + will_draw_ = will_draw; + if (update_submission_state_callback_) + update_submission_state_callback_.Run(will_draw); + } + + return primary_surface_id_.is_valid() && will_draw; +} + void SurfaceLayerImpl::AppendQuads(viz::RenderPass* render_pass, AppendQuadsData* append_quads_data) { AppendRainbowDebugBorder(render_pass);
diff --git a/cc/layers/surface_layer_impl.h b/cc/layers/surface_layer_impl.h index ce24320..cd433f7 100644 --- a/cc/layers/surface_layer_impl.h +++ b/cc/layers/surface_layer_impl.h
@@ -7,6 +7,7 @@ #include <memory> +#include "base/bind.h" #include "base/macros.h" #include "base/memory/ptr_util.h" #include "cc/cc_export.h" @@ -17,12 +18,25 @@ namespace cc { +// This must match SurfaceLayer::UpdateSubmissionStateCB. +using UpdateSubmissionStateCB = base::RepeatingCallback<void(bool)>; + class CC_EXPORT SurfaceLayerImpl : public LayerImpl { public: + static std::unique_ptr<SurfaceLayerImpl> Create( + LayerTreeImpl* tree_impl, + int id, + UpdateSubmissionStateCB update_submission_state_callback) { + return base::WrapUnique(new SurfaceLayerImpl( + tree_impl, id, std::move(update_submission_state_callback))); + } + static std::unique_ptr<SurfaceLayerImpl> Create(LayerTreeImpl* tree_impl, int id) { - return base::WrapUnique(new SurfaceLayerImpl(tree_impl, id)); + return base::WrapUnique( + new SurfaceLayerImpl(tree_impl, id, base::BindRepeating([](bool) {}))); } + ~SurfaceLayerImpl() override; void SetPrimarySurfaceId(const viz::SurfaceId& surface_id, @@ -56,12 +70,14 @@ // LayerImpl overrides. std::unique_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override; void PushPropertiesTo(LayerImpl* layer) override; + bool WillDraw(DrawMode draw_mode, + viz::ClientResourceProvider* resource_provider) override; void AppendQuads(viz::RenderPass* render_pass, AppendQuadsData* append_quads_data) override; bool is_surface_layer() const override; protected: - SurfaceLayerImpl(LayerTreeImpl* tree_impl, int id); + SurfaceLayerImpl(LayerTreeImpl* tree_impl, int id, UpdateSubmissionStateCB); private: viz::SurfaceDrawQuad* CreateSurfaceDrawQuad( @@ -74,12 +90,14 @@ void AsValueInto(base::trace_event::TracedValue* dict) const override; const char* LayerTypeAsString() const override; + UpdateSubmissionStateCB update_submission_state_callback_; viz::SurfaceId primary_surface_id_; viz::SurfaceId fallback_surface_id_; base::Optional<uint32_t> deadline_in_frames_; bool stretch_content_to_fill_bounds_ = false; bool surface_hit_testable_ = false; + bool will_draw_ = false; DISALLOW_COPY_AND_ASSIGN(SurfaceLayerImpl); };
diff --git a/cc/layers/surface_layer_impl_unittest.cc b/cc/layers/surface_layer_impl_unittest.cc index d8a5f6b..36a57d2 100644 --- a/cc/layers/surface_layer_impl_unittest.cc +++ b/cc/layers/surface_layer_impl_unittest.cc
@@ -44,6 +44,7 @@ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(), gfx::Rect(layer_size)); EXPECT_EQ(1u, impl.quad_list().size()); + EXPECT_TRUE(surface_layer_impl->WillDraw(DRAW_MODE_HARDWARE, nullptr)); } { @@ -53,6 +54,7 @@ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(), gfx::Rect()); EXPECT_EQ(impl.quad_list().size(), 0u); + EXPECT_FALSE(surface_layer_impl->WillDraw(DRAW_MODE_HARDWARE, nullptr)); } { @@ -66,6 +68,7 @@ // The layer outputs one quad, which is partially occluded. EXPECT_EQ(1u, impl.quad_list().size()); EXPECT_EQ(1u, partially_occluded_count); + EXPECT_TRUE(surface_layer_impl->WillDraw(DRAW_MODE_HARDWARE, nullptr)); } }
diff --git a/cc/layers/texture_layer_impl.cc b/cc/layers/texture_layer_impl.cc index 9bf803b..137534d 100644 --- a/cc/layers/texture_layer_impl.cc +++ b/cc/layers/texture_layer_impl.cc
@@ -88,6 +88,9 @@ return false; } + if (!LayerImpl::WillDraw(draw_mode, resource_provider)) + return false; + if (own_resource_) { DCHECK(!resource_id_); if (!transferable_resource_.mailbox_holder.mailbox.IsZero()) { @@ -98,7 +101,7 @@ own_resource_ = false; } - return resource_id_ && LayerImpl::WillDraw(draw_mode, resource_provider); + return resource_id_; } void TextureLayerImpl::AppendQuads(viz::RenderPass* render_pass,
diff --git a/cc/layers/texture_layer_unittest.cc b/cc/layers/texture_layer_unittest.cc index 4624e15..18c72de3 100644 --- a/cc/layers/texture_layer_unittest.cc +++ b/cc/layers/texture_layer_unittest.cc
@@ -850,6 +850,12 @@ EXPECT_TRUE(host_impl_.InitializeFrameSink(layer_tree_frame_sink_.get())); } + std::unique_ptr<TextureLayerImpl> CreateTextureLayer() { + auto layer = TextureLayerImpl::Create(host_impl_.active_tree(), 1); + layer->set_visible_layer_rect(gfx::Rect(100, 100)); + return layer; + } + bool WillDraw(TextureLayerImpl* layer, DrawMode mode) { bool will_draw = layer->WillDraw( mode, host_impl_.active_tree()->resource_provider()); @@ -873,8 +879,7 @@ .Times(AnyNumber()); // Hardware mode. { - std::unique_ptr<TextureLayerImpl> impl_layer = - TextureLayerImpl::Create(host_impl_.active_tree(), 1); + std::unique_ptr<TextureLayerImpl> impl_layer = CreateTextureLayer(); impl_layer->SetTransferableResource( test_data_.resource1_, viz::SingleReleaseCallback::Create(test_data_.release_callback1_)); @@ -890,8 +895,7 @@ // Software mode. { - std::unique_ptr<TextureLayerImpl> impl_layer = - TextureLayerImpl::Create(host_impl_.active_tree(), 1); + std::unique_ptr<TextureLayerImpl> impl_layer = CreateTextureLayer(); impl_layer->SetTransferableResource( test_data_.resource1_, viz::SingleReleaseCallback::Create(test_data_.release_callback1_)); @@ -899,16 +903,14 @@ } { - std::unique_ptr<TextureLayerImpl> impl_layer = - TextureLayerImpl::Create(host_impl_.active_tree(), 1); + std::unique_ptr<TextureLayerImpl> impl_layer = CreateTextureLayer(); impl_layer->SetTransferableResource(viz::TransferableResource(), nullptr); EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE)); } { // Software resource. - std::unique_ptr<TextureLayerImpl> impl_layer = - TextureLayerImpl::Create(host_impl_.active_tree(), 1); + std::unique_ptr<TextureLayerImpl> impl_layer = CreateTextureLayer(); impl_layer->SetTransferableResource( test_data_.sw_resource_, viz::SingleReleaseCallback::Create(test_data_.sw_release_callback_)); @@ -917,8 +919,7 @@ // Resourceless software mode. { - std::unique_ptr<TextureLayerImpl> impl_layer = - TextureLayerImpl::Create(host_impl_.active_tree(), 1); + std::unique_ptr<TextureLayerImpl> impl_layer = CreateTextureLayer(); impl_layer->SetTransferableResource( test_data_.resource1_, viz::SingleReleaseCallback::Create(test_data_.release_callback1_)); @@ -990,8 +991,7 @@ TEST_F(TextureLayerImplWithResourceTest, TestDestructorCallbackOnCreatedResource) { - std::unique_ptr<TextureLayerImpl> impl_layer; - impl_layer = TextureLayerImpl::Create(host_impl_.active_tree(), 1); + std::unique_ptr<TextureLayerImpl> impl_layer = CreateTextureLayer(); ASSERT_TRUE(impl_layer); EXPECT_CALL(test_data_.mock_callback_,
diff --git a/cc/layers/video_layer_impl.cc b/cc/layers/video_layer_impl.cc index 3e41407..d4a18b06 100644 --- a/cc/layers/video_layer_impl.cc +++ b/cc/layers/video_layer_impl.cc
@@ -82,6 +82,9 @@ if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE) return false; + if (!LayerImpl::WillDraw(draw_mode, resource_provider)) + return false; + // Explicitly acquire and release the provider mutex so it can be held from // WillDraw to DidDraw. Since the compositor thread is in the middle of // drawing, the layer will not be destroyed before DidDraw is called. @@ -99,9 +102,6 @@ return false; } - if (!LayerImpl::WillDraw(draw_mode, resource_provider)) - return false; - if (!updater_) { const LayerTreeSettings& settings = layer_tree_impl()->settings(); updater_ = std::make_unique<media::VideoResourceUpdater>(
diff --git a/cc/layers/video_layer_impl_unittest.cc b/cc/layers/video_layer_impl_unittest.cc index fc67628..56d9170 100644 --- a/cc/layers/video_layer_impl_unittest.cc +++ b/cc/layers/video_layer_impl_unittest.cc
@@ -50,6 +50,7 @@ impl.AddChildToRoot<VideoLayerImpl>(&provider, media::VIDEO_ROTATION_0); video_layer_impl->SetBounds(layer_size); video_layer_impl->SetDrawsContent(true); + video_layer_impl->set_visible_layer_rect(gfx::Rect(layer_size)); impl.CalcDrawProps(viewport_size); @@ -313,6 +314,7 @@ impl.AddChildToRoot<VideoLayerImpl>(&provider, media::VIDEO_ROTATION_0); video_layer_impl->SetBounds(layer_size); video_layer_impl->SetDrawsContent(true); + video_layer_impl->set_visible_layer_rect(gfx::Rect(layer_size)); impl.host_impl()->active_tree()->BuildLayerListAndPropertyTreesForTesting(); gfx::Rect occluded; @@ -350,6 +352,7 @@ impl.AddChildToRoot<VideoLayerImpl>(&provider, media::VIDEO_ROTATION_0); video_layer_impl->SetBounds(layer_size); video_layer_impl->SetDrawsContent(true); + video_layer_impl->set_visible_layer_rect(gfx::Rect(layer_size)); impl.host_impl()->active_tree()->BuildLayerListAndPropertyTreesForTesting(); gfx::Rect occluded; @@ -393,6 +396,7 @@ impl.AddChildToRoot<VideoLayerImpl>(&provider, media::VIDEO_ROTATION_0); video_layer_impl->SetBounds(layer_size); video_layer_impl->SetDrawsContent(true); + video_layer_impl->set_visible_layer_rect(gfx::Rect(layer_size)); impl.host_impl()->active_tree()->BuildLayerListAndPropertyTreesForTesting(); gfx::Rect occluded; @@ -436,6 +440,7 @@ impl.AddChildToRoot<VideoLayerImpl>(&provider, media::VIDEO_ROTATION_0); video_layer_impl->SetBounds(layer_size); video_layer_impl->SetDrawsContent(true); + video_layer_impl->set_visible_layer_rect(gfx::Rect(layer_size)); impl.host_impl()->active_tree()->BuildLayerListAndPropertyTreesForTesting(); gfx::Rect occluded;
diff --git a/cc/test/layer_test_common.cc b/cc/test/layer_test_common.cc index 58a40c0..a657f266 100644 --- a/cc/test/layer_test_common.cc +++ b/cc/test/layer_test_common.cc
@@ -191,9 +191,10 @@ SimpleEnclosedRegion(occluded), SimpleEnclosedRegion()); layer_impl->draw_properties().occlusion_in_content_space = occlusion; - layer_impl->WillDraw(DRAW_MODE_HARDWARE, resource_provider()); - layer_impl->AppendQuads(render_pass_.get(), &data); - layer_impl->DidDraw(resource_provider()); + if (layer_impl->WillDraw(DRAW_MODE_HARDWARE, resource_provider())) { + layer_impl->AppendQuads(render_pass_.get(), &data); + layer_impl->DidDraw(resource_provider()); + } } void LayerTestCommon::LayerImplTest::AppendQuadsForPassWithOcclusion(
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc index 434e417..0597570 100644 --- a/cc/test/pixel_test.cc +++ b/cc/test/pixel_test.cc
@@ -245,7 +245,8 @@ gpu_service_ = std::make_unique<viz::GpuServiceImpl>( gpu::GPUInfo(), nullptr /* watchdog_thread */, io_thread_->task_runner(), gpu::GpuFeatureInfo(), gpu::GpuPreferences(), gpu::GPUInfo(), - gpu::GpuFeatureInfo(), base::DoNothing() /* exit_callback */); + gpu::GpuFeatureInfo(), nullptr /* vulkan_implementation */, + base::DoNothing() /* exit_callback */); // Uses a null gpu_host here, because we don't want to receive any message. std::unique_ptr<viz::mojom::GpuHost> gpu_host;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index a329a48..308f811 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -1097,13 +1097,9 @@ render_surface->AppendQuads(draw_mode, target_render_pass, &append_quads_data); } - } else if (it.state() == EffectTreeLayerListIterator::State::LAYER && - !it.current_layer()->visible_layer_rect().IsEmpty()) { + } else if (it.state() == EffectTreeLayerListIterator::State::LAYER) { LayerImpl* layer = it.current_layer(); - bool occluded = - layer->draw_properties().occlusion_in_content_space.IsOccluded( - layer->visible_layer_rect()); - if (!occluded && layer->WillDraw(draw_mode, &resource_provider_)) { + if (layer->WillDraw(draw_mode, &resource_provider_)) { DCHECK_EQ(active_tree_.get(), layer->layer_tree_impl()); frame->will_draw_layers.push_back(layer); @@ -2205,6 +2201,8 @@ } void LayerTreeHostImpl::DidDrawAllLayers(const FrameData& frame) { + // TODO(lethalantidote): LayerImpl::DidDraw can be removed when + // VideoLayerImpl is removed. for (size_t i = 0; i < frame.will_draw_layers.size(); ++i) frame.will_draw_layers[i]->DidDraw(&resource_provider_);
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 9cd7cf6..f996663 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -4638,10 +4638,12 @@ bool WillDraw(DrawMode draw_mode, viz::ClientResourceProvider* provider) override { - will_draw_called_ = true; + if (!LayerImpl::WillDraw(draw_mode, provider)) + return false; if (will_draw_returns_false_) return false; - return LayerImpl::WillDraw(draw_mode, provider); + will_draw_returned_true_ = true; + return true; } void AppendQuads(viz::RenderPass* render_pass, @@ -4655,14 +4657,14 @@ LayerImpl::DidDraw(provider); } - bool will_draw_called() const { return will_draw_called_; } + bool will_draw_returned_true() const { return will_draw_returned_true_; } bool append_quads_called() const { return append_quads_called_; } bool did_draw_called() const { return did_draw_called_; } void set_will_draw_returns_false() { will_draw_returns_false_ = true; } void ClearDidDrawCheck() { - will_draw_called_ = false; + will_draw_returned_true_ = false; append_quads_called_ = false; did_draw_called_ = false; } @@ -4676,7 +4678,7 @@ DidDrawCheckLayer(LayerTreeImpl* tree_impl, int id) : LayerImpl(tree_impl, id), will_draw_returns_false_(false), - will_draw_called_(false), + will_draw_returned_true_(false), append_quads_called_(false), did_draw_called_(false) { SetBounds(gfx::Size(10, 10)); @@ -4686,7 +4688,7 @@ private: bool will_draw_returns_false_; - bool will_draw_called_; + bool will_draw_returned_true_; bool append_quads_called_; bool did_draw_called_; }; @@ -4786,7 +4788,7 @@ host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); - EXPECT_TRUE(layer->will_draw_called()); + EXPECT_TRUE(layer->will_draw_returned_true()); EXPECT_TRUE(layer->append_quads_called()); EXPECT_TRUE(layer->did_draw_called()); } @@ -4803,7 +4805,7 @@ host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); - EXPECT_TRUE(layer->will_draw_called()); + EXPECT_FALSE(layer->will_draw_returned_true()); EXPECT_FALSE(layer->append_quads_called()); EXPECT_FALSE(layer->did_draw_called()); } @@ -4829,14 +4831,14 @@ TestFrameData frame; - EXPECT_FALSE(layer->will_draw_called()); + EXPECT_FALSE(layer->will_draw_returned_true()); EXPECT_FALSE(layer->did_draw_called()); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); - EXPECT_FALSE(layer->will_draw_called()); + EXPECT_FALSE(layer->will_draw_returned_true()); EXPECT_FALSE(layer->did_draw_called()); EXPECT_TRUE(layer->visible_layer_rect().IsEmpty()); @@ -4846,14 +4848,14 @@ layer->NoteLayerPropertyChanged(); host_impl_->active_tree()->BuildPropertyTreesForTesting(); - EXPECT_FALSE(layer->will_draw_called()); + EXPECT_FALSE(layer->will_draw_returned_true()); EXPECT_FALSE(layer->did_draw_called()); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); - EXPECT_TRUE(layer->will_draw_called()); + EXPECT_TRUE(layer->will_draw_returned_true()); EXPECT_TRUE(layer->did_draw_called()); EXPECT_FALSE(layer->visible_layer_rect().IsEmpty()); @@ -4886,18 +4888,18 @@ TestFrameData frame; - EXPECT_FALSE(occluded_layer->will_draw_called()); + EXPECT_FALSE(occluded_layer->will_draw_returned_true()); EXPECT_FALSE(occluded_layer->did_draw_called()); - EXPECT_FALSE(top_layer->will_draw_called()); + EXPECT_FALSE(top_layer->will_draw_returned_true()); EXPECT_FALSE(top_layer->did_draw_called()); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); - EXPECT_FALSE(occluded_layer->will_draw_called()); + EXPECT_FALSE(occluded_layer->will_draw_returned_true()); EXPECT_FALSE(occluded_layer->did_draw_called()); - EXPECT_TRUE(top_layer->will_draw_called()); + EXPECT_TRUE(top_layer->will_draw_returned_true()); EXPECT_TRUE(top_layer->did_draw_called()); }
diff --git a/chrome/android/java/res/layout/icon_row_menu_footer.xml b/chrome/android/java/res/layout/icon_row_menu_footer.xml new file mode 100644 index 0000000..2c7f986 --- /dev/null +++ b/chrome/android/java/res/layout/icon_row_menu_footer.xml
@@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2018 The Chromium Authors. All rights reserved. + + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. +--> +<org.chromium.chrome.browser.appmenu.AppMenuIconRowFooter + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" > + + <View style="@style/Divider" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="?android:attr/listPreferredItemHeightSmall" + android:orientation="horizontal" + android:id="@+id/menu_items" > + + <org.chromium.chrome.browser.widget.TintedImageButton + android:id="@+id/forward_menu_id" + style="@style/OverflowMenuButton" + android:src="@drawable/btn_forward" + android:contentDescription="@string/accessibility_menu_forward" /> + + <org.chromium.chrome.browser.widget.TintedImageButton + android:id="@+id/bookmark_this_page_id" + style="@style/OverflowMenuButton" + android:src="@drawable/btn_star" + android:contentDescription="@string/accessibility_menu_bookmark" /> + + <org.chromium.chrome.browser.widget.TintedImageButton + android:id="@+id/offline_page_id" + style="@style/OverflowMenuButton" + android:src="@drawable/ic_file_download_white_24dp" + android:contentDescription="@string/download_page" /> + + <org.chromium.chrome.browser.widget.TintedImageButton + android:id="@+id/info_menu_id" + style="@style/OverflowMenuButton" + android:src="@drawable/btn_info" + android:contentDescription="@string/accessibility_menu_info" /> + + <org.chromium.chrome.browser.widget.TintedImageButton + android:id="@+id/reload_menu_id" + style="@style/OverflowMenuButton" + android:src="@drawable/btn_reload_stop" + android:contentDescription="@string/accessibility_btn_refresh" /> + </LinearLayout> +</org.chromium.chrome.browser.appmenu.AppMenuIconRowFooter>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java index ed85170..dafacd8d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -214,6 +214,7 @@ public static final String GENERIC_SENSOR_EXTRA_CLASSES = "GenericSensorExtraClasses"; public static final String HANDLE_MEDIA_INTENTS = "HandleMediaIntents"; public static final String HOME_PAGE_BUTTON_FORCE_ENABLED = "HomePageButtonForceEnabled"; + public static final String HOMEPAGE_TILE = "HomepageTile"; public static final String HORIZONTAL_TAB_SWITCHER_ANDROID = "HorizontalTabSwitcherAndroid"; public static final String INTEREST_FEED_CONTENT_SUGGESTIONS = "InterestFeedContentSuggestions"; public static final String LANGUAGES_PREFERENCE = "LanguagesPreference";
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 ef9e844..da6a225 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -53,6 +53,8 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.IntentHandler.IntentHandlerDelegate; import org.chromium.chrome.browser.IntentHandler.TabOpenType; +import org.chromium.chrome.browser.appmenu.AppMenu; +import org.chromium.chrome.browser.appmenu.AppMenuIconRowFooter; import org.chromium.chrome.browser.appmenu.AppMenuPropertiesDelegate; import org.chromium.chrome.browser.bookmarks.BookmarkUtils; import org.chromium.chrome.browser.browseractions.BrowserActionsService; @@ -1512,16 +1514,28 @@ @Override public int getFooterResourceId() { + if (FeatureUtilities.isBottomToolbarEnabled()) { + return this.shouldShowPageMenu() ? R.layout.icon_row_menu_footer : 0; + } return showDataSaverFooter() ? R.layout.data_reduction_main_menu_item : 0; } @Override + public void onFooterViewInflated(AppMenu menu, View view) { + if (view instanceof AppMenuIconRowFooter) { + ((AppMenuIconRowFooter) view) + .initialize(ChromeTabbedActivity.this, menu, mBookmarkBridge); + } + } + + @Override public View getHeaderView() { return null; } @Override public boolean shouldShowFooter(int maxMenuHeight) { + if (FeatureUtilities.isBottomToolbarEnabled()) return true; if (showDataSaverFooter()) { return canShowDataReductionItem(maxMenuHeight); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java index 18a6181..af12b47a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
@@ -529,6 +529,8 @@ ViewHighlighter.turnOnHighlight(viewToHighlight, viewToHighlight != mFooterView); } + if (mHandler != null) mHandler.onFooterInflated(mFooterView); + return mFooterView.getMeasuredHeight(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuHandler.java index 60de9ef..55df0064 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuHandler.java
@@ -233,4 +233,12 @@ mObservers.get(i).onMenuVisibilityChanged(isVisible); } } + + /** + * A notification that the footer view has been inflated. + * @param view The inflated view. + */ + void onFooterInflated(View view) { + if (mDelegate != null) mDelegate.onFooterViewInflated(mAppMenu, view); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuIconRowFooter.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuIconRowFooter.java new file mode 100644 index 0000000..72be6c58 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuIconRowFooter.java
@@ -0,0 +1,113 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.appmenu; + +import android.content.Context; +import android.support.v7.content.res.AppCompatResources; +import android.util.AttributeSet; +import android.view.View; +import android.widget.LinearLayout; + +import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.bookmarks.BookmarkBridge; +import org.chromium.chrome.browser.download.DownloadUtils; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.widget.TintedImageButton; + +/** + * A {@link LinearLayout} that displays a horizontal row of icons for page actions. + */ +public class AppMenuIconRowFooter extends LinearLayout implements View.OnClickListener { + private ChromeActivity mActivity; + private AppMenu mAppMenu; + + private TintedImageButton mForwardButton; + private TintedImageButton mBookmarkButton; + private TintedImageButton mDownloadButton; + private TintedImageButton mPageInfoButton; + private TintedImageButton mReloadButton; + + public AppMenuIconRowFooter(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + mForwardButton = (TintedImageButton) findViewById(R.id.forward_menu_id); + mForwardButton.setOnClickListener(this); + + mBookmarkButton = (TintedImageButton) findViewById(R.id.bookmark_this_page_id); + mBookmarkButton.setOnClickListener(this); + + mDownloadButton = (TintedImageButton) findViewById(R.id.offline_page_id); + mDownloadButton.setOnClickListener(this); + + mPageInfoButton = (TintedImageButton) findViewById(R.id.info_menu_id); + mPageInfoButton.setOnClickListener(this); + + mReloadButton = (TintedImageButton) findViewById(R.id.reload_menu_id); + mReloadButton.setOnClickListener(this); + } + + /** + * Initializes the icons, setting enabled state, drawables, and content descriptions. + * @param activity The {@link ChromeActivity} displaying the menu. + * @param appMenu The {@link AppMenu} that contains the icon row. + * @param bookmarkBridge The {@link BookmarkBridge} used to retrieve information about + * bookmarks. + */ + public void initialize( + ChromeActivity activity, AppMenu appMenu, BookmarkBridge bookmarkBridge) { + mActivity = activity; + mAppMenu = appMenu; + Tab currentTab = mActivity.getActivityTab(); + + mForwardButton.setEnabled(currentTab.canGoForward()); + + updateBookmarkMenuItem(bookmarkBridge, currentTab); + + mDownloadButton.setEnabled(DownloadUtils.isAllowedToDownloadPage(currentTab)); + + mReloadButton.setImageResource(R.drawable.btn_reload_stop); + loadingStateChanged(currentTab.isLoading()); + } + + @Override + public void onClick(View v) { + mActivity.onMenuOrKeyboardAction(v.getId(), true); + mAppMenu.dismiss(); + } + + /** + * Called when the current tab's load state has changed. + * @param isLoading Whether the tab is currently loading. + */ + public void loadingStateChanged(boolean isLoading) { + mReloadButton.getDrawable().setLevel(isLoading + ? getResources().getInteger(R.integer.reload_button_level_stop) + : getResources().getInteger(R.integer.reload_button_level_reload)); + mReloadButton.setContentDescription(isLoading + ? mActivity.getString(R.string.accessibility_btn_stop_loading) + : mActivity.getString(R.string.accessibility_btn_refresh)); + } + + private void updateBookmarkMenuItem(BookmarkBridge bookmarkBridge, Tab currentTab) { + mBookmarkButton.setEnabled(bookmarkBridge.isEditBookmarksEnabled()); + + if (currentTab.getBookmarkId() != Tab.INVALID_BOOKMARK_ID) { + mBookmarkButton.setImageResource(R.drawable.btn_star_filled); + mBookmarkButton.setContentDescription(mActivity.getString(R.string.edit_bookmark)); + mBookmarkButton.setTint( + AppCompatResources.getColorStateList(getContext(), R.color.blue_mode_tint)); + } else { + mBookmarkButton.setImageResource(R.drawable.btn_star); + mBookmarkButton.setContentDescription( + mActivity.getString(R.string.accessibility_menu_bookmark)); + } + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java index ff5958d..114d0b4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java
@@ -120,6 +120,10 @@ < DeviceFormFactor.getMinimumTabletWidthPx( mActivity.getWindowAndroid().getDisplay()); + boolean bottomToolbarEnabled = mActivity.getToolbarManager() != null + && mActivity.getToolbarManager().getBottomToolbarCoordinator() != null; + shouldShowIconRow &= !bottomToolbarEnabled; + // Update the icon row items (shown in narrow form factors). menu.findItem(R.id.icon_row_menu_id).setVisible(shouldShowIconRow); if (shouldShowIconRow) { @@ -412,4 +416,11 @@ ? mActivity.getString(R.string.menu_request_desktop_site_on) : mActivity.getString(R.string.menu_request_desktop_site_off)); } + + /** + * A notification that the footer view has finished inflating. + * @param view The view that was inflated. + * @param appMenu The menu the view is inside of. + */ + public void onFooterViewInflated(AppMenu appMenu, View view) {} }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java index 3ccf292..1efac69 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
@@ -8,6 +8,7 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; import android.os.Build; @@ -117,6 +118,7 @@ // Cache objects that should not be created frequently. private final RectF mCacheViewport = new RectF(); private final Rect mCacheRect = new Rect(); + private final Point mCachePoint = new Point(); // If we've drawn at least one frame. private boolean mHasDrawnOnce; @@ -213,7 +215,8 @@ // ViewAndroid that stores the size. View view = getContentView(); if (view != null) { - setSize(getWebContents(), view, getWidthForViewport(), getHeightForViewport()); + Point viewportSize = getViewportSize(); + setSize(getWebContents(), view, viewportSize.x, viewportSize.y); } onViewportChanged(); @@ -243,7 +246,7 @@ handleSystemUiVisibilityChange(); } - private int getWidthForViewport() { + private Point getViewportSize() { // When in fullscreen mode, the window does not get resized when showing the onscreen // keyboard[1]. To work around this, we monitor the visible display frame to mimic the // resize state to ensure the web contents has the correct width and height. @@ -255,26 +258,18 @@ // contents. // // [1] - https://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#FLAG_FULLSCREEN - if (mShowingFullscreenNonVideoContent) { + if (mShowingFullscreenNonVideoContent && UiUtils.isKeyboardShowing(getContext(), this)) { getWindowVisibleDisplayFrame(mCacheRect); // On certain devices, getWindowVisibleDisplayFrame is larger than the screen size, so // this ensures we never draw beyond the underlying dimensions of the view. // https://crbug.com/854109 - return Math.min(mCacheRect.width(), getWidth()); + mCachePoint.set(Math.min(mCacheRect.width(), getWidth()), + Math.min(mCacheRect.height(), getHeight())); } else { - return getWidth(); + mCachePoint.set(getWidth(), getHeight()); } - } - - private int getHeightForViewport() { - // See comment in getWidthForViewport() for an explainer of why this is done. - if (mShowingFullscreenNonVideoContent) { - getWindowVisibleDisplayFrame(mCacheRect); - return Math.min(mCacheRect.height(), getHeight()); - } else { - return getHeight(); - } + return mCachePoint; } private void handleSystemUiVisibilityChange() { @@ -313,8 +308,8 @@ mSystemUiFullscreenResizeRunnable = () -> { View contentView = getContentView(); if (contentView != null) { - setSize(getWebContents(), contentView, getWidthForViewport(), - getHeightForViewport()); + Point viewportSize = getViewportSize(); + setSize(getWebContents(), contentView, viewportSize.x, viewportSize.y); } onViewportChanged(); }; @@ -557,13 +552,12 @@ super.onSizeChanged(w, h, oldw, oldh); if (mTabModelSelector == null) return; - w = getWidthForViewport(); - h = getHeightForViewport(); + Point viewportSize = getViewportSize(); for (TabModel tabModel : mTabModelSelector.getModels()) { for (int i = 0; i < tabModel.getCount(); ++i) { Tab tab = tabModel.getTabAt(i); if (tab == null) continue; - setSize(tab.getWebContents(), tab.getContentView(), w, h); + setSize(tab.getWebContents(), tab.getContentView(), viewportSize.x, viewportSize.y); } } } @@ -646,8 +640,9 @@ public void onBottomControlsHeightChanged(int bottomControlsHeight) { if (mTabVisible == null) return; mTabVisible.setBottomControlsHeight(bottomControlsHeight); - setSize(mTabVisible.getWebContents(), mTabVisible.getContentView(), getWidthForViewport(), - getHeightForViewport()); + Point viewportSize = getViewportSize(); + setSize(mTabVisible.getWebContents(), mTabVisible.getContentView(), viewportSize.x, + viewportSize.y); } @Override @@ -660,7 +655,8 @@ @Override public void onUpdateViewportSize() { // Reflect the changes that may have happened in in view/control size. - setSize(getWebContents(), getContentView(), getWidthForViewport(), getHeightForViewport()); + Point viewportSize = getViewportSize(); + setSize(getWebContents(), getContentView(), viewportSize.x, viewportSize.y); } /** @@ -714,7 +710,8 @@ @Override public void getWindowViewport(RectF outRect) { - outRect.set(0, 0, getWidthForViewport(), getHeightForViewport()); + Point viewportSize = getViewportSize(); + outRect.set(0, 0, viewportSize.x, viewportSize.y); } @Override @@ -1067,8 +1064,9 @@ // size than the ContentViewCore it might think a future size update is a NOOP and not call // onSizeChanged() on the ContentViewCore. if (isAttachedToWindow(view)) return; - int width = getWidthForViewport(); - int height = getHeightForViewport(); + Point viewportSize = getViewportSize(); + int width = viewportSize.x; + int height = viewportSize.y; view.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/ToolbarSwipeLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/ToolbarSwipeLayout.java index 1e67eeb..95c03b5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/ToolbarSwipeLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/ToolbarSwipeLayout.java
@@ -312,22 +312,22 @@ mLeftTab.setX(leftX); needUpdate = mLeftTab.updateSnap(dt) || needUpdate; if (mLeftBottomToolbarSceneLayer != null) { - mLeftBottomToolbarSceneLayer.setIsVisibile(true); + mLeftBottomToolbarSceneLayer.setIsVisible(true); mLeftBottomToolbarSceneLayer.setXOffset((int) (mLeftTab.getX() * mDpToPx)); } } else if (mLeftBottomToolbarSceneLayer != null) { - mLeftBottomToolbarSceneLayer.setIsVisibile(false); + mLeftBottomToolbarSceneLayer.setIsVisible(false); } if (mRightTab != null) { mRightTab.setX(rightX); needUpdate = mRightTab.updateSnap(dt) || needUpdate; if (mRightBottomToolbarSceneLayer != null) { - mRightBottomToolbarSceneLayer.setIsVisibile(true); + mRightBottomToolbarSceneLayer.setIsVisible(true); mRightBottomToolbarSceneLayer.setXOffset((int) (mRightTab.getX() * mDpToPx)); } } else if (mRightBottomToolbarSceneLayer != null) { - mRightBottomToolbarSceneLayer.setIsVisibile(false); + mRightBottomToolbarSceneLayer.setIsVisible(false); } if (needUpdate) requestUpdate();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ScrollingBottomViewSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ScrollingBottomViewSceneLayer.java index 07a1db91..709d7a9c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ScrollingBottomViewSceneLayer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ScrollingBottomViewSceneLayer.java
@@ -40,7 +40,7 @@ private int mCurrentXOffsetPx; /** Whether the {@link SceneLayer}is visible. */ - private boolean mIsVisibile; + private boolean mIsVisible; /** The {@link ViewResourceFrameLayout} that this scene layer represents. */ private ViewResourceFrameLayout mBottomView; @@ -55,7 +55,7 @@ mBottomView = bottomView; mResourceId = mBottomView.getId(); mTopShadowHeightPx = topShadowHeightPx; - mIsVisibile = true; + mIsVisible = true; } /** @@ -86,8 +86,8 @@ /** * @param visible Whether this {@link SceneLayer} is visible. */ - public void setIsVisibile(boolean visible) { - mIsVisibile = visible; + public void setIsVisible(boolean visible) { + mIsVisible = visible; } @Override @@ -119,7 +119,7 @@ @Override public boolean isSceneOverlayTreeShowing() { // If the offset is greater than the toolbar's height, don't draw the layer. - return mIsVisibile && mCurrentYOffsetPx < mBottomView.getHeight() - mTopShadowHeightPx; + return mIsVisible && mCurrentYOffsetPx < mBottomView.getHeight() - mTopShadowHeightPx; } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRankerLogger.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRankerLogger.java index c85aa43..a25c183 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRankerLogger.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRankerLogger.java
@@ -4,57 +4,74 @@ package org.chromium.chrome.browser.contextualsearch; +import android.support.annotation.IntDef; import android.support.annotation.Nullable; import org.chromium.content_public.browser.WebContents; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * An interface for logging to UMA via Ranker. */ public interface ContextualSearchRankerLogger { - // TODO(donnd): consider changing this enum to an IntDef. // NOTE: this list needs to be kept in sync with the white list in // predictor_config_definitions.cc, the names list in ContextualSearchRankerLoggerImpl.java // and with ukm.xml! - enum Feature { - UNKNOWN, + @IntDef({Feature.UNKNOWN, Feature.OUTCOME_WAS_PANEL_OPENED, + Feature.OUTCOME_WAS_QUICK_ACTION_CLICKED, Feature.OUTCOME_WAS_QUICK_ANSWER_SEEN, + Feature.OUTCOME_WAS_CARDS_DATA_SHOWN, Feature.DURATION_AFTER_SCROLL_MS, + Feature.SCREEN_TOP_DPS, Feature.WAS_SCREEN_BOTTOM, + Feature.PREVIOUS_WEEK_IMPRESSIONS_COUNT, Feature.PREVIOUS_WEEK_CTR_PERCENT, + Feature.PREVIOUS_28DAY_IMPRESSIONS_COUNT, Feature.PREVIOUS_28DAY_CTR_PERCENT, + Feature.DID_OPT_IN, Feature.IS_SHORT_WORD, Feature.IS_LONG_WORD, Feature.IS_WORD_EDGE, + Feature.IS_ENTITY, Feature.TAP_DURATION_MS, Feature.FONT_SIZE, + Feature.IS_SECOND_TAP_OVERRIDE, Feature.IS_HTTP, Feature.IS_ENTITY_ELIGIBLE, + Feature.IS_LANGUAGE_MISMATCH, Feature.PORTION_OF_ELEMENT, Feature.TAP_COUNT, + Feature.OPEN_COUNT, Feature.QUICK_ANSWER_COUNT, Feature.ENTITY_IMPRESSIONS_COUNT, + Feature.ENTITY_OPENS_COUNT, Feature.QUICK_ACTION_IMPRESSIONS_COUNT, + Feature.QUICK_ACTIONS_TAKEN_COUNT, Feature.QUICK_ACTIONS_IGNORED_COUNT}) + @Retention(RetentionPolicy.SOURCE) + @interface Feature { + int UNKNOWN = 0; // Outcome labels: - OUTCOME_WAS_PANEL_OPENED, - OUTCOME_WAS_QUICK_ACTION_CLICKED, - OUTCOME_WAS_QUICK_ANSWER_SEEN, - OUTCOME_WAS_CARDS_DATA_SHOWN, // a UKM CS v2 label. - // Features: - DURATION_AFTER_SCROLL_MS, - SCREEN_TOP_DPS, - WAS_SCREEN_BOTTOM, + int OUTCOME_WAS_PANEL_OPENED = 1; + int OUTCOME_WAS_QUICK_ACTION_CLICKED = 2; + int OUTCOME_WAS_QUICK_ANSWER_SEEN = 3; + int OUTCOME_WAS_CARDS_DATA_SHOWN = 4; // a UKM CS v2 label. + // Features: + int DURATION_AFTER_SCROLL_MS = 5; + int SCREEN_TOP_DPS = 6; + int WAS_SCREEN_BOTTOM = 7; // User usage features: - PREVIOUS_WEEK_IMPRESSIONS_COUNT, - PREVIOUS_WEEK_CTR_PERCENT, - PREVIOUS_28DAY_IMPRESSIONS_COUNT, - PREVIOUS_28DAY_CTR_PERCENT, + int PREVIOUS_WEEK_IMPRESSIONS_COUNT = 8; + int PREVIOUS_WEEK_CTR_PERCENT = 9; + int PREVIOUS_28DAY_IMPRESSIONS_COUNT = 10; + int PREVIOUS_28DAY_CTR_PERCENT = 11; // UKM CS v2 features (see go/ukm-cs-2). - DID_OPT_IN, - IS_SHORT_WORD, - IS_LONG_WORD, - IS_WORD_EDGE, - IS_ENTITY, - TAP_DURATION_MS, + int DID_OPT_IN = 12; + int IS_SHORT_WORD = 13; + int IS_LONG_WORD = 14; + int IS_WORD_EDGE = 15; + int IS_ENTITY = 16; + int TAP_DURATION_MS = 17; // UKM CS v3 features (see go/ukm-cs-3). - FONT_SIZE, - IS_SECOND_TAP_OVERRIDE, - IS_HTTP, - IS_ENTITY_ELIGIBLE, - IS_LANGUAGE_MISMATCH, - PORTION_OF_ELEMENT, + int FONT_SIZE = 18; + int IS_SECOND_TAP_OVERRIDE = 19; + int IS_HTTP = 20; + int IS_ENTITY_ELIGIBLE = 21; + int IS_LANGUAGE_MISMATCH = 22; + int PORTION_OF_ELEMENT = 23; // UKM CS v4 features (see go/ukm-cs-4). - TAP_COUNT, - OPEN_COUNT, - QUICK_ANSWER_COUNT, - ENTITY_IMPRESSIONS_COUNT, - ENTITY_OPENS_COUNT, - QUICK_ACTION_IMPRESSIONS_COUNT, - QUICK_ACTIONS_TAKEN_COUNT, - QUICK_ACTIONS_IGNORED_COUNT, + int TAP_COUNT = 24; + int OPEN_COUNT = 25; + int QUICK_ANSWER_COUNT = 26; + int ENTITY_IMPRESSIONS_COUNT = 27; + int ENTITY_OPENS_COUNT = 28; + int QUICK_ACTION_IMPRESSIONS_COUNT = 29; + int QUICK_ACTIONS_TAKEN_COUNT = 30; + int QUICK_ACTIONS_IGNORED_COUNT = 31; } /** @@ -69,7 +86,7 @@ * @param feature The feature to log. * @param value The value to log, which is associated with the given key. */ - void logFeature(Feature feature, Object value); + void logFeature(@Feature int feature, Object value); /** * Returns whether or not AssistRanker query is enabled. @@ -81,7 +98,7 @@ * @param feature The feature to log. * @param value The outcome label value. */ - void logOutcome(Feature feature, Object value); + void logOutcome(@Feature int feature, Object value); /** * Tries to run the machine intelligence model for tap suppression and returns an int that
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRankerLoggerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRankerLoggerImpl.java index ab792cc1..200434b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRankerLoggerImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRankerLoggerImpl.java
@@ -21,13 +21,17 @@ private static final String TAG = "ContextualSearch"; // Names for all our features and labels. - private static final Map<Feature, String> ALL_NAMES; + // Integer values should contain @Feature values only. + private static final Map<Integer, String> ALL_NAMES; @VisibleForTesting - static final Map<Feature, String> OUTCOMES; + // Integer values should contain @Feature values only. + static final Map<Integer, String> OUTCOMES; @VisibleForTesting - static final Map<Feature, String> FEATURES; + // Integer values should contain @Feature values only. + static final Map<Integer, String> FEATURES; static { - Map<Feature, String> outcomes = new HashMap<Feature, String>(); + // Integer values should contain @Feature values only. + Map<Integer, String> outcomes = new HashMap<Integer, String>(); outcomes.put(Feature.OUTCOME_WAS_PANEL_OPENED, "OutcomeWasPanelOpened"); outcomes.put(Feature.OUTCOME_WAS_QUICK_ACTION_CLICKED, "OutcomeWasQuickActionClicked"); outcomes.put(Feature.OUTCOME_WAS_QUICK_ANSWER_SEEN, "OutcomeWasQuickAnswerSeen"); @@ -37,7 +41,8 @@ // NOTE: this list needs to be kept in sync with the white list in // predictor_config_definitions.cc and with ukm.xml! - Map<Feature, String> features = new HashMap<Feature, String>(); + // Integer values should contain @Feature values only. + Map<Integer, String> features = new HashMap<Integer, String>(); features.put(Feature.DURATION_AFTER_SCROLL_MS, "DurationAfterScrollMs"); features.put(Feature.SCREEN_TOP_DPS, "ScreenTopDps"); features.put(Feature.WAS_SCREEN_BOTTOM, "WasScreenBottom"); @@ -70,7 +75,8 @@ features.put(Feature.QUICK_ACTIONS_IGNORED_COUNT, "QuickActionsIgnored"); FEATURES = Collections.unmodifiableMap(features); - Map<Feature, String> allNames = new HashMap<Feature, String>(); + // Integer values should contain @Feature values only. + Map<Integer, String> allNames = new HashMap<Integer, String>(); allNames.putAll(outcomes); allNames.putAll(features); ALL_NAMES = Collections.unmodifiableMap(allNames); @@ -94,11 +100,13 @@ AssistRankerPrediction.UNDETERMINED; // Map that accumulates all of the Features to log for a specific user-interaction. - private Map<Feature, Object> mFeaturesToLog; + // Integer values should contain @Feature values only. + private Map<Integer, Object> mFeaturesToLog; // A for-testing copy of all the features to log setup so that it will survive a {@link #reset}. - private Map<Feature, Object> mFeaturesLoggedForTesting; - private Map<Feature, Object> mOutcomesLoggedForTesting; + // Integer values should contain @Feature values only. + private Map<Integer, Object> mFeaturesLoggedForTesting; + private Map<Integer, Object> mOutcomesLoggedForTesting; /** * Constructs a Ranker Logger and associated native implementation to write Contextual Search @@ -139,7 +147,7 @@ } @Override - public void logFeature(Feature feature, Object value) { + public void logFeature(@Feature int feature, Object value) { assert mIsLoggingReadyForPage : "mIsLoggingReadyForPage false."; assert !mHasInferenceOccurred; if (!isEnabled()) return; @@ -148,7 +156,7 @@ } @Override - public void logOutcome(Feature feature, Object value) { + public void logOutcome(@Feature int feature, Object value) { assert mIsLoggingReadyForPage; assert mHasInferenceOccurred; if (!isEnabled()) return; @@ -163,11 +171,11 @@ mHasInferenceOccurred = true; if (isEnabled() && mBasePageWebContents != null && mFeaturesToLog != null && !mFeaturesToLog.isEmpty()) { - for (Map.Entry<Feature, Object> entry : mFeaturesToLog.entrySet()) { + for (Map.Entry<Integer, Object> entry : mFeaturesToLog.entrySet()) { logObject(entry.getKey(), entry.getValue()); } mFeaturesLoggedForTesting = mFeaturesToLog; - mFeaturesToLog = new HashMap<Feature, Object>(); + mFeaturesToLog = new HashMap<Integer, Object>(); mAssistRankerPrediction = nativeRunInference(mNativePointer); ContextualSearchUma.logRecordedFeaturesToRanker(); } @@ -197,7 +205,7 @@ assert mHasInferenceOccurred; // Only the outcomes will be present, since we logged inference features at // inference time. - for (Map.Entry<Feature, Object> entry : mFeaturesToLog.entrySet()) { + for (Map.Entry<Integer, Object> entry : mFeaturesToLog.entrySet()) { logObject(entry.getKey(), entry.getValue()); } mOutcomesLoggedForTesting = mFeaturesToLog; @@ -214,8 +222,8 @@ * @param feature The feature to log. * @param value The value to log. */ - private void logInternal(Feature feature, Object value) { - if (mFeaturesToLog == null) mFeaturesToLog = new HashMap<Feature, Object>(); + private void logInternal(@Feature int feature, Object value) { + if (mFeaturesToLog == null) mFeaturesToLog = new HashMap<Integer, Object>(); mFeaturesToLog.put(feature, value); } @@ -230,7 +238,7 @@ * @param feature The feature to log. * @param value An {@link Object} value to log (must be convertible to a {@code long}). */ - private void logObject(Feature feature, Object value) { + private void logObject(@Feature int feature, Object value) { if (value instanceof Boolean) { logToNative(feature, ((boolean) value ? 1 : 0)); } else if (value instanceof Integer) { @@ -240,7 +248,8 @@ } else if (value instanceof Character) { logToNative(feature, Character.getNumericValue((char) value)); } else { - assert false : "Could not log feature to Ranker: " + feature.toString() + " of class " + assert false : "Could not log feature to Ranker: " + String.valueOf(feature) + + " of class " + value.getClass(); } } @@ -250,7 +259,7 @@ * @param feature The feature to log. * @param value The value to log. */ - private void logToNative(Feature feature, long value) { + private void logToNative(@Feature int feature, long value) { String featureName = getFeatureName(feature); assert featureName != null : "No Name for feature " + feature; nativeLogLong(mNativePointer, featureName, value); @@ -259,7 +268,7 @@ /** * @return The name of the given feature. */ - private String getFeatureName(Feature feature) { + private String getFeatureName(@Feature int feature) { return ALL_NAMES.get(feature); } @@ -270,7 +279,7 @@ */ @VisibleForTesting @Nullable - Map<Feature, Object> getFeaturesLogged() { + Map<Integer, Object> getFeaturesLogged() { return mFeaturesLoggedForTesting; } @@ -281,7 +290,7 @@ */ @VisibleForTesting @Nullable - Map<Feature, Object> getOutcomesLogged() { + Map<Integer, Object> getOutcomesLogged() { return mOutcomesLoggedForTesting; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java index cad17f4..2f98be01 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java
@@ -338,7 +338,7 @@ String referrer = IntentUtils.safeGetStringExtra(intent, Intent.EXTRA_REFERRER); DownloadManagerService.openDownloadedContent(context, downloadFilename, isSupportedMimeType, isOffTheRecord, contentId.id, id, originalUrl, referrer, - DownloadMetrics.NOTIFICATION); + DownloadMetrics.DownloadOpenSource.NOTIFICATION); } @Nullable
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundService.java index aaac06f..9095f646 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundService.java
@@ -24,6 +24,9 @@ import org.chromium.base.VisibleForTesting; import org.chromium.chrome.browser.AppHooks; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Keep-alive foreground service for downloads. */ @@ -34,15 +37,13 @@ private NotificationManager mNotificationManager; - @IntDef({ - StopForegroundNotification.KILL, // Kill notification regardless of ability to detach. - StopForegroundNotification.DETACH_OR_PERSIST, // Try to detach, otherwise persist info. - StopForegroundNotification.DETACH_OR_ADJUST // Try detach, otherwise kill and relaunch. - }) + @IntDef({StopForegroundNotification.KILL, StopForegroundNotification.DETACH_OR_PERSIST, + StopForegroundNotification.DETACH_OR_ADJUST}) + @Retention(RetentionPolicy.SOURCE) public @interface StopForegroundNotification { - int KILL = 0; - int DETACH_OR_PERSIST = 1; - int DETACH_OR_ADJUST = 2; + int KILL = 0; // Kill notification regardless of ability to detach. + int DETACH_OR_PERSIST = 1; // Try to detach, otherwise persist info. + int DETACH_OR_ADJUST = 2; // Try detach, otherwise kill and relaunch. } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadInfo.java index 0c84aab..ab07ca9d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadInfo.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadInfo.java
@@ -317,22 +317,22 @@ } switch (DownloadFilter.fromMimeType(downloadInfo.getMimeType())) { - case DownloadFilter.FILTER_PAGE: + case DownloadFilter.Type.PAGE: offlineItem.filter = OfflineItemFilter.FILTER_PAGE; break; - case DownloadFilter.FILTER_VIDEO: + case DownloadFilter.Type.VIDEO: offlineItem.filter = OfflineItemFilter.FILTER_VIDEO; break; - case DownloadFilter.FILTER_AUDIO: + case DownloadFilter.Type.AUDIO: offlineItem.filter = OfflineItemFilter.FILTER_AUDIO; break; - case DownloadFilter.FILTER_IMAGE: + case DownloadFilter.Type.IMAGE: offlineItem.filter = OfflineItemFilter.FILTER_IMAGE; break; - case DownloadFilter.FILTER_DOCUMENT: + case DownloadFilter.Type.DOCUMENT: offlineItem.filter = OfflineItemFilter.FILTER_DOCUMENT; break; - case DownloadFilter.FILTER_OTHER: + case DownloadFilter.Type.OTHER: default: offlineItem.filter = OfflineItemFilter.FILTER_OTHER; break;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadInfoBarController.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadInfoBarController.java index 5b7f5ba..d0a9989 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadInfoBarController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadInfoBarController.java
@@ -61,17 +61,24 @@ // Values for the histogram Android.Download.InfoBar.Shown. Keep this in sync with the // DownloadInfoBar.ShownState enum in enums.xml. - private static final int UMA_INFOBAR_SHOWN_ANY_STATE = 0; - private static final int UMA_INFOBAR_SHOWN_ACCELERATED = 1; - private static final int UMA_INFOBAR_SHOWN_DOWNLOADING = 2; - private static final int UMA_INFOBAR_SHOWN_COMPLETE = 3; - private static final int UMA_INFOBAR_SHOWN_FAILED = 4; - private static final int UMA_INFOBAR_SHOWN_PENDING = 5; - private static final int UMA_INFOBAR_SHOWN_MULTIPLE_DOWNLOADING = 6; - private static final int UMA_INFOBAR_SHOWN_MULTIPLE_COMPLETE = 7; - private static final int UMA_INFOBAR_SHOWN_MULTIPLE_FAILED = 8; - private static final int UMA_INFOBAR_SHOWN_MULTIPLE_PENDING = 9; - private static final int UMA_INFOBAR_SHOWN_COUNT = 10; + @IntDef({UmaInfobarShown.ANY_STATE, UmaInfobarShown.ACCELERATED, UmaInfobarShown.DOWNLOADING, + UmaInfobarShown.COMPLETE, UmaInfobarShown.FAILED, UmaInfobarShown.PENDING, + UmaInfobarShown.MULTIPLE_DOWNLOADING, UmaInfobarShown.MULTIPLE_COMPLETE, + UmaInfobarShown.MULTIPLE_FAILED, UmaInfobarShown.MULTIPLE_PENDING}) + @Retention(RetentionPolicy.SOURCE) + private @interface UmaInfobarShown { + int ANY_STATE = 0; + int ACCELERATED = 1; + int DOWNLOADING = 2; + int COMPLETE = 3; + int FAILED = 4; + int PENDING = 5; + int MULTIPLE_DOWNLOADING = 6; + int MULTIPLE_COMPLETE = 7; + int MULTIPLE_FAILED = 8; + int MULTIPLE_PENDING = 9; + int NUM_ENTRIES = 10; + } /** * Represents various UI states that the InfoBar cycles through. @@ -348,14 +355,13 @@ } private boolean isVisibleToUser(OfflineItem offlineItem) { - if (offlineItem.isTransient) return false; - if (offlineItem.isOffTheRecord != mIsIncognito) return false; - if (offlineItem.isSuggested) return false; - if (offlineItem.isDangerous) return false; - if (LegacyHelpers.isLegacyDownload(offlineItem.id)) { - if (TextUtils.isEmpty(offlineItem.filePath)) { - return false; - } + if (offlineItem.isTransient || offlineItem.isOffTheRecord != mIsIncognito + || offlineItem.isSuggested || offlineItem.isDangerous) { + return false; + } + if (LegacyHelpers.isLegacyDownload(offlineItem.id) + && TextUtils.isEmpty(offlineItem.filePath)) { + return false; } return true; @@ -888,8 +894,8 @@ mTrackedItems.remove(itemId); removeNotification(itemId); if (itemId != null) { - DownloadUtils.openItem( - itemId, mIsIncognito, DownloadMetrics.DOWNLOAD_PROGRESS_INFO_BAR); + DownloadUtils.openItem(itemId, mIsIncognito, + DownloadMetrics.DownloadOpenSource.DOWNLOAD_PROGRESS_INFO_BAR); } else { DownloadManagerService.getDownloadManagerService().openDownloadsPage(getContext()); } @@ -914,24 +920,23 @@ int multipleDownloadState = -1; if (state == DownloadInfoBarState.DOWNLOADING) { shownState = mEndTimerRunnable != null - ? UMA_INFOBAR_SHOWN_ACCELERATED - : (info.downloadCount.inProgress == 1 ? UMA_INFOBAR_SHOWN_DOWNLOADING - : UMA_INFOBAR_SHOWN_MULTIPLE_DOWNLOADING); + ? UmaInfobarShown.ACCELERATED + : (info.downloadCount.inProgress == 1 ? UmaInfobarShown.DOWNLOADING + : UmaInfobarShown.MULTIPLE_DOWNLOADING); } else if (state == DownloadInfoBarState.SHOW_RESULT) { switch (info.resultState) { case OfflineItemState.COMPLETE: shownState = info.downloadCount.completed == 1 - ? UMA_INFOBAR_SHOWN_COMPLETE - : UMA_INFOBAR_SHOWN_MULTIPLE_COMPLETE; + ? UmaInfobarShown.COMPLETE + : UmaInfobarShown.MULTIPLE_COMPLETE; break; case OfflineItemState.FAILED: - shownState = info.downloadCount.failed == 1 ? UMA_INFOBAR_SHOWN_FAILED - : UMA_INFOBAR_SHOWN_MULTIPLE_FAILED; + shownState = info.downloadCount.failed == 1 ? UmaInfobarShown.FAILED + : UmaInfobarShown.MULTIPLE_FAILED; break; case OfflineItemState.PENDING: - shownState = info.downloadCount.pending == 1 - ? UMA_INFOBAR_SHOWN_PENDING - : UMA_INFOBAR_SHOWN_MULTIPLE_PENDING; + shownState = info.downloadCount.pending == 1 ? UmaInfobarShown.PENDING + : UmaInfobarShown.MULTIPLE_PENDING; break; default: assert false : "Unexpected state " + info.resultState; @@ -942,12 +947,12 @@ assert shownState != -1 : "Invalid state " + state; RecordHistogram.recordEnumeratedHistogram( - "Android.Download.InfoBar.Shown", shownState, UMA_INFOBAR_SHOWN_COUNT); + "Android.Download.InfoBar.Shown", shownState, UmaInfobarShown.NUM_ENTRIES); RecordHistogram.recordEnumeratedHistogram("Android.Download.InfoBar.Shown", - UMA_INFOBAR_SHOWN_ANY_STATE, UMA_INFOBAR_SHOWN_COUNT); + UmaInfobarShown.ANY_STATE, UmaInfobarShown.NUM_ENTRIES); if (multipleDownloadState != -1) { RecordHistogram.recordEnumeratedHistogram("Android.Download.InfoBar.Shown", - multipleDownloadState, UMA_INFOBAR_SHOWN_COUNT); + multipleDownloadState, UmaInfobarShown.NUM_ENTRIES); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerDelegate.java index aa15cee..9cff4b2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerDelegate.java
@@ -215,18 +215,19 @@ new DownloadManager.Query().setFilterById(mDownloadItem.getSystemDownloadId())); if (c == null) { return new DownloadQueryResult(mDownloadItem, - DownloadManagerService.DOWNLOAD_STATUS_CANCELLED, 0, 0, false, 0); + DownloadManagerService.DownloadStatus.CANCELLED, 0, 0, false, 0); } long bytesDownloaded = 0; boolean canResolve = false; - int downloadStatus = DownloadManagerService.DOWNLOAD_STATUS_IN_PROGRESS; + @DownloadManagerService.DownloadStatus + int downloadStatus = DownloadManagerService.DownloadStatus.IN_PROGRESS; int failureReason = 0; long lastModifiedTime = 0; if (c.moveToNext()) { int statusIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS); int status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS)); if (status == DownloadManager.STATUS_SUCCESSFUL) { - downloadStatus = DownloadManagerService.DOWNLOAD_STATUS_COMPLETE; + downloadStatus = DownloadManagerService.DownloadStatus.COMPLETE; DownloadInfo.Builder builder = mDownloadItem.getDownloadInfo() == null ? new DownloadInfo.Builder() : DownloadInfo.Builder.fromDownloadInfo( @@ -241,7 +242,7 @@ mContext, mDownloadItem, false); } } else if (status == DownloadManager.STATUS_FAILED) { - downloadStatus = DownloadManagerService.DOWNLOAD_STATUS_FAILED; + downloadStatus = DownloadManagerService.DownloadStatus.FAILED; failureReason = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_REASON)); } lastModifiedTime = @@ -249,7 +250,7 @@ bytesDownloaded = c.getLong(c.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)); } else { - downloadStatus = DownloadManagerService.DOWNLOAD_STATUS_CANCELLED; + downloadStatus = DownloadManagerService.DownloadStatus.CANCELLED; } c.close(); long totalTime = Math.max(0, lastModifiedTime - mDownloadItem.getStartTime());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java index e83f185..8efcdee8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -14,6 +14,7 @@ import android.net.NetworkInfo; import android.net.Uri; import android.os.Handler; +import android.support.annotation.IntDef; import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.Pair; @@ -55,6 +56,8 @@ import org.chromium.ui.widget.Toast; import java.io.File; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -80,11 +83,16 @@ DownloadManagerDelegate.EnqueueDownloadRequestCallback, DownloadServiceDelegate, BackendProvider.DownloadDelegate { // Download status. - public static final int DOWNLOAD_STATUS_IN_PROGRESS = 0; - public static final int DOWNLOAD_STATUS_COMPLETE = 1; - public static final int DOWNLOAD_STATUS_FAILED = 2; - public static final int DOWNLOAD_STATUS_CANCELLED = 3; - public static final int DOWNLOAD_STATUS_INTERRUPTED = 4; + @IntDef({DownloadStatus.IN_PROGRESS, DownloadStatus.COMPLETE, DownloadStatus.FAILED, + DownloadStatus.CANCELLED, DownloadStatus.INTERRUPTED}) + @Retention(RetentionPolicy.SOURCE) + public @interface DownloadStatus { + int IN_PROGRESS = 0; + int COMPLETE = 1; + int FAILED = 2; + int CANCELLED = 3; + int INTERRUPTED = 4; + } private static final String TAG = "DownloadService"; private static final String DOWNLOAD_DIRECTORY = "Download"; @@ -102,12 +110,18 @@ "org.chromium.chrome.browser.download.IS_DOWNLOAD_HOME_ENABLED"; // Values for the histogram MobileDownloadResumptionCount. - private static final int UMA_DOWNLOAD_RESUMPTION_MANUAL_PAUSE = 0; - private static final int UMA_DOWNLOAD_RESUMPTION_BROWSER_KILLED = 1; - private static final int UMA_DOWNLOAD_RESUMPTION_CLICKED = 2; - private static final int UMA_DOWNLOAD_RESUMPTION_FAILED = 3; - private static final int UMA_DOWNLOAD_RESUMPTION_AUTO_STARTED = 4; - private static final int UMA_DOWNLOAD_RESUMPTION_COUNT = 5; + @IntDef({UmaDownloadResumption.MANUAL_PAUSE, UmaDownloadResumption.BROWSER_KILLED, + UmaDownloadResumption.CLICKED, UmaDownloadResumption.FAILED, + UmaDownloadResumption.AUTO_STARTED}) + @Retention(RetentionPolicy.SOURCE) + private @interface UmaDownloadResumption { + int MANUAL_PAUSE = 0; + int BROWSER_KILLED = 1; + int CLICKED = 2; + int FAILED = 3; + int AUTO_STARTED = 4; + int NUM_ENTRIES = 5; + } // Set will be more expensive to initialize, so use an ArrayList here. private static final List<String> MIME_TYPES_TO_OPEN = new ArrayList<String>(Arrays.asList( @@ -188,13 +202,14 @@ final long mStartTimeInMillis; boolean mCanDownloadWhileMetered; DownloadItem mDownloadItem; + @DownloadStatus int mDownloadStatus; boolean mIsAutoResumable; boolean mIsUpdated; boolean mIsSupportedMimeType; DownloadProgress(long startTimeInMillis, boolean canDownloadWhileMetered, - DownloadItem downloadItem, int downloadStatus) { + DownloadItem downloadItem, @DownloadStatus int downloadStatus) { mStartTimeInMillis = startTimeInMillis; mCanDownloadWhileMetered = canDownloadWhileMetered; mDownloadItem = downloadItem; @@ -296,9 +311,7 @@ hasChanges = true; } } - if (hasChanges) { - storeUmaEntries(); - } + if (hasChanges) storeUmaEntries(); } /** @@ -319,10 +332,11 @@ @Override public void onDownloadCompleted(final DownloadInfo downloadInfo) { - int status = DOWNLOAD_STATUS_COMPLETE; + @DownloadStatus + int status = DownloadStatus.COMPLETE; String mimeType = downloadInfo.getMimeType(); if (downloadInfo.getBytesReceived() == 0) { - status = DOWNLOAD_STATUS_FAILED; + status = DownloadStatus.FAILED; } else { String origMimeType = mimeType; if (TextUtils.isEmpty(origMimeType)) origMimeType = UNKNOWN_MIME_TYPE; @@ -342,7 +356,7 @@ if (downloadInfo.isPaused()) { removeAutoResumableDownload(item.getId()); } - updateDownloadProgress(item, DOWNLOAD_STATUS_IN_PROGRESS); + updateDownloadProgress(item, DownloadStatus.IN_PROGRESS); scheduleUpdateIfNeeded(); } @@ -350,15 +364,16 @@ public void onDownloadCancelled(final DownloadInfo downloadInfo) { DownloadItem item = new DownloadItem(false, downloadInfo); removeAutoResumableDownload(item.getId()); - updateDownloadProgress(new DownloadItem(false, downloadInfo), DOWNLOAD_STATUS_CANCELLED); + updateDownloadProgress(new DownloadItem(false, downloadInfo), DownloadStatus.CANCELLED); } @Override public void onDownloadInterrupted(final DownloadInfo downloadInfo, boolean isAutoResumable) { - int status = DOWNLOAD_STATUS_INTERRUPTED; + @DownloadStatus + int status = DownloadStatus.INTERRUPTED; DownloadItem item = new DownloadItem(false, downloadInfo); if (!downloadInfo.isResumable()) { - status = DOWNLOAD_STATUS_FAILED; + status = DownloadStatus.FAILED; } else if (isAutoResumable) { addAutoResumableDownload(item.getId()); } @@ -477,30 +492,30 @@ boolean notificationUpdateScheduled = true; boolean removeFromDownloadProgressMap = true; switch (progress.mDownloadStatus) { - case DOWNLOAD_STATUS_COMPLETE: + case DownloadStatus.COMPLETE: notificationUpdateScheduled = updateDownloadSuccessNotification(progress); removeFromDownloadProgressMap = notificationUpdateScheduled; break; - case DOWNLOAD_STATUS_FAILED: + case DownloadStatus.FAILED: // TODO(cmsy): Use correct FailState. mDownloadNotifier.notifyDownloadFailed(info, FailState.CANNOT_DOWNLOAD); Log.w(TAG, "Download failed: " + info.getFilePath()); onDownloadFailed(item, DownloadManager.ERROR_UNKNOWN); break; - case DOWNLOAD_STATUS_IN_PROGRESS: + case DownloadStatus.IN_PROGRESS: if (info.isPaused()) { mDownloadNotifier.notifyDownloadPaused(info); - recordDownloadResumption(UMA_DOWNLOAD_RESUMPTION_MANUAL_PAUSE); + recordDownloadResumption(UmaDownloadResumption.MANUAL_PAUSE); } else { mDownloadNotifier.notifyDownloadProgress( info, progress.mStartTimeInMillis, progress.mCanDownloadWhileMetered); removeFromDownloadProgressMap = false; } break; - case DOWNLOAD_STATUS_CANCELLED: + case DownloadStatus.CANCELLED: mDownloadNotifier.notifyDownloadCanceled(item.getContentId()); break; - case DOWNLOAD_STATUS_INTERRUPTED: + case DownloadStatus.INTERRUPTED: mDownloadNotifier.notifyDownloadInterrupted( info, progress.mIsAutoResumable, PendingState.PENDING_NETWORK); removeFromDownloadProgressMap = !progress.mIsAutoResumable; @@ -509,12 +524,8 @@ assert false; break; } - if (notificationUpdateScheduled) { - progress.mIsUpdated = false; - } - if (removeFromDownloadProgressMap) { - mDownloadProgressMap.remove(item.getId()); - } + if (notificationUpdateScheduled) progress.mIsUpdated = false; + if (removeFromDownloadProgressMap) mDownloadProgressMap.remove(item.getId()); } /** @@ -606,7 +617,7 @@ return; } openDownloadedContent(download.getDownloadInfo(), download.getSystemDownloadId(), - DownloadMetrics.AUTO_OPEN); + DownloadMetrics.DownloadOpenSource.AUTO_OPEN); } /** @@ -644,8 +655,9 @@ * @param downloadItem Information about the download. * @param downloadStatus Status of the download. */ - private void updateDownloadProgress(DownloadItem downloadItem, int downloadStatus) { - boolean isSupportedMimeType = downloadStatus == DOWNLOAD_STATUS_COMPLETE + private void updateDownloadProgress( + DownloadItem downloadItem, @DownloadStatus int downloadStatus) { + boolean isSupportedMimeType = downloadStatus == DownloadStatus.COMPLETE && isSupportedMimeType(downloadItem.getDownloadInfo().getMimeType()); String id = downloadItem.getId(); DownloadProgress progress = mDownloadProgressMap.get(id); @@ -661,17 +673,16 @@ sFirstSeenDownloadIds.add(id); DownloadUmaStatsEntry entry = getUmaStatsEntry(downloadItem.getId()); if (entry == null) { - addUmaStatsEntry(new DownloadUmaStatsEntry( - downloadItem.getId(), startTime, - downloadStatus == DOWNLOAD_STATUS_INTERRUPTED ? 1 : 0, false, false, + addUmaStatsEntry(new DownloadUmaStatsEntry(downloadItem.getId(), startTime, + downloadStatus == DownloadStatus.INTERRUPTED ? 1 : 0, false, false, bytesReceived, 0)); } else if (updateBytesReceived(entry, bytesReceived)) { storeUmaEntries(); } // This is mostly for testing, when the download is not tracked/progress is null but - // downloadStatus is not DOWNLOAD_STATUS_IN_PROGRESS. - if (downloadStatus != DOWNLOAD_STATUS_IN_PROGRESS) { + // downloadStatus is not DownloadStatus.IN_PROGRESS. + if (downloadStatus != DownloadStatus.IN_PROGRESS) { updateNotification(progress); } } @@ -685,9 +696,9 @@ progress.mIsSupportedMimeType = isSupportedMimeType; DownloadUmaStatsEntry entry; switch (downloadStatus) { - case DOWNLOAD_STATUS_COMPLETE: - case DOWNLOAD_STATUS_FAILED: - case DOWNLOAD_STATUS_CANCELLED: + case DownloadStatus.COMPLETE: + case DownloadStatus.FAILED: + case DownloadStatus.CANCELLED: recordDownloadFinishedUMA( downloadStatus, id, downloadItem.getDownloadInfo().getBytesReceived()); clearDownloadRetryCount(id, true); @@ -695,14 +706,14 @@ updateNotification(progress); sFirstSeenDownloadIds.remove(id); break; - case DOWNLOAD_STATUS_INTERRUPTED: + case DownloadStatus.INTERRUPTED: entry = getUmaStatsEntry(id); entry.numInterruptions++; updateBytesReceived(entry, bytesReceived); storeUmaEntries(); updateNotification(progress); break; - case DOWNLOAD_STATUS_IN_PROGRESS: + case DownloadStatus.IN_PROGRESS: entry = getUmaStatsEntry(id); if (entry.isPaused != downloadItem.getDownloadInfo().isPaused() || updateBytesReceived(entry, bytesReceived)) { @@ -761,7 +772,7 @@ if (!result) { onDownloadFailed(downloadItem, failureReason); recordDownloadCompletionStats( - true, DownloadManagerService.DOWNLOAD_STATUS_FAILED, 0, 0, 0, 0); + true, DownloadManagerService.DownloadStatus.FAILED, 0, 0, 0, 0); return; } @@ -956,13 +967,13 @@ @Override public void resumeDownload(ContentId id, DownloadItem item, boolean hasUserGesture) { DownloadProgress progress = mDownloadProgressMap.get(item.getId()); - if (progress != null && progress.mDownloadStatus == DOWNLOAD_STATUS_IN_PROGRESS + if (progress != null && progress.mDownloadStatus == DownloadStatus.IN_PROGRESS && !progress.mDownloadItem.getDownloadInfo().isPaused()) { // Download already in progress, do nothing return; } - int uma = hasUserGesture ? UMA_DOWNLOAD_RESUMPTION_CLICKED - : UMA_DOWNLOAD_RESUMPTION_AUTO_STARTED; + int uma = + hasUserGesture ? UmaDownloadResumption.CLICKED : UmaDownloadResumption.AUTO_STARTED; recordDownloadResumption(uma); if (progress == null) { assert !item.getDownloadInfo().isPaused(); @@ -970,9 +981,9 @@ // download is active. if (!sFirstSeenDownloadIds.contains(item.getId())) { sFirstSeenDownloadIds.add(item.getId()); - recordDownloadResumption(UMA_DOWNLOAD_RESUMPTION_BROWSER_KILLED); + recordDownloadResumption(UmaDownloadResumption.BROWSER_KILLED); } - updateDownloadProgress(item, DOWNLOAD_STATUS_IN_PROGRESS); + updateDownloadProgress(item, DownloadStatus.IN_PROGRESS); progress = mDownloadProgressMap.get(item.getId()); } if (hasUserGesture) { @@ -1016,7 +1027,7 @@ onDownloadCancelled(info); removeDownloadProgress(id.id); } - recordDownloadFinishedUMA(DOWNLOAD_STATUS_CANCELLED, id.id, 0); + recordDownloadFinishedUMA(DownloadStatus.CANCELLED, id.id, 0); } /** @@ -1031,8 +1042,9 @@ // Calling pause will stop listening to the download item. Update its progress now. // If download is already completed, canceled or failed, there is no need to update the // download notification. - if (progress != null && (progress.mDownloadStatus == DOWNLOAD_STATUS_INTERRUPTED - || progress.mDownloadStatus == DOWNLOAD_STATUS_IN_PROGRESS)) { + if (progress != null + && (progress.mDownloadStatus == DownloadStatus.INTERRUPTED + || progress.mDownloadStatus == DownloadStatus.IN_PROGRESS)) { DownloadInfo info = DownloadInfo.Builder.fromDownloadInfo( progress.mDownloadItem.getDownloadInfo()).setIsPaused(true) .setBytesReceived(UNKNOWN_BYTES_RECEIVED).build(); @@ -1107,8 +1119,8 @@ new DownloadInfo.Builder().setDownloadGuid(downloadGuid).build(), FailState.CANNOT_DOWNLOAD); removeDownloadProgress(downloadGuid); - recordDownloadResumption(UMA_DOWNLOAD_RESUMPTION_FAILED); - recordDownloadFinishedUMA(DOWNLOAD_STATUS_FAILED, downloadGuid, 0); + recordDownloadResumption(UmaDownloadResumption.FAILED); + recordDownloadFinishedUMA(DownloadStatus.FAILED, downloadGuid, 0); } /** @@ -1145,10 +1157,9 @@ * Helper method to record the download resumption UMA. * @param type UMA type to be recorded. */ - private void recordDownloadResumption(int type) { - assert type < UMA_DOWNLOAD_RESUMPTION_COUNT && type >= 0; + private void recordDownloadResumption(@UmaDownloadResumption int type) { RecordHistogram.recordEnumeratedHistogram( - "MobileDownload.DownloadResumption", type, UMA_DOWNLOAD_RESUMPTION_COUNT); + "MobileDownload.DownloadResumption", type, UmaDownloadResumption.NUM_ENTRIES); } /** @@ -1162,7 +1173,7 @@ private void recordDownloadCompletionStats(boolean useDownloadManager, int status, long totalDuration, long bytesDownloaded, int numInterruptions, long bytesWasted) { switch (status) { - case DOWNLOAD_STATUS_COMPLETE: + case DownloadStatus.COMPLETE: if (useDownloadManager) { RecordHistogram.recordLongTimesHistogram( "MobileDownload.DownloadTime.DownloadManager.Success", @@ -1184,7 +1195,7 @@ "MobileDownload.BytesWasted.ChromeNetworkStack.Success", bytesWasted); } break; - case DOWNLOAD_STATUS_FAILED: + case DownloadStatus.FAILED: if (useDownloadManager) { RecordHistogram.recordLongTimesHistogram( "MobileDownload.DownloadTime.DownloadManager.Failure", @@ -1206,7 +1217,7 @@ "MobileDownload.BytesWasted.ChromeNetworkStack.Failure", bytesWasted); } break; - case DOWNLOAD_STATUS_CANCELLED: + case DownloadStatus.CANCELLED: if (!useDownloadManager) { RecordHistogram.recordLongTimesHistogram( "MobileDownload.DownloadTime.ChromeNetworkStack.Cancel", @@ -1237,10 +1248,10 @@ @Override public void onQueryCompleted( DownloadManagerDelegate.DownloadQueryResult result, boolean showNotification) { - if (result.downloadStatus == DOWNLOAD_STATUS_IN_PROGRESS) return; + if (result.downloadStatus == DownloadStatus.IN_PROGRESS) return; if (showNotification) { switch (result.downloadStatus) { - case DOWNLOAD_STATUS_COMPLETE: + case DownloadStatus.COMPLETE: if (shouldOpenAfterDownload(result.item.getDownloadInfo()) && result.canResolve) { handleAutoOpenAfterDownload(result.item); @@ -1251,7 +1262,7 @@ result.item.getSystemDownloadId(), result.canResolve, true); } break; - case DOWNLOAD_STATUS_FAILED: + case DownloadStatus.FAILED: onDownloadFailed(result.item, result.failureReason); break; default:
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadMetrics.java index f41aaf4..064daa6e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadMetrics.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadMetrics.java
@@ -22,21 +22,24 @@ // Tracks where the users interact with download files on Android. Used in histogram. // See AndroidDownloadOpenSource in enums.xml. The values used by this enum will be persisted // to server logs and should not be deleted, changed or reused. + @IntDef({DownloadOpenSource.UNKNOWN, DownloadOpenSource.ANDROID_DOWNLOAD_MANAGER, + DownloadOpenSource.DOWNLOAD_HOME, DownloadOpenSource.NOTIFICATION, + DownloadOpenSource.NEW_TAP_PAGE, DownloadOpenSource.INFO_BAR, + DownloadOpenSource.SNACK_BAR, DownloadOpenSource.AUTO_OPEN, + DownloadOpenSource.DOWNLOAD_PROGRESS_INFO_BAR}) @Retention(RetentionPolicy.SOURCE) - @IntDef({UNKNOWN, ANDROID_DOWNLOAD_MANAGER, DOWNLOAD_HOME, NOTIFICATION, NEW_TAP_PAGE, INFO_BAR, - SNACK_BAR, AUTO_OPEN, DOWNLOAD_PROGRESS_INFO_BAR, DOWNLOAD_SOURCE_BOUNDARY}) - public @interface DownloadOpenSource {} - - public static final int UNKNOWN = 0; - public static final int ANDROID_DOWNLOAD_MANAGER = 1; - public static final int DOWNLOAD_HOME = 2; - public static final int NOTIFICATION = 3; - public static final int NEW_TAP_PAGE = 4; - public static final int INFO_BAR = 5; - public static final int SNACK_BAR = 6; - public static final int AUTO_OPEN = 7; - public static final int DOWNLOAD_PROGRESS_INFO_BAR = 8; - private static final int DOWNLOAD_SOURCE_BOUNDARY = 9; + public @interface DownloadOpenSource { + int UNKNOWN = 0; + int ANDROID_DOWNLOAD_MANAGER = 1; + int DOWNLOAD_HOME = 2; + int NOTIFICATION = 3; + int NEW_TAP_PAGE = 4; + int INFO_BAR = 5; + int SNACK_BAR = 6; + int AUTO_OPEN = 7; + int DOWNLOAD_PROGRESS_INFO_BAR = 8; + int NUM_ENTRIES = 9; + } private static final String TAG = "DownloadMetrics"; private static final int MAX_VIEW_RETENTION_MINUTES = 30 * 24 * 60; @@ -52,13 +55,14 @@ return; } + @DownloadFilter.Type int type = DownloadFilter.fromMimeType(mimeType); - if (type == DownloadFilter.FILTER_VIDEO) { - RecordHistogram.recordEnumeratedHistogram( - "Android.DownloadManager.OpenSource.Video", source, DOWNLOAD_SOURCE_BOUNDARY); - } else if (type == DownloadFilter.FILTER_AUDIO) { - RecordHistogram.recordEnumeratedHistogram( - "Android.DownloadManager.OpenSource.Audio", source, DOWNLOAD_SOURCE_BOUNDARY); + if (type == DownloadFilter.Type.VIDEO) { + RecordHistogram.recordEnumeratedHistogram("Android.DownloadManager.OpenSource.Video", + source, DownloadOpenSource.NUM_ENTRIES); + } else if (type == DownloadFilter.Type.AUDIO) { + RecordHistogram.recordEnumeratedHistogram("Android.DownloadManager.OpenSource.Audio", + source, DownloadOpenSource.NUM_ENTRIES); } } @@ -74,14 +78,15 @@ return; } + @DownloadFilter.Type int type = DownloadFilter.fromMimeType(mimeType); int viewRetentionTimeMinutes = (int) ((System.currentTimeMillis() - startTime) / 60000); - if (type == DownloadFilter.FILTER_VIDEO) { + if (type == DownloadFilter.Type.VIDEO) { RecordHistogram.recordCustomCountHistogram( "Android.DownloadManager.ViewRetentionTime.Video", viewRetentionTimeMinutes, 1, MAX_VIEW_RETENTION_MINUTES, 50); - } else if (type == DownloadFilter.FILTER_AUDIO) { + } else if (type == DownloadFilter.Type.AUDIO) { RecordHistogram.recordCustomCountHistogram( "Android.DownloadManager.ViewRetentionTime.Audio", viewRetentionTimeMinutes, 1, MAX_VIEW_RETENTION_MINUTES, 50);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java index 1e4983f..6a6c5a1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
@@ -1279,7 +1279,7 @@ ContentId contentId = DownloadNotificationService.getContentIdFromIntent(intent); DownloadManagerService.openDownloadedContent(context, downloadFilename, isSupportedMimeType, isOffTheRecord, contentId.id, id, originalUrl, referrer, - DownloadMetrics.NOTIFICATION); + DownloadMetrics.DownloadOpenSource.NOTIFICATION); } /** @@ -1321,10 +1321,9 @@ * @return delegate for interactions with the entry */ DownloadServiceDelegate getServiceDelegate(ContentId id) { - if (LegacyHelpers.isLegacyDownload(id)) { - return DownloadManagerService.getDownloadManagerService(); - } - return OfflineContentAggregatorNotificationBridgeUiFactory.instance(); + return LegacyHelpers.isLegacyDownload(id) + ? DownloadManagerService.getDownloadManagerService() + : OfflineContentAggregatorNotificationBridgeUiFactory.instance(); } @VisibleForTesting
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSnackbarController.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSnackbarController.java index 1b569eec..81ae4a5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSnackbarController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSnackbarController.java
@@ -63,7 +63,7 @@ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); } else { manager.openDownloadedContent(download.downloadInfo, download.systemDownloadId, - DownloadMetrics.SNACK_BAR); + DownloadMetrics.DownloadOpenSource.SNACK_BAR); } } else { OfflineContentAggregatorNotificationBridgeUiFactory.instance().openItem(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java index 4e07c63b..4bca328 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
@@ -368,13 +368,13 @@ } if (selectedItemsFilterType != wrappedItem.getFilterType()) { - selectedItemsFilterType = DownloadFilter.FILTER_ALL; + selectedItemsFilterType = DownloadFilter.Type.ALL; } - if (wrappedItem.getFilterType() == DownloadFilter.FILTER_OTHER) { + if (wrappedItem.getFilterType() == DownloadFilter.Type.OTHER) { RecordHistogram.recordEnumeratedHistogram( "Android.DownloadManager.OtherExtensions.Share", wrappedItem.getFileExtensionType(), - DownloadHistoryItemWrapper.FILE_EXTENSION_BOUNDARY); + DownloadHistoryItemWrapper.FileExtension.NUM_ENTRIES); } // If a mime type was not retrieved from the backend or could not be normalized, @@ -639,7 +639,7 @@ return true; } catch (ActivityNotFoundException e) { // Can't launch the Intent. - if (source != DownloadMetrics.DOWNLOAD_PROGRESS_INFO_BAR) { + if (source != DownloadMetrics.DownloadOpenSource.DOWNLOAD_PROGRESS_INFO_BAR) { Toast.makeText(context, context.getString(R.string.download_cant_open_file), Toast.LENGTH_SHORT) .show(); @@ -650,7 +650,7 @@ private static void recordShareHistograms(int count, int filterType) { RecordHistogram.recordEnumeratedHistogram("Android.DownloadManager.Share.FileTypes", - filterType, DownloadFilter.FILTER_BOUNDARY); + filterType, DownloadFilter.Type.NUM_ENTRIES); RecordHistogram.recordLinearCountHistogram("Android.DownloadManager.Share.Count", count, 1, 20, 20); @@ -695,11 +695,9 @@ switch (progress.unit) { case OfflineItemProgressUnit.PERCENTAGE: - if (progress.isIndeterminate()) { - return context.getResources().getString(R.string.download_started); - } else { - return getPercentageString(progress.getPercentage()); - } + return progress.isIndeterminate() + ? context.getResources().getString(R.string.download_started) + : getPercentageString(progress.getPercentage()); case OfflineItemProgressUnit.BYTES: String bytes = getStringForBytes(context, progress.value); if (progress.isIndeterminate()) { @@ -744,11 +742,9 @@ */ public static String getTimeOrFilesLeftString( Context context, Progress progress, long timeRemainingInMillis) { - if (progress.unit == OfflineItemProgressUnit.FILES) { - return formatRemainingFiles(context, progress); - } else { - return formatRemainingTime(context, timeRemainingInMillis); - } + return progress.unit == OfflineItemProgressUnit.FILES + ? formatRemainingFiles(context, progress) + : formatRemainingTime(context, timeRemainingInMillis); } /** @@ -758,11 +754,8 @@ */ public static String formatRemainingFiles(Context context, Progress progress) { int filesLeft = (int) (progress.max - progress.value); - if (filesLeft == 1) { - return context.getResources().getString(R.string.one_file_left); - } else { - return context.getResources().getString(R.string.files_left, filesLeft); - } + return filesLeft == 1 ? context.getResources().getString(R.string.one_file_left) + : context.getResources().getString(R.string.files_left, filesLeft); } /** @@ -836,7 +829,7 @@ case OfflineItemState.INTERRUPTED: // intentional fall through case OfflineItemState.FAILED: break; - case OfflineItemState.MAX_DOWNLOAD_STATE: + // case OfflineItemState.MAX_DOWNLOAD_STATE: default: assert false : "Unexpected OfflineItemState: " + item.state; } @@ -895,20 +888,21 @@ */ public static String getFailStatusString(@FailState int failState) { Context context = ContextUtils.getApplicationContext(); - if (BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER) - .isStartupSuccessfullyCompleted() - && ChromeFeatureList.isEnabled( - ChromeFeatureList.OFFLINE_PAGES_DESCRIPTIVE_FAIL_STATUS)) { - switch (failState) { - // TODO(cmsy): Return correct status for failure reasons once strings are finalized. - case FailState.CANNOT_DOWNLOAD: - case FailState.NETWORK_INSTABILITY: - default: - return context.getString(R.string.download_notification_failed); - } - } else { - return context.getString(R.string.download_notification_failed); - } + + // TODO(cmsy): Return correct status for failure reasons once strings are finalized. + // if (BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER) + // .isStartupSuccessfullyCompleted() + // && ChromeFeatureList.isEnabled( + // ChromeFeatureList.OFFLINE_PAGES_DESCRIPTIVE_FAIL_STATUS)) { + // switch (failState) { + // case FailState.CANNOT_DOWNLOAD: + // case FailState.NETWORK_INSTABILITY: + // default: + // return context.getString(R.string.download_notification_failed); + // } + // } + + return context.getString(R.string.download_notification_failed); } /** @@ -1048,9 +1042,7 @@ public static String getAbbreviatedFileName(String fileName, int limit) { assert limit >= 1; // Abbreviated file name should at least be 1 characters (a...) - if (TextUtils.isEmpty(fileName)) return fileName; - - if (fileName.length() <= limit) return fileName; + if (TextUtils.isEmpty(fileName) || fileName.length() <= limit) return fileName; // Find the file name extension int index = fileName.lastIndexOf("."); @@ -1073,19 +1065,19 @@ public static int getIconResId(int fileType, @IconSize int iconSize) { // TODO(huayinz): Make image view size same as icon size so that 36dp icons can be removed. switch (fileType) { - case DownloadFilter.FILTER_PAGE: + case DownloadFilter.Type.PAGE: return iconSize == ICON_SIZE_24_DP ? R.drawable.ic_globe_24dp : R.drawable.ic_globe_36dp; - case DownloadFilter.FILTER_VIDEO: + case DownloadFilter.Type.VIDEO: return iconSize == ICON_SIZE_24_DP ? R.drawable.ic_videocam_24dp : R.drawable.ic_videocam_36dp; - case DownloadFilter.FILTER_AUDIO: + case DownloadFilter.Type.AUDIO: return iconSize == ICON_SIZE_24_DP ? R.drawable.ic_music_note_24dp : R.drawable.ic_music_note_36dp; - case DownloadFilter.FILTER_IMAGE: + case DownloadFilter.Type.IMAGE: return iconSize == ICON_SIZE_24_DP ? R.drawable.ic_drive_image_24dp : R.drawable.ic_drive_image_36dp; - case DownloadFilter.FILTER_DOCUMENT: + case DownloadFilter.Type.DOCUMENT: return iconSize == ICON_SIZE_24_DP ? R.drawable.ic_drive_document_24dp : R.drawable.ic_drive_document_36dp; default: @@ -1156,7 +1148,6 @@ } if (primaryDir == null || path == null) return false; String primaryPath = primaryDir.getAbsolutePath(); - if (primaryPath == null) return false; - return path.contains(primaryPath); + return primaryPath == null ? false : path.contains(primaryPath); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java index 84aa906..a177f259 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java
@@ -294,7 +294,8 @@ manager.remove(mDownloadId); mFreeSpace = Environment.getExternalStorageDirectory().getUsableSpace(); DownloadMetrics.recordDownloadOpen( - DownloadMetrics.ANDROID_DOWNLOAD_MANAGER, mDownloadInfo.getMimeType()); + DownloadMetrics.DownloadOpenSource.ANDROID_DOWNLOAD_MANAGER, + mDownloadInfo.getMimeType()); return omaInfo; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java b/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java index 2d4bf9d2..896f446 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java
@@ -9,6 +9,7 @@ import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; +import android.support.annotation.IntDef; import org.chromium.base.Log; import org.chromium.base.ThreadUtils; @@ -18,6 +19,8 @@ import org.chromium.components.offline_items_collection.FailState; import org.chromium.components.offline_items_collection.PendingState; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; @@ -32,14 +35,22 @@ */ public class SystemDownloadNotifier implements DownloadNotifier, Observer { private static final String TAG = "DownloadNotifier"; - private static final int DOWNLOAD_NOTIFICATION_TYPE_PROGRESS = 0; - private static final int DOWNLOAD_NOTIFICATION_TYPE_SUCCESS = 1; - private static final int DOWNLOAD_NOTIFICATION_TYPE_FAILURE = 2; - private static final int DOWNLOAD_NOTIFICATION_TYPE_CANCEL = 3; - private static final int DOWNLOAD_NOTIFICATION_TYPE_RESUME_ALL = 4; - private static final int DOWNLOAD_NOTIFICATION_TYPE_PAUSE = 5; - private static final int DOWNLOAD_NOTIFICATION_TYPE_INTERRUPT = 6; - private static final int DOWNLOAD_NOTIFICATION_TYPE_REMOVE_NOTIFICATION = 7; + + @IntDef({DownloadNotificationType.PROGRESS, DownloadNotificationType.SUCCESS, + DownloadNotificationType.FAILURE, DownloadNotificationType.CANCEL, + DownloadNotificationType.RESUME_ALL, DownloadNotificationType.PAUSE, + DownloadNotificationType.INTERRUPT, DownloadNotificationType.REMOVE_NOTIFICATION}) + @Retention(RetentionPolicy.SOURCE) + private @interface DownloadNotificationType { + int PROGRESS = 0; + int SUCCESS = 1; + int FAILURE = 2; + int CANCEL = 3; + int RESUME_ALL = 4; + int PAUSE = 5; + int INTERRUPT = 6; + int REMOVE_NOTIFICATION = 7; + } private final Context mApplicationContext; @@ -171,14 +182,14 @@ public void notifyDownloadCanceled(ContentId id) { DownloadInfo downloadInfo = new DownloadInfo.Builder().setContentId(id).build(); updateDownloadNotification( - new PendingNotificationInfo(DOWNLOAD_NOTIFICATION_TYPE_CANCEL, downloadInfo), true); + new PendingNotificationInfo(DownloadNotificationType.CANCEL, downloadInfo), true); } @Override public void notifyDownloadSuccessful(DownloadInfo downloadInfo, long systemDownloadId, boolean canResolve, boolean isSupportedMimeType) { PendingNotificationInfo info = - new PendingNotificationInfo(DOWNLOAD_NOTIFICATION_TYPE_SUCCESS, downloadInfo); + new PendingNotificationInfo(DownloadNotificationType.SUCCESS, downloadInfo); info.canResolve = canResolve; info.systemDownloadId = systemDownloadId; info.isSupportedMimeType = isSupportedMimeType; @@ -188,15 +199,14 @@ @Override public void notifyDownloadFailed(DownloadInfo downloadInfo, @FailState int notUsed) { updateDownloadNotification( - new PendingNotificationInfo(DOWNLOAD_NOTIFICATION_TYPE_FAILURE, downloadInfo), - true); + new PendingNotificationInfo(DownloadNotificationType.FAILURE, downloadInfo), true); } @Override public void notifyDownloadProgress( DownloadInfo downloadInfo, long startTime, boolean canDownloadWhileMetered) { PendingNotificationInfo info = - new PendingNotificationInfo(DOWNLOAD_NOTIFICATION_TYPE_PROGRESS, downloadInfo); + new PendingNotificationInfo(DownloadNotificationType.PROGRESS, downloadInfo); info.startTime = startTime; info.canDownloadWhileMetered = canDownloadWhileMetered; updateDownloadNotification(info, true); @@ -205,7 +215,7 @@ @Override public void notifyDownloadPaused(DownloadInfo downloadInfo) { PendingNotificationInfo info = - new PendingNotificationInfo(DOWNLOAD_NOTIFICATION_TYPE_PAUSE, downloadInfo); + new PendingNotificationInfo(DownloadNotificationType.PAUSE, downloadInfo); updateDownloadNotification(info, true); } @@ -213,7 +223,7 @@ public void notifyDownloadInterrupted( DownloadInfo downloadInfo, boolean isAutoResumable, @PendingState int notUsed) { PendingNotificationInfo info = - new PendingNotificationInfo(DOWNLOAD_NOTIFICATION_TYPE_INTERRUPT, downloadInfo); + new PendingNotificationInfo(DownloadNotificationType.INTERRUPT, downloadInfo); info.isAutoResumable = isAutoResumable; updateDownloadNotification(info, true); } @@ -221,7 +231,7 @@ @Override public void removeDownloadNotification(int notificationId, DownloadInfo downloadInfo) { PendingNotificationInfo info = new PendingNotificationInfo( - DOWNLOAD_NOTIFICATION_TYPE_REMOVE_NOTIFICATION, downloadInfo); + DownloadNotificationType.REMOVE_NOTIFICATION, downloadInfo); info.notificationId = notificationId; updateDownloadNotification(info, true); } @@ -230,7 +240,7 @@ public void resumePendingDownloads() { if (!DownloadNotificationService.isTrackingResumableDownloads(mApplicationContext)) return; updateDownloadNotification( - new PendingNotificationInfo(DOWNLOAD_NOTIFICATION_TYPE_RESUME_ALL, null), true); + new PendingNotificationInfo(DownloadNotificationType.RESUME_ALL, null), true); } /** @@ -278,30 +288,30 @@ } DownloadInfo info = notificationInfo.downloadInfo; - if (notificationInfo.type == DOWNLOAD_NOTIFICATION_TYPE_PROGRESS) { + if (notificationInfo.type == DownloadNotificationType.PROGRESS) { mActiveDownloads.add(info.getDownloadGuid()); - } else if (notificationInfo.type != DOWNLOAD_NOTIFICATION_TYPE_RESUME_ALL) { + } else if (notificationInfo.type != DownloadNotificationType.RESUME_ALL) { mActiveDownloads.remove(info.getDownloadGuid()); } switch (notificationInfo.type) { - case DOWNLOAD_NOTIFICATION_TYPE_PROGRESS: + case DownloadNotificationType.PROGRESS: mBoundService.notifyDownloadProgress(info.getContentId(), info.getFileName(), info.getProgress(), info.getBytesReceived(), info.getTimeRemainingInMillis(), notificationInfo.startTime, info.isOffTheRecord(), notificationInfo.canDownloadWhileMetered, info.getIsTransient(), info.getIcon()); break; - case DOWNLOAD_NOTIFICATION_TYPE_PAUSE: + case DownloadNotificationType.PAUSE: mBoundService.notifyDownloadPaused(info.getContentId(), info.getFileName(), true, false, info.isOffTheRecord(), info.getIsTransient(), info.getIcon()); break; - case DOWNLOAD_NOTIFICATION_TYPE_INTERRUPT: + case DownloadNotificationType.INTERRUPT: mBoundService.notifyDownloadPaused(info.getContentId(), info.getFileName(), info.isResumable(), notificationInfo.isAutoResumable, info.isOffTheRecord(), info.getIsTransient(), info.getIcon()); break; - case DOWNLOAD_NOTIFICATION_TYPE_SUCCESS: + case DownloadNotificationType.SUCCESS: final int notificationId = mBoundService.notifyDownloadSuccessful( info.getContentId(), info.getFilePath(), info.getFileName(), notificationInfo.systemDownloadId, info.isOffTheRecord(), @@ -309,17 +319,17 @@ info.getOriginalUrl(), info.getReferrer()); onSuccessNotificationShown(notificationInfo, notificationId); break; - case DOWNLOAD_NOTIFICATION_TYPE_FAILURE: + case DownloadNotificationType.FAILURE: mBoundService.notifyDownloadFailed( info.getContentId(), info.getFileName(), info.getIcon()); break; - case DOWNLOAD_NOTIFICATION_TYPE_CANCEL: + case DownloadNotificationType.CANCEL: mBoundService.notifyDownloadCanceled(info.getContentId()); break; - case DOWNLOAD_NOTIFICATION_TYPE_RESUME_ALL: + case DownloadNotificationType.RESUME_ALL: mBoundService.resumeAllPendingDownloads(); break; - case DOWNLOAD_NOTIFICATION_TYPE_REMOVE_NOTIFICATION: + case DownloadNotificationType.REMOVE_NOTIFICATION: mBoundService.cancelNotification( notificationInfo.notificationId, info.getContentId()); break;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerCoordinatorImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerCoordinatorImpl.java index a3de2cd4..263ed23 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerCoordinatorImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerCoordinatorImpl.java
@@ -65,7 +65,7 @@ @Override public void showPrefetchSection() { - updateForUrl(Filters.toUrl(Filters.PREFETCHED)); + updateForUrl(Filters.toUrl(Filters.FilterType.PREFETCHED)); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterChipsProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterChipsProvider.java index e7258f55..0dfe5282 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterChipsProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterChipsProvider.java
@@ -44,24 +44,25 @@ mDelegate = delegate; mSource = source; - Chip noneChip = new Chip(Filters.NONE, R.string.download_manager_ui_all_downloads, - R.string.download_manager_ui_all_downloads, Chip.INVALID_ICON_ID, - () -> onChipSelected(Filters.NONE)); - Chip videosChip = new Chip(Filters.VIDEOS, R.string.download_manager_ui_video, + Chip noneChip = + new Chip(Filters.FilterType.NONE, R.string.download_manager_ui_all_downloads, + R.string.download_manager_ui_all_downloads, Chip.INVALID_ICON_ID, + () -> onChipSelected(Filters.FilterType.NONE)); + Chip videosChip = new Chip(Filters.FilterType.VIDEOS, R.string.download_manager_ui_video, R.string.download_manager_ui_video, R.drawable.ic_videocam_24dp, - () -> onChipSelected(Filters.VIDEOS)); - Chip musicChip = new Chip(Filters.MUSIC, R.string.download_manager_ui_audio, + () -> onChipSelected(Filters.FilterType.VIDEOS)); + Chip musicChip = new Chip(Filters.FilterType.MUSIC, R.string.download_manager_ui_audio, R.string.download_manager_ui_audio, R.drawable.ic_music_note_24dp, - () -> onChipSelected(Filters.MUSIC)); - Chip imagesChip = new Chip(Filters.IMAGES, R.string.download_manager_ui_images, + () -> onChipSelected(Filters.FilterType.MUSIC)); + Chip imagesChip = new Chip(Filters.FilterType.IMAGES, R.string.download_manager_ui_images, R.string.download_manager_ui_images, R.drawable.ic_drive_image_24dp, - () -> onChipSelected(Filters.IMAGES)); - Chip sitesChip = new Chip(Filters.SITES, R.string.download_manager_ui_pages, + () -> onChipSelected(Filters.FilterType.IMAGES)); + Chip sitesChip = new Chip(Filters.FilterType.SITES, R.string.download_manager_ui_pages, R.string.download_manager_ui_pages, R.drawable.ic_globe_24dp, - () -> onChipSelected(Filters.SITES)); - Chip otherChip = new Chip(Filters.OTHER, R.string.download_manager_ui_other, + () -> onChipSelected(Filters.FilterType.SITES)); + Chip otherChip = new Chip(Filters.FilterType.OTHER, R.string.download_manager_ui_other, R.string.download_manager_ui_other, R.drawable.ic_drive_file_24dp, - () -> onChipSelected(Filters.OTHER)); + () -> onChipSelected(Filters.FilterType.OTHER)); // By default select the none chip. noneChip.selected = true; @@ -119,7 +120,7 @@ if (chip.selected) return chip.id; } - return Filters.NONE; + return Filters.FilterType.NONE; } // ChipsProvider implementation. @@ -159,7 +160,7 @@ private void generateFilterStates() { // Build a set of all filter types in our data set. Set</* @FilterType */ Integer> filters = new HashSet<>(); - filters.add(Filters.NONE); + filters.add(Filters.FilterType.NONE); for (OfflineItem item : mSource.getItems()) { filters.add(Filters.fromOfflineItem(item.filter)); } @@ -170,7 +171,7 @@ // Validate that selection is on a valid type. for (Chip chip : mSortedChips) { if (chip.selected && !chip.enabled) { - onChipSelected(Filters.NONE); + onChipSelected(Filters.FilterType.NONE); break; } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterCoordinator.java index 4b17c42d..af04186 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterCoordinator.java
@@ -18,11 +18,12 @@ /** A Coordinator responsible for showing the tab filter selection UI for downloads home. */ public class FilterCoordinator { + @IntDef({TabType.FILES, TabType.PREFETCH}) @Retention(RetentionPolicy.SOURCE) - @IntDef({TAB_FILES, TAB_PREFETCH}) - public @interface TabType {} - public static final int TAB_FILES = 0; - public static final int TAB_PREFETCH = 1; + public @interface TabType { + int FILES = 0; + int PREFETCH = 1; + } /** An Observer to notify when the selected tab has changed. */ public interface Observer { @@ -52,7 +53,7 @@ mModel.addObserver(new PropertyModelChangeProcessor<>(mModel, mView, mViewBinder)); mModel.setChangeListener(selectedTab -> handleTabSelected(selectedTab)); - selectTab(TAB_FILES); + selectTab(TabType.FILES); } /** @return The {@link View} representing this widget. */ @@ -75,20 +76,20 @@ * components might need to update the UI state. */ public void setSelectedFilter(@FilterType int filter) { - if (filter == Filters.PREFETCHED) { - selectTab(TAB_PREFETCH); + if (filter == Filters.FilterType.PREFETCHED) { + selectTab(TabType.PREFETCH); } else { mChipsProvider.setFilterSelected(filter); - selectTab(TAB_FILES); + selectTab(TabType.FILES); } } private void selectTab(@TabType int selectedTab) { mModel.setSelectedTab(selectedTab); - if (selectedTab == TAB_FILES) { + if (selectedTab == TabType.FILES) { mModel.setContentView(mChipsCoordinator.getView()); - } else if (selectedTab == TAB_PREFETCH) { + } else if (selectedTab == TabType.PREFETCH) { mModel.setContentView(null); } } @@ -98,10 +99,10 @@ @FilterType int filterType; - if (selectedTab == TAB_FILES) { + if (selectedTab == TabType.FILES) { filterType = mChipsProvider.getSelectedFilter(); } else { - filterType = Filters.PREFETCHED; + filterType = Filters.FilterType.PREFETCHED; } for (Observer observer : mObserverList) observer.onFilterChanged(filterType);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterModel.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterModel.java index 26a0c73..42c90cda4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterModel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterModel.java
@@ -19,8 +19,6 @@ static final PropertyKey CONTENT_VIEW = new PropertyKey(); static final PropertyKey SELECTED_TAB = new PropertyKey(); static final PropertyKey CHANGE_LISTENER = new PropertyKey(); - - private PropertyKey() {} } private View mContentView;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterView.java index 76cd2da7..28f2673 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterView.java
@@ -47,8 +47,8 @@ if (mTabSelectedCallback == null) return; @TabType - int tabType = tab.getPosition() == 0 ? FilterCoordinator.TAB_FILES - : FilterCoordinator.TAB_PREFETCH; + int tabType = tab.getPosition() == 0 ? FilterCoordinator.TabType.FILES + : FilterCoordinator.TabType.PREFETCH; mTabSelectedCallback.onResult(tabType); } }); @@ -70,7 +70,7 @@ /** Sets which of the two tabs are selected based on {code selectedType}. */ public void setTabSelected(@TabType int selectedType) { - int selectedIndex = selectedType == FilterCoordinator.TAB_FILES ? 0 : 1; + int selectedIndex = selectedType == FilterCoordinator.TabType.FILES ? 0 : 1; if (mTabsView.getSelectedTabPosition() == selectedIndex) return; mTabsView.getTabAt(selectedIndex).select(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/Filters.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/Filters.java index 08b63d6..7c2e955 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/Filters.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/Filters.java
@@ -17,17 +17,19 @@ /** Helper containing a list of Downloads Home filter types and conversion methods. */ public class Filters { /** A list of possible filter types on offlined items. */ + @IntDef({FilterType.NONE, FilterType.VIDEOS, FilterType.MUSIC, FilterType.IMAGES, + FilterType.SITES, FilterType.OTHER, FilterType.PREFETCHED}) @Retention(RetentionPolicy.SOURCE) - @IntDef({NONE, VIDEOS, MUSIC, IMAGES, SITES, OTHER, PREFETCHED}) - public @interface FilterType {} - public static final int NONE = 0; - public static final int VIDEOS = 1; - public static final int MUSIC = 2; - public static final int IMAGES = 3; - public static final int SITES = 4; - public static final int OTHER = 5; - public static final int PREFETCHED = 6; - public static final int FILTER_BOUNDARY = 7; + public @interface FilterType { + int NONE = 0; + int VIDEOS = 1; + int MUSIC = 2; + int IMAGES = 3; + int SITES = 4; + int OTHER = 5; + int PREFETCHED = 6; + int NUM_ENTRIES = 7; + } /** * Converts from a {@link OfflineItem#filter} to a {@link FilterType}. Note that not all @@ -40,17 +42,17 @@ public static @FilterType int fromOfflineItem(@OfflineItemFilter int filter) { switch (filter) { case OfflineItemFilter.FILTER_PAGE: - return SITES; + return FilterType.SITES; case OfflineItemFilter.FILTER_VIDEO: - return VIDEOS; + return FilterType.VIDEOS; case OfflineItemFilter.FILTER_AUDIO: - return MUSIC; + return FilterType.MUSIC; case OfflineItemFilter.FILTER_IMAGE: - return IMAGES; - case OfflineItemFilter.FILTER_OTHER: - case OfflineItemFilter.FILTER_DOCUMENT: + return FilterType.IMAGES; + // case OfflineItemFilter.FILTER_OTHER + // case OfflineItemFilter.FILTER_DOCUMENT default: - return OTHER; + return FilterType.OTHER; } } @@ -59,18 +61,18 @@ @OfflineItemFilter int filter) { switch (filter) { case OfflineItemFilter.FILTER_PAGE: - return DownloadFilter.FILTER_PAGE; + return DownloadFilter.Type.PAGE; case OfflineItemFilter.FILTER_VIDEO: - return DownloadFilter.FILTER_VIDEO; + return DownloadFilter.Type.VIDEO; case OfflineItemFilter.FILTER_AUDIO: - return DownloadFilter.FILTER_AUDIO; + return DownloadFilter.Type.AUDIO; case OfflineItemFilter.FILTER_IMAGE: - return DownloadFilter.FILTER_IMAGE; + return DownloadFilter.Type.IMAGE; case OfflineItemFilter.FILTER_DOCUMENT: - return DownloadFilter.FILTER_DOCUMENT; - case OfflineItemFilter.FILTER_OTHER: + return DownloadFilter.Type.DOCUMENT; + // case OfflineItemFilter.FILTER_OTHER default: - return DownloadFilter.FILTER_OTHER; + return DownloadFilter.Type.OTHER; } } @@ -79,8 +81,8 @@ * @see DownloadFilter#getUrlForFilter(int) */ public static String toUrl(@FilterType int filter) { - if (filter == NONE) return UrlConstants.DOWNLOADS_URL; - return UrlConstants.DOWNLOADS_FILTER_URL + filter; + return filter == FilterType.NONE ? UrlConstants.DOWNLOADS_URL + : UrlConstants.DOWNLOADS_FILTER_URL + filter; } /** @@ -88,19 +90,18 @@ * @see DownloadFilter#getFilterFromUrl(String) */ public static @FilterType int fromUrl(String url) { - if (TextUtils.isEmpty(url)) return NONE; - if (!url.startsWith(UrlConstants.DOWNLOADS_FILTER_URL)) return NONE; + if (TextUtils.isEmpty(url) || !url.startsWith(UrlConstants.DOWNLOADS_FILTER_URL)) { + return FilterType.NONE; + } @FilterType - int filter = NONE; + int filter = FilterType.NONE; try { filter = Integer.parseInt(url.substring(UrlConstants.DOWNLOADS_FILTER_URL.length())); - if (filter < 0 || filter >= FILTER_BOUNDARY) filter = NONE; + if (filter < 0 || filter >= FilterType.NUM_ENTRIES) filter = FilterType.NONE; } catch (NumberFormatException ex) { } return filter; } - - private Filters() {} } \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/TypeOfflineItemFilter.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/TypeOfflineItemFilter.java index 0c41c92..402a772 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/TypeOfflineItemFilter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/TypeOfflineItemFilter.java
@@ -12,7 +12,7 @@ * {@link OfflineItem#filter} and {@link FilterType}. */ public class TypeOfflineItemFilter extends OfflineItemFilter { - private @FilterType int mFilter = Filters.NONE; + private @FilterType int mFilter = Filters.FilterType.NONE; /** Creates an instance of this filter and wraps {@code source}. */ public TypeOfflineItemFilter(OfflineItemFilterSource source) { @@ -28,14 +28,12 @@ // OfflineItemFilter implementation. @Override protected boolean isFilteredOut(OfflineItem item) { + @FilterType int requiredFilter = Filters.fromOfflineItem(item.filter); // Filter out based on prefetch suggestions before resorting to other types. - if (mFilter == Filters.PREFETCHED) return !item.isSuggested; - if (item.isSuggested) return mFilter != Filters.PREFETCHED; - if (mFilter == Filters.NONE) return false; - if (mFilter == requiredFilter) return false; - - return true; + if (mFilter == Filters.FilterType.PREFETCHED) return !item.isSuggested; + if (item.isSuggested) return mFilter != Filters.FilterType.PREFETCHED; + return !(mFilter == Filters.FilterType.NONE || mFilter == requiredFilter); } } \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/DownloadGlue.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/DownloadGlue.java index 455e5452..28e34f8e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/DownloadGlue.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/DownloadGlue.java
@@ -99,7 +99,7 @@ public void openItem(OfflineItem item) { // TODO(shaktisahu): May be pass metrics as a param. DownloadManagerService.getDownloadManagerService().openDownload( - item.id, item.isOffTheRecord, DownloadMetrics.DOWNLOAD_HOME); + item.id, item.isOffTheRecord, DownloadMetrics.DownloadOpenSource.DOWNLOAD_HOME); } /** @see OfflineContentProvider#removeItem(ContentId) */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListView.java index fc6a429..e6485a8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListView.java
@@ -129,13 +129,13 @@ if (position < 0 || position >= mModel.size()) return; switch (ListUtils.getViewTypeForItem(mModel.get(position))) { - case ListUtils.IMAGE: + case ListUtils.ViewType.IMAGE: outRect.left = mImagePaddingPx; outRect.right = mImagePaddingPx; outRect.top = mImagePaddingPx; outRect.bottom = mImagePaddingPx; break; - case ListUtils.PREFETCH: + case ListUtils.ViewType.PREFETCH: outRect.left = mPrefetchHorizontalPaddingPx; outRect.right = mPrefetchHorizontalPaddingPx; outRect.top = mPrefetchVerticalPaddingPx / 2;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListItemViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListItemViewHolder.java index 043da8b..62ad781 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListItemViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListItemViewHolder.java
@@ -51,19 +51,19 @@ */ public static ListItemViewHolder create(ViewGroup parent, @ListUtils.ViewType int viewType) { switch (viewType) { - case ListUtils.DATE: + case ListUtils.ViewType.DATE: return DateViewHolder.create(parent); - case ListUtils.IN_PROGRESS: + case ListUtils.ViewType.IN_PROGRESS: return new InProgressViewHolder(parent); - case ListUtils.GENERIC: + case ListUtils.ViewType.GENERIC: return GenericViewHolder.create(parent); - case ListUtils.VIDEO: + case ListUtils.ViewType.VIDEO: return new VideoViewHolder(parent); - case ListUtils.IMAGE: + case ListUtils.ViewType.IMAGE: return new ImageViewHolder(parent); - case ListUtils.CUSTOM_VIEW: + case ListUtils.ViewType.CUSTOM_VIEW: return new CustomViewHolder(parent); - case ListUtils.PREFETCH: + case ListUtils.ViewType.PREFETCH: return PrefetchViewHolder.create(parent); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListUtils.java index 915c11a..1d6ac3d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListUtils.java
@@ -18,16 +18,18 @@ /** Utility methods for representing {@link ListItem}s in a {@link RecyclerView} list. */ class ListUtils { /** The potential types of list items that could be displayed. */ + @IntDef({ViewType.DATE, ViewType.IN_PROGRESS, ViewType.GENERIC, ViewType.VIDEO, ViewType.IMAGE, + ViewType.CUSTOM_VIEW, ViewType.PREFETCH}) @Retention(RetentionPolicy.SOURCE) - @IntDef({DATE, IN_PROGRESS, GENERIC, VIDEO, IMAGE, CUSTOM_VIEW, PREFETCH}) - public @interface ViewType {} - public static final int DATE = 0; - public static final int IN_PROGRESS = 1; - public static final int GENERIC = 2; - public static final int VIDEO = 3; - public static final int IMAGE = 4; - public static final int CUSTOM_VIEW = 5; - public static final int PREFETCH = 6; + public @interface ViewType { + int DATE = 0; + int IN_PROGRESS = 1; + int GENERIC = 2; + int VIDEO = 3; + int IMAGE = 4; + int CUSTOM_VIEW = 5; + int PREFETCH = 6; + } private ListUtils() {} @@ -39,35 +41,35 @@ * @see ViewType */ public static @ViewType int getViewTypeForItem(ListItem item) { - if (item instanceof ViewListItem) return ListUtils.CUSTOM_VIEW; + if (item instanceof ViewListItem) return ViewType.CUSTOM_VIEW; if (item instanceof DateListItem) { if (item instanceof OfflineItemListItem) { OfflineItemListItem offlineItem = (OfflineItemListItem) item; - if (offlineItem.item.isSuggested) return ListUtils.PREFETCH; + if (offlineItem.item.isSuggested) return ViewType.PREFETCH; if (offlineItem.item.state == OfflineItemState.IN_PROGRESS) { - return ListUtils.IN_PROGRESS; + return ViewType.IN_PROGRESS; } switch (offlineItem.item.filter) { case OfflineItemFilter.FILTER_VIDEO: - return ListUtils.VIDEO; + return ViewType.VIDEO; case OfflineItemFilter.FILTER_IMAGE: - return ListUtils.IMAGE; - case OfflineItemFilter.FILTER_PAGE: - case OfflineItemFilter.FILTER_AUDIO: - case OfflineItemFilter.FILTER_OTHER: - case OfflineItemFilter.FILTER_DOCUMENT: + return ViewType.IMAGE; + // case OfflineItemFilter.FILTER_PAGE: + // case OfflineItemFilter.FILTER_AUDIO: + // case OfflineItemFilter.FILTER_OTHER: + // case OfflineItemFilter.FILTER_DOCUMENT: default: - return ListUtils.GENERIC; + return ViewType.GENERIC; } } else { - return ListUtils.DATE; + return ViewType.DATE; } } assert false; - return ListUtils.GENERIC; + return ViewType.GENERIC; } /** @@ -80,6 +82,6 @@ * @see GridLayoutManager.SpanSizeLookup */ public static int getSpanSize(ListItem item, int spanCount) { - return getViewTypeForItem(item) == IMAGE ? 1 : spanCount; + return getViewTypeForItem(item) == ViewType.IMAGE ? 1 : spanCount; } } \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/snackbars/UndoUiUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/snackbars/UndoUiUtils.java index a15789d2..2e49528 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/snackbars/UndoUiUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/snackbars/UndoUiUtils.java
@@ -19,20 +19,15 @@ /** @return A {@link String} representing the title text for an undo snackbar. */ public static String getTitleFor(Collection<OfflineItem> items) { - if (items.size() == 1) { - return items.iterator().next().title; - } else { - return String.format(Locale.getDefault(), "%d", items.size()); - } + return items.size() == 1 ? items.iterator().next().title + : String.format(Locale.getDefault(), "%d", items.size()); } /** @return A {@link String} representing the template text for an undo snackbar. */ public static String getTemplateTextFor(Collection<OfflineItem> items) { Context context = ContextUtils.getApplicationContext(); - if (items.size() == 1) { - return context.getString(R.string.undo_bar_delete_message); - } else { - return context.getString(R.string.undo_bar_multiple_downloads_delete_message); - } + return items.size() == 1 + ? context.getString(R.string.undo_bar_delete_message) + : context.getString(R.string.undo_bar_multiple_downloads_delete_message); } } \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUi.java b/chrome/android/java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUi.java index aee8dc4f..1516ea28 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUi.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUi.java
@@ -189,7 +189,7 @@ case OfflineItemState.FAILED: case OfflineItemState.PAUSED: return true; - case OfflineItemState.CANCELLED: + // OfflineItemState.CANCELLED default: return false; } @@ -200,11 +200,9 @@ case OfflineItemState.IN_PROGRESS: case OfflineItemState.PENDING: return true; - case OfflineItemState.COMPLETE: - case OfflineItemState.INTERRUPTED: - case OfflineItemState.FAILED: - case OfflineItemState.PAUSED: - case OfflineItemState.CANCELLED: + // OfflineItemState.COMPLETE, OfflineItemState.INTERRUPTED, + // OfflineItemState.FAILED, OfflineItemState.PAUSED, + // OfflineItemState.CANCELLED default: return false; } @@ -217,9 +215,8 @@ case OfflineItemState.INTERRUPTED: case OfflineItemState.PAUSED: return true; - case OfflineItemState.FAILED: - case OfflineItemState.COMPLETE: - case OfflineItemState.CANCELLED: + // OfflineItemState.FAILED, OfflineItemState.COMPLETE, + // OfflineItemState.CANCELLED default: return false; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/BackendItems.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/BackendItems.java index be7692d2..ab708f5c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/BackendItems.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/BackendItems.java
@@ -32,7 +32,7 @@ HashSet<String> filePaths = new HashSet<>(); for (DownloadHistoryItemWrapper item : this) { String path = item.getFilePath(); - if (item.isVisibleToUser(DownloadFilter.FILTER_ALL) && !filePaths.contains(path)) { + if (item.isVisibleToUser(DownloadFilter.Type.ALL) && !filePaths.contains(path)) { totalSize += item.getFileSize(); } if (path != null && !path.isEmpty()) filePaths.add(path);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadFilter.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadFilter.java index 933db93f..9ca6e3f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadFilter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadFilter.java
@@ -11,6 +11,8 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.UrlConstants; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Locale; /** @@ -20,18 +22,18 @@ public class DownloadFilter { // These statics are used for UMA logging. Please update the AndroidDownloadFilterType enum in // histograms.xml if these change. - @IntDef({FILTER_ALL, FILTER_PAGE, FILTER_VIDEO, FILTER_AUDIO, FILTER_IMAGE, FILTER_DOCUMENT, - FILTER_OTHER, FILTER_BOUNDARY}) - public @interface Type {} - - public static final int FILTER_ALL = 0; - public static final int FILTER_PAGE = 1; - public static final int FILTER_VIDEO = 2; - public static final int FILTER_AUDIO = 3; - public static final int FILTER_IMAGE = 4; - public static final int FILTER_DOCUMENT = 5; - public static final int FILTER_OTHER = 6; - public static final int FILTER_BOUNDARY = 7; + @IntDef({Type.ALL, Type.PAGE, Type.VIDEO, Type.AUDIO, Type.IMAGE, Type.DOCUMENT, Type.OTHER}) + @Retention(RetentionPolicy.SOURCE) + public @interface Type { + int ALL = 0; + int PAGE = 1; + int VIDEO = 2; + int AUDIO = 3; + int IMAGE = 4; + int DOCUMENT = 5; + int OTHER = 6; + int NUM_ENTRIES = 7; + } private static final String MIMETYPE_VIDEO = "video"; private static final String MIMETYPE_AUDIO = "audio"; @@ -81,18 +83,17 @@ * @return The URL representing the filter. */ public static String getUrlForFilter(@Type int filter) { - if (filter == FILTER_ALL) { - return UrlConstants.DOWNLOADS_URL; - } - return UrlConstants.DOWNLOADS_FILTER_URL + filter; + return filter == Type.ALL ? UrlConstants.DOWNLOADS_URL + : UrlConstants.DOWNLOADS_FILTER_URL + filter; } /** * @return The filter that the given URL represents. */ public static @Type int getFilterFromUrl(String url) { - if (TextUtils.isEmpty(url) || UrlConstants.DOWNLOADS_HOST.equals(url)) return FILTER_ALL; - int result = FILTER_ALL; + if (TextUtils.isEmpty(url) || UrlConstants.DOWNLOADS_HOST.equals(url)) return Type.ALL; + @Type + int result = Type.ALL; if (url.startsWith(UrlConstants.DOWNLOADS_FILTER_URL)) { try { result = Integer @@ -106,21 +107,21 @@ /** Identifies the type of file represented by the given MIME type string. */ public static @Type int fromMimeType(String mimeType) { - if (TextUtils.isEmpty(mimeType)) return DownloadFilter.FILTER_OTHER; + if (TextUtils.isEmpty(mimeType)) return Type.OTHER; String[] pieces = mimeType.toLowerCase(Locale.getDefault()).split("/"); - if (pieces.length != 2) return DownloadFilter.FILTER_OTHER; + if (pieces.length != 2) return Type.OTHER; if (MIMETYPE_VIDEO.equals(pieces[0])) { - return DownloadFilter.FILTER_VIDEO; + return Type.VIDEO; } else if (MIMETYPE_AUDIO.equals(pieces[0])) { - return DownloadFilter.FILTER_AUDIO; + return Type.AUDIO; } else if (MIMETYPE_IMAGE.equals(pieces[0])) { - return DownloadFilter.FILTER_IMAGE; + return Type.IMAGE; } else if (MIMETYPE_DOCUMENT.equals(pieces[0])) { - return DownloadFilter.FILTER_DOCUMENT; + return Type.DOCUMENT; } else { - return DownloadFilter.FILTER_OTHER; + return Type.OTHER; } } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java index b199d0b..704a914 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java
@@ -204,7 +204,7 @@ private final List<DownloadItemView> mViews = new ArrayList<>(); private BackendProvider mBackendProvider; - private @DownloadFilter.Type int mFilter = DownloadFilter.FILTER_ALL; + private @DownloadFilter.Type int mFilter = DownloadFilter.Type.ALL; private String mSearchQuery = EMPTY_QUERY; // TODO(xingliu): Remove deprecated storage info. See https://crbug/853260. private SpaceDisplay mSpaceDisplay; @@ -276,22 +276,22 @@ if (list.isInitialized()) return; assert list.size() == 0; - int[] itemCounts = new int[DownloadFilter.FILTER_BOUNDARY]; - int[] viewedItemCounts = new int[DownloadFilter.FILTER_BOUNDARY]; + int[] itemCounts = new int[DownloadFilter.Type.NUM_ENTRIES]; + int[] viewedItemCounts = new int[DownloadFilter.Type.NUM_ENTRIES]; for (DownloadItem item : result) { DownloadItemWrapper wrapper = createDownloadItemWrapper(item); if (addDownloadHistoryItemWrapper(wrapper) - && wrapper.isVisibleToUser(DownloadFilter.FILTER_ALL)) { + && wrapper.isVisibleToUser(DownloadFilter.Type.ALL)) { itemCounts[wrapper.getFilterType()]++; if (DownloadUtils.isDownloadViewed(wrapper.getItem())) viewedItemCounts[wrapper.getFilterType()]++; - if (!isOffTheRecord && wrapper.getFilterType() == DownloadFilter.FILTER_OTHER) { + if (!isOffTheRecord && wrapper.getFilterType() == DownloadFilter.Type.OTHER) { RecordHistogram.recordEnumeratedHistogram( "Android.DownloadManager.OtherExtensions.InitialCount", wrapper.getFileExtensionType(), - DownloadHistoryItemWrapper.FILE_EXTENSION_BOUNDARY); + DownloadHistoryItemWrapper.FileExtension.NUM_ENTRIES); } } } @@ -760,26 +760,26 @@ private void recordDownloadCountHistograms(int[] itemCounts, int[] viewedItemCounts) { RecordHistogram.recordCountHistogram("Android.DownloadManager.InitialCount.Audio", - itemCounts[DownloadFilter.FILTER_AUDIO]); + itemCounts[DownloadFilter.Type.AUDIO]); RecordHistogram.recordCountHistogram("Android.DownloadManager.InitialCount.Document", - itemCounts[DownloadFilter.FILTER_DOCUMENT]); + itemCounts[DownloadFilter.Type.DOCUMENT]); RecordHistogram.recordCountHistogram("Android.DownloadManager.InitialCount.Image", - itemCounts[DownloadFilter.FILTER_IMAGE]); + itemCounts[DownloadFilter.Type.IMAGE]); RecordHistogram.recordCountHistogram("Android.DownloadManager.InitialCount.Other", - itemCounts[DownloadFilter.FILTER_OTHER]); + itemCounts[DownloadFilter.Type.OTHER]); RecordHistogram.recordCountHistogram("Android.DownloadManager.InitialCount.Video", - itemCounts[DownloadFilter.FILTER_VIDEO]); + itemCounts[DownloadFilter.Type.VIDEO]); RecordHistogram.recordCountHistogram("Android.DownloadManager.InitialCount.Viewed.Audio", - viewedItemCounts[DownloadFilter.FILTER_AUDIO]); + viewedItemCounts[DownloadFilter.Type.AUDIO]); RecordHistogram.recordCountHistogram("Android.DownloadManager.InitialCount.Viewed.Document", - viewedItemCounts[DownloadFilter.FILTER_DOCUMENT]); + viewedItemCounts[DownloadFilter.Type.DOCUMENT]); RecordHistogram.recordCountHistogram("Android.DownloadManager.InitialCount.Viewed.Image", - viewedItemCounts[DownloadFilter.FILTER_IMAGE]); + viewedItemCounts[DownloadFilter.Type.IMAGE]); RecordHistogram.recordCountHistogram("Android.DownloadManager.InitialCount.Viewed.Other", - viewedItemCounts[DownloadFilter.FILTER_OTHER]); + viewedItemCounts[DownloadFilter.Type.OTHER]); RecordHistogram.recordCountHistogram("Android.DownloadManager.InitialCount.Viewed.Video", - viewedItemCounts[DownloadFilter.FILTER_VIDEO]); + viewedItemCounts[DownloadFilter.Type.VIDEO]); } private void recordTotalDownloadCountHistogram() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemWrapper.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemWrapper.java index dd7085d..1f5b2b72 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemWrapper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemWrapper.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.download.ui; import android.content.ComponentName; +import android.support.annotation.IntDef; import android.text.TextUtils; import org.chromium.base.VisibleForTesting; @@ -27,6 +28,8 @@ import org.chromium.components.url_formatter.UrlFormatter; import java.io.File; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Collections; import java.util.HashMap; import java.util.Locale; @@ -34,40 +37,47 @@ /** Wraps different classes that contain information about downloads. */ public abstract class DownloadHistoryItemWrapper extends TimedItem { - public static final Integer FILE_EXTENSION_OTHER = 0; - public static final Integer FILE_EXTENSION_APK = 1; - public static final Integer FILE_EXTENSION_CSV = 2; - public static final Integer FILE_EXTENSION_DOC = 3; - public static final Integer FILE_EXTENSION_DOCX = 4; - public static final Integer FILE_EXTENSION_EXE = 5; - public static final Integer FILE_EXTENSION_PDF = 6; - public static final Integer FILE_EXTENSION_PPT = 7; - public static final Integer FILE_EXTENSION_PPTX = 8; - public static final Integer FILE_EXTENSION_PSD = 9; - public static final Integer FILE_EXTENSION_RTF = 10; - public static final Integer FILE_EXTENSION_TXT = 11; - public static final Integer FILE_EXTENSION_XLS = 12; - public static final Integer FILE_EXTENSION_XLSX = 13; - public static final Integer FILE_EXTENSION_ZIP = 14; - public static final Integer FILE_EXTENSION_BOUNDARY = 15; + @IntDef({FileExtension.OTHER, FileExtension.APK, FileExtension.CSV, FileExtension.DOC, + FileExtension.DOCX, FileExtension.EXE, FileExtension.PDF, FileExtension.PPT, + FileExtension.PPTX, FileExtension.PSD, FileExtension.RTF, FileExtension.TXT, + FileExtension.XLS, FileExtension.XLSX, FileExtension.ZIP}) + @Retention(RetentionPolicy.SOURCE) + public @interface FileExtension { + int OTHER = 0; + int APK = 1; + int CSV = 2; + int DOC = 3; + int DOCX = 4; + int EXE = 5; + int PDF = 6; + int PPT = 7; + int PPTX = 8; + int PSD = 9; + int RTF = 10; + int TXT = 11; + int XLS = 12; + int XLSX = 13; + int ZIP = 14; + int NUM_ENTRIES = 15; + } private static final Map<String, Integer> EXTENSIONS_MAP; static { Map<String, Integer> extensions = new HashMap<>(); - extensions.put("apk", FILE_EXTENSION_APK); - extensions.put("csv", FILE_EXTENSION_CSV); - extensions.put("doc", FILE_EXTENSION_DOC); - extensions.put("docx", FILE_EXTENSION_DOCX); - extensions.put("exe", FILE_EXTENSION_EXE); - extensions.put("pdf", FILE_EXTENSION_PDF); - extensions.put("ppt", FILE_EXTENSION_PPT); - extensions.put("pptx", FILE_EXTENSION_PPTX); - extensions.put("psd", FILE_EXTENSION_PSD); - extensions.put("rtf", FILE_EXTENSION_RTF); - extensions.put("txt", FILE_EXTENSION_TXT); - extensions.put("xls", FILE_EXTENSION_XLS); - extensions.put("xlsx", FILE_EXTENSION_XLSX); - extensions.put("zip", FILE_EXTENSION_ZIP); + extensions.put("apk", FileExtension.APK); + extensions.put("csv", FileExtension.CSV); + extensions.put("doc", FileExtension.DOC); + extensions.put("docx", FileExtension.DOCX); + extensions.put("exe", FileExtension.EXE); + extensions.put("pdf", FileExtension.PDF); + extensions.put("ppt", FileExtension.PPT); + extensions.put("pptx", FileExtension.PPTX); + extensions.put("psd", FileExtension.PSD); + extensions.put("rtf", FileExtension.RTF); + extensions.put("txt", FileExtension.TXT); + extensions.put("xls", FileExtension.XLS); + extensions.put("xlsx", FileExtension.XLSX); + extensions.put("zip", FileExtension.ZIP); EXTENSIONS_MAP = Collections.unmodifiableMap(extensions); } @@ -107,7 +117,7 @@ /** @return Whether this download should be shown to the user. */ boolean isVisibleToUser(@DownloadFilter.Type int filter) { if (isDeletionPending()) return false; - return filter == getFilterType() || filter == DownloadFilter.FILTER_ALL; + return filter == getFilterType() || filter == DownloadFilter.Type.ALL; } /** Called when this download should be shared. */ @@ -234,23 +244,23 @@ protected void recordOpenSuccess() { RecordUserAction.record("Android.DownloadManager.Item.OpenSucceeded"); RecordHistogram.recordEnumeratedHistogram("Android.DownloadManager.Item.OpenSucceeded", - getFilterType(), DownloadFilter.FILTER_BOUNDARY); + getFilterType(), DownloadFilter.Type.NUM_ENTRIES); - if (getFilterType() == DownloadFilter.FILTER_OTHER) { + if (getFilterType() == DownloadFilter.Type.OTHER) { RecordHistogram.recordEnumeratedHistogram( - "Android.DownloadManager.OtherExtensions.OpenSucceeded", - getFileExtensionType(), FILE_EXTENSION_BOUNDARY); + "Android.DownloadManager.OtherExtensions.OpenSucceeded", getFileExtensionType(), + FileExtension.NUM_ENTRIES); } } protected void recordOpenFailure() { RecordHistogram.recordEnumeratedHistogram("Android.DownloadManager.Item.OpenFailed", - getFilterType(), DownloadFilter.FILTER_BOUNDARY); + getFilterType(), DownloadFilter.Type.NUM_ENTRIES); - if (getFilterType() == DownloadFilter.FILTER_OTHER) { + if (getFilterType() == DownloadFilter.Type.OTHER) { RecordHistogram.recordEnumeratedHistogram( - "Android.DownloadManager.OtherExtensions.OpenFailed", - getFileExtensionType(), FILE_EXTENSION_BOUNDARY); + "Android.DownloadManager.OtherExtensions.OpenFailed", getFileExtensionType(), + FileExtension.NUM_ENTRIES); } } @@ -329,7 +339,7 @@ if (mFileExtensionType == null) { int extensionIndex = getFilePath().lastIndexOf("."); if (extensionIndex == -1 || extensionIndex == getFilePath().length() - 1) { - mFileExtensionType = FILE_EXTENSION_OTHER; + mFileExtensionType = FileExtension.OTHER; return mFileExtensionType; } @@ -339,7 +349,7 @@ mFileExtensionType = EXTENSIONS_MAP.get( extension.toLowerCase(Locale.getDefault())); } else { - mFileExtensionType = FILE_EXTENSION_OTHER; + mFileExtensionType = FileExtension.OTHER; } } @@ -361,7 +371,8 @@ if (DownloadUtils.openFile(getFile(), getMimeType(), mItem.getDownloadInfo().getDownloadGuid(), isOffTheRecord(), mItem.getDownloadInfo().getOriginalUrl(), - mItem.getDownloadInfo().getReferrer(), DownloadMetrics.DOWNLOAD_HOME)) { + mItem.getDownloadInfo().getReferrer(), + DownloadMetrics.DownloadOpenSource.DOWNLOAD_HOME)) { recordOpenSuccess(); DownloadMetrics.recordDownloadViewRetentionTime( getMimeType(), getItem().getStartTime()); @@ -527,9 +538,9 @@ } @Override - public int getFilterType() { + public @DownloadFilter.Type int getFilterType() { // TODO(shaktisahu): Make DownloadFilter unnecessary. - return isOfflinePage() ? DownloadFilter.FILTER_PAGE + return isOfflinePage() ? DownloadFilter.Type.PAGE : DownloadFilter.fromMimeType(mItem.mimeType); } @@ -546,7 +557,7 @@ @Override public int getFileExtensionType() { // TODO(shaktisahu): Fix this. - return FILE_EXTENSION_OTHER; + return FileExtension.OTHER; } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java index 57e6a8ab..8d76460 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java
@@ -40,6 +40,8 @@ import org.chromium.components.variations.VariationsAssociatedData; import org.chromium.ui.UiUtils; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.List; /** @@ -53,17 +55,18 @@ // Please treat this list as append only and keep it in sync with // Android.DownloadManager.List.View.Actions in enums.xml. - @IntDef({VIEW_ACTION_OPEN, VIEW_ACTION_RESUME, VIEW_ACTION_PAUSE, VIEW_ACTION_CANCEL, - VIEW_ACTION_MENU_SHARE, VIEW_ACTION_MENU_DELETE}) - public @interface ViewAction {} - - private static final int VIEW_ACTION_OPEN = 0; - private static final int VIEW_ACTION_RESUME = 1; - private static final int VIEW_ACTION_PAUSE = 2; - private static final int VIEW_ACTION_CANCEL = 3; - private static final int VIEW_ACTION_MENU_SHARE = 4; - private static final int VIEW_ACTION_MENU_DELETE = 5; - private static final int VIEW_ACTION_BOUNDARY = 6; + @IntDef({ViewAction.OPEN, ViewAction.RESUME, ViewAction.PAUSE, ViewAction.CANCEL, + ViewAction.MENU_SHARE, ViewAction.MENU_DELETE}) + @Retention(RetentionPolicy.SOURCE) + private @interface ViewAction { + int OPEN = 0; + int RESUME = 1; + int PAUSE = 2; + int CANCEL = 3; + int MENU_SHARE = 4; + int MENU_DELETE = 5; + int NUM_ENTRIES = 6; + } /** * Set based on Chrome Variations to determine whether or not to show the "more" menu button on @@ -138,10 +141,10 @@ @Override public void onItemSelected(Item item) { if (item.getTextId() == R.string.share) { - recordViewActionHistogram(VIEW_ACTION_MENU_SHARE); + recordViewActionHistogram(ViewAction.MENU_SHARE); mItem.share(); } else if (item.getTextId() == R.string.delete) { - recordViewActionHistogram(VIEW_ACTION_MENU_DELETE); + recordViewActionHistogram(ViewAction.MENU_DELETE); mItem.startRemove(); RecordUserAction.record("Android.DownloadManager.RemoveItem"); } @@ -170,15 +173,15 @@ mMoreButton.setDelegate(this); mPauseResumeButton.setOnClickListener(view -> { if (mItem.isPaused()) { - recordViewActionHistogram(VIEW_ACTION_RESUME); + recordViewActionHistogram(ViewAction.RESUME); mItem.resume(); } else if (!mItem.isComplete()) { - recordViewActionHistogram(VIEW_ACTION_PAUSE); + recordViewActionHistogram(ViewAction.PAUSE); mItem.pause(); } }); mCancelButton.setOnClickListener(view -> { - recordViewActionHistogram(VIEW_ACTION_CANCEL); + recordViewActionHistogram(ViewAction.CANCEL); mItem.cancel(); }); } @@ -249,8 +252,7 @@ // immediately if the thumbnail is cached or asynchronously if it has to be fetched from a // remote source. mThumbnailBitmap = null; - if (item.isOfflinePage() - || (fileType == DownloadFilter.FILTER_IMAGE && item.isComplete())) { + if (item.isOfflinePage() || (fileType == DownloadFilter.Type.IMAGE && item.isComplete())) { thumbnailProvider.getThumbnail(this); } else { // TODO(dfalcantara): Get thumbnails for audio and video files when possible. @@ -337,18 +339,14 @@ @Override public void onClick() { if (mItem != null && mItem.isComplete()) { - recordViewActionHistogram(VIEW_ACTION_OPEN); + recordViewActionHistogram(ViewAction.OPEN); mItem.open(); } } @Override public boolean onLongClick(View view) { - if (mItem != null && mItem.isComplete()) { - return super.onLongClick(view); - } else { - return true; - } + return mItem != null && mItem.isComplete() ? super.onLongClick(view) : true; } @Override @@ -407,7 +405,7 @@ private static void recordViewActionHistogram(@ViewAction int action) { RecordHistogram.recordEnumeratedHistogram( - "Android.DownloadManager.List.View.Action", action, VIEW_ACTION_BOUNDARY); + "Android.DownloadManager.List.View.Action", action, ViewAction.NUM_ENTRIES); } /**
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 82d8e5e..e9e9594 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
@@ -452,8 +452,8 @@ mNativePage.onStateChange(DownloadFilter.getUrlForFilter(filter)); } - RecordHistogram.recordEnumeratedHistogram("Android.DownloadManager.Filter", filter, - DownloadFilter.FILTER_BOUNDARY); + RecordHistogram.recordEnumeratedHistogram( + "Android.DownloadManager.Filter", filter, DownloadFilter.Type.NUM_ENTRIES); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/LoadingStateDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/LoadingStateDelegate.java index 9c947caf..5eb9afc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/LoadingStateDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/LoadingStateDelegate.java
@@ -19,7 +19,7 @@ private static final int ALL_LOADED = 0b111; private int mLoadingState; - private @DownloadFilter.Type int mPendingFilter = DownloadFilter.FILTER_ALL; + private @DownloadFilter.Type int mPendingFilter = DownloadFilter.Type.ALL; /** @param offTheRecord Whether this delegate needs to consider incognito. */ public LoadingStateDelegate(boolean offTheRecord) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/historyreport/HistoryReportJniBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/historyreport/HistoryReportJniBridge.java index 2535bdbd..8338e3e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/historyreport/HistoryReportJniBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/historyreport/HistoryReportJniBridge.java
@@ -101,6 +101,12 @@ } @Override + public void clearUsageReports() { + if (!isInitialized()) return; + nativeClearUsageReports(mNativeHistoryReportJniBridge); + } + + @Override public boolean addHistoricVisitsToUsageReportsBuffer() { if (!isInitialized()) return false; return nativeAddHistoricVisitsToUsageReportsBuffer(mNativeHistoryReportJniBridge); @@ -171,6 +177,7 @@ int batchSize); private native void nativeRemoveUsageReports(long nativeHistoryReportJniBridge, String[] reportIds); + private native void nativeClearUsageReports(long nativeHistoryReportJniBridge); private native boolean nativeAddHistoricVisitsToUsageReportsBuffer( long nativeHistoryReportJniBridge); private native String nativeDump(long nativeHistoryReportJniBridge);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/historyreport/SearchJniBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/historyreport/SearchJniBridge.java index 2ba996d..a8e8c86 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/historyreport/SearchJniBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/historyreport/SearchJniBridge.java
@@ -45,6 +45,11 @@ void removeUsageReports(UsageReport[] reports); /** + * Clear the buffer of usage reports. + */ + void clearUsageReports(); + + /** * Adds all the historic visits to the usage report buffer. * * Should be done only once.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/DuplicateDownloadInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/DuplicateDownloadInfoBar.java index fe6d61e7..ad96cd7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/DuplicateDownloadInfoBar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/DuplicateDownloadInfoBar.java
@@ -89,7 +89,7 @@ protected void onPostExecute(Boolean fileExists) { if (fileExists) { DownloadUtils.openFile(file, mimeType, null, mIsIncognito, null, null, - DownloadMetrics.INFO_BAR); + DownloadMetrics.DownloadOpenSource.INFO_BAR); } else { DownloadManagerService.openDownloadsPage( ContextUtils.getApplicationContext());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java index d9455e1..858b308f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
@@ -35,7 +35,6 @@ import org.chromium.chrome.browser.ChromeApplication; import org.chromium.chrome.browser.ChromeStrictMode; import org.chromium.chrome.browser.ChromeSwitches; -import org.chromium.chrome.browser.ClassRegister; import org.chromium.chrome.browser.FileProviderHelper; import org.chromium.chrome.browser.crash.LogcatExtractionRunnable; import org.chromium.chrome.browser.download.DownloadManagerService; @@ -399,7 +398,6 @@ AppHooks.get().registerPolicyProviders(CombinedPolicyProvider.get()); SpeechRecognition.initialize(mApplication); - ClassRegister.get().registerContentClassFactory(); } private void onFinishNativeInitialization() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/JourneyLogger.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/JourneyLogger.java index e75acce..46491df 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/JourneyLogger.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/JourneyLogger.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.payments; import org.chromium.base.annotations.JNINamespace; +import org.chromium.content_public.browser.WebContents; /** * A class used to record journey metrics for the Payment Request feature. @@ -19,10 +20,10 @@ private boolean mWasPaymentRequestTriggered; private boolean mHasRecorded; - public JourneyLogger(boolean isIncognito, String url) { + public JourneyLogger(boolean isIncognito, WebContents webContents) { // Note that this pointer could leak the native object. The called must call destroy() to // ensure that the native object is destroyed. - mJourneyLoggerAndroid = nativeInitJourneyLoggerAndroid(isIncognito, url); + mJourneyLoggerAndroid = nativeInitJourneyLoggerAndroid(isIncognito, webContents); } /** Will destroy the native object. This class shouldn't be used afterwards. */ @@ -176,7 +177,8 @@ } } - private native long nativeInitJourneyLoggerAndroid(boolean isIncognito, String url); + private native long nativeInitJourneyLoggerAndroid( + boolean isIncognito, WebContents webContents); private native void nativeDestroy(long nativeJourneyLoggerAndroid); private native void nativeSetNumberOfSuggestionsShown(long nativeJourneyLoggerAndroid, int section, int number, boolean hasCompleteSuggestion);
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 f4da574..a73f044 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
@@ -404,7 +404,7 @@ new AddressEditor(/*emailFieldIncluded=*/false, /*saveToDisk=*/!mIsIncognito); mCardEditor = new CardEditor(mWebContents, mAddressEditor, sObserverForTest); - mJourneyLogger = new JourneyLogger(mIsIncognito, mWebContents.getLastCommittedUrl()); + mJourneyLogger = new JourneyLogger(mIsIncognito, mWebContents); if (sCanMakePaymentQueries == null) sCanMakePaymentQueries = new ArrayMap<>();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java index 82be72393..cf3a9ebb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
@@ -106,6 +106,7 @@ private static final String HOME_PAGE_BUTTON_FORCE_ENABLED_KEY = "home_page_button_force_enabled"; + private static final String HOMEPAGE_TILE_ENABLED_KEY = "homepage_tile_enabled"; private static final String NTP_BUTTON_ENABLED_KEY = "ntp_button_enabled"; @@ -469,6 +470,22 @@ } /** + * Set whether or not the homepage tile will be shown. + * @param isEnabled If homepage tile is enabled. + */ + public void setHomepageTileEnabled(boolean isEnabled) { + writeBoolean(HOMEPAGE_TILE_ENABLED_KEY, isEnabled); + } + + /** + * Get whether or not the homepage tile is enabled. + * @return True if the homepage tile is enabled. + */ + public boolean isHomepageTileEnabled() { + return mSharedPreferences.getBoolean(HOMEPAGE_TILE_ENABLED_KEY, false); + } + + /** * Clean up unused Chrome Home preferences. */ public void clearObsoleteChromeHomePrefs() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/MostVisitedSitesBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/MostVisitedSitesBridge.java index 53053f41..94567b8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/MostVisitedSitesBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/MostVisitedSitesBridge.java
@@ -40,7 +40,8 @@ mNativeMostVisitedSitesBridge = nativeInit(profile); // The first tile replaces is replaced with homepage tile if NTPButton is enabled. Setting // a homepage client to provide Java side information. - if (FeatureUtilities.isNewTabPageButtonEnabled()) { + if (FeatureUtilities.isNewTabPageButtonEnabled() + && FeatureUtilities.isHomepageTileEnabled()) { nativeSetHomepageClient(mNativeMostVisitedSitesBridge, new HomepageClient() { @Override public boolean isHomepageEnabled() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBinder.java index 5cef527..7b6a7850 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBinder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBinder.java
@@ -265,12 +265,13 @@ private void setDownloadThumbnail() { assert mSuggestion.isDownload(); if (!mSuggestion.isAssetDownload()) { - setThumbnailFromFileType(DownloadFilter.FILTER_PAGE); + setThumbnailFromFileType(DownloadFilter.Type.PAGE); return; } + @DownloadFilter.Type int fileType = DownloadFilter.fromMimeType(mSuggestion.getAssetDownloadMimeType()); - if (fileType == DownloadFilter.FILTER_IMAGE) { + if (fileType == DownloadFilter.Type.IMAGE) { // For image downloads, attempt to fetch a thumbnail. ImageFetcher.DownloadThumbnailRequest thumbnailRequest = mImageFetcher.makeDownloadThumbnailRequest(mSuggestion, mThumbnailSize);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java index 1215d57..32e5f92 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java
@@ -113,7 +113,7 @@ || windowOpenDisposition == WindowOpenDisposition.NEW_BACKGROUND_TAB; DownloadUtils.openFile(article.getAssetDownloadFile(), article.getAssetDownloadMimeType(), article.getAssetDownloadGuid(), false, null, - null, DownloadMetrics.NEW_TAP_PAGE); + null, DownloadMetrics.DownloadOpenSource.NEW_TAP_PAGE); return; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarCoordinator.java index ee1f40f4b..64c891e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarCoordinator.java
@@ -20,6 +20,7 @@ import org.chromium.chrome.browser.modelutil.PropertyModelChangeProcessor; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.toolbar.BottomToolbarViewBinder.ViewHolder; +import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.resources.ResourceManager; /** @@ -95,13 +96,14 @@ OnClickListener tabSwitcherListener, OnClickListener searchAcceleratorListener, OnClickListener homeButtonListener, OnTouchListener menuButtonListener, TabModelSelector tabModelSelector, OverviewModeBehavior overviewModeBehavior, - ContextualSearchManager contextualSearchManager) { + ContextualSearchManager contextualSearchManager, WindowAndroid windowAndroid) { mMediator.setSearchAcceleratorListener(searchAcceleratorListener); mMediator.setLayoutManager(layoutManager); mMediator.setResourceManager(resourceManager); mMediator.setOverviewModeBehavior(overviewModeBehavior); mMediator.setToolbarSwipeHandler(layoutManager.getToolbarSwipeHandler()); mMediator.setContextualSearchManager(contextualSearchManager); + mMediator.setWindowAndroid(windowAndroid); mTabSwitcherButtonCoordinator.setTabSwitcherListener(tabSwitcherListener); mTabSwitcherButtonCoordinator.setTabModelSelector(tabModelSelector);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarMediator.java index 3f314ea..5fb8bc92f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarMediator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarMediator.java
@@ -20,6 +20,8 @@ import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager; import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager.FullscreenListener; import org.chromium.chrome.browser.gsa.GSAContextDisplaySelection; +import org.chromium.ui.base.WindowAndroid; +import org.chromium.ui.base.WindowAndroid.KeyboardVisibilityListener; import org.chromium.ui.resources.ResourceManager; import javax.annotation.Nullable; @@ -29,8 +31,8 @@ * coordinators, running most of the business logic associated with the bottom toolbar, and updating * the model accordingly. */ -class BottomToolbarMediator - implements FullscreenListener, OverviewModeObserver, ContextualSearchObserver { +class BottomToolbarMediator implements ContextualSearchObserver, FullscreenListener, + KeyboardVisibilityListener, OverviewModeObserver { /** The model for the bottom toolbar that holds all of its state. */ private BottomToolbarModel mModel; @@ -43,6 +45,12 @@ /** The manager for Contextual Search to observe appearance/disappearance of the feature. */ private ContextualSearchManager mContextualSearchManger; + /** A {@link WindowAndroid} for watching keyboard visibility events. */ + private WindowAndroid mWindowAndroid; + + /** The previous height of the bottom toolbar. */ + private int mBottomToolbarHeightBeforeHide; + /** * Build a new mediator that handles events from outside the bottom toolbar. * @param model The {@link BottomToolbarModel} that holds all the state for the bottom toolbar. @@ -76,6 +84,7 @@ mFullscreenManager.removeListener(this); if (mContextualSearchManger != null) mContextualSearchManger.removeObserver(this); if (mOverviewModeBehavior != null) mOverviewModeBehavior.removeOverviewModeObserver(this); + if (mWindowAndroid != null) mWindowAndroid.removeKeyboardVisibilityListener(this); } @Override @@ -130,6 +139,24 @@ mModel.setValue(BottomToolbarModel.SEARCH_ACCELERATOR_LISTENER, searchAcceleratorListener); } + @Override + public void keyboardVisibilityChanged(boolean isShowing) { + // The toolbars are force shown when the keyboard is visible, so we can blindly set + // the bottom toolbar view to visible or invisible regardless of the previous state. + ChromeFullscreenManager fullscreenManager = + mModel.getValue(BottomToolbarModel.LAYOUT_MANAGER).getFullscreenManager(); + if (isShowing) { + mBottomToolbarHeightBeforeHide = fullscreenManager.getBottomControlsHeight(); + mModel.setValue(BottomToolbarModel.ANDROID_VIEW_VISIBLE, false); + mModel.setValue(BottomToolbarModel.COMPOSITED_VIEW_VISIBLE, false); + fullscreenManager.setBottomControlsHeight(0); + } else { + fullscreenManager.setBottomControlsHeight(mBottomToolbarHeightBeforeHide); + mModel.setValue(BottomToolbarModel.ANDROID_VIEW_VISIBLE, true); + mModel.setValue(BottomToolbarModel.COMPOSITED_VIEW_VISIBLE, true); + } + } + public void setLayoutManager(LayoutManager layoutManager) { mModel.setValue(BottomToolbarModel.LAYOUT_MANAGER, layoutManager); @@ -172,4 +199,12 @@ public void setToolbarSwipeLayout(ToolbarSwipeLayout layout) { mModel.setValue(BottomToolbarModel.TOOLBAR_SWIPE_LAYOUT, layout); } + + public void setWindowAndroid(WindowAndroid windowAndroid) { + assert mWindowAndroid == null : "#setWindowAndroid should only be called once per toolbar."; + + // Watch for keyboard events so we can hide the bottom toolbar when the keyboard is showing. + mWindowAndroid = windowAndroid; + mWindowAndroid.addKeyboardVisibilityListener(this); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarModel.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarModel.java index d0642b24..8a59f0d3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarModel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarModel.java
@@ -22,6 +22,9 @@ /** Whether the Android view version of the toolbar is visible. */ public static final BooleanPropertyKey ANDROID_VIEW_VISIBLE = new BooleanPropertyKey(); + /** Whether the composited version of the toolbar is visible. */ + public static final BooleanPropertyKey COMPOSITED_VIEW_VISIBLE = new BooleanPropertyKey(); + /** The click listener for the search accelerator. */ public static final ObjectPropertyKey<OnClickListener> SEARCH_ACCELERATOR_LISTENER = new ObjectPropertyKey<>(); @@ -46,8 +49,8 @@ /** Default constructor. */ public BottomToolbarModel() { - super(Y_OFFSET, ANDROID_VIEW_VISIBLE, SEARCH_ACCELERATOR_LISTENER, LAYOUT_MANAGER, - TOOLBAR_SWIPE_LAYOUT, RESOURCE_MANAGER, SEARCH_ACCELERATOR_VISIBLE, + super(Y_OFFSET, ANDROID_VIEW_VISIBLE, COMPOSITED_VIEW_VISIBLE, SEARCH_ACCELERATOR_LISTENER, + LAYOUT_MANAGER, TOOLBAR_SWIPE_LAYOUT, RESOURCE_MANAGER, SEARCH_ACCELERATOR_VISIBLE, TOOLBAR_SWIPE_HANDLER); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarViewBinder.java index 95bc86cf..03f1cac 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarViewBinder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarViewBinder.java
@@ -54,6 +54,10 @@ view.toolbarRoot.setVisibility(model.getValue(BottomToolbarModel.ANDROID_VIEW_VISIBLE) ? View.VISIBLE : View.INVISIBLE); + } else if (BottomToolbarModel.COMPOSITED_VIEW_VISIBLE == propertyKey) { + view.sceneLayer.setIsVisible( + model.getValue(BottomToolbarModel.COMPOSITED_VIEW_VISIBLE)); + model.getValue(BottomToolbarModel.LAYOUT_MANAGER).requestUpdate(); } else if (BottomToolbarModel.SEARCH_ACCELERATOR_LISTENER == propertyKey) { view.toolbarRoot.findViewById(R.id.search_button) .setOnClickListener(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java index b0508ea..5db08881 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -767,7 +767,7 @@ mActivity.getCompositorViewHolder().getLayoutManager(), tabSwitcherClickHandler, searchAcceleratorListener, homeButtonListener, mAppMenuButtonHelper, mTabModelSelector, mOverviewModeBehavior, - mActivity.getContextualSearchManager()); + mActivity.getContextualSearchManager(), mActivity.getWindowAndroid()); } onNativeLibraryReady();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java index 3b9e5be..83bf6c1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
@@ -1865,7 +1865,9 @@ assert mTextureCaptureMode != textureMode; mTextureCaptureMode = textureMode; if (mTextureCaptureMode) { - if (!hideShadowForIncognitoNtp()) mToolbarShadow.setVisibility(VISIBLE); + if (!hideShadowForIncognitoNtp() && !hideShadowForInterstitial()) { + mToolbarShadow.setVisibility(VISIBLE); + } mPreTextureCaptureAlpha = getAlpha(); setAlpha(1); } else { @@ -2525,7 +2527,8 @@ protected boolean shouldDrawShadow() { // TODO(twellington): Move this shadow state information to ToolbarDataProvider and show // shadow when incognito NTP is scrolled. - return mTabSwitcherState == STATIC_TAB && !hideShadowForIncognitoNtp(); + return mTabSwitcherState == STATIC_TAB && !hideShadowForIncognitoNtp() + && !hideShadowForInterstitial(); } private boolean hideShadowForIncognitoNtp() { @@ -2533,6 +2536,12 @@ && NewTabPage.isNTPUrl(getToolbarDataProvider().getCurrentUrl()); } + private boolean hideShadowForInterstitial() { + return mLocationBar.useModernDesign() && getToolbarDataProvider() != null + && getToolbarDataProvider().getTab() != null + && getToolbarDataProvider().getTab().isShowingInterstitialPage(); + } + private @VisualState int computeVisualState(boolean isInTabSwitcherMode) { if (isInTabSwitcherMode && isIncognito()) return VisualState.TAB_SWITCHER_INCOGNITO; if (isInTabSwitcherMode && !isIncognito()) return VisualState.TAB_SWITCHER_NORMAL;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java index 350b39ac..955d9d2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
@@ -49,6 +49,7 @@ private static Boolean sIsSoleEnabled; private static Boolean sIsChromeModernDesignEnabled; private static Boolean sIsHomePageButtonForceEnabled; + private static Boolean sIsHomepageTileEnabled; private static Boolean sIsNewTabPageButtonEnabled; private static Boolean sIsBottomToolbarEnabled; @@ -157,6 +158,7 @@ FirstRunUtils.cacheFirstRunPrefs(); cacheChromeModernDesignEnabled(); cacheHomePageButtonForceEnabled(); + cacheHomepageTileEnabled(); cacheNewTabPageButtonEnabled(); cacheBottomToolbarEnabled(); @@ -225,6 +227,29 @@ * Cache whether or not the new tab page button is enabled so on next startup, the value can * be made available immediately. */ + public static void cacheHomepageTileEnabled() { + ChromePreferenceManager.getInstance().setHomepageTileEnabled( + ChromeFeatureList.isEnabled(ChromeFeatureList.HOMEPAGE_TILE)); + } + + /** + * @return Whether or not the new tab page button is enabled. + */ + public static boolean isHomepageTileEnabled() { + if (sIsHomepageTileEnabled == null) { + ChromePreferenceManager prefManager = ChromePreferenceManager.getInstance(); + + try (StrictModeContext unused = StrictModeContext.allowDiskReads()) { + sIsHomepageTileEnabled = prefManager.isHomepageTileEnabled(); + } + } + return sIsHomepageTileEnabled; + } + + /** + * Cache whether or not the new tab page button is enabled so on next startup, the value can + * be made available immediately. + */ public static void cacheNewTabPageButtonEnabled() { ChromePreferenceManager.getInstance().setNewTabPageButtonEnabled( ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_BUTTON));
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index 9379e719..5ed73ce 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -85,6 +85,7 @@ "java/src/org/chromium/chrome/browser/appmenu/AppMenuButtonHelper.java", "java/src/org/chromium/chrome/browser/appmenu/AppMenuDragHelper.java", "java/src/org/chromium/chrome/browser/appmenu/AppMenuHandler.java", + "java/src/org/chromium/chrome/browser/appmenu/AppMenuIconRowFooter.java", "java/src/org/chromium/chrome/browser/appmenu/AppMenuItemIcon.java", "java/src/org/chromium/chrome/browser/appmenu/AppMenuObserver.java", "java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java index b1ae5b0..34762a1 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -139,21 +139,23 @@ private static final int ACTIVITY_STARTUP_DELAY_MS = 1000; // Ranker data that's expected to be logged. - private static final Set<ContextualSearchRankerLogger.Feature> EXPECTED_RANKER_OUTCOMES; + // Integer values should contain @Feature values only. + private static final Set<Integer> EXPECTED_RANKER_OUTCOMES; static { - Set<ContextualSearchRankerLogger.Feature> expectedOutcomes = - new HashSet<ContextualSearchRankerLogger.Feature>( - ContextualSearchRankerLoggerImpl.OUTCOMES.keySet()); + // Integer values should contain @Feature values only. + Set<Integer> expectedOutcomes = + new HashSet<Integer>(ContextualSearchRankerLoggerImpl.OUTCOMES.keySet()); // We don't log whether the quick action was clicked unless we actually have a quick action. expectedOutcomes.remove( ContextualSearchRankerLogger.Feature.OUTCOME_WAS_QUICK_ACTION_CLICKED); EXPECTED_RANKER_OUTCOMES = Collections.unmodifiableSet(expectedOutcomes); } - private static final Set<ContextualSearchRankerLogger.Feature> EXPECTED_RANKER_FEATURES; + // Integer values should contain @Feature values only. + private static final Set<Integer> EXPECTED_RANKER_FEATURES; static { - Set<ContextualSearchRankerLogger.Feature> expectedFeatures = - new HashSet<ContextualSearchRankerLogger.Feature>( - ContextualSearchRankerLoggerImpl.FEATURES.keySet()); + // Integer values should contain @Feature values only. + Set<Integer> expectedFeatures = + new HashSet<Integer>(ContextualSearchRankerLoggerImpl.FEATURES.keySet()); // We don't log previous user impressions and CTR if not available for the current user. expectedFeatures.remove(ContextualSearchRankerLogger.Feature.PREVIOUS_WEEK_CTR_PERCENT); expectedFeatures.remove( @@ -1109,20 +1111,20 @@ } /** @return The value of the given logged feature, or {@code null} if not logged. */ - private Object loggedToRanker(ContextualSearchRankerLogger.Feature feature) { + private Object loggedToRanker(@ContextualSearchRankerLogger.Feature int feature) { return getRankerLogger().getFeaturesLogged().get(feature); } /** Asserts that all the expected features have been logged to Ranker. **/ private void assertLoggedAllExpectedFeaturesToRanker() { - for (ContextualSearchRankerLogger.Feature feature : EXPECTED_RANKER_FEATURES) { + for (@ContextualSearchRankerLogger.Feature Integer feature : EXPECTED_RANKER_FEATURES) { Assert.assertNotNull(loggedToRanker(feature)); } } /** Asserts that all the expected outcomes have been logged to Ranker. **/ private void assertLoggedAllExpectedOutcomesToRanker() { - for (ContextualSearchRankerLogger.Feature feature : EXPECTED_RANKER_OUTCOMES) { + for (@ContextualSearchRankerLogger.Feature Integer feature : EXPECTED_RANKER_OUTCOMES) { Assert.assertNotNull("Expected this outcome to be logged: " + feature, getRankerLogger().getOutcomesLogged().get(feature)); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/OMADownloadHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/OMADownloadHandlerTest.java index d2a14e5..59778ae 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/OMADownloadHandlerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/OMADownloadHandlerTest.java
@@ -296,14 +296,13 @@ DownloadManagerDelegate downloadManagerDelegate = new DownloadManagerDelegate(context); DownloadQueryResultVerifier verifier = - new DownloadQueryResultVerifier(DownloadManagerService.DOWNLOAD_STATUS_COMPLETE); + new DownloadQueryResultVerifier(DownloadManagerService.DownloadStatus.COMPLETE); downloadManagerDelegate.queryDownloadResult(downloadItem, false, verifier); waitForQueryCompletion(verifier); manager.remove(downloadId1); downloadItem.setSystemDownloadId(downloadId1); - verifier = - new DownloadQueryResultVerifier(DownloadManagerService.DOWNLOAD_STATUS_CANCELLED); + verifier = new DownloadQueryResultVerifier(DownloadManagerService.DownloadStatus.CANCELLED); downloadManagerDelegate.queryDownloadResult(downloadItem, false, verifier); waitForQueryCompletion(verifier); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapterTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapterTest.java index 97940b2..c7a73cb 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapterTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapterTest.java
@@ -499,20 +499,20 @@ HEADER, null, item5, item4, item6, null, item3, item2, null, item1, item0); Assert.assertEquals(1666, mAdapter.getTotalDownloadSize()); - onFilterChanged(DownloadFilter.FILTER_AUDIO, 2); + onFilterChanged(DownloadFilter.Type.AUDIO, 2); checkAdapterContents(HEADER, null, item5, item4); Assert.assertEquals(1666, mAdapter.getTotalDownloadSize()); // Total size ignores filters. - onFilterChanged(DownloadFilter.FILTER_VIDEO, 2); + onFilterChanged(DownloadFilter.Type.VIDEO, 2); checkAdapterContents(HEADER, null, item3); - onFilterChanged(DownloadFilter.FILTER_IMAGE, 2); + onFilterChanged(DownloadFilter.Type.IMAGE, 2); checkAdapterContents(HEADER, null, item1, item0); - onFilterChanged(DownloadFilter.FILTER_PAGE, 2); + onFilterChanged(DownloadFilter.Type.PAGE, 2); checkAdapterContents(HEADER, null, item6); - onFilterChanged(DownloadFilter.FILTER_ALL, 2); + onFilterChanged(DownloadFilter.Type.ALL, 2); checkAdapterContents( HEADER, null, item5, item4, item6, null, item3, item2, null, item1, item0); Assert.assertEquals(1666, mAdapter.getTotalDownloadSize()); @@ -537,13 +537,13 @@ checkAdapterContents(HEADER, null, item2, null, item0); // Filter shows nothing when the item is deleted because it's a different kind of item. - onFilterChanged(DownloadFilter.FILTER_AUDIO, 1); + onFilterChanged(DownloadFilter.Type.AUDIO, 1); Assert.assertEquals(0, mAdapter.getItemCount()); onOfflineItemDeleted(item0.id, 0); Assert.assertEquals(0, mAdapter.getItemCount()); // Filter shows just pages. - onFilterChanged(DownloadFilter.FILTER_PAGE, 2); + onFilterChanged(DownloadFilter.Type.PAGE, 2); checkAdapterContents(HEADER, null, item2); onOfflineItemDeleted(item2.id, 1); Assert.assertEquals(0, mAdapter.getItemCount()); @@ -668,7 +668,7 @@ HEADER, null, item5, item4, item6, null, item3, item2, null, item1, item0); // Change the filter - onFilterChanged(DownloadFilter.FILTER_IMAGE, 2); + onFilterChanged(DownloadFilter.Type.IMAGE, 2); checkAdapterContents(HEADER, null, item1, item0); ThreadUtils.runOnUiThreadBlocking(new Runnable() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java index 351fdf6..7c4496f 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
@@ -202,6 +202,7 @@ } @Test + @DisabledTest(message = "https://crbug.com/813589") @MediumTest @Feature({"NewTabPage", "RenderTest"}) @DisableFeatures({ChromeFeatureList.SIMPLIFIED_NTP})
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/download/home/filter/FiltersTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/download/home/filter/FiltersTest.java index 62abf602..6cc5fb7 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/download/home/filter/FiltersTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/download/home/filter/FiltersTest.java
@@ -18,14 +18,17 @@ public class FiltersTest { @Test public void testFilterConversions() { - Assert.assertEquals(Filters.SITES, Filters.fromOfflineItem(OfflineItemFilter.FILTER_PAGE)); Assert.assertEquals( - Filters.VIDEOS, Filters.fromOfflineItem(OfflineItemFilter.FILTER_VIDEO)); - Assert.assertEquals(Filters.MUSIC, Filters.fromOfflineItem(OfflineItemFilter.FILTER_AUDIO)); + Filters.FilterType.SITES, Filters.fromOfflineItem(OfflineItemFilter.FILTER_PAGE)); Assert.assertEquals( - Filters.IMAGES, Filters.fromOfflineItem(OfflineItemFilter.FILTER_IMAGE)); - Assert.assertEquals(Filters.OTHER, Filters.fromOfflineItem(OfflineItemFilter.FILTER_OTHER)); + Filters.FilterType.VIDEOS, Filters.fromOfflineItem(OfflineItemFilter.FILTER_VIDEO)); Assert.assertEquals( - Filters.OTHER, Filters.fromOfflineItem(OfflineItemFilter.FILTER_DOCUMENT)); + Filters.FilterType.MUSIC, Filters.fromOfflineItem(OfflineItemFilter.FILTER_AUDIO)); + Assert.assertEquals( + Filters.FilterType.IMAGES, Filters.fromOfflineItem(OfflineItemFilter.FILTER_IMAGE)); + Assert.assertEquals( + Filters.FilterType.OTHER, Filters.fromOfflineItem(OfflineItemFilter.FILTER_OTHER)); + Assert.assertEquals(Filters.FilterType.OTHER, + Filters.fromOfflineItem(OfflineItemFilter.FILTER_DOCUMENT)); } } \ No newline at end of file
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/download/home/filter/TypeOfflineItemFilterTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/download/home/filter/TypeOfflineItemFilterTest.java index edcd55cc..63e36bc 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/download/home/filter/TypeOfflineItemFilterTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/download/home/filter/TypeOfflineItemFilterTest.java
@@ -56,37 +56,37 @@ Assert.assertEquals(CollectionUtil.newHashSet(item1, item2, item3, item4, item5, item6), filter.getItems()); - filter.onFilterSelected(Filters.VIDEOS); + filter.onFilterSelected(Filters.FilterType.VIDEOS); verify(mObserver, times(1)) .onItemsRemoved(CollectionUtil.newHashSet(item1, item3, item4, item5, item6)); Assert.assertEquals(CollectionUtil.newHashSet(item2), filter.getItems()); - filter.onFilterSelected(Filters.MUSIC); + filter.onFilterSelected(Filters.FilterType.MUSIC); verify(mObserver, times(1)).onItemsRemoved(CollectionUtil.newHashSet(item2)); verify(mObserver, times(1)).onItemsAdded(CollectionUtil.newHashSet(item3)); Assert.assertEquals(CollectionUtil.newHashSet(item3), filter.getItems()); - filter.onFilterSelected(Filters.IMAGES); + filter.onFilterSelected(Filters.FilterType.IMAGES); verify(mObserver, times(1)).onItemsRemoved(CollectionUtil.newHashSet(item3)); verify(mObserver, times(1)).onItemsAdded(CollectionUtil.newHashSet(item4)); Assert.assertEquals(CollectionUtil.newHashSet(item4), filter.getItems()); - filter.onFilterSelected(Filters.SITES); + filter.onFilterSelected(Filters.FilterType.SITES); verify(mObserver, times(1)).onItemsRemoved(CollectionUtil.newHashSet(item4)); verify(mObserver, times(1)).onItemsAdded(CollectionUtil.newHashSet(item1)); Assert.assertEquals(CollectionUtil.newHashSet(item1), filter.getItems()); - filter.onFilterSelected(Filters.OTHER); + filter.onFilterSelected(Filters.FilterType.OTHER); verify(mObserver, times(1)).onItemsRemoved(CollectionUtil.newHashSet(item1)); verify(mObserver, times(1)).onItemsAdded(CollectionUtil.newHashSet(item5, item6)); Assert.assertEquals(CollectionUtil.newHashSet(item5, item6), filter.getItems()); - filter.onFilterSelected(Filters.PREFETCHED); + filter.onFilterSelected(Filters.FilterType.PREFETCHED); verify(mObserver, times(1)).onItemsRemoved(CollectionUtil.newHashSet(item5, item6)); verify(mObserver, times(1)).onItemsAdded(CollectionUtil.newHashSet(item7, item8)); Assert.assertEquals(CollectionUtil.newHashSet(item7, item8), filter.getItems()); - filter.onFilterSelected(Filters.NONE); + filter.onFilterSelected(Filters.FilterType.NONE); verify(mObserver, times(1)) .onItemsAdded(CollectionUtil.newHashSet(item1, item2, item3, item4, item5, item6)); Assert.assertEquals(CollectionUtil.newHashSet(item1, item2, item3, item4, item5, item6),
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index d4cdb7b1..94cd53ab 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -1942,6 +1942,9 @@ {"enable-ntp-button", flag_descriptions::kNtpButtonName, flag_descriptions::kNtpButtonDescription, kOsAndroid, FEATURE_VALUE_TYPE(chrome::android::kNTPButton)}, + {"enable-homepage-tile", flag_descriptions::kHomepageTileName, + flag_descriptions::kHomepageTileDescription, kOsAndroid, + FEATURE_VALUE_TYPE(chrome::android::kHomepageTile)}, #endif // OS_ANDROID #if defined(OS_ANDROID) {"enable-tab-modal-js-dialog-android",
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc index 7126ee9..59762341 100644 --- a/chrome/browser/android/chrome_feature_list.cc +++ b/chrome/browser/android/chrome_feature_list.cc
@@ -103,6 +103,7 @@ &kFullscreenActivity, &kHandleMediaIntents, &kHomePageButtonForceEnabled, + &kHomepageTile, &kHorizontalTabSwitcherAndroid, &kImprovedA2HS, &kLanguagesPreference, @@ -284,6 +285,9 @@ const base::Feature kHomePageButtonForceEnabled{ "HomePageButtonForceEnabled", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kHomepageTile{"HomepageTile", + base::FEATURE_ENABLED_BY_DEFAULT}; + const base::Feature kHorizontalTabSwitcherAndroid{ "HorizontalTabSwitcherAndroid", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h index 5d24a03f..ad96f313 100644 --- a/chrome/browser/android/chrome_feature_list.h +++ b/chrome/browser/android/chrome_feature_list.h
@@ -49,6 +49,7 @@ extern const base::Feature kFullscreenActivity; extern const base::Feature kHandleMediaIntents; extern const base::Feature kHomePageButtonForceEnabled; +extern const base::Feature kHomepageTile; extern const base::Feature kHorizontalTabSwitcherAndroid; extern const base::Feature kImprovedA2HS; extern const base::Feature kLanguagesPreference;
diff --git a/chrome/browser/android/history_report/history_report_jni_bridge.cc b/chrome/browser/android/history_report/history_report_jni_bridge.cc index 37acfe9..0c847ce 100644 --- a/chrome/browser/android/history_report/history_report_jni_bridge.cc +++ b/chrome/browser/android/history_report/history_report_jni_bridge.cc
@@ -9,6 +9,7 @@ #include <vector> +#include "base/android/jni_android.h" #include "base/android/jni_array.h" #include "base/android/jni_string.h" #include "base/bind.h" @@ -145,6 +146,12 @@ usage_reports_buffer_service_->Remove(to_remove); } +void HistoryReportJniBridge::ClearUsageReports( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj) { + usage_reports_buffer_service_->Clear(); +} + void HistoryReportJniBridge::NotifyDataChanged() { JNIEnv* env = base::android::AttachCurrentThread(); ScopedJavaLocalRef<jobject> obj = weak_java_provider_.get(env);
diff --git a/chrome/browser/android/history_report/history_report_jni_bridge.h b/chrome/browser/android/history_report/history_report_jni_bridge.h index df596da..cb8a5ed 100644 --- a/chrome/browser/android/history_report/history_report_jni_bridge.h +++ b/chrome/browser/android/history_report/history_report_jni_bridge.h
@@ -50,6 +50,9 @@ JNIEnv* env, const base::android::JavaParamRef<jobject>& obj, const base::android::JavaParamRef<jobjectArray>& batch); + // Clear all entries from the usage reports. + void ClearUsageReports(JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj); // Populates the usage reports buffer with historic visits. // This should happen only once per corpus registration. jboolean AddHistoricVisitsToUsageReportsBuffer(
diff --git a/chrome/browser/android/vr/vr_shell_delegate.cc b/chrome/browser/android/vr/vr_shell_delegate.cc index 09f64b0..f843dd95 100644 --- a/chrome/browser/android/vr/vr_shell_delegate.cc +++ b/chrome/browser/android/vr/vr_shell_delegate.cc
@@ -176,7 +176,7 @@ void VrShellDelegate::OnPresentResult( device::mojom::VRDisplayInfoPtr display_info, device::mojom::XRDeviceRuntimeSessionOptionsPtr options, - device::mojom::VRDisplayHost::RequestSessionCallback callback, + base::OnceCallback<void(device::mojom::XRSessionPtr)> callback, bool success) { DVLOG(1) << __FUNCTION__ << ": success=" << success; if (!success) { @@ -227,8 +227,11 @@ connection->provider = provider.PassInterface(); connection->transport_options = std::move(transport_options); + device::mojom::XRSessionPtr xr_session = device::mojom::XRSession::New(); + xr_session->connection = std::move(connection); + base::ResetAndReturn(&request_present_response_callback_) - .Run(std::move(connection)); + .Run(std::move(xr_session)); } else { base::ResetAndReturn(&request_present_response_callback_).Run(nullptr); } @@ -299,7 +302,7 @@ void VrShellDelegate::StartWebXRPresentation( device::mojom::VRDisplayInfoPtr display_info, device::mojom::XRDeviceRuntimeSessionOptionsPtr options, - device::mojom::VRDisplayHost::RequestSessionCallback callback) { + base::OnceCallback<void(device::mojom::XRSessionPtr)> callback) { if (!on_present_result_callback_.is_null() || !request_present_response_callback_.is_null()) { // Can only handle one request at a time. This is also extremely unlikely to
diff --git a/chrome/browser/android/vr/vr_shell_delegate.h b/chrome/browser/android/vr/vr_shell_delegate.h index 9a4f6d4..859f616 100644 --- a/chrome/browser/android/vr/vr_shell_delegate.h +++ b/chrome/browser/android/vr/vr_shell_delegate.h
@@ -84,7 +84,7 @@ void StartWebXRPresentation( device::mojom::VRDisplayInfoPtr display_info, device::mojom::XRDeviceRuntimeSessionOptionsPtr options, - device::mojom::VRDisplayHost::RequestSessionCallback callback) override; + base::OnceCallback<void(device::mojom::XRSessionPtr)> callback) override; void OnListeningForActivateChanged(bool listening) override; void OnActivateDisplayHandled(bool will_not_present); @@ -92,7 +92,7 @@ void OnPresentResult( device::mojom::VRDisplayInfoPtr display_info, device::mojom::XRDeviceRuntimeSessionOptionsPtr options, - device::mojom::VRDisplayHost::RequestSessionCallback callback, + base::OnceCallback<void(device::mojom::XRSessionPtr)> callback, bool success); std::unique_ptr<VrCoreInfo> MakeVrCoreInfo(JNIEnv* env); @@ -108,7 +108,7 @@ // Mojo callback waiting for request present response. This is temporarily // stored here from OnPresentResult's outgoing ConnectPresentingService call // until the reply arguments are received by SendRequestPresentReply. - device::mojom::VRDisplayHost::RequestSessionCallback + base::OnceCallback<void(device::mojom::XRSessionPtr)> request_present_response_callback_; bool pending_successful_present_request_ = false;
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm index b1cd4aa..70ec6d2 100644 --- a/chrome/browser/app_controller_mac.mm +++ b/chrome/browser/app_controller_mac.mm
@@ -81,6 +81,7 @@ #include "chrome/browser/ui/startup/startup_browser_creator_impl.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/user_manager.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/browser/web_applications/web_app_mac.h" #include "chrome/common/chrome_features.h" #include "chrome/common/chrome_paths_internal.h"
diff --git a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc index 0f48942..2d71f4a 100644 --- a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc +++ b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc
@@ -27,6 +27,7 @@ #include "chrome/browser/ui/extensions/extension_enable_flow.h" #include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h" #include "chrome/browser/ui/user_manager.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/browser/web_applications/web_app_mac.h" #include "chrome/common/extensions/extension_constants.h" #include "chrome/common/extensions/extension_metrics.h"
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index f208051..5c6069f 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd
@@ -421,6 +421,7 @@ <include name="IDR_DICE_SYNC_CONFIRMATION_BROWSER_PROXY_JS" file="resources\signin\dice_sync_confirmation\sync_confirmation_browser_proxy.js" type="BINDATA" /> <include name="IDR_DICE_SYNC_CONFIRMATION_APP_HTML" file="resources\signin\dice_sync_confirmation\sync_confirmation_app.html" type="BINDATA" flattenhtml="true" allowexternalscript="true" /> <include name="IDR_DICE_SYNC_CONFIRMATION_APP_JS" file="resources\signin\dice_sync_confirmation\sync_confirmation_app.js" type="BINDATA" /> + <include name="IDR_DICE_SYNC_CONFIRMATION_ICONS_HTML" file="resources\signin\dice_sync_confirmation\icons.html" type="BINDATA" /> <include name="IDR_SIGNIN_EMAIL_CONFIRMATION_HTML" file="resources\signin\signin_email_confirmation\signin_email_confirmation.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> <include name="IDR_SIGNIN_EMAIL_CONFIRMATION_JS" file="resources\signin\signin_email_confirmation\signin_email_confirmation.js" type="BINDATA" /> <include name="IDR_SIGNIN_ERROR_HTML" file="resources\signin\signin_error\signin_error.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc index bff4877..ccb9ca7 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -1081,11 +1081,13 @@ ~MockNetworkErrorLoggingService() override = default; - void OnHeader(const url::Origin& origin, const std::string& value) override { + void OnHeader(const url::Origin& origin, + const net::IPAddress& received_ip_address, + const std::string& value) override { NOTREACHED(); } - void OnRequest(const RequestDetails& details) override { NOTREACHED(); } + void OnRequest(RequestDetails details) override { NOTREACHED(); } void RemoveBrowsingData(const base::RepeatingCallback<bool(const GURL&)>& origin_filter) override {
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 21415b5..e0946c0 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -925,15 +925,6 @@ } #endif -// Gets the URL request context getter for the browser process. -// Must be called on the UI thread. -scoped_refptr<net::URLRequestContextGetter> -GetSystemRequestContextOnUIThread() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - return scoped_refptr<net::URLRequestContextGetter>( - g_browser_process->system_request_context()); -} - chrome::mojom::PrerenderCanceler* GetPrerenderCanceller( const base::Callback<content::WebContents*()>& wc_getter) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -2557,12 +2548,14 @@ return NULL; } -void ChromeContentBrowserClient::GetGeolocationRequestContext( - base::OnceCallback<void(scoped_refptr<net::URLRequestContextGetter>)> - callback) { - BrowserThread::PostTaskAndReplyWithResult( - BrowserThread::UI, FROM_HERE, - base::BindOnce(&GetSystemRequestContextOnUIThread), std::move(callback)); +scoped_refptr<network::SharedURLLoaderFactory> +ChromeContentBrowserClient::GetSystemSharedURLLoaderFactory() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (!g_browser_process->system_network_context_manager()) + return nullptr; + + return g_browser_process->system_network_context_manager() + ->GetSharedURLLoaderFactory(); } std::string ChromeContentBrowserClient::GetGeolocationApiKey() {
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index e925fdb9..ff1be12 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h
@@ -233,9 +233,8 @@ net::URLRequestContext* OverrideRequestContextForURL( const GURL& url, content::ResourceContext* context) override; - void GetGeolocationRequestContext( - base::OnceCallback<void(scoped_refptr<net::URLRequestContextGetter>)> - callback) override; + scoped_refptr<network::SharedURLLoaderFactory> + GetSystemSharedURLLoaderFactory() override; std::string GetGeolocationApiKey() override; #if defined(OS_ANDROID)
diff --git a/chrome/browser/chromeos/login/screen_manager.cc b/chrome/browser/chromeos/login/screen_manager.cc index 23ee4fa..5a2e9a91 100644 --- a/chrome/browser/chromeos/login/screen_manager.cc +++ b/chrome/browser/chromeos/login/screen_manager.cc
@@ -9,20 +9,21 @@ namespace chromeos { -ScreenManager::ScreenManager(WizardController* wizard_controller) - : wizard_controller_(wizard_controller) {} +ScreenManager::ScreenManager() = default; -ScreenManager::~ScreenManager() {} +ScreenManager::~ScreenManager() = default; BaseScreen* ScreenManager::GetScreen(OobeScreen screen) { auto iter = screens_.find(screen); if (iter != screens_.end()) return iter->second.get(); - BaseScreen* result = wizard_controller_->CreateScreen(screen); + std::unique_ptr<BaseScreen> result = + WizardController::default_controller()->CreateScreen(screen); DCHECK(result) << "Can not create screen named " << GetOobeScreenName(screen); - screens_[screen] = base::WrapUnique(result); - return result; + BaseScreen* unowned_result = result.get(); + screens_[screen] = std::move(result); + return unowned_result; } bool ScreenManager::HasScreen(OobeScreen screen) {
diff --git a/chrome/browser/chromeos/login/screen_manager.h b/chrome/browser/chromeos/login/screen_manager.h index 9c52cd5..159b0019 100644 --- a/chrome/browser/chromeos/login/screen_manager.h +++ b/chrome/browser/chromeos/login/screen_manager.h
@@ -15,13 +15,10 @@ namespace chromeos { -class WizardController; - // Class that manages creation and ownership of screens. class ScreenManager { public: - // |wizard_controller| is not owned by this class. - explicit ScreenManager(WizardController* wizard_controller); + ScreenManager(); ~ScreenManager(); // Getter for screen with lazy initialization. @@ -41,9 +38,6 @@ // Created screens. std::map<OobeScreen, std::unique_ptr<BaseScreen>> screens_; - // Used to allocate BaseScreen instances. Unowned. - WizardController* wizard_controller_; - DISALLOW_COPY_AND_ASSIGN(ScreenManager); };
diff --git a/chrome/browser/chromeos/login/ui/fake_login_display_host.cc b/chrome/browser/chromeos/login/ui/fake_login_display_host.cc index b889c171..3a54ba0 100644 --- a/chrome/browser/chromeos/login/ui/fake_login_display_host.cc +++ b/chrome/browser/chromeos/login/ui/fake_login_display_host.cc
@@ -56,10 +56,7 @@ void FakeLoginDisplayHost::SetStatusAreaVisible(bool visible) {} void FakeLoginDisplayHost::StartWizard(OobeScreen first_screen) { - // Reset the controller first since there could only be one wizard - // controller at any time. - wizard_controller_.reset(); - wizard_controller_ = std::make_unique<WizardController>(nullptr, nullptr); + wizard_controller_ = std::make_unique<WizardController>(); fake_screen_ = std::make_unique<FakeBaseScreen>(first_screen); wizard_controller_->SetCurrentScreenForTesting(fake_screen_.get());
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc b/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc index 0c3a91d..2e673b39 100644 --- a/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc +++ b/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc
@@ -148,10 +148,7 @@ void LoginDisplayHostMojo::StartWizard(OobeScreen first_screen) { DCHECK(GetOobeUI()); - // Dtor of the old WizardController should be called before ctor of the - // new one to ensure only one |ExistingUserController| instance at a time. - wizard_controller_.reset(); - wizard_controller_.reset(new WizardController(this, GetOobeUI())); + wizard_controller_ = std::make_unique<WizardController>(); wizard_controller_->Init(first_screen); // Post login screens should not be closable by escape key.
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc index 5b111be..87522ff 100644 --- a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc +++ b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
@@ -602,11 +602,7 @@ DVLOG(1) << "Starting wizard, first_screen: " << GetOobeScreenName(first_screen); // Create and show the wizard. - // Note, dtor of the old WizardController should be called before ctor of the - // new one, because "default_controller()" is updated there. So pure "reset()" - // is done before new controller creation. - wizard_controller_.reset(); - wizard_controller_.reset(CreateWizardController()); + wizard_controller_ = std::make_unique<WizardController>(); oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered(); SetOobeProgressBarVisible(oobe_progress_bar_visible_); @@ -755,12 +751,6 @@ //////////////////////////////////////////////////////////////////////////////// // LoginDisplayHostWebUI, public -WizardController* LoginDisplayHostWebUI::CreateWizardController() { - // TODO(altimofeev): ensure that WebUI is ready. - OobeUI* oobe_ui = GetOobeUI(); - return new WizardController(this, oobe_ui); -} - void LoginDisplayHostWebUI::OnBrowserCreated() { // Close lock window now so that the launched browser can receive focus. ResetLoginWindowAndView();
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_webui.h b/chrome/browser/chromeos/login/ui/login_display_host_webui.h index 585e88f..c8f55db 100644 --- a/chrome/browser/chromeos/login/ui/login_display_host_webui.h +++ b/chrome/browser/chromeos/login/ui/login_display_host_webui.h
@@ -81,9 +81,6 @@ void ShowFeedback() override; void OnCancelPasswordChangedFlow() override; - // Creates WizardController instance. - WizardController* CreateWizardController(); - // Trace id for ShowLoginWebUI event (since there exists at most one login // WebUI at a time). static const int kShowLoginWebUIid;
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc index a737896..901b4319 100644 --- a/chrome/browser/chromeos/login/wizard_controller.cc +++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -251,6 +251,15 @@ chromeos::switches::kEnableOobeRecommendAppsScreen); } +chromeos::LoginDisplayHost* GetLoginDisplayHost() { + return chromeos::LoginDisplayHost::default_host(); +} + +chromeos::OobeUI* GetOobeUI() { + auto* host = chromeos::LoginDisplayHost::default_host(); + return host ? host->GetOobeUI() : nullptr; +} + } // namespace namespace chromeos { @@ -258,10 +267,6 @@ // static const int WizardController::kMinAudibleOutputVolumePercent = 10; -// Initialize default controller. -// static -WizardController* WizardController::default_controller_ = nullptr; - // static bool WizardController::skip_post_login_screens_ = false; @@ -271,16 +276,19 @@ // static bool WizardController::zero_delay_enabled_ = false; +// static +WizardController* WizardController::default_controller() { + auto* host = chromeos::LoginDisplayHost::default_host(); + return host ? host->GetWizardController() : nullptr; +} + /////////////////////////////////////////////////////////////////////////////// // WizardController, public: PrefService* WizardController::local_state_for_testing_ = nullptr; -WizardController::WizardController(LoginDisplayHost* host, OobeUI* oobe_ui) - : host_(host), oobe_ui_(oobe_ui), weak_factory_(this) { - DCHECK(default_controller_ == nullptr); - default_controller_ = this; - screen_manager_ = std::make_unique<ScreenManager>(this); +WizardController::WizardController() + : screen_manager_(std::make_unique<ScreenManager>()), weak_factory_(this) { // In session OOBE was initiated from voice interaction keyboard shortcuts. is_in_session_oobe_ = session_manager::SessionManager::Get()->IsSessionStarted(); @@ -308,11 +316,6 @@ base::ThreadTaskRunnerHandle::Get()->DeleteSoon( FROM_HERE, shark_connection_listener_.release()); } - if (default_controller_ == this) { - default_controller_ = nullptr; - } else { - NOTREACHED() << "More than one controller are alive."; - } } void WizardController::Init(OobeScreen first_screen) { @@ -378,7 +381,7 @@ } ErrorScreen* WizardController::GetErrorScreen() { - return oobe_ui_->GetErrorScreen(); + return GetOobeUI()->GetErrorScreen(); } BaseScreen* WizardController::GetScreen(OobeScreen screen) { @@ -387,66 +390,74 @@ return screen_manager_->GetScreen(screen); } -BaseScreen* WizardController::CreateScreen(OobeScreen screen) { +std::unique_ptr<BaseScreen> WizardController::CreateScreen(OobeScreen screen) { + OobeUI* oobe_ui = GetOobeUI(); + if (screen == OobeScreen::SCREEN_OOBE_WELCOME) { - return new WelcomeScreen(this, this, oobe_ui_->GetWelcomeView()); + return std::make_unique<WelcomeScreen>(this, this, + oobe_ui->GetWelcomeView()); } else if (screen == OobeScreen::SCREEN_OOBE_UPDATE) { - return new UpdateScreen(this, oobe_ui_->GetUpdateView(), - remora_controller_.get()); + return std::make_unique<UpdateScreen>(this, oobe_ui->GetUpdateView(), + remora_controller_.get()); } else if (screen == OobeScreen::SCREEN_USER_IMAGE_PICKER) { - return new UserImageScreen(this, oobe_ui_->GetUserImageView()); + return std::make_unique<UserImageScreen>(this, oobe_ui->GetUserImageView()); } else if (screen == OobeScreen::SCREEN_OOBE_EULA) { - return new EulaScreen(this, this, oobe_ui_->GetEulaView()); + return std::make_unique<EulaScreen>(this, this, oobe_ui->GetEulaView()); } else if (screen == OobeScreen::SCREEN_OOBE_ENROLLMENT) { - return new EnrollmentScreen(this, oobe_ui_->GetEnrollmentScreenView()); + return std::make_unique<EnrollmentScreen>( + this, oobe_ui->GetEnrollmentScreenView()); } else if (screen == OobeScreen::SCREEN_OOBE_RESET) { - return new chromeos::ResetScreen(this, oobe_ui_->GetResetView()); + return std::make_unique<chromeos::ResetScreen>(this, + oobe_ui->GetResetView()); } else if (screen == OobeScreen::SCREEN_OOBE_DEMO_SETUP) { - return new chromeos::DemoSetupScreen(this, - oobe_ui_->GetDemoSetupScreenView()); + return std::make_unique<chromeos::DemoSetupScreen>( + this, oobe_ui->GetDemoSetupScreenView()); } else if (screen == OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES) { - return new chromeos::DemoPreferencesScreen( - this, oobe_ui_->GetDemoPreferencesScreenView()); + return std::make_unique<chromeos::DemoPreferencesScreen>( + this, oobe_ui->GetDemoPreferencesScreenView()); } else if (screen == OobeScreen::SCREEN_OOBE_ENABLE_DEBUGGING) { - return new EnableDebuggingScreen(this, - oobe_ui_->GetEnableDebuggingScreenView()); + return std::make_unique<EnableDebuggingScreen>( + this, oobe_ui->GetEnableDebuggingScreenView()); } else if (screen == OobeScreen::SCREEN_KIOSK_ENABLE) { - return new KioskEnableScreen(this, oobe_ui_->GetKioskEnableScreenView()); + return std::make_unique<KioskEnableScreen>( + this, oobe_ui->GetKioskEnableScreenView()); } else if (screen == OobeScreen::SCREEN_KIOSK_AUTOLAUNCH) { - return new KioskAutolaunchScreen(this, - oobe_ui_->GetKioskAutolaunchScreenView()); + return std::make_unique<KioskAutolaunchScreen>( + this, oobe_ui->GetKioskAutolaunchScreenView()); } else if (screen == OobeScreen::SCREEN_TERMS_OF_SERVICE) { - return new TermsOfServiceScreen(this, - oobe_ui_->GetTermsOfServiceScreenView()); + return std::make_unique<TermsOfServiceScreen>( + this, oobe_ui->GetTermsOfServiceScreenView()); } else if (screen == OobeScreen::SCREEN_SYNC_CONSENT) { - return new SyncConsentScreen(this, oobe_ui_->GetSyncConsentScreenView()); + return std::make_unique<SyncConsentScreen>( + this, oobe_ui->GetSyncConsentScreenView()); } else if (screen == OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE) { - return new ArcTermsOfServiceScreen( - this, oobe_ui_->GetArcTermsOfServiceScreenView()); + return std::make_unique<ArcTermsOfServiceScreen>( + this, oobe_ui->GetArcTermsOfServiceScreenView()); } else if (screen == OobeScreen::SCREEN_RECOMMEND_APPS) { - return new RecommendAppsScreen(this, - oobe_ui_->GetRecommendAppsScreenView()); + return std::make_unique<RecommendAppsScreen>( + this, oobe_ui->GetRecommendAppsScreenView()); } else if (screen == OobeScreen::SCREEN_APP_DOWNLOADING) { - return new AppDownloadingScreen(this, - oobe_ui_->GetAppDownloadingScreenView()); + return std::make_unique<AppDownloadingScreen>( + this, oobe_ui->GetAppDownloadingScreenView()); } else if (screen == OobeScreen::SCREEN_WRONG_HWID) { - return new WrongHWIDScreen(this, oobe_ui_->GetWrongHWIDScreenView()); + return std::make_unique<WrongHWIDScreen>(this, + oobe_ui->GetWrongHWIDScreenView()); } else if (screen == OobeScreen::SCREEN_CREATE_SUPERVISED_USER_FLOW) { - return new SupervisedUserCreationScreen( - this, oobe_ui_->GetSupervisedUserCreationScreenView()); + return std::make_unique<SupervisedUserCreationScreen>( + this, oobe_ui->GetSupervisedUserCreationScreenView()); } else if (screen == OobeScreen::SCREEN_OOBE_HID_DETECTION) { - return new chromeos::HIDDetectionScreen(this, - oobe_ui_->GetHIDDetectionView()); + return std::make_unique<chromeos::HIDDetectionScreen>( + this, oobe_ui->GetHIDDetectionView()); } else if (screen == OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK) { - return new AutoEnrollmentCheckScreen( - this, oobe_ui_->GetAutoEnrollmentCheckScreenView()); + return std::make_unique<AutoEnrollmentCheckScreen>( + this, oobe_ui->GetAutoEnrollmentCheckScreenView()); } else if (screen == OobeScreen::SCREEN_OOBE_CONTROLLER_PAIRING) { if (!shark_controller_) { shark_controller_.reset( new pairing_chromeos::BluetoothControllerPairingController()); } - return new ControllerPairingScreen( - this, this, oobe_ui_->GetControllerPairingScreenView(), + return std::make_unique<ControllerPairingScreen>( + this, this, oobe_ui->GetControllerPairingScreenView(), shark_controller_.get()); } else if (screen == OobeScreen::SCREEN_OOBE_HOST_PAIRING) { if (!remora_controller_) { @@ -458,24 +469,24 @@ new pairing_chromeos::BluetoothHostPairingController(connector)); remora_controller_->StartPairing(); } - return new HostPairingScreen(this, this, - oobe_ui_->GetHostPairingScreenView(), - remora_controller_.get()); + return std::make_unique<HostPairingScreen>( + this, this, oobe_ui->GetHostPairingScreenView(), + remora_controller_.get()); } else if (screen == OobeScreen::SCREEN_DEVICE_DISABLED) { - return new DeviceDisabledScreen(this, - oobe_ui_->GetDeviceDisabledScreenView()); + return std::make_unique<DeviceDisabledScreen>( + this, oobe_ui->GetDeviceDisabledScreenView()); } else if (screen == OobeScreen::SCREEN_ENCRYPTION_MIGRATION) { - return new EncryptionMigrationScreen( - this, oobe_ui_->GetEncryptionMigrationScreenView()); + return std::make_unique<EncryptionMigrationScreen>( + this, oobe_ui->GetEncryptionMigrationScreenView()); } else if (screen == OobeScreen::SCREEN_VOICE_INTERACTION_VALUE_PROP) { - return new VoiceInteractionValuePropScreen( - this, oobe_ui_->GetVoiceInteractionValuePropScreenView()); + return std::make_unique<VoiceInteractionValuePropScreen>( + this, oobe_ui->GetVoiceInteractionValuePropScreenView()); } else if (screen == OobeScreen::SCREEN_WAIT_FOR_CONTAINER_READY) { - return new WaitForContainerReadyScreen( - this, oobe_ui_->GetWaitForContainerReadyScreenView()); + return std::make_unique<WaitForContainerReadyScreen>( + this, oobe_ui->GetWaitForContainerReadyScreenView()); } else if (screen == OobeScreen::SCREEN_UPDATE_REQUIRED) { - return new UpdateRequiredScreen(this, - oobe_ui_->GetUpdateRequiredScreenView()); + return std::make_unique<UpdateRequiredScreen>( + this, oobe_ui->GetUpdateRequiredScreenView()); } return nullptr; } @@ -512,7 +523,7 @@ } VLOG(1) << "Showing login screen."; UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_SPECIAL_LOGIN); - host_->StartSignInScreen(context); + GetLoginDisplayHost()->StartSignInScreen(context); smooth_show_timer_.Stop(); login_screen_started_ = true; } @@ -630,7 +641,7 @@ // which use ArcSupport for now, because we're interested in only OOBE flow. // Note that this part also needs to be updated on b/65861628. // TODO(khmel): add unit test once we have support for OobeUI. - if (!host_->IsVoiceInteractionOobe()) { + if (!GetLoginDisplayHost()->IsVoiceInteractionOobe()) { ProfileManager::GetActiveUserProfile()->GetPrefs()->SetBoolean( arc::prefs::kArcTermsShownInOobe, true); } @@ -1055,9 +1066,8 @@ void WizardController::OnOobeFlowFinished() { if (is_in_session_oobe_) { - host_->SetStatusAreaVisible(true); - host_->Finalize(base::OnceClosure()); - host_ = nullptr; + GetLoginDisplayHost()->SetStatusAreaVisible(true); + GetLoginDisplayHost()->Finalize(base::OnceClosure()); return; } @@ -1074,8 +1084,8 @@ BrowserThread::UI, FROM_HERE, base::BindOnce(&UserSessionManager::DoBrowserLaunch, base::Unretained(UserSessionManager::GetInstance()), - ProfileManager::GetActiveUserProfile(), host_)); - host_ = nullptr; + ProfileManager::GetActiveUserProfile(), + GetLoginDisplayHost())); } void WizardController::OnDeviceDisabledChecked(bool device_disabled) { @@ -1151,7 +1161,7 @@ NetworkHandler::Get()->network_state_handler()->SetCheckPortalList( NetworkStateHandler::kDefaultCheckPortalList); GetAutoEnrollmentController()->Start(); - host_->PrewarmAuthentication(); + GetLoginDisplayHost()->PrewarmAuthentication(); network_portal_detector::GetInstance()->Enable(true); } @@ -1180,7 +1190,7 @@ void WizardController::ShowCurrentScreen() { // ShowCurrentScreen may get called by smooth_show_timer_ even after // flow has been switched to sign in screen (ExistingUserController). - if (!oobe_ui_) + if (!GetOobeUI()) return; // First remember how far have we reached so that we can resume if needed. @@ -1201,7 +1211,7 @@ VLOG(1) << "SetCurrentScreenSmooth: " << GetOobeScreenName(new_current->screen_id()); if (current_screen_ == new_current || new_current == nullptr || - oobe_ui_ == nullptr) { + GetOobeUI() == nullptr) { return; } @@ -1232,7 +1242,7 @@ if (screen == OobeScreen::SCREEN_OOBE_WELCOME) { // Hide the status area initially; it only appears after OOBE first animates // in. Keep it visible if the user goes back to the existing welcome screen. - host_->SetStatusAreaVisible( + GetLoginDisplayHost()->SetStatusAreaVisible( screen_manager_->HasScreen(OobeScreen::SCREEN_OOBE_WELCOME)); } else if (screen == OobeScreen::SCREEN_OOBE_RESET || screen == OobeScreen::SCREEN_KIOSK_ENABLE || @@ -1242,14 +1252,14 @@ screen == OobeScreen::SCREEN_ARC_KIOSK_SPLASH || screen == OobeScreen::SCREEN_OOBE_CONTROLLER_PAIRING || screen == OobeScreen::SCREEN_OOBE_HOST_PAIRING) { - host_->SetStatusAreaVisible(false); + GetLoginDisplayHost()->SetStatusAreaVisible(false); } else { - host_->SetStatusAreaVisible(true); + GetLoginDisplayHost()->SetStatusAreaVisible(true); } } void WizardController::OnHIDScreenNecessityCheck(bool screen_needed) { - if (!oobe_ui_) + if (!GetOobeUI()) return; if (screen_needed) { @@ -1337,7 +1347,7 @@ base::Callback<void(bool)> on_check = base::Bind(&WizardController::OnHIDScreenNecessityCheck, weak_factory_.GetWeakPtr()); - oobe_ui_->GetHIDDetectionView()->CheckIsScreenRequired(on_check); + GetOobeUI()->GetHIDDetectionView()->CheckIsScreenRequired(on_check); } else { ShowWelcomeScreen(); } @@ -1623,7 +1633,7 @@ // If the |cros_settings_| are permanently untrusted, show an error message // and refuse to auto-launch the kiosk app. GetErrorScreen()->SetUIState(NetworkError::UI_STATE_LOCAL_STATE_ERROR); - host_->SetStatusAreaVisible(false); + GetLoginDisplayHost()->SetStatusAreaVisible(false); ShowErrorScreen(); return; } @@ -1636,7 +1646,7 @@ const bool diagnostic_mode = false; const bool auto_launch = true; - host_->StartAppLaunch(app_id, diagnostic_mode, auto_launch); + GetLoginDisplayHost()->StartAppLaunch(app_id, diagnostic_mode, auto_launch); } // static @@ -1664,16 +1674,16 @@ // static void WizardController::SkipPostLoginScreensForTesting() { skip_post_login_screens_ = true; - if (!default_controller_ || !default_controller_->current_screen()) + if (!default_controller() || !default_controller()->current_screen()) return; const OobeScreen current_screen_id = - default_controller_->current_screen()->screen_id(); + default_controller()->current_screen()->screen_id(); if (current_screen_id == OobeScreen::SCREEN_TERMS_OF_SERVICE || current_screen_id == OobeScreen::SCREEN_SYNC_CONSENT || current_screen_id == OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE || current_screen_id == OobeScreen::SCREEN_USER_IMAGE_PICKER) { - default_controller_->OnOobeFlowFinished(); + default_controller()->OnOobeFlowFinished(); } else { LOG(WARNING) << "SkipPostLoginScreensForTesting(): Ignore screen " << static_cast<int>(current_screen_id); @@ -1698,7 +1708,7 @@ return; } GetErrorScreen()->SetUIState(NetworkError::UI_STATE_LOCAL_STATE_ERROR); - host_->SetStatusAreaVisible(false); + GetLoginDisplayHost()->SetStatusAreaVisible(false); ShowErrorScreen(); }
diff --git a/chrome/browser/chromeos/login/wizard_controller.h b/chrome/browser/chromeos/login/wizard_controller.h index 588f4e51..4b5cc9a5 100644 --- a/chrome/browser/chromeos/login/wizard_controller.h +++ b/chrome/browser/chromeos/login/wizard_controller.h
@@ -44,7 +44,6 @@ struct Geoposition; class LoginDisplayHost; class LoginScreenContext; -class OobeUI; class SimpleGeolocationProvider; class TimeZoneProvider; struct TimeZoneResponseData; @@ -59,11 +58,12 @@ public HIDDetectionScreen::Delegate, public OobeConfiguration::Observer { public: - WizardController(LoginDisplayHost* host, OobeUI* oobe_ui); + WizardController(); ~WizardController() override; - // Returns the default wizard controller if it has been created. - static WizardController* default_controller() { return default_controller_; } + // Returns the default wizard controller if it has been created. This is a + // helper for LoginDisplayHost::default_host()->GetWizardController(); + static WizardController* default_controller(); // Whether to skip any screens that may normally be shown after login // (registration, Terms of Service, user image selection). @@ -144,7 +144,7 @@ // Allocate a given BaseScreen for the given |Screen|. Used by // |screen_manager_|. - BaseScreen* CreateScreen(OobeScreen screen); + std::unique_ptr<BaseScreen> CreateScreen(OobeScreen screen); // Set the current screen. For Test use only. void SetCurrentScreenForTesting(BaseScreen* screen); @@ -393,16 +393,8 @@ // Value of the screen name that WizardController was started with. OobeScreen first_screen_; - // OOBE/login display host. - LoginDisplayHost* host_ = nullptr; - - // Default WizardController. - static WizardController* default_controller_; - base::OneShotTimer smooth_show_timer_; - OobeUI* const oobe_ui_; - // State of Usage stat/error reporting checkbox on EULA screen // during wizard lifetime. bool usage_statistics_reporting_ = true;
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc index aa044a3..d3c65a1 100644 --- a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc +++ b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
@@ -224,8 +224,15 @@ ASSERT_FALSE(profile()->HasOffTheRecordProfile()); } +#if defined(OS_MACOSX) +// Timeout on Mac. crbug.com/864250 +#define MAYBE_OffscreenTabEvilTests DISABLED_OffscreenTabEvilTests +#else +#define MAYBE_OffscreenTabEvilTests OffscreenTabEvilTests +#endif + // Tests that off-screen tabs can't do evil things (e.g., access local files). -IN_PROC_BROWSER_TEST_F(TabCaptureApiPixelTest, OffscreenTabEvilTests) { +IN_PROC_BROWSER_TEST_F(TabCaptureApiPixelTest, MAYBE_OffscreenTabEvilTests) { if (IsTooIntensiveForThisPlatform()) { LOG(WARNING) << "Skipping this CPU-intensive test on this platform/build."; return;
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc index f2e7c6f..6dbd04f 100644 --- a/chrome/browser/extensions/api/tabs/tabs_api.cc +++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -53,7 +53,7 @@ #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/tabs/tab_utils.h" #include "chrome/browser/ui/window_sizer/window_sizer.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/api/tabs.h" #include "chrome/common/extensions/api/windows.h"
diff --git a/chrome/browser/extensions/bookmark_app_navigation_throttle_browsertest.cc b/chrome/browser/extensions/bookmark_app_navigation_throttle_browsertest.cc index e4cfe51d..4dd5db6a 100644 --- a/chrome/browser/extensions/bookmark_app_navigation_throttle_browsertest.cc +++ b/chrome/browser/extensions/bookmark_app_navigation_throttle_browsertest.cc
@@ -19,7 +19,7 @@ #include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/common/chrome_features.h" #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" #include "chrome/test/base/ui_test_utils.h"
diff --git a/chrome/browser/extensions/bookmark_app_navigation_throttle_utils.cc b/chrome/browser/extensions/bookmark_app_navigation_throttle_utils.cc index 94ee3ff..9466a41 100644 --- a/chrome/browser/extensions/bookmark_app_navigation_throttle_utils.cc +++ b/chrome/browser/extensions/bookmark_app_navigation_throttle_utils.cc
@@ -11,7 +11,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_window.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/common/extensions/api/url_handlers/url_handlers_parser.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/navigation_handle.h"
diff --git a/chrome/browser/extensions/browsertest_util.cc b/chrome/browser/extensions/browsertest_util.cc index d085db6..7a917e00 100644 --- a/chrome/browser/extensions/browsertest_util.cc +++ b/chrome/browser/extensions/browsertest_util.cc
@@ -14,7 +14,7 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/common/web_application_info.h" #include "content/public/browser/notification_service.h" #include "content/public/test/test_utils.h"
diff --git a/chrome/browser/extensions/tab_helper.cc b/chrome/browser/extensions/tab_helper.cc index ec493e80..ce98467 100644 --- a/chrome/browser/extensions/tab_helper.cc +++ b/chrome/browser/extensions/tab_helper.cc
@@ -29,7 +29,7 @@ #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/browser_finder.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/common/extensions/api/webstore/webstore_api_constants.h" #include "chrome/common/extensions/extension_constants.h" #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 33b48ec..dc8cea4 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -2353,8 +2353,15 @@ const char kHomePageButtonName[] = "Force Enable Home Page Button"; const char kHomePageButtonDescription[] = "Displays a home button if enabled."; +const char kHomepageTileName[] = + "Enable Homepage tile shown in Suggested Tiles"; +const char kHomepageTileDescription[] = + "When NTPButton is enabled, the first tile of the Suggested Tiles will be " + "used for homepage. It will not have an effect when NTPButton is disabled."; + const char kInterestFeedContentSuggestionsDescription[] = - "Use the interest feed to render content suggestions. Currently content " + "Use the interest feed to render content suggestions. Currently " + "content " "suggestions are shown on the New Tab Page."; const char kInterestFeedContentSuggestionsName[] = "Interest Feed Content Suggestions";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 22bfea0e..076d6e6 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1427,6 +1427,9 @@ extern const char kHomePageButtonName[]; extern const char kHomePageButtonDescription[]; +extern const char kHomepageTileName[]; +extern const char kHomepageTileDescription[]; + extern const char kInterestFeedContentSuggestionsName[]; extern const char kInterestFeedContentSuggestionsDescription[];
diff --git a/chrome/browser/payments/android/journey_logger_android.cc b/chrome/browser/payments/android/journey_logger_android.cc index 9d2edea..8280ce7 100644 --- a/chrome/browser/payments/android/journey_logger_android.cc +++ b/chrome/browser/payments/android/journey_logger_android.cc
@@ -5,9 +5,9 @@ #include "chrome/browser/payments/android/journey_logger_android.h" #include "base/android/jni_string.h" +#include "components/ukm/content/source_url_recorder.h" +#include "content/public/browser/web_contents.h" #include "jni/JourneyLogger_jni.h" -#include "services/metrics/public/cpp/ukm_recorder.h" -#include "url/gurl.h" namespace payments { namespace { @@ -18,8 +18,8 @@ } // namespace JourneyLoggerAndroid::JourneyLoggerAndroid(bool is_incognito, - const std::string& url) - : journey_logger_(is_incognito, GURL(url), ukm::UkmRecorder::Get()) {} + ukm::SourceId source_id) + : journey_logger_(is_incognito, source_id) {} JourneyLoggerAndroid::~JourneyLoggerAndroid() {} @@ -137,9 +137,11 @@ JNIEnv* env, const JavaParamRef<jobject>& jcaller, jboolean jis_incognito, - const base::android::JavaParamRef<jstring>& jurl) { + const JavaParamRef<jobject>& jweb_contents) { + content::WebContents* web_contents = + content::WebContents::FromJavaWebContents(jweb_contents); return reinterpret_cast<jlong>(new JourneyLoggerAndroid( - jis_incognito, ConvertJavaStringToUTF8(env, jurl))); + jis_incognito, ukm::GetSourceIdForWebContentsDocument(web_contents))); } } // namespace payments
diff --git a/chrome/browser/payments/android/journey_logger_android.h b/chrome/browser/payments/android/journey_logger_android.h index e2ca58b..ed9a062 100644 --- a/chrome/browser/payments/android/journey_logger_android.h +++ b/chrome/browser/payments/android/journey_logger_android.h
@@ -8,13 +8,14 @@ #include "base/android/scoped_java_ref.h" #include "base/macros.h" #include "components/payments/core/journey_logger.h" +#include "services/metrics/public/cpp/ukm_source_id.h" namespace payments { // Forwarding calls to payments::JourneyLogger. class JourneyLoggerAndroid { public: - JourneyLoggerAndroid(bool is_incognito, const std::string& url); + JourneyLoggerAndroid(bool is_incognito, ukm::SourceId source_id); ~JourneyLoggerAndroid(); // Message from Java to destroy this object.
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc index 6970e77..20f74be 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc +++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -64,7 +64,7 @@ #include "chrome/browser/ui/exclusive_access/keyboard_lock_controller.h" #include "chrome/browser/ui/tab_contents/core_tab_helper.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_features.h" #include "chrome/common/chrome_render_frame.mojom.h"
diff --git a/chrome/browser/resource_coordinator/discard_metrics_lifecycle_unit_observer.cc b/chrome/browser/resource_coordinator/discard_metrics_lifecycle_unit_observer.cc index 4fa7171..aef0bc89 100644 --- a/chrome/browser/resource_coordinator/discard_metrics_lifecycle_unit_observer.cc +++ b/chrome/browser/resource_coordinator/discard_metrics_lifecycle_unit_observer.cc
@@ -19,7 +19,8 @@ void DiscardMetricsLifecycleUnitObserver::OnLifecycleUnitStateChanged( LifecycleUnit* lifecycle_unit, - LifecycleUnitState last_state) { + LifecycleUnitState last_state, + LifecycleUnitStateChangeReason reason) { if (lifecycle_unit->GetState() == LifecycleUnitState::DISCARDED) OnDiscard(lifecycle_unit); else if (last_state == LifecycleUnitState::DISCARDED)
diff --git a/chrome/browser/resource_coordinator/discard_metrics_lifecycle_unit_observer.h b/chrome/browser/resource_coordinator/discard_metrics_lifecycle_unit_observer.h index 426d0ff3..55e5ef46 100644 --- a/chrome/browser/resource_coordinator/discard_metrics_lifecycle_unit_observer.h +++ b/chrome/browser/resource_coordinator/discard_metrics_lifecycle_unit_observer.h
@@ -22,8 +22,10 @@ ~DiscardMetricsLifecycleUnitObserver() override; // LifecycleUnitObserver: - void OnLifecycleUnitStateChanged(LifecycleUnit* lifecycle_unit, - LifecycleUnitState last_state) override; + void OnLifecycleUnitStateChanged( + LifecycleUnit* lifecycle_unit, + LifecycleUnitState last_state, + LifecycleUnitStateChangeReason reason) override; void OnLifecycleUnitDestroyed(LifecycleUnit* lifecycle_unit) override; private:
diff --git a/chrome/browser/resource_coordinator/lifecycle_unit_base.cc b/chrome/browser/resource_coordinator/lifecycle_unit_base.cc index a6e6563..54937b0 100644 --- a/chrome/browser/resource_coordinator/lifecycle_unit_base.cc +++ b/chrome/browser/resource_coordinator/lifecycle_unit_base.cc
@@ -63,7 +63,7 @@ state_change_time_ = NowTicks(); OnLifecycleUnitStateChanged(last_state, reason); for (auto& observer : observers_) - observer.OnLifecycleUnitStateChanged(this, last_state); + observer.OnLifecycleUnitStateChanged(this, last_state, reason); } void LifecycleUnitBase::OnLifecycleUnitStateChanged(
diff --git a/chrome/browser/resource_coordinator/lifecycle_unit_base_unittest.cc b/chrome/browser/resource_coordinator/lifecycle_unit_base_unittest.cc index 4fcfff04..3abe79d 100644 --- a/chrome/browser/resource_coordinator/lifecycle_unit_base_unittest.cc +++ b/chrome/browser/resource_coordinator/lifecycle_unit_base_unittest.cc
@@ -23,8 +23,10 @@ public: MockLifecycleUnitObserver() = default; - MOCK_METHOD2(OnLifecycleUnitStateChanged, - void(LifecycleUnit*, LifecycleUnitState)); + MOCK_METHOD3(OnLifecycleUnitStateChanged, + void(LifecycleUnit*, + LifecycleUnitState, + LifecycleUnitStateChangeReason)); MOCK_METHOD2(OnLifecycleUnitVisibilityChanged, void(LifecycleUnit*, content::Visibility)); MOCK_METHOD1(OnLifecycleUnitDestroyed, void(LifecycleUnit*)); @@ -101,8 +103,10 @@ lifecycle_unit.AddObserver(&observer_); // Observer is notified when the state changes. - EXPECT_CALL(observer_, OnLifecycleUnitStateChanged( - &lifecycle_unit, lifecycle_unit.GetState())); + EXPECT_CALL(observer_, + OnLifecycleUnitStateChanged( + &lifecycle_unit, lifecycle_unit.GetState(), + LifecycleUnitStateChangeReason::BROWSER_INITIATED)); lifecycle_unit.SetState(LifecycleUnitState::DISCARDED, LifecycleUnitStateChangeReason::BROWSER_INITIATED); testing::Mock::VerifyAndClear(&observer_);
diff --git a/chrome/browser/resource_coordinator/lifecycle_unit_observer.cc b/chrome/browser/resource_coordinator/lifecycle_unit_observer.cc index 65a3fb8..4c7ddb6e 100644 --- a/chrome/browser/resource_coordinator/lifecycle_unit_observer.cc +++ b/chrome/browser/resource_coordinator/lifecycle_unit_observer.cc
@@ -10,7 +10,8 @@ void LifecycleUnitObserver::OnLifecycleUnitStateChanged( LifecycleUnit* lifecycle_unit, - LifecycleUnitState last_state) {} + LifecycleUnitState last_state, + LifecycleUnitStateChangeReason reason) {} void LifecycleUnitObserver::OnLifecycleUnitVisibilityChanged( LifecycleUnit* lifecycle_unit,
diff --git a/chrome/browser/resource_coordinator/lifecycle_unit_observer.h b/chrome/browser/resource_coordinator/lifecycle_unit_observer.h index 6e4560bf8..4ef437c 100644 --- a/chrome/browser/resource_coordinator/lifecycle_unit_observer.h +++ b/chrome/browser/resource_coordinator/lifecycle_unit_observer.h
@@ -11,6 +11,7 @@ namespace resource_coordinator { using ::mojom::LifecycleUnitState; +using ::mojom::LifecycleUnitStateChangeReason; class LifecycleUnit; @@ -20,8 +21,10 @@ virtual ~LifecycleUnitObserver(); // Invoked when the state of the observed LifecycleUnit changes. - virtual void OnLifecycleUnitStateChanged(LifecycleUnit* lifecycle_unit, - LifecycleUnitState last_state); + virtual void OnLifecycleUnitStateChanged( + LifecycleUnit* lifecycle_unit, + LifecycleUnitState last_state, + LifecycleUnitStateChangeReason reason); // Invoked when the visibility of the observed LifecyleUnit changes. virtual void OnLifecycleUnitVisibilityChanged(LifecycleUnit* lifecycle_unit,
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source_unittest.cc b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source_unittest.cc index b5f56b51..91d2a0ac 100644 --- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source_unittest.cc +++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source_unittest.cc
@@ -74,8 +74,10 @@ public: MockLifecycleUnitObserver() = default; - MOCK_METHOD2(OnLifecycleUnitStateChanged, - void(LifecycleUnit* lifecycle_unit, LifecycleUnitState)); + MOCK_METHOD3(OnLifecycleUnitStateChanged, + void(LifecycleUnit* lifecycle_unit, + LifecycleUnitState, + LifecycleUnitStateChangeReason)); MOCK_METHOD2(OnLifecycleUnitVisibilityChanged, void(LifecycleUnit* lifecycle_unit, content::Visibility visibility));
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc b/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc index 940e7419..0b2d807 100644 --- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc +++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc
@@ -61,8 +61,10 @@ public: MockLifecycleUnitObserver() = default; - MOCK_METHOD2(OnLifecycleUnitStateChanged, - void(LifecycleUnit*, LifecycleUnitState)); + MOCK_METHOD3(OnLifecycleUnitStateChanged, + void(LifecycleUnit*, + LifecycleUnitState, + LifecycleUnitStateChangeReason)); MOCK_METHOD1(OnLifecycleUnitDestroyed, void(LifecycleUnit*)); MOCK_METHOD2(OnLifecycleUnitVisibilityChanged, void(LifecycleUnit*, content::Visibility));
diff --git a/chrome/browser/resource_coordinator/tab_manager.cc b/chrome/browser/resource_coordinator/tab_manager.cc index eb20716..e52483c8 100644 --- a/chrome/browser/resource_coordinator/tab_manager.cc +++ b/chrome/browser/resource_coordinator/tab_manager.cc
@@ -1102,8 +1102,10 @@ return base::TimeTicks::Max(); } -void TabManager::OnLifecycleUnitStateChanged(LifecycleUnit* lifecycle_unit, - LifecycleUnitState last_state) { +void TabManager::OnLifecycleUnitStateChanged( + LifecycleUnit* lifecycle_unit, + LifecycleUnitState last_state, + LifecycleUnitStateChangeReason reason) { LifecycleUnitState state = lifecycle_unit->GetState(); bool was_discarded = (last_state == LifecycleUnitState::PENDING_DISCARD || last_state == LifecycleUnitState::DISCARDED);
diff --git a/chrome/browser/resource_coordinator/tab_manager.h b/chrome/browser/resource_coordinator/tab_manager.h index d02e58a7..83b7c1f 100644 --- a/chrome/browser/resource_coordinator/tab_manager.h +++ b/chrome/browser/resource_coordinator/tab_manager.h
@@ -462,8 +462,10 @@ LifecycleUnit* lifecycle_unit, content::Visibility visibility) override; void OnLifecycleUnitDestroyed(LifecycleUnit* lifecycle_unit) override; - void OnLifecycleUnitStateChanged(LifecycleUnit* lifecycle_unit, - LifecycleUnitState last_state) override; + void OnLifecycleUnitStateChanged( + LifecycleUnit* lifecycle_unit, + LifecycleUnitState last_state, + LifecycleUnitStateChangeReason reason) override; // LifecycleUnitSourceObserver: void OnLifecycleUnitCreated(LifecycleUnit* lifecycle_unit) override;
diff --git a/chrome/browser/resource_coordinator/tab_manager_browsertest.cc b/chrome/browser/resource_coordinator/tab_manager_browsertest.cc index 0a930729..db2b3eda 100644 --- a/chrome/browser/resource_coordinator/tab_manager_browsertest.cc +++ b/chrome/browser/resource_coordinator/tab_manager_browsertest.cc
@@ -99,8 +99,10 @@ private: // LifecycleUnitObserver: - void OnLifecycleUnitStateChanged(LifecycleUnit* lifecycle_unit, - LifecycleUnitState last_state) override { + void OnLifecycleUnitStateChanged( + LifecycleUnit* lifecycle_unit, + LifecycleUnitState last_state, + LifecycleUnitStateChangeReason reason) override { EXPECT_EQ(lifecycle_unit, lifecycle_unit_); if (lifecycle_unit_->GetState() == expected_state_) { run_loop_.Quit();
diff --git a/chrome/browser/resources/chromeos/login/offline_ad_login.css b/chrome/browser/resources/chromeos/login/offline_ad_login.css new file mode 100644 index 0000000..b4c9f83 --- /dev/null +++ b/chrome/browser/resources/chromeos/login/offline_ad_login.css
@@ -0,0 +1,21 @@ +/* Copyright 2018 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Offline AD login page mostly uses styles from offline_gaia.css. + * Only changes to offline gaia style are defined here. + */ + +.advanced-option-subtitle { + color: rgba(0, 0, 0, 0.54); + font: 13px Roboto, sans-serif; +} + +iron-icon[icon='warning'] { + -webkit-margin-end: 15px; + -webkit-margin-start: 0; + color: var(--google-yellow-500); + margin-bottom: 0; + margin-top: 0; +}
diff --git a/chrome/browser/resources/chromeos/login/offline_ad_login.html b/chrome/browser/resources/chromeos/login/offline_ad_login.html index 2bed4df..1fbb55b 100644 --- a/chrome/browser/resources/chromeos/login/offline_ad_login.html +++ b/chrome/browser/resources/chromeos/login/offline_ad_login.html
@@ -47,6 +47,7 @@ <link rel="stylesheet" href="offline_gaia.css"> <link rel="stylesheet" href="oobe_flex_layout.css"> <link rel="stylesheet" href="gaia_card_parameters.css"> + <link rel="stylesheet" href="offline_ad_login.css"> <template> <style include="md-select"></style> <gaia-card id="gaiaCard" class="fit">
diff --git a/chrome/browser/resources/chromeos/login/offline_gaia.css b/chrome/browser/resources/chromeos/login/offline_gaia.css index 7e65290..08c58858 100644 --- a/chrome/browser/resources/chromeos/login/offline_gaia.css +++ b/chrome/browser/resources/chromeos/login/offline_gaia.css
@@ -3,6 +3,12 @@ * found in the LICENSE file. */ :host { + --title-font-size: 28px; + --title-font-distance-to-baseline: 7px; + --subtitle-font-size: 13px; + --subtitle-font-distance-to-baseline: 3px; + --subtitle-line-height: 18px; + --offline-gaia-dialog-width: 768px; display: flex; flex-direction: column; font-size: 18px; @@ -18,68 +24,72 @@ } } -/* - * Due to |margin-right| of e-mail section required for animations, containers - * store oversized items. - */ -#headerContainer, -#footerContainer { - max-width: 640px; - min-width: 640px; +/* icon, title, subtitle styles must approximate current Gaia style. */ + +#icon { + height: 32px; + margin: 60px 64px 0 64px; } -/* - * e-mail and password section headers have slightly different size. - * To make animations move same size objects, fix it here. - */ -#headerContainer { - min-height: 90px; +#title-container { + min-height: calc(64px + var(--title-font-distance-to-baseline)); +} + +h1 { + color: var(--google-grey-900); + font-size: var(--title-font-size); + font-weight: normal; + margin: 0; +} + +#subtitle-container { + min-height: calc(64px - var(--title-font-distance-to-baseline)); +} + +#subtitle-container * { + color: var(--google-grey-900); + font-size: var(--subtitle-font-size); + line-height: var(--subtitle-line-height); + /* margin 12px = 32 - line-height + - 5 (lihe height - font size) + + 3 (distance to baseline 13px) + = 32 + font size + distance to baseline 13px */ + margin: calc(32 + var(--subtitle-font-size) + + var(--subtitle-font-distance-to-baseline)) 0 0 0; } /** ******** Animations ******* */ - /* * Normally, only e-mail section is animated, pushing password section to the * right outside of visible area. */ -/* - * Animation of e-mail parts (to the 'start' to hide, and to the 'end' to show) - * allows password section to either slide-in (from the right) or slide-out - * (to the right). - * - * --webkit-margin-start doesn't work with animations, so use conventional - * left/right margins. - */ - -:host(:not([rtl])) .email-section { - /* - * OOBE dialog header/footer width is less than oobe-dialog width. - * To make sure password section is completely shifted out of visible area, - * we need right margin that matches dialog margins. - */ - margin-left: 0; - margin-right: 128px; /** double dialog margin = 2 * (768 - 640) / 2 */ +/* Fixed window over sliding content in #animation-inner-container. */ +#animation-outer-container { + overflow: hidden; + width: var(--offline-gaia-dialog-width); } -:host([rtl]) .email-section { - margin-left: 128px; /** double dialog margin = 2 * (768 - 640) / 2 */ - margin-right: 0; +#animation-inner-container { + width: calc(2 * var(--offline-gaia-dialog-width)); } - .section { + --section-padding: 64px; + --section-width: calc(var(--offline-gaia-dialog-width) + - 2 * var(--section-padding)); animation-duration: 700ms; display: none; /** For sliding to work correctly we need fixed size of moving objects. */ - max-width: 640px; - min-width: 640px; + max-width: var(--section-width); + min-width: var(--section-width); + padding: 0 var(--section-padding); } @keyframes show-from-left { from { - margin-left: -768px; /** container width + double margin = 640 + 2 * 64 */ + margin-left: -768px; /** Full dialog width negative. */ } to { margin-left: 0; @@ -88,10 +98,10 @@ @keyframes show-from-right { from { - margin-right: -768px; /** container width + double margin = 640 + 2 * 64 */ + margin-left: var(--offline-gaia-dialog-width); } to { - margin-right: 0; + margin-left: 0; } } @@ -100,21 +110,21 @@ margin-left: 0; } to { - margin-left: -768px; /** container width + double margin = 640 + 2 * 64 */ + margin-left: calc(-1 * var(--offline-gaia-dialog-width)); } } @keyframes hide-to-right { from { - margin-right: 0; + margin-left: 0; } to { - margin-right: -768px; /** container width + double margin = 640 + 2 * 64 */ + margin-left: var(--offline-gaia-dialog-width); } } -oobe-dialog[selected='emailSection'] .email-section, -oobe-dialog[selected='passwordSection'] .password-section { +oobe-dialog[selected='emailSection'] #email-section, +oobe-dialog[selected='passwordSection'] #password-section { display: block; } @@ -123,19 +133,19 @@ * Dialog always starts with e-mail section visible, so only "show" animation * depends on |animation-in-progress| attribute. */ -oobe-dialog[animation-in-progress] .email-section { +oobe-dialog[animation-in-progress] #email-section { animation-name: show-from-left; } -oobe-dialog[selected='passwordSection'] .email-section { +oobe-dialog[selected='passwordSection'] #email-section { animation-name: hide-to-left; } -:host([rtl]) oobe-dialog[animation-in-progress] .email-section { +:host([rtl]) oobe-dialog[animation-in-progress] #email-section { animation-name: show-from-right; } -:host([rtl]) oobe-dialog[selected='passwordSection'] .email-section { +:host([rtl]) oobe-dialog[selected='passwordSection'] #email-section { animation-name: hide-to-right; } @@ -143,16 +153,3 @@ oobe-dialog[animation-in-progress] .section { display: block; } - -.advanced-option-subtitle { - color: rgba(0, 0, 0, 0.54); - font: 13px Roboto, sans-serif; -} - -iron-icon[icon='warning'] { - -webkit-margin-end: 15px; - -webkit-margin-start: 0; - color: var(--google-yellow-500); - margin-bottom: 0; - margin-top: 0; -}
diff --git a/chrome/browser/resources/chromeos/login/offline_gaia.html b/chrome/browser/resources/chromeos/login/offline_gaia.html index 72b2ae09..2a5ea7c2 100644 --- a/chrome/browser/resources/chromeos/login/offline_gaia.html +++ b/chrome/browser/resources/chromeos/login/offline_gaia.html
@@ -53,27 +53,25 @@ <link rel="stylesheet" href="oobe_flex_layout.css"> <link rel="stylesheet" href="oobe_dialog_host.css"> <link rel="stylesheet" href="gaia_card_parameters.css"> - <template is="dom-if" if="[[glifMode]]" restamp> - <oobe-dialog role="dialog" has-buttons selected$="[[activeSection]]" - animation-in-progress$="[[animationInProgress]]"> - <img src="chrome://theme/IDR_LOGO_GOOGLE_COLOR_90" - slot="oobe-icon" alt=""> - <div id="headerContainer" slot="header" class="layout horizontal" - on-animationend="onSlideAnimationEnd_"> - <div id="emailSectionHeader" class="section email-section"> - <h1 class="title"> - [[i18nDynamic(locale, 'loginWelcomeMessage')]] - </h1> - <p id="managedBy" class="enterprise-info" - hidden$="[[!showEnterpriseMessage]]"> - </p> - </div> - <div id="passwordSectionHeader" class="section password-section"> - <gaia-header class="title" id="passwordHeader"></gaia-header> - </div> - </div> - <div id="footerContainer" slot="footer" class="layout horizontal"> - <div id="emailSectionFooter" class="section email-section"> + <oobe-dialog role="dialog" has-buttons selected$="[[activeSection]]" + animation-in-progress$="[[animationInProgress]]" no-header + no-footer-padding> + <div slot="footer"> + <img id="icon" src="chrome://theme/IDR_LOGO_GOOGLE_COLOR_90" alt=""> + </div> + <div id="animation-outer-container" slot="footer"> + <div id="animation-inner-container" class="flex layout horizontal"> + <div id="email-section" class="section" + on-animationend="onSlideAnimationEnd_"> + <div id="title-container"> + <h1>[[i18nDynamic(locale, 'loginWelcomeMessage')]]</h1> + </div> + <div id="subtitle-container"> + <div id="managedBy" class="enterprise-info" + hidden$="[[!domain]]"> + [[i18nDynamic(locale, 'enterpriseInfoMessage', domain)]] + </div> + </div> <gaia-input-form on-submit="onEmailSubmitted_" disabled="[[disabled]]" button-text="[[i18nDynamic(locale, 'offlineLoginNextBtn')]]"> @@ -84,8 +82,13 @@ </gaia-input> </gaia-input-form> </div> - <div id="passwordSectionFooter" class="section password-section"> - <gaia-input-form slot="footer" disabled="[[disabled]]" + <div id="password-section" class="section"> + <div id="title-container"> + <gaia-header id="passwordHeader"></gaia-header> + </div> + <div id="subtitle-container"> + </div> + <gaia-input-form disabled="[[disabled]]" on-submit="onPasswordSubmitted_" button-text="[[i18nDynamic(locale, 'offlineLoginNextBtn')]]"> <gaia-input slot="inputs" id="passwordInput" type="password" @@ -100,67 +103,14 @@ </gaia-input-form> </div> </div> - <div slot="bottom-buttons" class="flex layout horizontal"> - <oobe-back-button id="offline-gaia-back-button" - on-tap="onBackButtonClicked_"></oobe-back-button> - <div class="flex"> - </div> + </div> + <div slot="bottom-buttons" class="flex layout horizontal"> + <oobe-back-button id="offline-gaia-back-button" + on-tap="onBackButtonClicked_"></oobe-back-button> + <div class="flex"> </div> - </oobe-dialog> - </template> - - <template is="dom-if" if="[[!glifMode]]" restamp> - <neon-animated-pages id="animatedPages" class="fit" attr-for-selected="id" - entry-animation="slide-from-right-animation" - exit-animation="slide-to-left-animation" - on-neon-animation-finish="onAnimationFinish_" selected="emailSection"> - - <neon-animatable id="emailSection" class="fit"> - <gaia-card class="fit"> - <div slot="header" - class="flex vertical layout end-justified start"> - <h1 class="welcome-message" i18n-content="loginWelcomeMessage"> - </h1> - <p id="managedBy" class="enterprise-info" - hidden$="[[!showEnterpriseMessage]]"> - </p> - </div> - <div slot="footer" class="flex vertical layout justified"> - <gaia-input-form on-submit="onEmailSubmitted_" - disabled="[[disabled]]" - i18n-values="button-text:offlineLoginNextBtn"> - <gaia-input slot="inputs" id="emailInput" type="email" - domain="[[emailDomain]]" - i18n-values="error:offlineLoginInvalidEmail; - label:offlineLoginEmail" required> - </gaia-input> - </gaia-input-form> - <img src="chrome://theme/IDR_LOGO_GOOGLE_COLOR_90" - class="self-center" alt=""> - </div> - </gaia-card> - </neon-animatable> - - <neon-animatable id="passwordSection" class="fit"> - <gaia-card id="passwordCard" class="fit"> - <gaia-header slot="header" class="flex" id="passwordHeader"> - </gaia-header> - <gaia-input-form slot="footer" disabled="[[disabled]]" - on-submit="onPasswordSubmitted_" - i18n-values="button-text:offlineLoginNextBtn"> - <gaia-input slot="inputs" id="passwordInput" type="password" - i18n-values="error:offlineLoginInvalidPassword; - label:offlineLoginPassword" required> - </gaia-input> - <gaia-button type="link" on-tap="onForgotPasswordClicked_" - i18n-content="offlineLoginForgotPasswordBtn"> - </gaia-button> - </gaia-input-form> - </gaia-card> - </neon-animatable> - </neon-animated-pages> - </template> - + </div> + </oobe-dialog> <cr-dialog id="forgotPasswordDlg" on-close="onDialogOverlayClosed_"> <div slot="body"
diff --git a/chrome/browser/resources/chromeos/login/offline_gaia.js b/chrome/browser/resources/chromeos/login/offline_gaia.js index 372edd6..39b39eae 100644 --- a/chrome/browser/resources/chromeos/login/offline_gaia.js +++ b/chrome/browser/resources/chromeos/login/offline_gaia.js
@@ -18,14 +18,8 @@ value: false, }, - showEnterpriseMessage: { - type: Boolean, - value: false, - }, - domain: { type: String, - observer: 'onDomainChanged_', }, emailDomain: String, @@ -36,14 +30,6 @@ }, animationInProgress: Boolean, - - /** - * Controls GLIF MM mode. - */ - glifMode: { - type: Boolean, - value: false, - }, }, attached: function() { @@ -62,12 +48,6 @@ this.switchToEmailCard(true /* animated */); }, - onDomainChanged_: function() { - this.$$('#managedBy').textContent = - loadTimeData.getStringF('enterpriseInfoMessage', this.domain); - this.showEnterpriseMessage = !!this.domain.length; - }, - onAnimationFinish_: function() { this.fire('backButton', !this.isEmailSectionActive_()); this.focus(); @@ -77,7 +57,6 @@ this.disabled = true; this.fire('dialogShown'); this.$$('#forgotPasswordDlg').showModal(); - this.$$('#passwordCard').classList.add('full-disabled'); }, onForgotPasswordCloseTap_: function() { @@ -87,7 +66,6 @@ onDialogOverlayClosed_: function() { this.fire('dialogHidden'); this.disabled = false; - this.$$('#passwordCard').classList.remove('full-disabled'); }, setEmail: function(email) {
diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js index 65b14d53..1611e5b 100644 --- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js +++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
@@ -716,14 +716,12 @@ $('signin-frame-container-v2').appendChild($('signin-frame')); $('gaia-signin') .insertBefore($('offline-gaia'), $('gaia-step-contents')); - $('offline-gaia').glifMode = true; $('offline-gaia').removeAttribute('not-a-dialog'); $('offline-gaia').classList.toggle('fit', false); } else { $('gaia-signin-form-container').appendChild($('signin-frame')); $('gaia-signin-form-container') .appendChild($('offline-gaia'), $('gaia-step-contents')); - $('offline-gaia').glifMode = false; $('offline-gaia').setAttribute('not-a-dialog', true); $('offline-gaia').classList.toggle('fit', true); }
diff --git a/chrome/browser/resources/print_preview/new/model.js b/chrome/browser/resources/print_preview/new/model.js index ac495e4..4e73435 100644 --- a/chrome/browser/resources/print_preview/new/model.js +++ b/chrome/browser/resources/print_preview/new/model.js
@@ -741,7 +741,7 @@ } } if (this.settings.copies.available) - cjt.print.copies = {copies: this.settings.copies.value}; + cjt.print.copies = {copies: parseInt(this.getSettingValue('copies'), 10)}; if (this.settings.duplex.available) { cjt.print.duplex = { type: this.settings.duplex.value ? 'LONG_EDGE' : 'NO_DUPLEX' @@ -769,7 +769,7 @@ } } else { cjt.print.page_orientation = { - type: this.settings.layout ? 'LANDSCAPE' : 'PORTRAIT' + type: this.settings.layout.value ? 'LANDSCAPE' : 'PORTRAIT' }; } if (this.settings.dpi.available) {
diff --git a/chrome/browser/resources/settings/icons.html b/chrome/browser/resources/settings/icons.html index 6257edc..e3749b6 100644 --- a/chrome/browser/resources/settings/icons.html +++ b/chrome/browser/resources/settings/icons.html
@@ -138,7 +138,6 @@ <g id="smartphone"><path d="M17 1.01L7 1c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99zM17 19H7V5h10v14z"></path></g> </if> <g id="supervisor-account"><path d="M16.5 12c1.38 0 2.49-1.12 2.49-2.5S17.88 7 16.5 7C15.12 7 14 8.12 14 9.5s1.12 2.5 2.5 2.5zM9 11c1.66 0 2.99-1.34 2.99-3S10.66 5 9 5C7.34 5 6 6.34 6 8s1.34 3 3 3zm7.5 3c-1.83 0-5.5.92-5.5 2.75V19h11v-2.25c0-1.83-3.67-2.75-5.5-2.75zM9 13c-2.33 0-7 1.17-7 3.5V19h7v-2.25c0-.85.33-2.34 2.37-3.47C10.5 13.1 9.66 13 9 13z"></path></g> - <g id="sync"><path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z"></path></g> <g id="sync-disabled"><path d="M10 6.35V4.26c-.8.21-1.55.54-2.23.96l1.46 1.46c.25-.12.5-.24.77-.33zm-7.14-.94l2.36 2.36C4.45 8.99 4 10.44 4 12c0 2.21.91 4.2 2.36 5.64L4 20h6v-6l-2.24 2.24C6.68 15.15 6 13.66 6 12c0-1 .25-1.94.68-2.77l8.08 8.08c-.25.13-.5.25-.77.34v2.09c.8-.21 1.55-.54 2.23-.96l2.36 2.36 1.27-1.27L4.14 4.14 2.86 5.41zM20 4h-6v6l2.24-2.24C17.32 8.85 18 10.34 18 12c0 1-.25 1.94-.68 2.77l1.46 1.46C19.55 15.01 20 13.56 20 12c0-2.21-.91-4.2-2.36-5.64L20 4z"></path></g> <g id="sync-problem"><path d="M3 12c0 2.21.91 4.2 2.36 5.64L3 20h6v-6l-2.24 2.24C5.68 15.15 5 13.66 5 12c0-2.61 1.67-4.83 4-5.65V4.26C5.55 5.15 3 8.27 3 12zm8 5h2v-2h-2v2zM21 4h-6v6l2.24-2.24C18.32 8.85 19 10.34 19 12c0 2.61-1.67 4.83-4 5.65v2.09c3.45-.89 6-4.01 6-7.74 0-2.21-.91-4.2-2.36-5.64L21 4zm-10 9h2V7h-2v6z"></path></g> <if expr="chromeos">
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.js b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.js index 79c1bfc6..f2ed052 100644 --- a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.js +++ b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.js
@@ -151,13 +151,14 @@ /** @override */ attached: function() { // Create listener functions. - const setSavedPasswordsListener = list => this.updateList( - 'savedPasswords', - item => `${item.entry.index}_${item.entry.loginPair.urls.shown}`, - list.map(entry => ({ - entry: entry, - password: '', - }))); + const setSavedPasswordsListener = list => + this.updateList('savedPasswords', item => { + return item.entry.loginPair.urls.origin + '_' + + item.entry.loginPair.username; + }, list.map(entry => ({ + entry: entry, + password: '', + }))); const setPasswordExceptionsListener = list => { this.passwordExceptions = list;
diff --git a/chrome/browser/resources/settings/people_page/people_page.html b/chrome/browser/resources/settings/people_page/people_page.html index 4097de8..757d4115 100644 --- a/chrome/browser/resources/settings/people_page/people_page.html +++ b/chrome/browser/resources/settings/people_page/people_page.html
@@ -63,7 +63,7 @@ font-weight: bold; } - iron-icon[icon='settings:sync'] { + iron-icon[icon='cr:sync'] { --iron-icon-fill-color: var(--google-green-700); }
diff --git a/chrome/browser/resources/settings/people_page/people_page.js b/chrome/browser/resources/settings/people_page/people_page.js index 1195b1e..5302d6a 100644 --- a/chrome/browser/resources/settings/people_page/people_page.js +++ b/chrome/browser/resources/settings/people_page/people_page.js
@@ -548,7 +548,7 @@ if (!syncStatus) return ''; - let syncIcon = 'settings:sync'; + let syncIcon = 'cr:sync'; if (syncStatus.hasError) syncIcon = 'settings:sync-problem';
diff --git a/chrome/browser/resources/settings/people_page/sync_account_control.html b/chrome/browser/resources/settings/people_page/sync_account_control.html index dd6c0fd..fa9129c 100644 --- a/chrome/browser/resources/settings/people_page/sync_account_control.html +++ b/chrome/browser/resources/settings/people_page/sync_account_control.html
@@ -1,6 +1,7 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html"> +<link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> @@ -164,7 +165,7 @@ class$="[[getSyncIconStyle_( syncStatus.hasError, syncStatus.statusAction, syncStatus.disabled)]]"> - <iron-icon icon$="settings:[[getSyncIcon_( + <iron-icon icon$="[[getSyncIcon_( syncStatus.hasError, syncStatus.statusAction, syncStatus.disabled)]]"></iron-icon> </div>
diff --git a/chrome/browser/resources/settings/people_page/sync_account_control.js b/chrome/browser/resources/settings/people_page/sync_account_control.js index 76fb87e..1a5f4b10 100644 --- a/chrome/browser/resources/settings/people_page/sync_account_control.js +++ b/chrome/browser/resources/settings/people_page/sync_account_control.js
@@ -228,11 +228,11 @@ getSyncIcon_: function() { switch (this.getSyncIconStyle_()) { case 'sync-problem': - return 'sync-problem'; + return 'settings:sync-problem'; case 'sync-paused': - return 'sync-disabled'; + return 'settings:sync-disabled'; default: - return 'sync'; + return 'cr:sync'; } },
diff --git a/chrome/browser/resources/settings/site_settings/site_details.html b/chrome/browser/resources/settings/site_settings/site_details.html index ab798c7..5741588cb 100644 --- a/chrome/browser/resources/settings/site_settings/site_details.html +++ b/chrome/browser/resources/settings/site_settings/site_details.html
@@ -6,6 +6,7 @@ <link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html"> <link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html"> +<link rel="import" href="../icons.html"> <link rel="import" href="../route.html"> <link rel="import" href="../settings_shared_css.html"> <link rel="import" href="constants.html"> @@ -142,7 +143,7 @@ </site-details-permission> <site-details-permission category="{{ContentSettingsTypes.BACKGROUND_SYNC}}" - icon="settings:sync" id="backgroundSync" + icon="cr:sync" id="backgroundSync" label="$i18n{siteSettingsBackgroundSync}"> </site-details-permission> <site-details-permission category="{{ContentSettingsTypes.SOUND}}"
diff --git a/chrome/browser/resources/settings/site_settings/site_details_permission.html b/chrome/browser/resources/settings/site_settings/site_details_permission.html index 76881dc..3e305be01 100644 --- a/chrome/browser/resources/settings/site_settings/site_details_permission.html +++ b/chrome/browser/resources/settings/site_settings/site_details_permission.html
@@ -9,6 +9,8 @@ <link rel="import" href="site_settings_behavior.html"> <link rel="import" href="site_settings_prefs_browser_proxy.html"> +<!-- `site-details-permission` does not include any icon-set, so containing + elements should import the icon-set needed for the specified |icon|. --> <dom-module id="site-details-permission"> <template> <style include="settings-shared md-select"></style>
diff --git a/chrome/browser/resources/settings/site_settings_page/site_settings_page.html b/chrome/browser/resources/settings/site_settings_page/site_settings_page.html index bbd499c..92c863f 100644 --- a/chrome/browser/resources/settings/site_settings_page/site_settings_page.html +++ b/chrome/browser/resources/settings/site_settings_page/site_settings_page.html
@@ -245,7 +245,7 @@ category$="[[ContentSettingsTypes.BACKGROUND_SYNC]]" data-route="SITE_SETTINGS_BACKGROUND_SYNC" on-click="onTapNavigate_" actionable> - <iron-icon icon="settings:sync"></iron-icon> + <iron-icon icon="cr:sync"></iron-icon> <div class="middle"> $i18n{siteSettingsBackgroundSync} <div class="secondary" id="backgroundSyncSecondary">
diff --git a/chrome/browser/resources/signin/dice_sync_confirmation/icons.html b/chrome/browser/resources/signin/dice_sync_confirmation/icons.html new file mode 100644 index 0000000..6dec71c --- /dev/null +++ b/chrome/browser/resources/signin/dice_sync_confirmation/icons.html
@@ -0,0 +1,11 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-iconset-svg/iron-iconset-svg.html"> + +<iron-iconset-svg name="sync-confirmation" size="24"> +<svg> +<defs> + <g id="assistant"><path d="M19 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h4l3 3 3-3h4c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-5.12 10.88L12 17l-1.88-4.12L6 11l4.12-1.88L12 5l1.88 4.12L18 11l-4.12 1.88z"></path></g> + <g id="settings"><path d="M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.3-.61-.22l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.23-.09-.49 0-.61.22l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98s.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.12.22.39.3.61.22l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.23.09.49 0 .61-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zM12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z"></path></g> +</defs> +</svg> +</iron-iconset-svg>
diff --git a/chrome/browser/resources/signin/dice_sync_confirmation/sync_confirmation_app.html b/chrome/browser/resources/signin/dice_sync_confirmation/sync_confirmation_app.html index 9b51f8c..d01186f1 100644 --- a/chrome/browser/resources/signin/dice_sync_confirmation/sync_confirmation_app.html +++ b/chrome/browser/resources/signin/dice_sync_confirmation/sync_confirmation_app.html
@@ -1,16 +1,15 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/cr_elements/cr_radio_button/cr_radio_button.html"> +<link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html"> <link rel="import" href="chrome://resources/html/cr.html"> <link rel="import" href="chrome://resources/html/load_time_data.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/image-icons.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/notification-icons.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-group/paper-radio-group.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html"> +<link rel="import" href="icons.html"> <link rel="import" href="signin_shared_css.html"> <link rel="import" href="sync_confirmation_browser_proxy.html"> @@ -215,13 +214,13 @@ <div class="message-container"> <!-- Container needed to contain the icon in a green circle. --> <div id="sync-logo-container" class="logo"> - <iron-icon icon="notification:sync" class="logo"> - </iron-icon> + <iron-icon icon="cr:sync" class="logo"></iron-icon> </div> <div consent-description>$i18n{syncConfirmationChromeSyncBody}</div> </div> <div class="message-container"> - <iron-icon icon="image:assistant" id="personalize-logo" class="logo"> + <iron-icon icon="sync-confirmation:assistant" id="personalize-logo" + class="logo"> </iron-icon> <div consent-description> $i18n{syncConfirmationPersonalizeServicesBody} @@ -233,7 +232,7 @@ </div> <div class="footer"> <div class="message-container"> - <iron-icon icon="icons:settings" class="logo"></iron-icon> + <iron-icon icon="sync-confirmation:settings" class="logo"></iron-icon> <div consent-description> $i18n{syncConfirmationSyncSettingsDescription} </div>
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer.cc index eaa18de..c80eae9 100644 --- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer.cc +++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer.cc
@@ -40,7 +40,8 @@ frame_id(-1), last_updated(base::Time::Now()), navigation_initiation(ReferrerChainEntry::UNDEFINED), - has_committed(false) {} + has_committed(false), + maybe_launched_by_external_application() {} NavigationEvent::NavigationEvent(NavigationEvent&& nav_event) : source_url(std::move(nav_event.source_url)), @@ -52,7 +53,9 @@ frame_id(nav_event.frame_id), last_updated(nav_event.last_updated), navigation_initiation(nav_event.navigation_initiation), - has_committed(nav_event.has_committed) {} + has_committed(nav_event.has_committed), + maybe_launched_by_external_application( + nav_event.maybe_launched_by_external_application) {} NavigationEvent& NavigationEvent::operator=(NavigationEvent&& nav_event) { source_url = std::move(nav_event.source_url); @@ -64,6 +67,8 @@ last_updated = nav_event.last_updated; navigation_initiation = nav_event.navigation_initiation; has_committed = nav_event.has_committed; + maybe_launched_by_external_application = + nav_event.maybe_launched_by_external_application; server_redirect_urls = std::move(nav_event.server_redirect_urls); return *this; } @@ -233,6 +238,9 @@ } NavigationEvent* nav_event = navigation_handle_map_[navigation_handle].get(); + nav_event->maybe_launched_by_external_application = + PageTransitionCoreTypeIs(navigation_handle->GetPageTransition(), + ui::PAGE_TRANSITION_AUTO_TOPLEVEL); nav_event->has_committed = navigation_handle->HasCommitted(); nav_event->target_tab_id = SessionTabHelper::IdForTab(navigation_handle->GetWebContents()); @@ -268,7 +276,7 @@ bool renderer_initiated) { manager_->RecordNewWebContents( web_contents(), source_render_frame_host->GetProcess()->GetID(), - source_render_frame_host->GetRoutingID(), url, new_contents, + source_render_frame_host->GetRoutingID(), url, transition, new_contents, renderer_initiated); }
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer.h b/chrome/browser/safe_browsing/safe_browsing_navigation_observer.h index 1cfb5f07..6bd61fb3 100644 --- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer.h +++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer.h
@@ -68,6 +68,9 @@ // committed. bool has_committed; + // Whether we think this event was launched by an external application. + bool maybe_launched_by_external_application; + const GURL& GetDestinationUrl() const { if (!server_redirect_urls.empty()) return server_redirect_urls.back();
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc index 0a03332c..07972af 100644 --- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc +++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc
@@ -366,12 +366,9 @@ AddToReferrerChain(out_referrer_chain, nav_event, GURL(), ReferrerChainEntry::EVENT_URL); int user_gesture_count = 0; - GetRemainingReferrerChain( - nav_event, - user_gesture_count, - user_gesture_count_limit, - out_referrer_chain, - &result); + GetRemainingReferrerChain(nav_event, user_gesture_count, + user_gesture_count_limit, out_referrer_chain, + &result); return result; } @@ -427,12 +424,9 @@ ReferrerChainEntry::CLIENT_REDIRECT); } - GetRemainingReferrerChain( - nav_event, - user_gesture_count, - user_gesture_count_limit, - out_referrer_chain, - &result); + GetRemainingReferrerChain(nav_event, user_gesture_count, + user_gesture_count_limit, out_referrer_chain, + &result); return result; } @@ -444,6 +438,7 @@ int source_render_process_id, int source_render_frame_id, GURL target_url, + ui::PageTransition page_transition, content::WebContents* target_web_contents, bool renderer_initiated) { DCHECK(source_web_contents); @@ -469,6 +464,9 @@ nav_event->original_request_url = cleaned_target_url; nav_event->target_tab_id = SessionTabHelper::IdForTab(target_web_contents); nav_event->frame_id = rfh ? rfh->GetFrameTreeNodeId() : -1; + nav_event->maybe_launched_by_external_application = + ui::PageTransitionCoreTypeIs(page_transition, + ui::PAGE_TRANSITION_AUTO_TOPLEVEL); auto it = user_gesture_map_.find(source_web_contents); if (it == user_gesture_map_.end() || @@ -623,6 +621,8 @@ server_redirect->set_url(ShortURLForReporting(redirect)); } } + referrer_chain_entry->set_maybe_launched_by_external_application( + nav_event->maybe_launched_by_external_application); referrer_chain->Add()->Swap(referrer_chain_entry.get()); }
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h index 700e24c..f6f10da0 100644 --- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h +++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h
@@ -200,6 +200,7 @@ int source_render_process_id, int source_render_frame_id, GURL target_url, + ui::PageTransition page_transition, content::WebContents* target_web_contents, bool renderer_initiated);
diff --git a/chrome/browser/search_engines/template_url_fetcher_factory.cc b/chrome/browser/search_engines/template_url_fetcher_factory.cc index 0a058349..581151f3 100644 --- a/chrome/browser/search_engines/template_url_fetcher_factory.cc +++ b/chrome/browser/search_engines/template_url_fetcher_factory.cc
@@ -9,7 +9,6 @@ #include "chrome/browser/search_engines/template_url_service_factory.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/search_engines/template_url_fetcher.h" -#include "content/public/browser/storage_partition.h" // static TemplateURLFetcher* TemplateURLFetcherFactory::GetForProfile( @@ -43,9 +42,7 @@ KeyedService* TemplateURLFetcherFactory::BuildServiceInstanceFor( content::BrowserContext* profile) const { return new TemplateURLFetcher( - TemplateURLServiceFactory::GetForProfile(static_cast<Profile*>(profile)), - content::BrowserContext::GetDefaultStoragePartition(profile)-> - GetURLRequestContext()); + TemplateURLServiceFactory::GetForProfile(static_cast<Profile*>(profile))); } content::BrowserContext* TemplateURLFetcherFactory::GetBrowserContextToUse(
diff --git a/chrome/browser/search_engines/template_url_fetcher_unittest.cc b/chrome/browser/search_engines/template_url_fetcher_unittest.cc index e58a047..07564fdeb 100644 --- a/chrome/browser/search_engines/template_url_fetcher_unittest.cc +++ b/chrome/browser/search_engines/template_url_fetcher_unittest.cc
@@ -20,8 +20,11 @@ #include "chrome/test/base/testing_profile.h" #include "components/search_engines/template_url.h" #include "components/search_engines/template_url_service.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/storage_partition.h" #include "content/public/test/test_browser_thread_bundle.h" #include "net/test/embedded_test_server/embedded_test_server.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" @@ -32,9 +35,8 @@ class TestTemplateUrlFetcher : public TemplateURLFetcher { public: TestTemplateUrlFetcher(TemplateURLService* template_url_service, - net::URLRequestContextGetter* request_context, const base::Closure& request_completed_callback) - : TemplateURLFetcher(template_url_service, request_context), + : TemplateURLFetcher(template_url_service), callback_(request_completed_callback) {} ~TestTemplateUrlFetcher() override {} @@ -57,10 +59,8 @@ TemplateURLFetcherTest(); void SetUp() override { - TestingProfile* profile = test_util_.profile(); - ASSERT_TRUE(profile->GetRequestContext()); template_url_fetcher_.reset(new TestTemplateUrlFetcher( - test_util_.model(), profile->GetRequestContext(), + test_util_.model(), base::Bind(&TemplateURLFetcherTest::RequestCompletedCallback, base::Unretained(this)))); @@ -145,9 +145,14 @@ // Start the fetch. GURL osdd_url = test_server_.GetURL("/" + osdd_file_name); GURL favicon_url; + + TestingProfile* profile = test_util_.profile(); template_url_fetcher_->ScheduleDownload( - keyword, osdd_url, favicon_url, - TemplateURLFetcher::URLFetcherCustomizeCallback()); + keyword, osdd_url, favicon_url, url::Origin::Create(GURL()), + content::BrowserContext::GetDefaultStoragePartition(profile) + ->GetURLLoaderFactoryForBrowserProcess() + .get(), + 0 /* render_frame_id */, 0 /* resource_type */); } void TemplateURLFetcherTest::WaitForDownloadToFinish() {
diff --git a/chrome/browser/shell_integration_linux_unittest.cc b/chrome/browser/shell_integration_linux_unittest.cc index d005dae..1c603bb8 100644 --- a/chrome/browser/shell_integration_linux_unittest.cc +++ b/chrome/browser/shell_integration_linux_unittest.cc
@@ -22,6 +22,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/test/scoped_path_override.h" +#include "chrome/browser/web_applications/components/web_app_helpers.h" #include "chrome/common/chrome_constants.h" #include "content/public/test/test_browser_thread_bundle.h" #include "testing/gmock/include/gmock/gmock.h"
diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc index 7f8f3e6a..1f68085 100644 --- a/chrome/browser/shell_integration_win.cc +++ b/chrome/browser/shell_integration_win.cc
@@ -40,7 +40,8 @@ #include "base/win/windows_version.h" #include "chrome/browser/policy/policy_path_parser.h" #include "chrome/browser/shell_integration.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/components/web_app_helpers.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/browser/win/settings_app_monitor.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths_internal.h"
diff --git a/chrome/browser/shell_integration_win_unittest.cc b/chrome/browser/shell_integration_win_unittest.cc index 89596e7..42d14dc 100644 --- a/chrome/browser/shell_integration_win_unittest.cc +++ b/chrome/browser/shell_integration_win_unittest.cc
@@ -17,7 +17,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/test/test_shortcut_win.h" #include "base/win/scoped_com_initializer.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths_internal.h" #include "chrome/install_static/install_util.h"
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 80c3909..b1e13ab5 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1753,9 +1753,13 @@ sources += [ "media_router/cloud_services_dialog.cc" ] } - # TODO(loyso): Rework these dependencies. http://crbug.com/862049 if (enable_extensions) { - deps += [ "//chrome/browser/web_applications" ] + deps += [ + # TODO(loyso): Remove the first dependency. http://crbug.com/862049 + "//chrome/browser/web_applications", + "//chrome/browser/web_applications/components", + "//chrome/browser/web_applications/extensions", + ] } }
diff --git a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc index 6d760f9..b5054d5 100644 --- a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc +++ b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc
@@ -24,7 +24,7 @@ #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc index f4d3ee4..5c57d574 100644 --- a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc +++ b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
@@ -24,7 +24,7 @@ #include "chrome/browser/ui/chrome_pages.h" #include "chrome/browser/ui/settings_window_manager_chromeos.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/common/extensions/extension_constants.h" #include "chrome/grit/generated_resources.h" #include "chrome/grit/theme_resources.h"
diff --git a/chrome/browser/ui/ash/launcher/browser_status_monitor.cc b/chrome/browser/ui/ash/launcher/browser_status_monitor.cc index 545fd12..da36018 100644 --- a/chrome/browser/ui/ash/launcher/browser_status_monitor.cc +++ b/chrome/browser/ui/ash/launcher/browser_status_monitor.cc
@@ -17,7 +17,7 @@ #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_observer.h"
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc index ddcbb1a..52d459d 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -59,7 +59,7 @@ #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/common/pref_names.h" #include "chrome/grit/chromium_strings.h" #include "chrome/grit/generated_resources.h"
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc index 8d94b6f..0bc3636 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
@@ -50,7 +50,7 @@ #include "chrome/browser/ui/settings_window_manager_chromeos.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/test/test_app_window_icon_observer.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" #include "chrome/test/base/ui_test_utils.h"
diff --git a/chrome/browser/ui/ash/launcher/launcher_controller_helper.cc b/chrome/browser/ui/ash/launcher/launcher_controller_helper.cc index 1a558bc..91e3da05 100644 --- a/chrome/browser/ui/ash/launcher/launcher_controller_helper.cc +++ b/chrome/browser/ui/ash/launcher/launcher_controller_helper.cc
@@ -27,7 +27,7 @@ #include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/extensions/extension_enable_flow.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" #include "components/arc/arc_util.h" #include "content/public/browser/navigation_entry.h"
diff --git a/chrome/browser/ui/autofill/OWNERS b/chrome/browser/ui/autofill/OWNERS index 8d6b49f..389a1a38 100644 --- a/chrome/browser/ui/autofill/OWNERS +++ b/chrome/browser/ui/autofill/OWNERS
@@ -1,4 +1,5 @@ estade@chromium.org +ftirelo@chromium.org mathp@chromium.org -# COMPONENT: UI>Browser>Autofill +# COMPONENT: UI>Browser>Autofill>UI
diff --git a/chrome/browser/ui/autofill/popup_view_common.cc b/chrome/browser/ui/autofill/popup_view_common.cc index baacfff1..004e9cb 100644 --- a/chrome/browser/ui/autofill/popup_view_common.cc +++ b/chrome/browser/ui/autofill/popup_view_common.cc
@@ -24,6 +24,37 @@ namespace { +// CalculateWidthValues below ultimately determines the maximum popup width +// given the constraints of the window and the element's position within it. +// Returning a struct allows callers to reuse intermediary values produced +// during this calculation which are also relevant to positioning and sizing. +struct WidthCalculationResults { + int right_growth_start; // Popup start coordinate when growing to the right. + int left_growth_end; // Popup end coordinate when growing to the left. + int right_available; // Amount of space available if drawing to the right. + int left_available; // Amount of space available if drawing to the left. + int max_popup_width; // The max of |right_available| and |left_available|. +}; + +WidthCalculationResults CalculateWidthValues(int leftmost_available_x, + int rightmost_available_x, + const gfx::Rect& element_bounds) { + WidthCalculationResults result; + result.right_growth_start = + std::max(leftmost_available_x, + std::min(rightmost_available_x, element_bounds.x())); + result.left_growth_end = + std::max(leftmost_available_x, + std::min(rightmost_available_x, element_bounds.right())); + + result.right_available = rightmost_available_x - result.right_growth_start; + result.left_available = result.left_growth_end - leftmost_available_x; + + result.max_popup_width = + std::max(result.right_available, result.left_available); + return result; +} + // Sets the |x| and |width| components of |popup_bounds| as the x-coordinate of // the starting point and the width of the popup, taking into account the // direction it's supposed to grow (either to the left or to the right). @@ -34,36 +65,26 @@ const gfx::Rect& element_bounds, bool is_rtl, gfx::Rect* popup_bounds) { - // Calculate the start coordinates for the popup if it is growing right or - // the end position if it is growing to the left, capped to screen space. - int right_growth_start = - std::max(leftmost_available_x, - std::min(rightmost_available_x, element_bounds.x())); - int left_growth_end = - std::max(leftmost_available_x, - std::min(rightmost_available_x, element_bounds.right())); + WidthCalculationResults result = CalculateWidthValues( + leftmost_available_x, rightmost_available_x, element_bounds); - int right_available = rightmost_available_x - right_growth_start; - int left_available = left_growth_end - leftmost_available_x; - - int popup_width = - std::min(popup_required_width, std::max(right_available, left_available)); + int popup_width = std::min(popup_required_width, result.max_popup_width); // Prefer to grow towards the end (right for LTR, left for RTL). But if there // is not enough space available in the desired direction and more space in // the other direction, reverse it. bool grow_left = false; if (is_rtl) { - grow_left = - left_available >= popup_width || left_available >= right_available; + grow_left = result.left_available >= popup_width || + result.left_available >= result.right_available; } else { - grow_left = - right_available < popup_width && right_available < left_available; + grow_left = result.right_available < popup_width && + result.right_available < result.left_available; } popup_bounds->set_width(popup_width); - popup_bounds->set_x(grow_left ? left_growth_end - popup_width - : right_growth_start); + popup_bounds->set_x(grow_left ? result.left_growth_end - popup_width + : result.right_growth_start); } // Sets the |y| and |height| components of |popup_bounds| as the y-coordinate of @@ -171,4 +192,14 @@ #endif } +int PopupViewCommon::CalculateMaxWidth(const gfx::Rect& element_bounds, + gfx::NativeView container_view) { + const gfx::Rect window_bounds = GetWindowBounds(container_view); + int leftmost_available_x = window_bounds.x(); + int rightmost_available_x = window_bounds.x() + window_bounds.width(); + return CalculateWidthValues(leftmost_available_x, rightmost_available_x, + element_bounds) + .max_popup_width; +} + } // namespace autofill
diff --git a/chrome/browser/ui/autofill/popup_view_common.h b/chrome/browser/ui/autofill/popup_view_common.h index 347a734d..555337c5 100644 --- a/chrome/browser/ui/autofill/popup_view_common.h +++ b/chrome/browser/ui/autofill/popup_view_common.h
@@ -48,6 +48,12 @@ // testing. virtual gfx::Rect GetWindowBounds(gfx::NativeView container_view); + // Returns the greatest possible width for the popup, based on the distances + // between the edges of the element and the respective far edges of the + // window. + int CalculateMaxWidth(const gfx::Rect& element_bounds, + gfx::NativeView container_view); + DISALLOW_COPY_AND_ASSIGN(PopupViewCommon); };
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc index f87da74..ff9edd8 100644 --- a/chrome/browser/ui/browser_commands.cc +++ b/chrome/browser/ui/browser_commands.cc
@@ -101,7 +101,7 @@ #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" #include "chrome/browser/extensions/tab_helper.h" #include "chrome/browser/ui/extensions/settings_api_bubble_helpers.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/common/extensions/extension_metrics.h" #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" #include "extensions/browser/extension_registry.h"
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc index f5baeba..47ec2e9 100644 --- a/chrome/browser/ui/browser_navigator.cc +++ b/chrome/browser/ui/browser_navigator.cc
@@ -57,7 +57,7 @@ #if BUILDFLAG(ENABLE_EXTENSIONS) #include "chrome/browser/extensions/extension_util.h" #include "chrome/browser/extensions/tab_helper.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "extensions/browser/extension_registry.h" #include "extensions/common/extension.h" #include "extensions/common/extension_set.h"
diff --git a/chrome/browser/ui/cocoa/apps/quit_with_apps_controller_mac.cc b/chrome/browser/ui/cocoa/apps/quit_with_apps_controller_mac.cc index 23eac50..42fdfa05 100644 --- a/chrome/browser/ui/cocoa/apps/quit_with_apps_controller_mac.cc +++ b/chrome/browser/ui/cocoa/apps/quit_with_apps_controller_mac.cc
@@ -17,7 +17,7 @@ #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "chrome/grit/chrome_unscaled_resources.h"
diff --git a/chrome/browser/ui/extensions/application_launch.cc b/chrome/browser/ui/extensions/application_launch.cc index 969fb98..a52f4c1 100644 --- a/chrome/browser/ui/extensions/application_launch.cc +++ b/chrome/browser/ui/extensions/application_launch.cc
@@ -31,7 +31,8 @@ #include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h" #include "chrome/browser/ui/extensions/hosted_app_browser_controller.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/components/web_app_helpers.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" #include "chrome/common/url_constants.h" #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc index 18566d9..937eef4 100644 --- a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc +++ b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
@@ -13,7 +13,7 @@ #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/location_bar/location_bar.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/common/chrome_features.h" #include "chrome/common/extensions/api/url_handlers/url_handlers_parser.h" #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
diff --git a/chrome/browser/ui/extensions/hosted_app_browsertest.cc b/chrome/browser/ui/extensions/hosted_app_browsertest.cc index 3e2ca90..9e50d18 100644 --- a/chrome/browser/ui/extensions/hosted_app_browsertest.cc +++ b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
@@ -37,7 +37,7 @@ #include "chrome/browser/ui/page_info/page_info_dialog.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/toolbar/app_menu_model.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/common/chrome_features.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/web_application_info.h"
diff --git a/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc b/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc index 2c9c32a..b9880aa 100644 --- a/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc +++ b/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc
@@ -13,7 +13,6 @@ #include "build/build_config.h" #include "build/buildflag.h" #include "chrome/app/chrome_command_ids.h" -#include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" @@ -33,7 +32,6 @@ #include "chrome/test/base/find_in_page_observer.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" -#include "components/history/core/browser/history_service.h" #include "components/prefs/pref_service.h" #include "content/public/browser/download_manager.h" #include "content/public/browser/notification_service.h" @@ -197,14 +195,6 @@ base::FilePath().AppendASCII("find_in_page"), base::FilePath().AppendASCII(filename)); } - - void FlushHistoryService() { - HistoryServiceFactory::GetForProfile(browser()->profile(), - ServiceAccessType::IMPLICIT_ACCESS) - ->FlushForTest( - base::Bind(&base::RunLoop::QuitCurrentWhenIdleDeprecated)); - content::RunMessageLoop(); - } }; // This test loads a page with frames and starts FindInPage requests.
diff --git a/chrome/browser/ui/omnibox/omnibox_theme.cc b/chrome/browser/ui/omnibox/omnibox_theme.cc index 9d527940..65260f7 100644 --- a/chrome/browser/ui/omnibox/omnibox_theme.cc +++ b/chrome/browser/ui/omnibox/omnibox_theme.cc
@@ -246,7 +246,7 @@ gfx::ToRoundedInt(GetOmniboxStateAlpha(state) * 0xff)); case OmniboxPart::LOCATION_BAR_TEXT_DEFAULT: case OmniboxPart::RESULTS_TEXT_DEFAULT: - return dark ? gfx::kGoogleGrey100 : gfx::kGoogleGrey800; + return dark ? gfx::kGoogleGrey100 : gfx::kGoogleGrey900; case OmniboxPart::LOCATION_BAR_TEXT_DIMMED: case OmniboxPart::RESULTS_ICON:
diff --git a/chrome/browser/ui/search_engines/search_engine_tab_helper.cc b/chrome/browser/ui/search_engines/search_engine_tab_helper.cc index df76810..f1c6133 100644 --- a/chrome/browser/ui/search_engines/search_engine_tab_helper.cc +++ b/chrome/browser/ui/search_engines/search_engine_tab_helper.cc
@@ -24,7 +24,7 @@ #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/web_contents.h" -#include "content/public/common/url_fetcher.h" +#include "content/public/common/resource_type.h" using content::NavigationController; using content::NavigationEntry; @@ -71,14 +71,6 @@ return TemplateURL::GenerateKeyword(url); } -void AssociateURLFetcherWithWebContents(content::WebContents* web_contents, - net::URLFetcher* url_fetcher) { - content::AssociateURLFetcherWithRenderFrame( - url_fetcher, url::Origin::Create(web_contents->GetURL()), - web_contents->GetMainFrame()->GetProcess()->GetID(), - web_contents->GetMainFrame()->GetRoutingID()); -} - } // namespace SearchEngineTabHelper::~SearchEngineTabHelper() { @@ -146,11 +138,17 @@ if (keyword.empty()) return; + auto* frame = web_contents()->GetMainFrame(); + network::mojom::URLLoaderFactoryPtr url_loader_factory; + frame->CreateNetworkServiceDefaultFactory( + mojo::MakeRequest(&url_loader_factory)); + // Download the OpenSearch description document. If this is successful, a // new keyword will be created when done. TemplateURLFetcherFactory::GetForProfile(profile)->ScheduleDownload( keyword, osdd_url, entry->GetFavicon().url, - base::Bind(&AssociateURLFetcherWithWebContents, web_contents())); + url::Origin::Create(web_contents()->GetURL()), url_loader_factory.get(), + frame->GetRoutingID(), content::RESOURCE_TYPE_SUB_RESOURCE); } void SearchEngineTabHelper::OnFaviconUpdated(
diff --git a/chrome/browser/ui/toolbar/media_router_action.cc b/chrome/browser/ui/toolbar/media_router_action.cc index da9ed70..b3e02bbc 100644 --- a/chrome/browser/ui/toolbar/media_router_action.cc +++ b/chrome/browser/ui/toolbar/media_router_action.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/ui/toolbar/media_router_action.h" +#include "base/bind.h" +#include "base/location.h" #include "base/metrics/user_metrics.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/media/router/media_router.h" @@ -22,6 +24,7 @@ #include "chrome/common/media_router/media_route.h" #include "chrome/grit/generated_resources.h" #include "components/vector_icons/vector_icons.h" +#include "content/public/browser/browser_thread.h" #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/color_palette.h" #include "ui/gfx/image/image_skia.h" @@ -137,6 +140,9 @@ } ui::MenuModel* MediaRouterAction::GetContextMenu() { + // If there is an existing context menu, destroy it before we instantiate a + // new one. + DestroyContextMenu(); MediaRouterActionController* controller = media_router::MediaRouterUIService::Get(browser_->profile()) ->action_controller(); @@ -155,7 +161,14 @@ !GetMediaRouterDialogController()->IsShowingMediaRouterDialog()) { toolbar_actions_bar_->UndoPopOut(); } - contextual_menu_.reset(); + // We must destroy the context menu asynchronously to prevent it from being + // destroyed before the command execution. + // TODO(takumif): Using task sequence to order operations is fragile. Consider + // other ways to do so when we move the icon to the trusted area. + content::BrowserThread::PostTask( + content::BrowserThread::UI, FROM_HERE, + base::BindOnce(&MediaRouterAction::DestroyContextMenu, + weak_ptr_factory_.GetWeakPtr())); } bool MediaRouterAction::ExecuteAction(bool by_user) { @@ -302,3 +315,7 @@ return has_local_display_route_ ? vector_icons::kMediaRouterActiveIcon : vector_icons::kMediaRouterIdleIcon; } + +void MediaRouterAction::DestroyContextMenu() { + contextual_menu_.reset(); +}
diff --git a/chrome/browser/ui/toolbar/media_router_action.h b/chrome/browser/ui/toolbar/media_router_action.h index d4512f31..3cddec5 100644 --- a/chrome/browser/ui/toolbar/media_router_action.h +++ b/chrome/browser/ui/toolbar/media_router_action.h
@@ -115,6 +115,8 @@ const gfx::VectorIcon& GetCurrentIcon() const; + void DestroyContextMenu(); + // The current icon to show. This is updated based on the current issues and // routes since |this| is an IssueObserver and MediaRoutesObserver. const gfx::VectorIcon* current_icon_;
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc index 8d850904..b241544 100644 --- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc
@@ -11,7 +11,7 @@ #include "build/build_config.h" #include "chrome/browser/ui/views/apps/app_window_easy_resize_window_targeter.h" #include "chrome/browser/ui/views/apps/shaped_app_window_targeter.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" #include "ui/aura/window_observer.h"
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_win.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_win.cc index f58c6ac5..fae187d 100644 --- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_win.cc +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_win.cc
@@ -12,7 +12,7 @@ #include "chrome/browser/shell_integration_win.h" #include "chrome/browser/ui/views/apps/app_window_desktop_native_widget_aura_win.h" #include "chrome/browser/ui/views/apps/glass_app_window_frame_view_win.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/browser/web_applications/web_app_win.h" #include "chrome/common/chrome_switches.h" #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc index 2088cd8e..a362a72 100644 --- a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc +++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
@@ -40,10 +40,11 @@ namespace { -// By spec, dropdowns should have a min width of 64, and should always have -// a width which is a multiple of 12. +// By spec, dropdowns should have a min width of 64, a max width of 456, and +// should always have a width which is a multiple of 12. const int kAutofillPopupWidthMultiple = 12; const int kAutofillPopupMinWidth = 64; +const int kAutofillPopupMaxWidth = 456; // TODO(crbug.com/831603): Determine how colors should be shared with menus // and/or omnibox, and how these should interact (if at all) with native @@ -52,6 +53,7 @@ const SkColor kAutofillPopupSelectedBackgroundColor = gfx::kGoogleGrey200; const SkColor kAutofillPopupFooterBackgroundColor = gfx::kGoogleGrey050; const SkColor kAutofillPopupSeparatorColor = gfx::kGoogleGrey200; +const SkColor kAutofillPopupWarningColor = gfx::kGoogleRed600; // A space between the input element and the dropdown, so that the dropdown's // border doesn't look too close to the element. @@ -67,6 +69,11 @@ DISTANCE_CONTENT_LIST_VERTICAL_MULTI); } +int GetHorizontalMargin() { + return views::MenuConfig::instance().item_horizontal_padding + + GetCornerRadius(); +} + } // namespace namespace autofill { @@ -83,6 +90,7 @@ // views::View: void GetAccessibleNodeData(ui::AXNodeData* node_data) override; void OnMouseEntered(const ui::MouseEvent& event) override; + void OnMouseExited(const ui::MouseEvent& event) override; void OnMouseReleased(const ui::MouseEvent& event) override; protected: @@ -165,6 +173,7 @@ // views::View: void GetAccessibleNodeData(ui::AXNodeData* node_data) override; void OnMouseEntered(const ui::MouseEvent& event) override {} + void OnMouseExited(const ui::MouseEvent& event) override {} void OnMouseReleased(const ui::MouseEvent& event) override {} protected: @@ -180,6 +189,32 @@ DISALLOW_COPY_AND_ASSIGN(AutofillPopupSeparatorView); }; +// Draws a row which contains a warning message. +class AutofillPopupWarningView : public AutofillPopupRowView { + public: + ~AutofillPopupWarningView() override = default; + + static AutofillPopupWarningView* Create(AutofillPopupController* controller, + int line_number); + + // views::View: + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + void OnMouseEntered(const ui::MouseEvent& event) override {} + void OnMouseReleased(const ui::MouseEvent& event) override {} + + protected: + // AutofillPopupRowView: + void CreateContent() override; + void RefreshStyle() override {} + std::unique_ptr<views::Background> CreateBackground() override; + + private: + AutofillPopupWarningView(AutofillPopupController* controller, int line_number) + : AutofillPopupRowView(controller, line_number) {} + + DISALLOW_COPY_AND_ASSIGN(AutofillPopupWarningView); +}; + void AutofillPopupItemView::GetAccessibleNodeData(ui::AXNodeData* node_data) { auto suggestion = controller_->GetSuggestionAt(line_number_); std::vector<base::string16> text; @@ -220,6 +255,10 @@ controller_->SetSelectedLine(line_number_); } +void AutofillPopupItemView::OnMouseExited(const ui::MouseEvent& event) { + controller_->SelectionCleared(); +} + void AutofillPopupItemView::OnMouseReleased(const ui::MouseEvent& event) { if (event.IsOnlyLeftMouseButton() && HitTestPoint(event.location())) controller_->AcceptSuggestion(line_number_); @@ -227,9 +266,7 @@ void AutofillPopupItemView::CreateContent() { auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>( - views::BoxLayout::kHorizontal, - gfx::Insets(0, views::MenuConfig::instance().item_horizontal_padding + - GetCornerRadius()))); + views::BoxLayout::kHorizontal, gfx::Insets(0, GetHorizontalMargin()))); layout->set_cross_axis_alignment( views::BoxLayout::CrossAxisAlignment::CROSS_AXIS_ALIGNMENT_CENTER); @@ -309,8 +346,7 @@ } int AutofillPopupSuggestionView::GetPrimaryTextStyle() { - return is_warning_ ? ChromeTextStyle::STYLE_RED - : views::style::TextStyle::STYLE_PRIMARY; + return views::style::TextStyle::STYLE_PRIMARY; } AutofillPopupSuggestionView::AutofillPopupSuggestionView( @@ -405,6 +441,53 @@ SetFocusBehavior(FocusBehavior::NEVER); } +// static +AutofillPopupWarningView* AutofillPopupWarningView::Create( + AutofillPopupController* controller, + int line_number) { + AutofillPopupWarningView* result = + new AutofillPopupWarningView(controller, line_number); + result->Init(); + return result; +} + +void AutofillPopupWarningView::GetAccessibleNodeData( + ui::AXNodeData* node_data) { + node_data->SetName(controller_->GetSuggestionAt(line_number_).value); + node_data->role = ax::mojom::Role::kStaticText; +} + +void AutofillPopupWarningView::CreateContent() { + int horizontal_margin = GetHorizontalMargin(); + int vertical_margin = GetCornerRadius(); + + SetLayoutManager(std::make_unique<views::FillLayout>()); + SetBorder(views::CreateEmptyBorder( + gfx::Insets(vertical_margin, horizontal_margin))); + + views::Label* text_label = new views::Label( + controller_->GetElidedValueAt(line_number_), + {views::style::GetFont(ChromeTextContext::CONTEXT_BODY_TEXT_LARGE, + ChromeTextStyle::STYLE_RED)}); + text_label->SetEnabledColor(kAutofillPopupWarningColor); + text_label->SetMultiLine(true); + int max_width = + std::min(kAutofillPopupMaxWidth, + PopupViewCommon().CalculateMaxWidth( + gfx::ToEnclosingRect(controller_->element_bounds()), + controller_->container_view())); + max_width -= 2 * horizontal_margin; + text_label->SetMaximumWidth(max_width); + text_label->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT); + + AddChildView(text_label); +} + +std::unique_ptr<views::Background> +AutofillPopupWarningView::CreateBackground() { + return views::CreateSolidBackground(SK_ColorWHITE); +} + } // namespace void AutofillPopupRowView::SetSelected(bool is_selected) { @@ -426,12 +509,7 @@ AutofillPopupRowView::AutofillPopupRowView(AutofillPopupController* controller, int line_number) - : controller_(controller), line_number_(line_number) { - int frontend_id = controller_->GetSuggestionAt(line_number_).frontend_id; - is_warning_ = - frontend_id == - autofill::POPUP_ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE; -} + : controller_(controller), line_number_(line_number) {} void AutofillPopupRowView::Init() { CreateContent(); @@ -505,7 +583,6 @@ rows_.clear(); // Create one container to wrap the "regular" (non-footer) rows. - // TODO(crbug.com/768881): Make |body_container| scrollable. views::View* body_container = new views::View(); views::BoxLayout* body_layout = body_container->SetLayoutManager(std::make_unique<views::BoxLayout>( @@ -520,28 +597,36 @@ // Process and add all the suggestions which are in the primary container. // Stop once the first footer item is found, or there are no more items. while (line_number < controller_->GetLineCount()) { - int item_id = controller_->GetSuggestionAt(line_number).frontend_id; + switch (controller_->GetSuggestionAt(line_number).frontend_id) { + case autofill::PopupItemId::POPUP_ITEM_ID_CLEAR_FORM: + case autofill::PopupItemId::POPUP_ITEM_ID_AUTOFILL_OPTIONS: + case autofill::PopupItemId::POPUP_ITEM_ID_SCAN_CREDIT_CARD: + case autofill::PopupItemId::POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO: + case autofill::PopupItemId::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY: + // This is a footer, so this suggestion will be processed later. Don't + // increment |line_number|, or else it will be skipped when adding + // footer rows below. + has_footer = true; + break; - if (item_id == autofill::PopupItemId::POPUP_ITEM_ID_CLEAR_FORM || - item_id == autofill::PopupItemId::POPUP_ITEM_ID_AUTOFILL_OPTIONS || - item_id == autofill::PopupItemId::POPUP_ITEM_ID_SCAN_CREDIT_CARD || - item_id == - autofill::PopupItemId::POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO || - item_id == POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY) { - // This is a footer, so this suggestion will be processed later. Don't - // increment |line_number|, or else it will be skipped when adding footer - // rows below. - has_footer = true; + case autofill::PopupItemId::POPUP_ITEM_ID_SEPARATOR: + rows_.push_back( + AutofillPopupSeparatorView::Create(controller_, line_number)); + break; + + case autofill::PopupItemId:: + POPUP_ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE: + rows_.push_back( + AutofillPopupWarningView::Create(controller_, line_number)); + break; + + default: + rows_.push_back( + AutofillPopupSuggestionView::Create(controller_, line_number)); + } + + if (has_footer) break; - } - - if (item_id == autofill::PopupItemId::POPUP_ITEM_ID_SEPARATOR) { - rows_.push_back( - AutofillPopupSeparatorView::Create(controller_, line_number)); - } else { - rows_.push_back( - AutofillPopupSuggestionView::Create(controller_, line_number)); - } body_container->AddChildView(rows_.back()); line_number++; } @@ -580,27 +665,31 @@ } int AutofillPopupViewNativeViews::AdjustWidth(int width) const { - // The border of the input element should be aligned with the border of the - // dropdown when suggestions are not too wide. - int adjusted_width = - gfx::ToEnclosingRect(controller_->element_bounds()).width(); + if (width >= kAutofillPopupMaxWidth) + return kAutofillPopupMaxWidth; - // Allow the dropdown to grow beyond the element width if it requires more - // horizontal space to render the suggestions. - if (adjusted_width < width) { - adjusted_width = width; - // Use multiples of |kAutofillPopupWidthMultiple| if the required width is - // larger than the element width. - if (adjusted_width % kAutofillPopupWidthMultiple) { - adjusted_width += kAutofillPopupWidthMultiple - - (adjusted_width % kAutofillPopupWidthMultiple); - } + int elem_width = gfx::ToEnclosingRect(controller_->element_bounds()).width(); + + // If the element width is within the range of legal sizes for the popup, use + // it as the min width, so that the popup will align with its edges when + // possible. + int min_width = (kAutofillPopupMinWidth <= elem_width && + elem_width < kAutofillPopupMaxWidth) + ? elem_width + : kAutofillPopupMinWidth; + + if (width <= min_width) + return min_width; + + // The popup size is being determined by the contents, rather than the min/max + // or the element bounds. Round up to a multiple of + // |kAutofillPopupWidthMultiple|. + if (width % kAutofillPopupWidthMultiple) { + width += + (kAutofillPopupWidthMultiple - (width % kAutofillPopupWidthMultiple)); } - // Notwithstanding all the above rules, enforce a hard minimum so the dropdown - // is not too small to interact with. - adjusted_width = std::max(kAutofillPopupMinWidth, adjusted_width); - return adjusted_width; + return width; } void AutofillPopupViewNativeViews::AddExtraInitParams(
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.h b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.h index e943ce6..ea5cbc6 100644 --- a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.h +++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.h
@@ -54,7 +54,6 @@ AutofillPopupController* controller_; const int line_number_; - bool is_warning_ = false; // overwritten in ctor bool is_selected_ = false; };
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views_unittest.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views_unittest.cc index 064a74e7..bc9ff542 100644 --- a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views_unittest.cc +++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views_unittest.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "base/no_destructor.h" #include "base/strings/string_util.h" #include "build/build_config.h" #include "chrome/browser/ui/autofill/autofill_popup_controller.h" @@ -30,7 +31,7 @@ const struct TypeClicks kClickTestCase[] = { {autofill::POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY, 1}, - {autofill::POPUP_ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE, 1}, + {autofill::POPUP_ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE, 0}, {autofill::POPUP_ITEM_ID_PASSWORD_ENTRY, 1}, {autofill::POPUP_ITEM_ID_SEPARATOR, 0}, {autofill::POPUP_ITEM_ID_CLEAR_FORM, 1}, @@ -61,7 +62,10 @@ MOCK_CONST_METHOD0(HasSelection, bool()); MOCK_CONST_METHOD0(popup_bounds, gfx::Rect()); MOCK_METHOD0(container_view, gfx::NativeView()); - MOCK_CONST_METHOD0(element_bounds, const gfx::RectF&()); + const gfx::RectF& element_bounds() const override { + static base::NoDestructor<gfx::RectF> bounds({100, 100, 250, 50}); + return *bounds; + } MOCK_CONST_METHOD0(IsRTL, bool()); const std::vector<autofill::Suggestion> GetSuggestions() override { return suggestions_;
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc index 597f400d..0ae0b376 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
@@ -45,7 +45,6 @@ #include "chrome/browser/ui/views/tab_icon_view.h" #include "chrome/browser/ui/views/tabs/tab_strip.h" #include "chrome/browser/ui/views/toolbar/toolbar_view.h" -#include "chrome/browser/web_applications/web_app.h" #include "content/public/browser/web_contents.h" #include "content/public/common/service_manager_connection.h" #include "services/service_manager/public/cpp/connector.h"
diff --git a/chrome/browser/ui/views/frame/browser_window_property_manager_win.cc b/chrome/browser/ui/views/frame/browser_window_property_manager_win.cc index 3080979d..b8d609b 100644 --- a/chrome/browser/ui/views/frame/browser_window_property_manager_win.cc +++ b/chrome/browser/ui/views/frame/browser_window_property_manager_win.cc
@@ -13,7 +13,7 @@ #include "chrome/browser/profiles/profile_shortcut_manager_win.h" #include "chrome/browser/shell_integration_win.h" #include "chrome/browser/ui/views/frame/browser_view.h" -#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/browser/web_applications/web_app_win.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/ui/views/frame/desktop_browser_frame_aura.cc b/chrome/browser/ui/views/frame/desktop_browser_frame_aura.cc index 466add9..c1d558c 100644 --- a/chrome/browser/ui/views/frame/desktop_browser_frame_aura.cc +++ b/chrome/browser/ui/views/frame/desktop_browser_frame_aura.cc
@@ -7,7 +7,6 @@ #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/ui/views/frame/browser_desktop_window_tree_host.h" #include "chrome/browser/ui/views/frame/browser_view.h" -#include "chrome/browser/web_applications/web_app.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h"
diff --git a/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc b/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc index c78d555..9f20b90e 100644 --- a/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc +++ b/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc
@@ -97,10 +97,14 @@ nav_observer.StopWatchingNewWebContents(); } - MediaRouterAction* GetMediaRouterAction() { + // Returns the dialog controller for the active WebContents. + MediaRouterDialogControllerImplBase* GetDialogController() { return MediaRouterDialogControllerImplBase::GetOrCreateForWebContents( - browser()->tab_strip_model()->GetActiveWebContents()) - ->action(); + browser()->tab_strip_model()->GetActiveWebContents()); + } + + MediaRouterAction* GetMediaRouterAction() { + return GetDialogController()->action(); } ui::SimpleMenuModel* GetActionContextMenu() { @@ -134,9 +138,7 @@ content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); - MediaRouterDialogController* dialog_controller = - MediaRouterDialogController::GetOrCreateForWebContents( - browser()->tab_strip_model()->GetActiveWebContents()); + MediaRouterDialogController* dialog_controller = GetDialogController(); content::ContextMenuParams params; params.page_url = web_contents->GetController().GetLastCommittedEntry()->GetURL(); @@ -164,9 +166,7 @@ test::AppMenuTestApi::Create(browser()); app_menu_test_api->ShowMenu(); - MediaRouterDialogController* dialog_controller = - MediaRouterDialogController::GetOrCreateForWebContents( - browser()->tab_strip_model()->GetActiveWebContents()); + MediaRouterDialogController* dialog_controller = GetDialogController(); ASSERT_FALSE(dialog_controller->IsShowingMediaRouterDialog()); app_menu_test_api->ExecuteCommand(IDC_ROUTE_MEDIA); EXPECT_TRUE(dialog_controller->IsShowingMediaRouterDialog()); @@ -180,9 +180,7 @@ } void TestEphemeralToolbarIconForDialog() { - MediaRouterDialogController* dialog_controller = - MediaRouterDialogController::GetOrCreateForWebContents( - browser()->tab_strip_model()->GetActiveWebContents()); + MediaRouterDialogController* dialog_controller = GetDialogController(); EXPECT_FALSE(ActionExists()); dialog_controller->ShowMediaRouterDialog(); @@ -211,6 +209,31 @@ EXPECT_FALSE(ActionExists()); } + void TestPinAndUnpinToolbarIcon() { + GetDialogController()->ShowMediaRouterDialog(); + EXPECT_TRUE(ActionExists()); + + // Pin the icon via its context menu. + ui::SimpleMenuModel* context_menu = GetActionContextMenu(); + const int command_index = context_menu->GetIndexOfCommandId( + IDC_MEDIA_ROUTER_ALWAYS_SHOW_TOOLBAR_ACTION); + if (IsCocoaBrowser()) { + // With Cocoa, OnContextMenuClosed() gets called before command execution. + GetMediaRouterAction()->OnContextMenuClosed(); + context_menu->ActivatedAt(command_index); + } else { + context_menu->ActivatedAt(command_index); + GetMediaRouterAction()->OnContextMenuClosed(); + } + GetDialogController()->HideMediaRouterDialog(); + EXPECT_TRUE(ActionExists()); + + // Unpin the icon via its context menu. + GetActionContextMenu()->ActivatedAt(command_index); + GetMediaRouterAction()->OnContextMenuClosed(); + EXPECT_FALSE(ActionExists()); + } + ToolbarActionsBar* toolbar_actions_bar_ = nullptr; Issue issue_; @@ -393,6 +416,10 @@ toolbar_actions_bar_->IsActionVisibleOnMainBar(GetMediaRouterAction())); } +IN_PROC_BROWSER_TEST_F(MediaRouterUIBrowserTest, PinAndUnpinToolbarIcon) { + TestPinAndUnpinToolbarIcon(); +} + // Runs dialog-related tests with the Views Cast dialog. class MediaRouterViewsUIBrowserTest : public MediaRouterUIBrowserTest { protected: @@ -424,4 +451,10 @@ TestEphemeralToolbarIconForDialog(); } +IN_PROC_BROWSER_TEST_F(MediaRouterViewsUIBrowserTest, PinAndUnpinToolbarIcon) { + if (IsCocoaBrowser()) + return; + TestPinAndUnpinToolbarIcon(); +} + } // namespace media_router
diff --git a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc index 7bc77e8..68d0d8a0b 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc
@@ -318,9 +318,6 @@ !match.image_url.empty()); is_search_type_ = AutocompleteMatch::IsSearchType(match.type); has_tab_match_ = match.has_tab_match; - is_definition_ = - !!match.answer && - match.answer->type() == SuggestionAnswer::ANSWER_TYPE_DICTIONARY; // Set up the small icon. if (is_rich_suggestion_) { @@ -483,15 +480,9 @@ description_view_->SetSize(gfx::Size()); } else { const int text_height = content_view_->GetLineHeight(); - int content_y = y; - int description_y = y + text_height; - if (OmniboxFieldTrial::IsReverseAnswersEnabled() && !is_definition_) { - std::swap(content_y, description_y); - } - content_view_->SetBounds(x + kTextIndent, content_y, text_width, - text_height); + content_view_->SetBounds(x + kTextIndent, y, text_width, text_height); description_view_->SetBounds( - x + kTextIndent, description_y, text_width, + x + kTextIndent, y + text_height, text_width, description_view_->GetHeightForWidth(text_width)); } }
diff --git a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.h b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.h index 81c7ca7..838798c 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.h +++ b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.h
@@ -46,7 +46,6 @@ void LayoutNewStyleTwoLineSuggestion(); void LayoutSplit(int icon_view_width, int text_indent); - bool is_definition_ = false; bool is_old_style_answer_; bool is_rich_suggestion_; bool is_search_type_;
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc index 7717ed7..da79a97 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -120,8 +120,9 @@ } // Reapply the dim color to account for the highlight state. - suggestion_view_->separator()->Dim(); - keyword_view_->separator()->Dim(); + const OmniboxPart dim = OmniboxPart::RESULTS_TEXT_DIMMED; + suggestion_view_->separator()->ApplyTextColor(dim); + keyword_view_->separator()->ApplyTextColor(dim); if (suggestion_tab_switch_button_) suggestion_tab_switch_button_->UpdateBackground(); @@ -135,15 +136,33 @@ omnibox::kKeywordSearchIcon, GetLayoutConstant(LOCATION_BAR_ICON_SIZE), GetColor(OmniboxPart::RESULTS_ICON))); - // The content text is set to the match text and calculated classifications. // Answers use their own styling for additional content text and the // description text, whereas non-answer suggestions use the match text and // calculated classifications for the description text. - suggestion_view_->content()->SetText(match_.contents, match_.contents_class); if (match_.answer) { - suggestion_view_->content()->AppendExtraText(match_.answer->first_line()); - suggestion_view_->description()->SetText(match_.answer->second_line()); + if (OmniboxFieldTrial::IsReverseAnswersEnabled()) { + // Answers may swap the content and description fields to change emphasis. + // But even when fields swap, the font size and color changes should not. + OmniboxTextView* primary = suggestion_view_->content(); + OmniboxTextView* secondary = suggestion_view_->description(); + bool swap = !match_.IsExceptedFromLineReversal(); + if (swap) + std::swap(primary, secondary); + primary->SetText(match_.contents, match_.contents_class, swap ? -1 : 0); + primary->AppendExtraText(match_.answer->first_line()); + primary->ApplyTextColor(swap ? dim : OmniboxPart::RESULTS_TEXT_DEFAULT); + secondary->SetText(match_.answer->second_line(), swap ? 0 : -1); + secondary->ApplyTextColor(swap ? OmniboxPart::RESULTS_TEXT_DEFAULT : dim); + } else { + suggestion_view_->content()->SetText(match_.contents, + match_.contents_class); + suggestion_view_->content()->AppendExtraText(match_.answer->first_line()); + suggestion_view_->description()->SetText(match_.answer->second_line()); + } } else { + // Content and description use match text and calculated classifications. + suggestion_view_->content()->SetText(match_.contents, + match_.contents_class); suggestion_view_->description()->SetText(match_.description, match_.description_class); } @@ -157,7 +176,7 @@ keyword_match->contents_class); keyword_view_->description()->SetText(keyword_match->description, keyword_match->description_class); - keyword_view_->description()->Dim(); + keyword_view_->description()->ApplyTextColor(dim); } }
diff --git a/chrome/browser/ui/views/omnibox/omnibox_text_view.cc b/chrome/browser/ui/views/omnibox/omnibox_text_view.cc index 6663d701..ce2be0b 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_text_view.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_text_view.cc
@@ -137,7 +137,10 @@ } // namespace OmniboxTextView::OmniboxTextView(OmniboxResultView* result_view) - : result_view_(result_view), font_height_(0), wrap_text_lines_(false) {} + : result_view_(result_view), + font_height_(0), + font_size_delta_(0), + wrap_text_lines_(false) {} OmniboxTextView::~OmniboxTextView() {} @@ -179,9 +182,8 @@ render_text_->Draw(canvas); } -void OmniboxTextView::Dim() { - render_text_->SetColor( - result_view_->GetColor(OmniboxPart::RESULTS_TEXT_DIMMED)); +void OmniboxTextView::ApplyTextColor(OmniboxPart part) { + render_text_->SetColor(result_view_->GetColor(part)); } const base::string16& OmniboxTextView::text() const { @@ -191,15 +193,17 @@ return render_text_->text(); } -void OmniboxTextView::SetText(const base::string16& text) { +void OmniboxTextView::SetText(const base::string16& text, int size_delta) { if (cached_classifications_) { cached_classifications_.reset(); - } else if (render_text_ && render_text_->text() == text) { + } else if (render_text_ && render_text_->text() == text && + size_delta == font_size_delta_) { // Only exit early if |cached_classifications_| was empty, // i.e. the last time text was set was through this method. return; } + font_size_delta_ = size_delta; render_text_.reset(); render_text_ = CreateRenderText(text); UpdateLineHeight(); @@ -207,11 +211,15 @@ } void OmniboxTextView::SetText(const base::string16& text, - const ACMatchClassifications& classifications) { + const ACMatchClassifications& classifications, + int size_delta) { if (render_text_ && render_text_->text() == text && cached_classifications_ && - classifications == *cached_classifications_) + classifications == *cached_classifications_ && + size_delta == font_size_delta_) return; + font_size_delta_ = size_delta; + cached_classifications_ = std::make_unique<ACMatchClassifications>(classifications); render_text_ = CreateRenderText(text); @@ -248,11 +256,14 @@ SetPreferredSize(CalculatePreferredSize()); } -void OmniboxTextView::SetText(const SuggestionAnswer::ImageLine& line) { +void OmniboxTextView::SetText(const SuggestionAnswer::ImageLine& line, + int size_delta) { + font_size_delta_ = size_delta; cached_classifications_.reset(); wrap_text_lines_ = line.num_text_lines() > 1; render_text_.reset(); render_text_ = CreateRenderText(base::string16()); + if (!OmniboxFieldTrial::IsNewAnswerLayoutEnabled()) { // This assumes that the first text type in the line can be used to specify // the font for all the text fields in the line. For now this works but @@ -304,8 +315,13 @@ render_text->SetDisplayRect(gfx::Rect(gfx::Size(INT_MAX, 0))); render_text->SetCursorEnabled(false); render_text->SetElideBehavior(gfx::ELIDE_TAIL); - render_text->SetFontList( - views::style::GetFont(CONTEXT_OMNIBOX_PRIMARY, kTextStyle)); + const gfx::FontList& font = + views::style::GetFont(CONTEXT_OMNIBOX_PRIMARY, kTextStyle); + if (font_size_delta_ == 0) { + render_text->SetFontList(font); + } else { + render_text->SetFontList(font.DeriveWithSizeDelta(font_size_delta_)); + } render_text->SetText(text); return render_text; }
diff --git a/chrome/browser/ui/views/omnibox/omnibox_text_view.h b/chrome/browser/ui/views/omnibox/omnibox_text_view.h index 49734393..020633e 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_text_view.h +++ b/chrome/browser/ui/views/omnibox/omnibox_text_view.h
@@ -36,9 +36,11 @@ int GetHeightForWidth(int width) const override; void OnPaint(gfx::Canvas* canvas) override; - // Dims the text (i.e. makes it gray). This is used for secondary text (so - // that the non-dimmed text stands out more). - void Dim(); + // Applies given part's theme color to underlying render text. Using + // OmniboxPart::RESULTS_TEXT_DIMMED gives the gray used by Dim() in the past. + // This is called Apply* instead of Set* because the only state kept is in + // render_text, so call this after setting text with methods below. + void ApplyTextColor(OmniboxPart part); // Returns the render text, or an empty string if there is none. const base::string16& text() const; @@ -46,10 +48,13 @@ // Sets the render text with default rendering for the given |text|. The // |classifications| are used to style the text. An ImageLine incorporates // both the text and the styling. - void SetText(const base::string16& text); + // The size_delta is specified here so it can be known in advance of creating + // the render text. Applying later would kill bold (clear weights BreakList). + void SetText(const base::string16& text, int size_delta = 0); void SetText(const base::string16& text, - const ACMatchClassifications& classifications); - void SetText(const SuggestionAnswer::ImageLine& line); + const ACMatchClassifications& classifications, + int font_size_delta = 0); + void SetText(const SuggestionAnswer::ImageLine& line, int size_delta = 0); // Adds the "additional" and "status" text from |line|, if any. void AppendExtraText(const SuggestionAnswer::ImageLine& line); @@ -77,6 +82,9 @@ // Font settings for this view. int font_height_; + // Delta (in px) from default font size. + int font_size_delta_; + // Whether to wrap lines if the width is too narrow for the whole string. bool wrap_text_lines_;
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.cc b/chrome/browser/ui/views/overlay/overlay_window_views.cc index 611b221..2177268 100644 --- a/chrome/browser/ui/views/overlay/overlay_window_views.cc +++ b/chrome/browser/ui/views/overlay/overlay_window_views.cc
@@ -169,40 +169,39 @@ // on UI affordances, such as buttons. min_size_ = kMinWindowSize; - // Initial size of the window is always 20% of the display width and height, - // constrained by the min and max sizes. Only explicitly update this the first - // time |window_size| is being calculated. - // Once |window_size| is calculated at least once, it should stay within the - // bounds of |min_size_| and |max_size_|. gfx::Size window_size; - if (!window_bounds_.size().IsEmpty()) { + gfx::Point origin; + + if (is_initialized_) { window_size = window_bounds_.size(); + origin = window_bounds_.origin(); } else { + // Determine the initial window bounds: + // The initial window size is 20% of the |work_area| screen. window_size = gfx::Size(work_area.width() / 5, work_area.height() / 5); window_size.set_width(std::min( max_size_.width(), std::max(min_size_.width(), window_size.width()))); window_size.set_height( std::min(max_size_.height(), std::max(min_size_.height(), window_size.height()))); + + // Determine the initial origin point: + // The window is positioned on the bottom right of the |work_area| screen. + int window_diff_width = work_area.right() - window_size.width(); + int window_diff_height = work_area.bottom() - window_size.height(); + + // There will be a margin between the edges of the Picture-in-Picture + // window and the |work_area| screen by taking 2% of the average of the + // window dimensions. + int margin = (window_diff_width + window_diff_height) / 2 * 0.02; + + origin = + gfx::Point(window_diff_width - margin, window_diff_height - margin); } - // Determine the window size by fitting |natural_size_| within - // |window_size|, keeping to |natural_size_|'s aspect ratio. - if (!natural_size_.IsEmpty()) { - UpdateVideoLayerSizeWithAspectRatio(window_size); - window_size = video_bounds_.size(); - } + UpdateVideoLayerSizeWithAspectRatio(window_size); - int window_diff_width = work_area.right() - window_size.width(); - int window_diff_height = work_area.bottom() - window_size.height(); - - // Keep a margin distance of 2% the average of the two window size - // differences, keeping the margins consistent. - int buffer = (window_diff_width + window_diff_height) / 2 * 0.02; - window_bounds_ = gfx::Rect( - gfx::Point(window_diff_width - buffer, window_diff_height - buffer), - window_size); - + window_bounds_ = gfx::Rect(origin, window_size); return window_bounds_; } @@ -573,6 +572,13 @@ views::Widget::OnNativeBlur(); } +void OverlayWindowViews::OnNativeWidgetMove() { + // Update the existing |window_bounds_| when the window moves. This allows + // the window to reappear with the same origin point when a new video is + // shown. + window_bounds_ = GetBounds(); +} + void OverlayWindowViews::OnNativeWidgetSizeChanged(const gfx::Size& new_size) { // Update the view layers to scale to |new_size|. UpdateCloseControlsSize();
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.h b/chrome/browser/ui/views/overlay/overlay_window_views.h index abac8a3b..3649222 100644 --- a/chrome/browser/ui/views/overlay/overlay_window_views.h +++ b/chrome/browser/ui/views/overlay/overlay_window_views.h
@@ -48,6 +48,7 @@ // views::internal::NativeWidgetDelegate: void OnNativeFocus() override; void OnNativeBlur() override; + void OnNativeWidgetMove() override; void OnNativeWidgetSizeChanged(const gfx::Size& new_size) override; // Gets the bounds of the controls.
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc index 9d53835..9066e64 100644 --- a/chrome/browser/ui/views/tabs/tab.cc +++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -154,29 +154,37 @@ flags); } -// Scales |bounds| by scale and aligns so that the layout portion is snapped to -// the pixel grid. This ensures adjacent tabs meet up exactly during painting. +// Scales |bounds| by scale and aligns so that adjacent tabs meet up exactly +// during painting. const gfx::RectF ScaleAndAlignBounds(const gfx::Rect& bounds, float scale) { - // Convert full bounds to layout bounds and scale from DIP to px. + // Convert to layout bounds. We must inset the width such that the right edge + // of one tab's layout bounds is the same as the left edge of the next tab's; + // this way the two tabs' separators will be drawn at the same coordinate. gfx::RectF aligned_bounds(bounds); + const int stroke_height = Tab::GetStrokeHeight(); const int corner_radius = Tab::GetCornerRadius(); - aligned_bounds.Inset(corner_radius, 0); + // Note: This intentionally doesn't subtract TABSTRIP_TOOLBAR_OVERLAP from the + // bottom inset, because we want to pixel-align the bottom of the stroke, not + // the bottom of the overlap. + gfx::InsetsF layout_insets(stroke_height, corner_radius, stroke_height, + corner_radius + Tab::kSeparatorThickness); + aligned_bounds.Inset(layout_insets); + + // Scale layout bounds from DIP to px. aligned_bounds.Scale(scale); - // Snap layout bounds to nearest pixels. + // Snap layout bounds to nearest pixels so we get clean lines. const float x = std::round(aligned_bounds.x()); const float y = std::round(aligned_bounds.y()); // It's important to round the right edge and not the width, since rounding // both x and width would mean the right edge would accumulate error. const float right = std::round(aligned_bounds.right()); - // The bottom is ceiled rather than rounded to ensure it overlaps the toolbar - // rather than leaving a gap. - const float bottom = std::ceil(aligned_bounds.bottom()); + const float bottom = std::round(aligned_bounds.bottom()); aligned_bounds = gfx::RectF(x, y, right - x, bottom - y); - // Convert back to full bounds. The endcap widths are not rounded, since it's - // OK if the corners do not snap to the pixel grid. - aligned_bounds.Inset(-corner_radius * scale, 0); + // Convert back to full bounds. It's OK that the outer corners of the curves + // around the separator may not be snapped to the pixel grid as a result. + aligned_bounds.Inset(-layout_insets.Scale(scale)); return aligned_bounds; } @@ -1189,7 +1197,10 @@ gfx::Insets Tab::GetContentsInsets() { const int endcap_width = MD::IsRefreshUi() ? (GetCornerRadius() * 2) : GetTabEndcapWidthForLayout(); - return gfx::Insets(GetStrokeHeight(), endcap_width); + return gfx::Insets( + GetStrokeHeight(), endcap_width, + GetStrokeHeight() + GetLayoutConstant(TABSTRIP_TOOLBAR_OVERLAP), + endcap_width); } // static
diff --git a/chrome/browser/ui/webui/settings/chromeos/smb_handler.cc b/chrome/browser/ui/webui/settings/chromeos/smb_handler.cc index b50b708d..8a5af4e 100644 --- a/chrome/browser/ui/webui/settings/chromeos/smb_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/smb_handler.cc
@@ -59,9 +59,17 @@ mo.display_name = mount_name.empty() ? mount_url : mount_name; mo.writable = true; - service->Mount(mo, base::FilePath(mount_url), username, password, - base::BindOnce(&SmbHandler::HandleSmbMountResponse, - weak_ptr_factory_.GetWeakPtr())); + auto mount_response = base::BindOnce(&SmbHandler::HandleSmbMountResponse, + weak_ptr_factory_.GetWeakPtr()); + auto mount_call = base::BindOnce( + &smb_client::SmbService::Mount, base::Unretained(service), mo, + base::FilePath(mount_url), username, password, std::move(mount_response)); + + if (host_discovery_done_) { + std::move(mount_call).Run(); + } else { + stored_mount_call_ = std::move(mount_call); + } } void SmbHandler::HandleSmbMountResponse(SmbMountResult result) { @@ -78,6 +86,11 @@ void SmbHandler::HandleGatherSharesResponse( const std::vector<smb_client::SmbUrl>& shares_gathered) { + host_discovery_done_ = true; + if (!stored_mount_call_.is_null()) { + std::move(stored_mount_call_).Run(); + } + // TODO(zentaro): Pass the shares discovered back to the UI. // https://crbug.com/852199. }
diff --git a/chrome/browser/ui/webui/settings/chromeos/smb_handler.h b/chrome/browser/ui/webui/settings/chromeos/smb_handler.h index 5e8ee1d0..fe6c85d 100644 --- a/chrome/browser/ui/webui/settings/chromeos/smb_handler.h +++ b/chrome/browser/ui/webui/settings/chromeos/smb_handler.h
@@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_SMB_HANDLER_H_ #define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_SMB_HANDLER_H_ +#include "base/callback_forward.h" #include "base/files/file.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" @@ -41,6 +42,8 @@ void HandleGatherSharesResponse( const std::vector<smb_client::SmbUrl>& shares_gathered); + bool host_discovery_done_ = false; + base::OnceClosure stored_mount_call_; Profile* const profile_; base::WeakPtrFactory<SmbHandler> weak_ptr_factory_;
diff --git a/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc b/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc index 1912aa4..fd173de 100644 --- a/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc +++ b/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc
@@ -41,6 +41,8 @@ int undo_button_ids = -1; if (is_unified_consent_enabled && is_sync_allowed) { source->SetDefaultResource(IDR_DICE_SYNC_CONFIRMATION_HTML); + source->AddResourcePath("icons.html", + IDR_DICE_SYNC_CONFIRMATION_ICONS_HTML); source->AddResourcePath("sync_confirmation_browser_proxy.html", IDR_DICE_SYNC_CONFIRMATION_BROWSER_PROXY_HTML); source->AddResourcePath("sync_confirmation_browser_proxy.js",
diff --git a/chrome/browser/vr/service/browser_xr_device.cc b/chrome/browser/vr/service/browser_xr_device.cc index 0c95f94..b70ed62 100644 --- a/chrome/browser/vr/service/browser_xr_device.cc +++ b/chrome/browser/vr/service/browser_xr_device.cc
@@ -119,7 +119,10 @@ presenting_display_host_ = display; immersive_session_controller_ = std::move(immersive_session_controller); } - std::move(callback).Run(std::move(connection)); + + device::mojom::XRSessionPtr xr_session = device::mojom::XRSession::New(); + xr_session->connection = std::move(connection); + std::move(callback).Run(std::move(xr_session)); } else { std::move(callback).Run(nullptr); if (connection) {
diff --git a/chrome/browser/vr/service/vr_display_host.cc b/chrome/browser/vr/service/vr_display_host.cc index 7aa883f..5918a2f 100644 --- a/chrome/browser/vr/service/vr_display_host.cc +++ b/chrome/browser/vr/service/vr_display_host.cc
@@ -62,39 +62,58 @@ render_frame_host_(render_frame_host), binding_(this), weak_ptr_factory_(this) { - device::mojom::VRMagicWindowProviderPtr magic_window_provider; - device->GetRuntime()->RequestMagicWindowSession( - mojo::MakeRequest(&magic_window_provider), - mojo::MakeRequest(&magic_window_controller_), - base::BindOnce(&VRDisplayHost::OnMagicWindowSessionCreated, - weak_ptr_factory_.GetWeakPtr())); - // Tell blink that we are available. device::mojom::VRDisplayHostPtr display_host; binding_.Bind(mojo::MakeRequest(&display_host)); - service_client->OnDisplayConnected( - std::move(magic_window_provider), std::move(display_host), - mojo::MakeRequest(&client_), browser_device_->GetVRDisplayInfo()); - // Tell the BrowserXrDevice about us. browser_device_->OnDisplayHostAdded(this); + service_client->OnDisplayConnected(std::move(display_host), + mojo::MakeRequest(&client_), + device->GetVRDisplayInfo()); } -void VRDisplayHost::OnMagicWindowSessionCreated(bool success) { - if (success) { - // Start giving out magic window data if we are focused. - magic_window_controller_->SetFrameDataRestricted(!in_focused_frame_); +void VRDisplayHost::OnARSessionCreated( + device::mojom::VRDisplayHost::RequestSessionCallback callback, + device::mojom::XRSessionPtr session) { + if (!session) { + std::move(callback).Run(nullptr); + return; } + + browser_device_->GetRuntime()->RequestMagicWindowSession( + base::BindOnce(&VRDisplayHost::OnMagicWindowSessionCreated, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); +} + +void VRDisplayHost::OnMagicWindowSessionCreated( + device::mojom::VRDisplayHost::RequestSessionCallback callback, + device::mojom::VRMagicWindowProviderPtr magic_window_provider, + device::mojom::XRSessionControllerPtr controller) { + if (!magic_window_provider) { + std::move(callback).Run(nullptr); + return; + } + + // Start giving out magic window data if we are focused. + controller->SetFrameDataRestricted(!in_focused_frame_); + + magic_window_controllers_.AddPtr(std::move(controller)); + + device::mojom::XRSessionPtr xr_session = device::mojom::XRSession::New(); + xr_session->magic_window_provider = magic_window_provider.PassInterface(); + + std::move(callback).Run(std::move(xr_session)); } VRDisplayHost::~VRDisplayHost() { browser_device_->OnDisplayHostRemoved(this); } -void VRDisplayHost::RequestSession(device::mojom::XRSessionOptionsPtr options, - bool triggered_by_displayactive, - RequestSessionCallback callback) { +void VRDisplayHost::RequestSession( + device::mojom::XRSessionOptionsPtr options, + bool triggered_by_displayactive, + device::mojom::VRDisplayHost::RequestSessionCallback callback) { DCHECK(options); if (!InternalSupportsSession(options.get()) || @@ -121,28 +140,26 @@ // AR currently uses a non-immersive session but we still want to call request // session on it. - if (runtime_options->immersive || - base::FeatureList::IsEnabled(features::kWebXrHitTest)) { + if (runtime_options->immersive) { if (!triggered_by_displayactive) { ReportRequestPresent(); } browser_device_->RequestSession(this, std::move(runtime_options), std::move(callback)); + } else if (base::FeatureList::IsEnabled(features::kWebXrHitTest)) { + // WebXrHitTest enabled means we are requesting an AR session. This means + // we make two requests to the device - one to request permissions and start + // the runtime, then a followup to actually get the magic window provider. + // TODO(offenwanger): Clean this up and make only one request. + browser_device_->RequestSession( + this, std::move(runtime_options), + base::BindOnce(&VRDisplayHost::OnARSessionCreated, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } else { - // TODO(offenwanger) When the XRMagicWindowProvider or equivalent is - // returned here, clean out this dummy code. - auto connection = device::mojom::XRPresentationConnection::New(); - device::mojom::VRSubmitFrameClientPtr submit_client; - connection->client_request = mojo::MakeRequest(&submit_client); - device::mojom::VRPresentationProviderPtr provider; - mojo::MakeRequest(&provider); - connection->provider = provider.PassInterface(); - connection->transport_options = - device::mojom::VRDisplayFrameTransportOptions::New(); - // Non immersive session setup happens on device initialization, so we don't - // need to do anything further. - std::move(callback).Run(std::move(connection)); + browser_device_->GetRuntime()->RequestMagicWindowSession( + base::BindOnce(&VRDisplayHost::OnMagicWindowSessionCreated, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } } @@ -186,8 +203,11 @@ void VRDisplayHost::SetInFocusedFrame(bool in_focused_frame) { in_focused_frame_ = in_focused_frame; browser_device_->UpdateListeningForActivate(this); - if (magic_window_controller_) - magic_window_controller_->SetFrameDataRestricted(!in_focused_frame_); + + magic_window_controllers_.ForAllPtrs( + [&in_focused_frame](device::mojom::XRSessionController* controller) { + controller->SetFrameDataRestricted(!in_focused_frame); + }); } void VRDisplayHost::OnChanged(device::mojom::VRDisplayInfoPtr vr_device_info) {
diff --git a/chrome/browser/vr/service/vr_display_host.h b/chrome/browser/vr/service/vr_display_host.h index acd354b..a9db54c 100644 --- a/chrome/browser/vr/service/vr_display_host.h +++ b/chrome/browser/vr/service/vr_display_host.h
@@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_VR_SERVICE_VR_DISPLAY_HOST_H_ #define CHROME_BROWSER_VR_SERVICE_VR_DISPLAY_HOST_H_ +#include <map> #include <memory> #include "base/macros.h" @@ -12,6 +13,7 @@ #include "device/vr/public/mojom/vr_service.mojom.h" #include "device/vr/vr_device.h" #include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/interface_ptr_set.h" namespace content { class RenderFrameHost; @@ -36,9 +38,10 @@ ~VRDisplayHost() override; // device::mojom::VRDisplayHost - void RequestSession(device::mojom::XRSessionOptionsPtr options, - bool triggered_by_displayactive, - RequestSessionCallback callback) override; + void RequestSession( + device::mojom::XRSessionOptionsPtr options, + bool triggered_by_displayactive, + device::mojom::VRDisplayHost::RequestSessionCallback callback) override; void SupportsSession(device::mojom::XRSessionOptionsPtr options, SupportsSessionCallback callback) override; void ExitPresent() override; @@ -62,7 +65,13 @@ bool IsAnotherHostPresenting(); bool InternalSupportsSession(device::mojom::XRSessionOptions* options); - void OnMagicWindowSessionCreated(bool success); + void OnMagicWindowSessionCreated( + device::mojom::VRDisplayHost::RequestSessionCallback callback, + device::mojom::VRMagicWindowProviderPtr session, + device::mojom::XRSessionControllerPtr controller); + void OnARSessionCreated( + device::mojom::VRDisplayHost::RequestSessionCallback callback, + device::mojom::XRSessionPtr session); // TODO(https://crbug.com/837538): Instead, check before returning this // object. @@ -76,7 +85,9 @@ mojo::Binding<device::mojom::VRDisplayHost> binding_; device::mojom::VRDisplayClientPtr client_; - device::mojom::XRSessionControllerPtr magic_window_controller_; + mojo::InterfacePtrSet<device::mojom::XRSessionController> + magic_window_controllers_; + int next_key_ = 0; base::WeakPtrFactory<VRDisplayHost> weak_ptr_factory_;
diff --git a/chrome/browser/web_applications/components/BUILD.gn b/chrome/browser/web_applications/components/BUILD.gn index a168494..83a7034 100644 --- a/chrome/browser/web_applications/components/BUILD.gn +++ b/chrome/browser/web_applications/components/BUILD.gn
@@ -3,5 +3,12 @@ # found in the LICENSE file. source_set("components") { - # TODO(loyso): Add os_shortcuts component here. + sources = [ + "web_app_helpers.cc", + "web_app_helpers.h", + ] + + deps = [ + "//base", + ] }
diff --git a/chrome/browser/web_applications/components/web_app_helpers.cc b/chrome/browser/web_applications/components/web_app_helpers.cc new file mode 100644 index 0000000..b53b454 --- /dev/null +++ b/chrome/browser/web_applications/components/web_app_helpers.cc
@@ -0,0 +1,19 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/web_applications/components/web_app_helpers.h" + +#include "url/gurl.h" + +namespace web_app { + +std::string GenerateApplicationNameFromURL(const GURL& url) { + std::string t; + t.append(url.host()); + t.append("_"); + t.append(url.path()); + return t; +} + +} // namespace web_app
diff --git a/chrome/browser/web_applications/components/web_app_helpers.h b/chrome/browser/web_applications/components/web_app_helpers.h new file mode 100644 index 0000000..2dd9f1bf --- /dev/null +++ b/chrome/browser/web_applications/components/web_app_helpers.h
@@ -0,0 +1,21 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_HELPERS_H_ +#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_HELPERS_H_ + +#include <string> + +class GURL; + +namespace web_app { + +// Compute a deterministic name based on the URL. We use this pseudo name +// as a key to store window location per application URLs in Browser and +// as app id for BrowserWindow, shortcut and jump list. +std::string GenerateApplicationNameFromURL(const GURL& url); + +} // namespace web_app + +#endif // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_HELPERS_H_
diff --git a/chrome/browser/web_applications/extensions/BUILD.gn b/chrome/browser/web_applications/extensions/BUILD.gn index 073b8be..c8058dd 100644 --- a/chrome/browser/web_applications/extensions/BUILD.gn +++ b/chrome/browser/web_applications/extensions/BUILD.gn
@@ -10,9 +10,12 @@ sources = [ "pending_bookmark_app_manager.cc", "pending_bookmark_app_manager.h", + "web_app_extension_helpers.cc", + "web_app_extension_helpers.h", ] deps = [ + "//base", "//chrome/browser/web_applications/components", ] }
diff --git a/chrome/browser/web_applications/extensions/web_app_extension_helpers.cc b/chrome/browser/web_applications/extensions/web_app_extension_helpers.cc new file mode 100644 index 0000000..0d42b0d --- /dev/null +++ b/chrome/browser/web_applications/extensions/web_app_extension_helpers.cc
@@ -0,0 +1,30 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" + +namespace web_app { + +// The following string is used to build the directory name for +// shortcuts to chrome applications (the kind which are installed +// from a CRX). Application shortcuts to URLs use the {host}_{path} +// for the name of this directory. Hosts can't include an underscore. +// By starting this string with an underscore, we ensure that there +// are no naming conflicts. +static const char kCrxAppPrefix[] = "_crx_"; + +std::string GenerateApplicationNameFromExtensionId(const std::string& id) { + std::string t(kCrxAppPrefix); + t.append(id); + return t; +} + +std::string GetExtensionIdFromApplicationName(const std::string& app_name) { + std::string prefix(kCrxAppPrefix); + if (app_name.substr(0, prefix.length()) != prefix) + return std::string(); + return app_name.substr(prefix.length()); +} + +} // namespace web_app
diff --git a/chrome/browser/web_applications/extensions/web_app_extension_helpers.h b/chrome/browser/web_applications/extensions/web_app_extension_helpers.h new file mode 100644 index 0000000..d55a74f0 --- /dev/null +++ b/chrome/browser/web_applications/extensions/web_app_extension_helpers.h
@@ -0,0 +1,20 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_WEB_APP_EXTENSION_HELPERS_H_ +#define CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_WEB_APP_EXTENSION_HELPERS_H_ + +#include <string> + +namespace web_app { + +// Compute a deterministic name based on an extension/apps's id. +std::string GenerateApplicationNameFromExtensionId(const std::string& id); + +// Extracts the extension id from the app name. +std::string GetExtensionIdFromApplicationName(const std::string& app_name); + +} // namespace web_app + +#endif // CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_WEB_APP_EXTENSION_HELPERS_H_
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc index 220f6240..911cec9 100644 --- a/chrome/browser/web_applications/web_app.cc +++ b/chrome/browser/web_applications/web_app.cc
@@ -23,6 +23,8 @@ #include "chrome/browser/extensions/extension_ui_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/web_applications/components/web_app_helpers.h" +#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" @@ -135,14 +137,6 @@ namespace web_app { -// The following string is used to build the directory name for -// shortcuts to chrome applications (the kind which are installed -// from a CRX). Application shortcuts to URLs use the {host}_{path} -// for the name of this directory. Hosts can't include an underscore. -// By starting this string with an underscore, we ensure that there -// are no naming conflicts. -static const char kCrxAppPrefix[] = "_crx_"; - void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { registry->RegisterListPref(prefs::kWebAppInstallForceList); } @@ -369,27 +363,6 @@ return GenerateApplicationNameFromURL(shortcut_info.url); } -std::string GenerateApplicationNameFromURL(const GURL& url) { - std::string t; - t.append(url.host()); - t.append("_"); - t.append(url.path()); - return t; -} - -std::string GenerateApplicationNameFromExtensionId(const std::string& id) { - std::string t(kCrxAppPrefix); - t.append(id); - return t; -} - -std::string GetExtensionIdFromApplicationName(const std::string& app_name) { - std::string prefix(kCrxAppPrefix); - if (app_name.substr(0, prefix.length()) != prefix) - return std::string(); - return app_name.substr(prefix.length()); -} - void CreateShortcutsWithInfo(ShortcutCreationReason reason, const ShortcutLocations& locations, std::unique_ptr<ShortcutInfo> shortcut_info) {
diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h index a2f68083..4d4e43e 100644 --- a/chrome/browser/web_applications/web_app.h +++ b/chrome/browser/web_applications/web_app.h
@@ -140,17 +140,6 @@ // Compute a deterministic name based on data in the shortcut_info. std::string GenerateApplicationNameFromInfo(const ShortcutInfo& shortcut_info); -// Compute a deterministic name based on the URL. We use this pseudo name -// as a key to store window location per application URLs in Browser and -// as app id for BrowserWindow, shortcut and jump list. -std::string GenerateApplicationNameFromURL(const GURL& url); - -// Compute a deterministic name based on an extension/apps's id. -std::string GenerateApplicationNameFromExtensionId(const std::string& id); - -// Extracts the extension id from the app name. -std::string GetExtensionIdFromApplicationName(const std::string& app_name); - // Create shortcuts for web application based on given shortcut data. // |shortcut_info| contains information about the shortcuts to create, and // |locations| contains information about where to create them.
diff --git a/chrome/test/data/webui/print_preview/model_test.js b/chrome/test/data/webui/print_preview/model_test.js index 67733dd..e0ffbd0 100644 --- a/chrome/test/data/webui/print_preview/model_test.js +++ b/chrome/test/data/webui/print_preview/model_test.js
@@ -6,6 +6,8 @@ /** @enum {string} */ const TestNames = { SetStickySettings: 'set sticky settings', + GetPrintTicket: 'get print ticket', + GetCloudPrintTicket: 'get cloud print ticket', }; const suiteName = 'ModelTest'; @@ -81,14 +83,11 @@ */ function(e) { let settings = JSON.parse(e.detail); - for (let settingName in stickySettingsDefault) { - if (stickySettingsDefault.hasOwnProperty(settingName)) { - let toCompare = settingName == field ? stickySettingsChange : - stickySettingsDefault; - assertDeepEquals( - toCompare[settingName], settings[settingName]); - } - } + Object.keys(stickySettingsDefault).forEach(settingName => { + let toCompare = settingName == field ? stickySettingsChange : + stickySettingsDefault; + assertDeepEquals(toCompare[settingName], settings[settingName]); + }); let restorePromise = test_util.eventToPromise('save-sticky-settings', model); model.set( @@ -97,7 +96,7 @@ }); }; - model.initialized_ = true; + model.applyStickySettings(); return testStickySetting('collate', 'isCollateEnabled') .then(() => testStickySetting('color', 'isColorEnabled')) .then( @@ -115,6 +114,225 @@ .then(() => testStickySetting('fitToPage', 'isFitToPageEnabled')) .then(() => testStickySetting('vendorItems', 'vendorOptions')); }); + + function toggleSettings() { + // Some non default setting values to change to. + const settingsChange = { + pages: [2], + copies: '2', + collate: false, + layout: true, + color: false, + mediaSize: { + width_microns: 240000, + height_microns: 200000, + }, + margins: print_preview.ticket_items.MarginsTypeValue.CUSTOM, + customMargins: { + marginTop: 100, + marginRight: 200, + marginBottom: 300, + marginLeft: 400, + }, + dpi: { + horizontal_dpi: 100, + vertical_dpi: 100, + }, + fitToPage: true, + scaling: '90', + duplex: false, + cssBackground: true, + selectionOnly: true, + headerFooter: false, + rasterize: true, + vendorItems: { + paperType: 1, + printArea: 6, + }, + ranges: [{from: 2, to: 2}], + }; + + // Update settings + Object.keys(settingsChange).forEach(setting => { + model.set(`settings.${setting}.value`, settingsChange[setting]); + }); + } + + function initializeModel() { + model.documentInfo = new print_preview.DocumentInfo(); + model.documentInfo.init(true, 'title', true); + model.documentInfo.updatePageCount(3); + // Update pages accordingly. + model.set('settings.pages.value', [1, 2, 3]); + + // Initialize some settings that don't have defaults to the destination + // defaults. + model.set('settings.dpi.value', {horizontal_dpi: 200, vertical_dpi: 200}); + model.set('settings.vendorItems.value', {paperType: 0, printArea: 4}); + + // Set rasterize available so that it can be tested. + model.set('settings.rasterize.available', true); + } + + /** + * Tests that toggling each setting results in the expected change to the + * print ticket. + */ + test(assert(TestNames.GetPrintTicket), function() { + const testDestination = new print_preview.Destination( + 'FooDevice', print_preview.DestinationType.LOCAL, + print_preview.DestinationOrigin.LOCAL, 'FooName', true /* isRecent */, + print_preview.DestinationConnectionStatus.ONLINE); + testDestination.capabilities = + print_preview_test_utils.getCddTemplateWithAdvancedSettings(2) + .capabilities; + + initializeModel(); + const defaultTicket = + model.createPrintTicket(testDestination, false, false); + const expectedDefaultTicket = JSON.stringify({ + mediaSize: {width_microns: 215900, height_microns: 279400}, + pageCount: 3, + landscape: false, + color: testDestination.getNativeColorModel(true), + headerFooterEnabled: false, // Only used in print preview + marginsType: print_preview.ticket_items.MarginsTypeValue.DEFAULT, + duplex: print_preview_new.DuplexMode.LONG_EDGE, + copies: 1, + collate: true, + shouldPrintBackgrounds: false, + shouldPrintSelectionOnly: false, + previewModifiable: true, + printToPDF: false, + printWithCloudPrint: false, + printWithPrivet: false, + printWithExtension: false, + rasterizePDF: false, + scaleFactor: 100, + pagesPerSheet: 1, + dpiHorizontal: 200, + dpiVertical: 200, + deviceName: 'FooDevice', + fitToPageEnabled: false, + pageWidth: 612, + pageHeight: 792, + showSystemDialog: false, + }); + expectEquals(expectedDefaultTicket, defaultTicket); + + // Toggle all the values and create a new print ticket. + toggleSettings(); + const newTicket = model.createPrintTicket(testDestination, false, false); + const expectedNewTicket = JSON.stringify({ + mediaSize: {width_microns: 240000, height_microns: 200000}, + pageCount: 1, + landscape: true, + color: testDestination.getNativeColorModel(false), + headerFooterEnabled: false, + marginsType: print_preview.ticket_items.MarginsTypeValue.CUSTOM, + duplex: print_preview_new.DuplexMode.SIMPLEX, + copies: 2, + collate: false, + shouldPrintBackgrounds: true, + shouldPrintSelectionOnly: false, // Only for Print Preview. + previewModifiable: true, + printToPDF: false, + printWithCloudPrint: false, + printWithPrivet: false, + printWithExtension: false, + rasterizePDF: true, + scaleFactor: 90, + pagesPerSheet: 1, + dpiHorizontal: 100, + dpiVertical: 100, + deviceName: 'FooDevice', + fitToPageEnabled: true, + pageWidth: 612, + pageHeight: 792, + showSystemDialog: false, + marginsCustom: { + marginTop: 100, + marginRight: 200, + marginBottom: 300, + marginLeft: 400, + }, + }); + expectEquals(expectedNewTicket, newTicket); + }); + + /** + * Tests that toggling each setting results in the expected change to the + * cloud job print ticket. + */ + test(assert(TestNames.GetCloudPrintTicket), function() { + initializeModel(); + + // Create a test cloud destination. + const testDestination = new print_preview.Destination( + 'FooCloudDevice', print_preview.DestinationType.GOOGLE, + print_preview.DestinationOrigin.COOKIES, 'FooCloudName', + true /* isRecent */, + print_preview.DestinationConnectionStatus.ONLINE); + testDestination.capabilities = + print_preview_test_utils.getCddTemplateWithAdvancedSettings(2) + .capabilities; + + const defaultTicket = model.createCloudJobTicket(testDestination); + const expectedDefaultTicket = JSON.stringify({ + version: '1.0', + print: { + collate: {collate: true}, + color: { + type: testDestination.getSelectedColorOption(true).type, + }, + copies: {copies: 1}, + duplex: {type: 'LONG_EDGE'}, + media_size: { + width_microns: 215900, + height_microns: 279400, + }, + page_orientation: {type: 'PORTRAIT'}, + dpi: { + horizontal_dpi: 200, + vertical_dpi: 200, + }, + vendor_ticket_item: [ + {id: 'paperType', value: 0}, + {id: 'printArea', value: 4}, + ], + }, + }); + expectEquals(expectedDefaultTicket, defaultTicket); + + // Toggle all the values and create a new cloud job ticket. + toggleSettings(); + const newTicket = model.createCloudJobTicket(testDestination); + const expectedNewTicket = JSON.stringify({ + version: '1.0', + print: { + collate: {collate: false}, + color: { + type: testDestination.getSelectedColorOption(false).type, + }, + copies: {copies: 2}, + duplex: {type: 'NO_DUPLEX'}, + media_size: { + width_microns: 240000, + height_microns: 200000, + }, + page_orientation: {type: 'LANDSCAPE'}, + dpi: { + horizontal_dpi: 100, + vertical_dpi: 100, + }, + vendor_ticket_item: [ + {id: 'paperType', value: 1}, + {id: 'printArea', value: 6}, + ], + }, + }); + expectEquals(expectedNewTicket, newTicket); + }); }); return {
diff --git a/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js b/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js index d051f5e9..6b2e28b 100644 --- a/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js +++ b/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js
@@ -252,6 +252,7 @@ get extraLibraries() { return super.extraLibraries.concat([ '../settings/test_util.js', + 'print_preview_test_utils.js', 'model_test.js', ]); } @@ -266,6 +267,14 @@ this.runMochaTest(model_test.TestNames.SetStickySettings); }); +TEST_F('PrintPreviewModelTest', 'GetPrintTicket', function() { + this.runMochaTest(model_test.TestNames.GetPrintTicket); +}); + +TEST_F('PrintPreviewModelTest', 'GetCloudPrintTicket', function() { + this.runMochaTest(model_test.TestNames.GetCloudPrintTicket); +}); + PrintPreviewPreviewGenerationTest = class extends NewPrintPreviewTest { /** @override */ get browsePreload() {
diff --git a/chrome/test/data/webui/settings/passwords_and_autofill_fake_data.js b/chrome/test/data/webui/settings/passwords_and_autofill_fake_data.js index a8c9580..b8a485ef 100644 --- a/chrome/test/data/webui/settings/passwords_and_autofill_fake_data.js +++ b/chrome/test/data/webui/settings/passwords_and_autofill_fake_data.js
@@ -11,18 +11,18 @@ /** * Creates a single item for the list of passwords. - * @param {string|undefined} url - * @param {string|undefined} username - * @param {number|undefined} passwordLength + * @param {string=} url + * @param {string=} username + * @param {number=} passwordLength + * @param {number=} index * @return {chrome.passwordsPrivate.PasswordUiEntry} */ -FakeDataMaker.passwordEntry = function(url, username, passwordLength) { +FakeDataMaker.passwordEntry = function(url, username, passwordLength, index) { // Generate fake data if param is undefined. url = url || FakeDataMaker.patternMaker_('www.xxxxxx.com', 16); username = username || FakeDataMaker.patternMaker_('user_xxxxx', 16); passwordLength = passwordLength || Math.floor(Math.random() * 15) + 3; - entryIndex = -1; - exceptionIndex = -1; + index = index || 0; return { loginPair: { @@ -34,24 +34,26 @@ username: username, }, numCharactersInPassword: passwordLength, - index: ++entryIndex, + index: index, }; }; /** * Creates a single item for the list of password exceptions. - * @param {string|undefined} url + * @param {string=} url + * @param {number=} index * @return {chrome.passwordsPrivate.ExceptionEntry} */ -FakeDataMaker.exceptionEntry = function(url) { +FakeDataMaker.exceptionEntry = function(url, index) { url = url || FakeDataMaker.patternMaker_('www.xxxxxx.com', 16); + index = index || 0; return { urls: { origin: 'http://' + url + '/login', shown: url, link: 'http://' + url + '/login', }, - index: ++exceptionIndex, + index: index, }; };
diff --git a/chrome/test/data/webui/settings/settings_passwords_section_browsertest.js b/chrome/test/data/webui/settings/settings_passwords_section_browsertest.js index 120fda8..70d08c9 100644 --- a/chrome/test/data/webui/settings/settings_passwords_section_browsertest.js +++ b/chrome/test/data/webui/settings/settings_passwords_section_browsertest.js
@@ -59,11 +59,11 @@ */ function validatePasswordList(listElement, passwordList) { assertEquals(passwordList.length, listElement.items.length); - if (passwordList.length > 0) { + for (let index = 0; index < passwordList.length; ++index) { // The first child is a template, skip and get the real 'first child'. - const node = Polymer.dom(listElement).children[1]; + const node = Polymer.dom(listElement).children[index + 1]; assert(node); - const passwordInfo = passwordList[0]; + const passwordInfo = passwordList[index]; assertEquals( passwordInfo.loginPair.urls.shown, node.$$('#originUrl').textContent.trim()); @@ -290,6 +290,32 @@ validatePasswordList(passwordsSection.$.passwordList, passwordList); }); + // Test verifies that removing one out of two passwords for the same website + // will update the elements. + test('verifyPasswordListRemoveSameWebsite', function() { + const passwordsSection = createPasswordsSection(passwordManager, [], []); + + // Set-up initial list. + let passwordList = [ + FakeDataMaker.passwordEntry('website.com', 'mario', 1, 0), + FakeDataMaker.passwordEntry('website.com', 'luigi', 7, 1) + ]; + + passwordManager.lastCallback.addSavedPasswordListChangedListener( + passwordList); + Polymer.dom.flush(); + validatePasswordList(passwordsSection.$.passwordList, passwordList); + + // Simulate '(website.com, mario)' being removed from the list. + passwordList = + [FakeDataMaker.passwordEntry('website.com', 'luigi', 7, 0)]; + + passwordManager.lastCallback.addSavedPasswordListChangedListener( + passwordList); + Polymer.dom.flush(); + validatePasswordList(passwordsSection.$.passwordList, passwordList); + }); + // Test verifies that pressing the 'remove' button will trigger a remove // event. Does not actually remove any passwords. test('verifyPasswordItemRemoveButton', function(done) {
diff --git a/chrome/test/data/webui/settings/sync_account_control_test.js b/chrome/test/data/webui/settings/sync_account_control_test.js index 2ce9148..5a8bc9b 100644 --- a/chrome/test/data/webui/settings/sync_account_control_test.js +++ b/chrome/test/data/webui/settings/sync_account_control_test.js
@@ -279,7 +279,7 @@ assertTrue(testElement.$$('#sync-icon-container') .classList.contains('sync-disabled')); - assertTrue(!!testElement.$$('[icon=\'settings:sync\']')); + assertTrue(!!testElement.$$('[icon=\'cr:sync\']')); displayedText = userInfo.querySelector('span:not([hidden])').textContent; assertFalse(displayedText.includes('barName')); assertFalse(displayedText.includes('fooName'));
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc index 05b22d807..3266999 100644 --- a/chromecast/browser/cast_content_browser_client.cc +++ b/chromecast/browser/cast_content_browser_client.cc
@@ -148,17 +148,6 @@ } #endif // defined(OS_ANDROID) && !BUILDFLAG(IS_CAST_USING_CMA_BACKEND) -// Gets the URL request context getter for the single Cast browser context. -// Must be called on the UI thread. -scoped_refptr<net::URLRequestContextGetter> -GetRequestContextGetterFromBrowserContext() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - return scoped_refptr<net::URLRequestContextGetter>( - content::BrowserContext::GetDefaultStoragePartition( - CastBrowserProcess::GetInstance()->browser_context()) - ->GetURLRequestContext()); -} - } // namespace CastContentBrowserClient::CastContentBrowserClient() @@ -513,15 +502,6 @@ return locale.empty() ? "en-US" : locale; } -void CastContentBrowserClient::GetGeolocationRequestContext( - base::OnceCallback<void(scoped_refptr<net::URLRequestContextGetter>)> - callback) { - content::BrowserThread::PostTaskAndReplyWithResult( - content::BrowserThread::UI, FROM_HERE, - base::BindOnce(&GetRequestContextGetterFromBrowserContext), - std::move(callback)); -} - content::QuotaPermissionContext* CastContentBrowserClient::CreateQuotaPermissionContext() { return new CastQuotaPermissionContext();
diff --git a/chromecast/browser/cast_content_browser_client.h b/chromecast/browser/cast_content_browser_client.h index b027928..e708e762 100644 --- a/chromecast/browser/cast_content_browser_client.h +++ b/chromecast/browser/cast_content_browser_client.h
@@ -137,9 +137,6 @@ content::WebPreferences* prefs) override; void ResourceDispatcherHostCreated() override; std::string GetApplicationLocale() override; - void GetGeolocationRequestContext( - base::OnceCallback<void(scoped_refptr<net::URLRequestContextGetter>)> - callback) override; content::QuotaPermissionContext* CreateQuotaPermissionContext() override; void GetQuotaSettings( content::BrowserContext* context,
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 50c1eda..31d36995 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -10877.0.0 \ No newline at end of file +10883.0.0 \ No newline at end of file
diff --git a/chromeos/services/assistant/assistant_manager_service_impl.cc b/chromeos/services/assistant/assistant_manager_service_impl.cc index ec106dd..b3deb38 100644 --- a/chromeos/services/assistant/assistant_manager_service_impl.cc +++ b/chromeos/services/assistant/assistant_manager_service_impl.cc
@@ -29,7 +29,8 @@ #include "services/service_manager/public/cpp/connector.h" #include "url/gurl.h" -using assistant_client::ActionModule; +using ActionModule = assistant_client::ActionModule; +using Resolution = assistant_client::ConversationStateListener::Resolution; namespace api = ::assistant::api; @@ -197,10 +198,12 @@ } void AssistantManagerServiceImpl::StartVoiceInteraction() { + platform_api_.SetMicState(true); assistant_manager_->StartAssistantInteraction(); } void AssistantManagerServiceImpl::StopActiveInteraction() { + platform_api_.SetMicState(false); assistant_manager_->StopAssistantInteraction(); } @@ -254,16 +257,22 @@ dismissed_interaction, "DismissNotification", options, [](auto) {}); } -void AssistantManagerServiceImpl::OnConversationTurnStarted() { +void AssistantManagerServiceImpl::OnConversationTurnStarted(bool is_mic_open) { main_thread_task_runner_->PostTask( FROM_HERE, base::BindOnce( &AssistantManagerServiceImpl::OnConversationTurnStartedOnMainThread, - weak_factory_.GetWeakPtr())); + weak_factory_.GetWeakPtr(), is_mic_open)); } void AssistantManagerServiceImpl::OnConversationTurnFinished( - assistant_client::ConversationStateListener::Resolution resolution) { + Resolution resolution) { + // TODO(updowndota): Find a better way to handle the edge cases. + if (resolution != Resolution::NORMAL_WITH_FOLLOW_ON && + resolution != Resolution::CANCELLED && + resolution != Resolution::BARGE_IN) { + platform_api_.SetMicState(false); + } main_thread_task_runner_->PostTask( FROM_HERE, base::BindOnce( @@ -551,45 +560,45 @@ RegisterFallbackMediaHandler(); } -void AssistantManagerServiceImpl::OnConversationTurnStartedOnMainThread() { +void AssistantManagerServiceImpl::OnConversationTurnStartedOnMainThread( + bool is_mic_open) { + // TODO(dmblack): Pipe |is_mic_open| through the OnInteractionStarted event. interaction_subscribers_.ForAllPtrs( [](auto* ptr) { ptr->OnInteractionStarted(); }); } void AssistantManagerServiceImpl::OnConversationTurnFinishedOnMainThread( - assistant_client::ConversationStateListener::Resolution resolution) { + Resolution resolution) { switch (resolution) { // Interaction ended normally. // Note that TIMEOUT here does not refer to server timeout, but rather mic // timeout due to speech inactivity. As this case does not require special // UI logic, it is treated here as a normal interaction completion. - case assistant_client::ConversationStateListener::Resolution::NORMAL: - case assistant_client::ConversationStateListener::Resolution:: - NORMAL_WITH_FOLLOW_ON: - case assistant_client::ConversationStateListener::Resolution::TIMEOUT: + case Resolution::NORMAL: + case Resolution::NORMAL_WITH_FOLLOW_ON: + case Resolution::TIMEOUT: interaction_subscribers_.ForAllPtrs([](auto* ptr) { ptr->OnInteractionFinished( mojom::AssistantInteractionResolution::kNormal); }); break; // Interaction ended due to interruption. - case assistant_client::ConversationStateListener::Resolution::BARGE_IN: - case assistant_client::ConversationStateListener::Resolution::CANCELLED: + case Resolution::BARGE_IN: + case Resolution::CANCELLED: interaction_subscribers_.ForAllPtrs([](auto* ptr) { ptr->OnInteractionFinished( mojom::AssistantInteractionResolution::kInterruption); }); break; // Interaction ended due to multi-device hotword loss. - case assistant_client::ConversationStateListener::Resolution::NO_RESPONSE: + case Resolution::NO_RESPONSE: interaction_subscribers_.ForAllPtrs([](auto* ptr) { ptr->OnInteractionFinished( mojom::AssistantInteractionResolution::kMultiDeviceHotwordLoss); }); break; // Interaction ended due to error. - case assistant_client::ConversationStateListener::Resolution:: - COMMUNICATION_ERROR: + case Resolution::COMMUNICATION_ERROR: interaction_subscribers_.ForAllPtrs([](auto* ptr) { ptr->OnInteractionFinished( mojom::AssistantInteractionResolution::kError);
diff --git a/chromeos/services/assistant/assistant_manager_service_impl.h b/chromeos/services/assistant/assistant_manager_service_impl.h index 4afe0649..344c4ba 100644 --- a/chromeos/services/assistant/assistant_manager_service_impl.h +++ b/chromeos/services/assistant/assistant_manager_service_impl.h
@@ -108,7 +108,7 @@ void OnSpeechLevelUpdated(float speech_level) override; // assistant_client::ConversationStateListener overrides: - void OnConversationTurnStarted() override; + void OnConversationTurnStarted(bool is_mic_open) override; void OnConversationTurnFinished( assistant_client::ConversationStateListener::Resolution resolution) override; @@ -158,7 +158,7 @@ base::RepeatingCallback<void(const std::string&)> callback, const std::string& result); - void OnConversationTurnStartedOnMainThread(); + void OnConversationTurnStartedOnMainThread(bool is_mic_open); void OnConversationTurnFinishedOnMainThread( assistant_client::ConversationStateListener::Resolution resolution); void OnShowHtmlOnMainThread(const std::string& html);
diff --git a/chromeos/services/assistant/platform/audio_input_provider_impl.cc b/chromeos/services/assistant/platform/audio_input_provider_impl.cc index 6c80769..76af680e 100644 --- a/chromeos/services/assistant/platform/audio_input_provider_impl.cc +++ b/chromeos/services/assistant/platform/audio_input_provider_impl.cc
@@ -50,10 +50,12 @@ } AudioInputImpl::AudioInputImpl( - std::unique_ptr<service_manager::Connector> connector) + std::unique_ptr<service_manager::Connector> connector, + bool default_on) : source_(audio::CreateInputDevice( std::move(connector), media::AudioDeviceDescription::kDefaultDeviceId)), + default_on_(default_on), task_runner_(base::ThreadTaskRunnerHandle::Get()), weak_factory_(this) { DETACH_FROM_SEQUENCE(observer_sequence_checker_); @@ -112,7 +114,7 @@ should_start = observers_.size() == 1; } - if (should_start) { + if (default_on_ && should_start) { // Post to main thread runner to start audio recording. Assistant thread // does not have thread context defined in //base and will fail sequence // check in AudioCapturerSource::Start(). @@ -138,6 +140,16 @@ } } +void AudioInputImpl::SetMicState(bool mic_open) { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + if (!default_on_) { + if (mic_open) + source_->Start(); + else + source_->Stop(); + } +} + void AudioInputImpl::StartRecording() { DCHECK(task_runner_->RunsTasksInCurrentSequence()); source_->Start(); @@ -149,8 +161,9 @@ } AudioInputProviderImpl::AudioInputProviderImpl( - service_manager::Connector* connector) - : audio_input_(connector->Clone()) {} + service_manager::Connector* connector, + bool default_on) + : audio_input_(connector->Clone(), default_on) {} AudioInputProviderImpl::~AudioInputProviderImpl() = default; @@ -163,5 +176,9 @@ return 0; } +void AudioInputProviderImpl::SetMicState(bool mic_open) { + audio_input_.SetMicState(mic_open); +} + } // namespace assistant } // namespace chromeos
diff --git a/chromeos/services/assistant/platform/audio_input_provider_impl.h b/chromeos/services/assistant/platform/audio_input_provider_impl.h index fdbf6d1d..e735e94 100644 --- a/chromeos/services/assistant/platform/audio_input_provider_impl.h +++ b/chromeos/services/assistant/platform/audio_input_provider_impl.h
@@ -49,8 +49,8 @@ class AudioInputImpl : public assistant_client::AudioInput, public media::AudioCapturerSource::CaptureCallback { public: - explicit AudioInputImpl( - std::unique_ptr<service_manager::Connector> connector); + AudioInputImpl(std::unique_ptr<service_manager::Connector> connector, + bool default_on); ~AudioInputImpl() override; // media::AudioCapturerSource::CaptureCallback overrides: @@ -69,12 +69,18 @@ void RemoveObserver( assistant_client::AudioInput::Observer* observer) override; + // Called when the mic state associated with the interaction is changed. + void SetMicState(bool mic_open); + private: void StartRecording(); void StopRecording(); scoped_refptr<media::AudioCapturerSource> source_; + // Should audio input always recording actively. + const bool default_on_; + // Guards observers_; base::Lock lock_; std::vector<assistant_client::AudioInput::Observer*> observers_; @@ -92,13 +98,17 @@ class AudioInputProviderImpl : public assistant_client::AudioInputProvider { public: - explicit AudioInputProviderImpl(service_manager::Connector* connector); + explicit AudioInputProviderImpl(service_manager::Connector* connector, + bool default_on); ~AudioInputProviderImpl() override; // assistant_client::AudioInputProvider overrides: assistant_client::AudioInput& GetAudioInput() override; int64_t GetCurrentAudioTime() override; + // Called when the mic state associated with the interaction is changed. + void SetMicState(bool mic_open); + private: AudioInputImpl audio_input_;
diff --git a/chromeos/services/assistant/platform/system_provider_impl.cc b/chromeos/services/assistant/platform/system_provider_impl.cc index 9b1d445..6bb123a 100644 --- a/chromeos/services/assistant/platform/system_provider_impl.cc +++ b/chromeos/services/assistant/platform/system_provider_impl.cc
@@ -16,12 +16,8 @@ namespace assistant { SystemProviderImpl::SystemProviderImpl( - device::mojom::BatteryMonitorPtr battery_monitor, - bool muted) - : battery_monitor_(std::move(battery_monitor)), - mic_mute_state_( - muted ? assistant_client::MicMuteState::MICROPHONE_OFF - : assistant_client::MicMuteState::MICROPHONE_ENABLED) { + device::mojom::BatteryMonitorPtr battery_monitor) + : battery_monitor_(std::move(battery_monitor)) { battery_monitor_->QueryNextStatus(base::BindOnce( &SystemProviderImpl::OnBatteryStatus, base::Unretained(this))); } @@ -29,7 +25,8 @@ SystemProviderImpl::~SystemProviderImpl() = default; assistant_client::MicMuteState SystemProviderImpl::GetMicMuteState() { - return mic_mute_state_; + // CRAS input is never muted. + return assistant_client::MicMuteState::MICROPHONE_ENABLED; } void SystemProviderImpl::RegisterMicMuteChangeCallback(
diff --git a/chromeos/services/assistant/platform/system_provider_impl.h b/chromeos/services/assistant/platform/system_provider_impl.h index 4d4843c..c3b035fd 100644 --- a/chromeos/services/assistant/platform/system_provider_impl.h +++ b/chromeos/services/assistant/platform/system_provider_impl.h
@@ -16,8 +16,7 @@ class SystemProviderImpl : public assistant_client::SystemProvider { public: - explicit SystemProviderImpl(device::mojom::BatteryMonitorPtr battery_monitor, - bool muted); + explicit SystemProviderImpl(device::mojom::BatteryMonitorPtr battery_monitor); ~SystemProviderImpl() override; // assistant_client::SystemProvider implementation: @@ -36,7 +35,6 @@ device::mojom::BatteryMonitorPtr battery_monitor_; device::mojom::BatteryStatusPtr current_battery_status_; - const assistant_client::MicMuteState mic_mute_state_; DISALLOW_COPY_AND_ASSIGN(SystemProviderImpl); };
diff --git a/chromeos/services/assistant/platform_api_impl.cc b/chromeos/services/assistant/platform_api_impl.cc index b07f067b..574f7d4 100644 --- a/chromeos/services/assistant/platform_api_impl.cc +++ b/chromeos/services/assistant/platform_api_impl.cc
@@ -77,9 +77,9 @@ service_manager::Connector* connector, device::mojom::BatteryMonitorPtr battery_monitor, bool enable_hotword) - : audio_input_provider_(connector), + : audio_input_provider_(connector, enable_hotword), audio_output_provider_(CreateLibAssistantConfig(!enable_hotword), this), - system_provider_(std::move(battery_monitor), !enable_hotword) {} + system_provider_(std::move(battery_monitor)) {} PlatformApiImpl::~PlatformApiImpl() = default; @@ -111,5 +111,9 @@ return system_provider_; } +void PlatformApiImpl::SetMicState(bool mic_open) { + audio_input_provider_.SetMicState(mic_open); +} + } // namespace assistant } // namespace chromeos
diff --git a/chromeos/services/assistant/platform_api_impl.h b/chromeos/services/assistant/platform_api_impl.h index d01a6bd8..f2fcf5c3 100644 --- a/chromeos/services/assistant/platform_api_impl.h +++ b/chromeos/services/assistant/platform_api_impl.h
@@ -48,6 +48,9 @@ assistant_client::ResourceProvider& GetResourceProvider() override; assistant_client::SystemProvider& GetSystemProvider() override; + // Called when the mic state associated with the interaction is changed. + void SetMicState(bool mic_open); + private: // ChromeOS does not use auth manager, so we don't yet need to implement a // real auth provider.
diff --git a/chromeos/services/multidevice_setup/host_verifier.h b/chromeos/services/multidevice_setup/host_verifier.h index aef1b949..dfbbc6c 100644 --- a/chromeos/services/multidevice_setup/host_verifier.h +++ b/chromeos/services/multidevice_setup/host_verifier.h
@@ -13,9 +13,14 @@ namespace multidevice_setup { // Verifies that this device can connect to the currently-set MultiDevice host. -// The verification process consists of creating a Bluetooth connection to the -// device, performing an authentication handshake, and enabling the per-device -// features which are supported. +// In order for a host device to be considered set, its BETTER_TOGETHER_HOST +// software feature must be enabled, and in order for a host device to be +// considered verified, at least one of its other host software features must be +// enabled. +// +// HostVerifier waits for that situation to occur and has the ability (via its +// AttemptVerificationNow() function) to send a tickle message to the phone to +// ask it to enable its software features. class HostVerifier { public: class Observer { @@ -26,9 +31,9 @@ virtual ~HostVerifier(); - // Returns whether the host has completed verification; note that if - // verification is still in the process of being completed but has not - // finished, this function still returns false. + // Returns whether verification for the current MultiDevice host device has + // completed (see description above). If no MultiDevice host is set at all, + // false is returned. virtual bool IsHostVerified() = 0; // Attempts the verification flow; successful completion of the flow is
diff --git a/chromeos/services/multidevice_setup/host_verifier_impl.cc b/chromeos/services/multidevice_setup/host_verifier_impl.cc index b86c9b9..908fb81 100644 --- a/chromeos/services/multidevice_setup/host_verifier_impl.cc +++ b/chromeos/services/multidevice_setup/host_verifier_impl.cc
@@ -7,13 +7,48 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/no_destructor.h" -#include "chromeos/services/device_sync/public/cpp/device_sync_client.h" -#include "chromeos/services/secure_channel/public/cpp/client/secure_channel_client.h" +#include "chromeos/components/proximity_auth/logging/logging.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/pref_service.h" namespace chromeos { namespace multidevice_setup { +namespace { + +// Software features which, when enabled, represent a verified host. +constexpr const cryptauth::SoftwareFeature kPotentialHostFeatures[] = { + cryptauth::SoftwareFeature::EASY_UNLOCK_HOST, + cryptauth::SoftwareFeature::MAGIC_TETHER_HOST, + cryptauth::SoftwareFeature::SMS_CONNECT_HOST}; + +// Name of the preference containing the time (in milliseconds since Unix +// epoch) at which a verification attempt should be retried. If the preference +// value is kTimestampNotSet, no retry is scheduled. +const char kRetryTimestampPrefName[] = + "multidevice_setup.current_retry_timestamp_ms"; + +// Value set for the kRetryTimestampPrefName preference when no retry attempt is +// underway (i.e., verification is complete or there is no current host). +const int64_t kTimestampNotSet = 0; + +// Name of the preference containing the time delta (in ms) between the +// timestamp present in the kRetryTimestampPrefName preference and the attempt +// before that one. If the value of kRetryTimestampPrefName is kTimestampNotSet, +// the value at this preference is meaningless. +const char kLastUsedTimeDeltaMsPrefName[] = + "multidevice_setup.last_used_time_delta_ms"; + +// Delta to set for the first retry. +constexpr const base::TimeDelta kFirstRetryDelta = + base::TimeDelta::FromMinutes(10); + +// The multiplier for increasing the backoff timer between retries. +const double kExponentialBackoffMultiplier = 1.5; + +} // namespace + // static HostVerifierImpl::Factory* HostVerifierImpl::Factory::test_factory_ = nullptr; @@ -36,40 +71,171 @@ std::unique_ptr<HostVerifier> HostVerifierImpl::Factory::BuildInstance( HostBackendDelegate* host_backend_delegate, device_sync::DeviceSyncClient* device_sync_client, - secure_channel::SecureChannelClient* secure_channel_client) { - return base::WrapUnique(new HostVerifierImpl( - host_backend_delegate, device_sync_client, secure_channel_client)); + PrefService* pref_service, + base::Clock* clock, + std::unique_ptr<base::OneShotTimer> timer) { + return base::WrapUnique(new HostVerifierImpl(host_backend_delegate, + device_sync_client, pref_service, + clock, std::move(timer))); +} + +// static +void HostVerifierImpl::RegisterPrefs(PrefRegistrySimple* registry) { + registry->RegisterInt64Pref(kRetryTimestampPrefName, kTimestampNotSet); + registry->RegisterInt64Pref(kLastUsedTimeDeltaMsPrefName, 0); } HostVerifierImpl::HostVerifierImpl( HostBackendDelegate* host_backend_delegate, device_sync::DeviceSyncClient* device_sync_client, - secure_channel::SecureChannelClient* secure_channel_client) + PrefService* pref_service, + base::Clock* clock, + std::unique_ptr<base::OneShotTimer> timer) : host_backend_delegate_(host_backend_delegate), device_sync_client_(device_sync_client), - secure_channel_client_(secure_channel_client) { + pref_service_(pref_service), + clock_(clock), + timer_(std::move(timer)) { host_backend_delegate_->AddObserver(this); + device_sync_client_->AddObserver(this); + + UpdateRetryState(); } HostVerifierImpl::~HostVerifierImpl() { host_backend_delegate_->RemoveObserver(this); + device_sync_client_->RemoveObserver(this); } bool HostVerifierImpl::IsHostVerified() { - NOTIMPLEMENTED(); + base::Optional<cryptauth::RemoteDeviceRef> current_host = + host_backend_delegate_->GetMultiDeviceHostFromBackend(); + if (!current_host) + return false; - // Use both |device_sync_client_| and |secure_channel_client_| to prevent - // unused field compiler warning. - return static_cast<void*>(device_sync_client_) == - static_cast<void*>(secure_channel_client_); + // If one or more potential host sofware features is enabled, the host is + // considered verified. + for (const auto& software_feature : kPotentialHostFeatures) { + if (current_host->GetSoftwareFeatureState(software_feature) == + cryptauth::SoftwareFeatureState::kEnabled) { + return true; + } + } + + return false; } void HostVerifierImpl::PerformAttemptVerificationNow() { - NOTIMPLEMENTED(); + AttemptHostVerification(); } void HostVerifierImpl::OnHostChangedOnBackend() { - NOTIMPLEMENTED(); + UpdateRetryState(); +} + +void HostVerifierImpl::OnNewDevicesSynced() { + UpdateRetryState(); +} + +void HostVerifierImpl::UpdateRetryState() { + // If there is no host, verification is not applicable. + if (!host_backend_delegate_->GetMultiDeviceHostFromBackend()) { + StopTimerAndClearPrefs(); + return; + } + + // If there is a host and it is verified, verification is no longer necessary. + if (IsHostVerified()) { + bool was_timer_running = timer_->IsRunning(); + StopTimerAndClearPrefs(); + if (was_timer_running) + NotifyHostVerified(); + return; + } + + // If |timer_| is running, an ongoing retry attempt is in progress. + if (timer_->IsRunning()) + return; + + int64_t timestamp_from_prefs = + pref_service_->GetInt64(kRetryTimestampPrefName); + + // If no retry timer was set, set the timer to the initial value and attempt + // to verify now. + if (timestamp_from_prefs == kTimestampNotSet) { + AttemptVerificationWithInitialTimeout(); + return; + } + + base::Time retry_time_from_prefs = + base::Time::FromJavaTime(timestamp_from_prefs); + + // If a timeout value was set but has not yet occurred, start the timer. + if (clock_->Now() < retry_time_from_prefs) { + StartTimer(retry_time_from_prefs); + return; + } + + AttemptVerificationAfterInitialTimeout(retry_time_from_prefs); +} + +void HostVerifierImpl::StopTimerAndClearPrefs() { + timer_->Stop(); + pref_service_->SetInt64(kRetryTimestampPrefName, kTimestampNotSet); + pref_service_->SetInt64(kLastUsedTimeDeltaMsPrefName, 0); +} + +void HostVerifierImpl::AttemptVerificationWithInitialTimeout() { + base::Time retry_time = clock_->Now() + kFirstRetryDelta; + + pref_service_->SetInt64(kRetryTimestampPrefName, retry_time.ToJavaTime()); + pref_service_->SetInt64(kLastUsedTimeDeltaMsPrefName, + kFirstRetryDelta.InMilliseconds()); + + StartTimer(retry_time); + AttemptHostVerification(); +} + +void HostVerifierImpl::AttemptVerificationAfterInitialTimeout( + const base::Time& retry_time_from_prefs) { + int64_t time_delta_ms = pref_service_->GetInt64(kLastUsedTimeDeltaMsPrefName); + DCHECK(time_delta_ms > 0); + + base::Time retry_time = retry_time_from_prefs; + while (clock_->Now() >= retry_time) { + time_delta_ms *= kExponentialBackoffMultiplier; + retry_time += base::TimeDelta::FromMilliseconds(time_delta_ms); + } + + pref_service_->SetInt64(kRetryTimestampPrefName, retry_time.ToJavaTime()); + pref_service_->SetInt64(kLastUsedTimeDeltaMsPrefName, time_delta_ms); + + StartTimer(retry_time); + AttemptHostVerification(); +} + +void HostVerifierImpl::StartTimer(const base::Time& time_to_fire) { + base::Time now = clock_->Now(); + DCHECK(now < time_to_fire); + + timer_->Start( + FROM_HERE, time_to_fire - now /* delay */, + base::Bind(&HostVerifierImpl::UpdateRetryState, base::Unretained(this))); +} + +void HostVerifierImpl::AttemptHostVerification() { + base::Optional<cryptauth::RemoteDeviceRef> current_host = + host_backend_delegate_->GetMultiDeviceHostFromBackend(); + if (!current_host) { + PA_LOG(WARNING) << "HostVerifierImpl::AttemptHostVerification(): Cannot " + << "attempt verification because there is no active host."; + return; + } + + PA_LOG(INFO) << "HostVerifierImpl::AttemptHostVerification(): Attempting " + << "host verification now."; + device_sync_client_->FindEligibleDevices( + cryptauth::SoftwareFeature::BETTER_TOGETHER_HOST, base::DoNothing()); } } // namespace multidevice_setup
diff --git a/chromeos/services/multidevice_setup/host_verifier_impl.h b/chromeos/services/multidevice_setup/host_verifier_impl.h index 2c135f3..2fc3e92 100644 --- a/chromeos/services/multidevice_setup/host_verifier_impl.h +++ b/chromeos/services/multidevice_setup/host_verifier_impl.h
@@ -5,20 +5,20 @@ #ifndef CHROMEOS_SERVICES_MULTIDEVICE_SETUP_HOST_VERIFIER_IMPL_H_ #define CHROMEOS_SERVICES_MULTIDEVICE_SETUP_HOST_VERIFIER_IMPL_H_ +#include <memory> + #include "base/macros.h" +#include "base/time/default_clock.h" +#include "base/timer/timer.h" +#include "chromeos/services/device_sync/public/cpp/device_sync_client.h" #include "chromeos/services/multidevice_setup/host_backend_delegate.h" #include "chromeos/services/multidevice_setup/host_verifier.h" +class PrefRegistrySimple; +class PrefService; + namespace chromeos { -namespace device_sync { -class DeviceSyncClient; -} // namespace device_sync - -namespace secure_channel { -class SecureChannelClient; -} // namespace secure_channel - namespace multidevice_setup { // Concrete HostVerifier implementation, which starts trying to verify a host as @@ -28,10 +28,9 @@ // If the MultiDevice host is changed while verification is in progress, the // previous verification attempt is canceled and a new attempt begins with the // updated device. -// -// TODO(khorimoto): Fill out implementation. class HostVerifierImpl : public HostVerifier, - public HostBackendDelegate::Observer { + public HostBackendDelegate::Observer, + public device_sync::DeviceSyncClient::Observer { public: class Factory { public: @@ -41,18 +40,25 @@ virtual std::unique_ptr<HostVerifier> BuildInstance( HostBackendDelegate* host_backend_delegate, device_sync::DeviceSyncClient* device_sync_client, - secure_channel::SecureChannelClient* secure_channel_client); + PrefService* pref_service, + base::Clock* clock = base::DefaultClock::GetInstance(), + std::unique_ptr<base::OneShotTimer> timer = + std::make_unique<base::OneShotTimer>()); private: static Factory* test_factory_; }; + static void RegisterPrefs(PrefRegistrySimple* registry); + ~HostVerifierImpl() override; private: HostVerifierImpl(HostBackendDelegate* host_backend_delegate, device_sync::DeviceSyncClient* device_sync_client, - secure_channel::SecureChannelClient* secure_channel_client); + PrefService* pref_service, + base::Clock* clock, + std::unique_ptr<base::OneShotTimer> timer); // HostVerifier: bool IsHostVerified() override; @@ -61,9 +67,22 @@ // HostBackendDelegate::Observer: void OnHostChangedOnBackend() override; + // device_sync::DeviceSyncClient::Observer: + void OnNewDevicesSynced() override; + + void UpdateRetryState(); + void StopTimerAndClearPrefs(); + void AttemptVerificationWithInitialTimeout(); + void AttemptVerificationAfterInitialTimeout( + const base::Time& retry_time_from_prefs); + void StartTimer(const base::Time& time_to_fire); + void AttemptHostVerification(); + HostBackendDelegate* host_backend_delegate_; device_sync::DeviceSyncClient* device_sync_client_; - secure_channel::SecureChannelClient* secure_channel_client_; + PrefService* pref_service_; + base::Clock* clock_; + std::unique_ptr<base::OneShotTimer> timer_; DISALLOW_COPY_AND_ASSIGN(HostVerifierImpl); };
diff --git a/chromeos/services/multidevice_setup/host_verifier_impl_unittest.cc b/chromeos/services/multidevice_setup/host_verifier_impl_unittest.cc index 5b82a4be..26b5f3d 100644 --- a/chromeos/services/multidevice_setup/host_verifier_impl_unittest.cc +++ b/chromeos/services/multidevice_setup/host_verifier_impl_unittest.cc
@@ -7,54 +7,310 @@ #include <memory> #include "base/macros.h" +#include "base/test/simple_test_clock.h" +#include "base/timer/mock_timer.h" #include "chromeos/services/device_sync/public/cpp/fake_device_sync_client.h" #include "chromeos/services/multidevice_setup/fake_host_backend_delegate.h" #include "chromeos/services/multidevice_setup/fake_host_verifier.h" -#include "chromeos/services/secure_channel/public/cpp/client/fake_secure_channel_client.h" +#include "components/cryptauth/remote_device_test_util.h" +#include "components/sync_preferences/testing_pref_service_syncable.h" #include "testing/gtest/include/gtest/gtest.h" namespace chromeos { namespace multidevice_setup { +namespace { + +const int64_t kTestTimeMs = 1500000000000; + +constexpr const cryptauth::SoftwareFeature kPotentialHostSoftwareFeatures[] = { + cryptauth::SoftwareFeature::EASY_UNLOCK_HOST, + cryptauth::SoftwareFeature::MAGIC_TETHER_HOST, + cryptauth::SoftwareFeature::SMS_CONNECT_HOST}; + +const char kRetryTimestampPrefName[] = + "multidevice_setup.current_retry_timestamp_ms"; +const char kLastUsedTimeDeltaMsPrefName[] = + "multidevice_setup.last_used_time_delta_ms"; + +const int64_t kFirstRetryDeltaMs = 10 * 60 * 1000; +const double kExponentialBackoffMultiplier = 1.5; + +enum class HostState { kHostNotSet, kHostSetButNotVerified, kHostVerified }; + +} // namespace + class MultiDeviceSetupHostVerifierImplTest : public testing::Test { protected: - MultiDeviceSetupHostVerifierImplTest() = default; + MultiDeviceSetupHostVerifierImplTest() + : test_device_(cryptauth::CreateRemoteDeviceRefForTest()) {} ~MultiDeviceSetupHostVerifierImplTest() override = default; // testing::Test: void SetUp() override { fake_host_backend_delegate_ = std::make_unique<FakeHostBackendDelegate>(); + fake_device_sync_client_ = std::make_unique<device_sync::FakeDeviceSyncClient>(); - fake_secure_channel_client_ = - std::make_unique<secure_channel::FakeSecureChannelClient>(); + + test_pref_service_ = + std::make_unique<sync_preferences::TestingPrefServiceSyncable>(); + HostVerifierImpl::RegisterPrefs(test_pref_service_->registry()); + + test_clock_ = std::make_unique<base::SimpleTestClock>(); + test_clock_->SetNow(base::Time::FromJavaTime(kTestTimeMs)); + } + + void TearDown() override { + if (fake_observer_) + host_verifier_->RemoveObserver(fake_observer_.get()); + } + + void CreateVerifier(HostState initial_host_state, + int64_t initial_timer_pref_value = 0, + int64_t initial_time_delta_pref_value = 0) { + SetHostState(initial_host_state); + test_pref_service_->SetInt64(kRetryTimestampPrefName, + initial_timer_pref_value); + test_pref_service_->SetInt64(kLastUsedTimeDeltaMsPrefName, + initial_time_delta_pref_value); + + auto mock_timer = std::make_unique<base::MockOneShotTimer>(); + mock_timer_ = mock_timer.get(); host_verifier_ = HostVerifierImpl::Factory::Get()->BuildInstance( fake_host_backend_delegate_.get(), fake_device_sync_client_.get(), - fake_secure_channel_client_.get()); + test_pref_service_.get(), test_clock_.get(), std::move(mock_timer)); fake_observer_ = std::make_unique<FakeHostVerifierObserver>(); host_verifier_->AddObserver(fake_observer_.get()); } - void TearDown() override { - host_verifier_->RemoveObserver(fake_observer_.get()); + void SetHostState(HostState host_state) { + for (const auto& feature : kPotentialHostSoftwareFeatures) { + GetMutableRemoteDevice(test_device_)->software_features[feature] = + host_state == HostState::kHostVerified + ? cryptauth::SoftwareFeatureState::kEnabled + : cryptauth::SoftwareFeatureState::kSupported; + } + + if (host_state == HostState::kHostNotSet) + fake_host_backend_delegate_->NotifyHostChangedOnBackend(base::nullopt); + else + fake_host_backend_delegate_->NotifyHostChangedOnBackend(test_device_); + + fake_device_sync_client_->NotifyNewDevicesSynced(); + } + + void VerifyState(bool expected_is_verified, + size_t expected_num_verified_events, + int64_t expected_retry_timestamp_value, + int64_t expected_retry_delta_value) { + EXPECT_EQ(expected_is_verified, host_verifier_->IsHostVerified()); + EXPECT_EQ(expected_num_verified_events, + fake_observer_->num_host_verifications()); + EXPECT_EQ(expected_retry_timestamp_value, + test_pref_service_->GetInt64(kRetryTimestampPrefName)); + EXPECT_EQ(expected_retry_delta_value, + test_pref_service_->GetInt64(kLastUsedTimeDeltaMsPrefName)); + + // If a retry timestamp is set, the timer should be running. + EXPECT_EQ(expected_retry_timestamp_value != 0, mock_timer_->IsRunning()); + } + + void VerifyFindEligibleDevicesCalled() { + fake_device_sync_client_->InvokePendingFindEligibleDevicesCallback( + base::nullopt /* error_code */, + cryptauth::RemoteDeviceRefList() /* eligible_devices */, + cryptauth::RemoteDeviceRefList() /* ineligible_devices */); + } + + void SimulateTimePassing(const base::TimeDelta& delta, + bool simulate_timeout = false) { + test_clock_->Advance(delta); + + if (simulate_timeout) + mock_timer_->Fire(); } private: + cryptauth::RemoteDeviceRef test_device_; + std::unique_ptr<FakeHostVerifierObserver> fake_observer_; std::unique_ptr<FakeHostBackendDelegate> fake_host_backend_delegate_; std::unique_ptr<device_sync::FakeDeviceSyncClient> fake_device_sync_client_; - std::unique_ptr<secure_channel::FakeSecureChannelClient> - fake_secure_channel_client_; + std::unique_ptr<sync_preferences::TestingPrefServiceSyncable> + test_pref_service_; + std::unique_ptr<base::SimpleTestClock> test_clock_; + base::MockOneShotTimer* mock_timer_ = nullptr; std::unique_ptr<HostVerifier> host_verifier_; DISALLOW_COPY_AND_ASSIGN(MultiDeviceSetupHostVerifierImplTest); }; -TEST_F(MultiDeviceSetupHostVerifierImplTest, Test) {} +TEST_F(MultiDeviceSetupHostVerifierImplTest, StartWithoutHost_SetAndVerify) { + CreateVerifier(HostState::kHostNotSet); + + SetHostState(HostState::kHostSetButNotVerified); + VerifyFindEligibleDevicesCalled(); + VerifyState( + false /* expected_is_verified */, 0u /* expected_num_verified_events */, + kTestTimeMs + kFirstRetryDeltaMs /* expected_retry_timestamp_value */, + kFirstRetryDeltaMs /* expected_retry_delta_value */); + + SimulateTimePassing(base::TimeDelta::FromMinutes(1)); + SetHostState(HostState::kHostVerified); + VerifyState(true /* expected_is_verified */, + 1u /* expected_num_verified_events */, + 0 /* expected_retry_timestamp_value */, + 0 /* expected_retry_delta_value */); +} + +TEST_F(MultiDeviceSetupHostVerifierImplTest, StartWithoutHost_Retry) { + CreateVerifier(HostState::kHostNotSet); + + SetHostState(HostState::kHostSetButNotVerified); + VerifyFindEligibleDevicesCalled(); + VerifyState( + false /* expected_is_verified */, 0u /* expected_num_verified_events */, + kTestTimeMs + kFirstRetryDeltaMs /* expected_retry_timestamp_value */, + kFirstRetryDeltaMs /* expected_retry_delta_value */); + + // Simulate enough time pasing to time out and retry. + SimulateTimePassing(base::TimeDelta::FromMilliseconds(kFirstRetryDeltaMs), + true /* simulate_timeout */); + VerifyFindEligibleDevicesCalled(); + VerifyState(false /* expected_is_verified */, + 0u /* expected_num_verified_events */, + kTestTimeMs + kFirstRetryDeltaMs + + kFirstRetryDeltaMs * kExponentialBackoffMultiplier + /* expected_retry_timestamp_value */, + kFirstRetryDeltaMs * kExponentialBackoffMultiplier + /* expected_retry_delta_value */); + + // Simulate the next retry timeout passing.. + SimulateTimePassing(base::TimeDelta::FromMilliseconds( + kFirstRetryDeltaMs * kExponentialBackoffMultiplier), + true /* simulate_timeout */); + VerifyFindEligibleDevicesCalled(); + VerifyState(false /* expected_is_verified */, + 0u /* expected_num_verified_events */, + kTestTimeMs + kFirstRetryDeltaMs + + kFirstRetryDeltaMs * kExponentialBackoffMultiplier + + kFirstRetryDeltaMs * kExponentialBackoffMultiplier * + kExponentialBackoffMultiplier + /* expected_retry_timestamp_value */, + kFirstRetryDeltaMs * kExponentialBackoffMultiplier * + kExponentialBackoffMultiplier + /* expected_retry_delta_value */); + + // Succeed. + SetHostState(HostState::kHostVerified); + VerifyState(true /* expected_is_verified */, + 1u /* expected_num_verified_events */, + 0 /* expected_retry_timestamp_value */, + 0 /* expected_retry_delta_value */); +} + +TEST_F(MultiDeviceSetupHostVerifierImplTest, + StartWithUnverifiedHost_NoInitialPrefs) { + CreateVerifier(HostState::kHostSetButNotVerified); + + VerifyFindEligibleDevicesCalled(); + VerifyState( + false /* expected_is_verified */, 0u /* expected_num_verified_events */, + kTestTimeMs + kFirstRetryDeltaMs /* expected_retry_timestamp_value */, + kFirstRetryDeltaMs /* expected_retry_delta_value */); +} + +TEST_F(MultiDeviceSetupHostVerifierImplTest, + StartWithUnverifiedHost_InitialPrefs_HasNotPassedRetryTime) { + // Simulate starting up the device to find that the retry timer is in 5 + // minutes. + CreateVerifier(HostState::kHostSetButNotVerified, + kTestTimeMs + base::TimeDelta::FromMinutes(5).InMilliseconds() + /* initial_timer_pref_value */, + kFirstRetryDeltaMs /* initial_time_delta_pref_value */); + + SimulateTimePassing(base::TimeDelta::FromMinutes(5), + true /* simulate_timeout */); + VerifyFindEligibleDevicesCalled(); + VerifyState(false /* expected_is_verified */, + 0u /* expected_num_verified_events */, + kTestTimeMs + base::TimeDelta::FromMinutes(5).InMilliseconds() + + kFirstRetryDeltaMs * kExponentialBackoffMultiplier + /* expected_retry_timestamp_value */, + kFirstRetryDeltaMs * kExponentialBackoffMultiplier + /* expected_retry_delta_value */); +} + +TEST_F(MultiDeviceSetupHostVerifierImplTest, + StartWithUnverifiedHost_InitialPrefs_AlreadyPassedRetryTime) { + // Simulate starting up the device to find that the retry timer had already + // fired 5 minutes ago. + CreateVerifier(HostState::kHostSetButNotVerified, + kTestTimeMs - base::TimeDelta::FromMinutes(5).InMilliseconds() + /* initial_timer_pref_value */, + kFirstRetryDeltaMs /* initial_time_delta_pref_value */); + + VerifyFindEligibleDevicesCalled(); + VerifyState(false /* expected_is_verified */, + 0u /* expected_num_verified_events */, + kTestTimeMs - base::TimeDelta::FromMinutes(5).InMilliseconds() + + kFirstRetryDeltaMs * kExponentialBackoffMultiplier + /* expected_retry_timestamp_value */, + kFirstRetryDeltaMs * kExponentialBackoffMultiplier + /* expected_retry_delta_value */); +} + +TEST_F(MultiDeviceSetupHostVerifierImplTest, + StartWithUnverifiedHost_InitialPrefs_AlreadyPassedMultipleRetryTimes) { + // Simulate starting up the device to find that the retry timer had already + // fired 20 minutes ago. + CreateVerifier(HostState::kHostSetButNotVerified, + kTestTimeMs - base::TimeDelta::FromMinutes(20).InMilliseconds() + /* initial_timer_pref_value */, + kFirstRetryDeltaMs /* initial_time_delta_pref_value */); + + // Because the first delta is 10 minutes, the second delta is 10 * 1.5 = 15 + // minutes. In this case, that means that *two* previous timeouts were missed, + // so the third one should be scheduled. + VerifyFindEligibleDevicesCalled(); + VerifyState(false /* expected_is_verified */, + 0u /* expected_num_verified_events */, + kTestTimeMs - base::TimeDelta::FromMinutes(20).InMilliseconds() + + kFirstRetryDeltaMs * kExponentialBackoffMultiplier + + kFirstRetryDeltaMs * kExponentialBackoffMultiplier * + kExponentialBackoffMultiplier + /* expected_retry_timestamp_value */, + kFirstRetryDeltaMs * kExponentialBackoffMultiplier * + kExponentialBackoffMultiplier + /* expected_retry_delta_value */); +} + +TEST_F(MultiDeviceSetupHostVerifierImplTest, + StartWithVerifiedHost_HostChanges) { + CreateVerifier(HostState::kHostVerified); + VerifyState(true /* expected_is_verified */, + 0u /* expected_num_verified_events */, + 0 /* expected_retry_timestamp_value */, + 0 /* expected_retry_delta_value */); + + SetHostState(HostState::kHostNotSet); + VerifyState(false /* expected_is_verified */, + 0u /* expected_num_verified_events */, + 0 /* expected_retry_timestamp_value */, + 0 /* expected_retry_delta_value */); + + SetHostState(HostState::kHostSetButNotVerified); + VerifyFindEligibleDevicesCalled(); + VerifyState( + false /* expected_is_verified */, 0u /* expected_num_verified_events */, + kTestTimeMs + kFirstRetryDeltaMs /* expected_retry_timestamp_value */, + kFirstRetryDeltaMs /* expected_retry_delta_value */); +} } // namespace multidevice_setup
diff --git a/chromeos/services/multidevice_setup/multidevice_setup_impl.cc b/chromeos/services/multidevice_setup/multidevice_setup_impl.cc index cf85e76..661497d4 100644 --- a/chromeos/services/multidevice_setup/multidevice_setup_impl.cc +++ b/chromeos/services/multidevice_setup/multidevice_setup_impl.cc
@@ -64,7 +64,7 @@ host_verifier_(HostVerifierImpl::Factory::Get()->BuildInstance( host_backend_delegate_.get(), device_sync_client, - secure_channel_client)), + pref_service)), host_status_provider_( HostStatusProviderImpl::Factory::Get()->BuildInstance( eligible_host_devices_provider_.get(),
diff --git a/chromeos/services/multidevice_setup/multidevice_setup_impl_unittest.cc b/chromeos/services/multidevice_setup/multidevice_setup_impl_unittest.cc index e2b4d3c..7cb0576e 100644 --- a/chromeos/services/multidevice_setup/multidevice_setup_impl_unittest.cc +++ b/chromeos/services/multidevice_setup/multidevice_setup_impl_unittest.cc
@@ -136,10 +136,11 @@ FakeHostVerifierFactory( FakeHostBackendDelegateFactory* fake_host_backend_delegate_factory, device_sync::FakeDeviceSyncClient* expected_device_sync_client, - secure_channel::FakeSecureChannelClient* expected_secure_channel_client) + sync_preferences::TestingPrefServiceSyncable* + expected_testing_pref_service) : fake_host_backend_delegate_factory_(fake_host_backend_delegate_factory), expected_device_sync_client_(expected_device_sync_client), - expected_secure_channel_client_(expected_secure_channel_client) {} + expected_testing_pref_service_(expected_testing_pref_service) {} ~FakeHostVerifierFactory() override = default; @@ -150,12 +151,14 @@ std::unique_ptr<HostVerifier> BuildInstance( HostBackendDelegate* host_backend_delegate, device_sync::DeviceSyncClient* device_sync_client, - secure_channel::SecureChannelClient* secure_channel_client) override { + PrefService* pref_service, + base::Clock* clock, + std::unique_ptr<base::OneShotTimer> timer) override { EXPECT_FALSE(instance_); EXPECT_EQ(fake_host_backend_delegate_factory_->instance(), host_backend_delegate); EXPECT_EQ(expected_device_sync_client_, device_sync_client); - EXPECT_EQ(expected_secure_channel_client_, secure_channel_client); + EXPECT_EQ(expected_testing_pref_service_, pref_service); auto instance = std::make_unique<FakeHostVerifier>(); instance_ = instance.get(); @@ -164,7 +167,7 @@ FakeHostBackendDelegateFactory* fake_host_backend_delegate_factory_; device_sync::FakeDeviceSyncClient* expected_device_sync_client_; - secure_channel::FakeSecureChannelClient* expected_secure_channel_client_; + sync_preferences::TestingPrefServiceSyncable* expected_testing_pref_service_; FakeHostVerifier* instance_ = nullptr; @@ -330,7 +333,7 @@ fake_host_verifier_factory_ = std::make_unique<FakeHostVerifierFactory>( fake_host_backend_delegate_factory_.get(), - fake_device_sync_client_.get(), fake_secure_channel_client_.get()); + fake_device_sync_client_.get(), test_pref_service_.get()); HostVerifierImpl::Factory::SetFactoryForTesting( fake_host_verifier_factory_.get());
diff --git a/chromeos/services/multidevice_setup/multidevice_setup_service.cc b/chromeos/services/multidevice_setup/multidevice_setup_service.cc index 829b4ea..9e3816c 100644 --- a/chromeos/services/multidevice_setup/multidevice_setup_service.cc +++ b/chromeos/services/multidevice_setup/multidevice_setup_service.cc
@@ -7,6 +7,7 @@ #include "chromeos/components/proximity_auth/logging/logging.h" #include "chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl.h" #include "chromeos/services/multidevice_setup/host_backend_delegate_impl.h" +#include "chromeos/services/multidevice_setup/host_verifier_impl.h" #include "chromeos/services/multidevice_setup/multidevice_setup_base.h" #include "chromeos/services/multidevice_setup/multidevice_setup_initializer.h" @@ -19,6 +20,7 @@ PrefRegistrySimple* registry) { AccountStatusChangeDelegateNotifierImpl::RegisterPrefs(registry); HostBackendDelegateImpl::RegisterPrefs(registry); + HostVerifierImpl::RegisterPrefs(registry); } MultiDeviceSetupService::MultiDeviceSetupService(
diff --git a/components/data_reduction_proxy/content/browser/content_resource_type_provider.cc b/components/data_reduction_proxy/content/browser/content_resource_type_provider.cc index 17184ed..94b24fe 100644 --- a/components/data_reduction_proxy/content/browser/content_resource_type_provider.cc +++ b/components/data_reduction_proxy/content/browser/content_resource_type_provider.cc
@@ -68,4 +68,13 @@ resource_content_types_.Put(request.url().spec(), content_type); } +bool ContentResourceTypeProvider::IsNonContentInitiatedRequest( + const net::URLRequest& request) const { + const auto* resource_request_info = + content::ResourceRequestInfo::ForRequest(&request); + return !resource_request_info || + (resource_request_info->GetGlobalRequestID() == + content::GlobalRequestID()); +} + } // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/content/browser/content_resource_type_provider.h b/components/data_reduction_proxy/content/browser/content_resource_type_provider.h index d4ed06ef20..07f1c0b 100644 --- a/components/data_reduction_proxy/content/browser/content_resource_type_provider.h +++ b/components/data_reduction_proxy/content/browser/content_resource_type_provider.h
@@ -30,6 +30,8 @@ void SetContentType(const net::URLRequest& request) override; ResourceTypeProvider::ContentType GetContentType( const GURL& url) const override; + bool IsNonContentInitiatedRequest( + const net::URLRequest& request) const override; // Map that evicts entries lazily based on the recency of being added. base::MRUCache<std::string, ResourceTypeProvider::ContentType>
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_use_observer.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_use_observer.cc index f61dd41..43fabeb 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_use_observer.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_use_observer.cc
@@ -44,10 +44,6 @@ int64_t original_bytes_; }; -// Hostname used for the other bucket which consists of chrome-services traffic. -// This should be in sync with the same in DataReductionSiteBreakdownView.java -const char kOtherHostName[] = "Other"; - // static const void* const DataUseUserDataBytes::kUserDataKey = &DataUseUserDataBytes::kUserDataKey; @@ -133,12 +129,14 @@ network_bytes, original_bytes)); } } else { + // Report the datause that cannot be scoped to a page load to the other + // host. These include chrome services, service-worker, Downloads, etc. data_reduction_proxy_io_data_->UpdateDataUseForHost( network_bytes, original_bytes, data_use->traffic_type() == data_use_measurement::DataUse::TrafficType::USER_TRAFFIC ? data_use->url().HostNoBrackets() - : kOtherHostName); + : util::GetSiteBreakdownOtherHostName()); } }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc index 107d6a0..75ba84f 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
@@ -32,6 +32,7 @@ #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h" #include "components/previews/core/previews_decider.h" #include "net/base/load_flags.h" +#include "net/http/http_request_headers.h" #include "net/url_request/http_user_agent_settings.h" #include "net/url_request/static_http_user_agent_settings.h" #include "net/url_request/url_request_context.h" @@ -145,6 +146,13 @@ request_options_.reset( new DataReductionProxyRequestOptions(client_, config_.get())); request_options_->Init(); + // It is safe to use base::Unretained here, since it gets executed + // synchronously on the IO thread, and |this| outlives the caller (since the + // caller is owned by |this|. + request_options_->SetUpdateHeaderCallback( + base::BindRepeating(&DataReductionProxyIOData::UpdateProxyRequestHeaders, + base::Unretained(this))); + if (use_config_client) { // It is safe to use base::Unretained here, since it gets executed // synchronously on the IO thread, and |this| outlives the caller (since the @@ -444,4 +452,12 @@ previews_decider_ = previews_decider; } +void DataReductionProxyIOData::UpdateProxyRequestHeaders( + net::HttpRequestHeaders headers) { + ui_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&DataReductionProxyService::SetProxyRequestHeaders, + service_, std::move(headers))); +} + } // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h index 7d562ec..e5d8ba2 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h
@@ -150,6 +150,9 @@ // cleared. void OnCacheCleared(const base::Time start, const base::Time end); + // Forwards proxy authentication headers to the UI thread. + void UpdateProxyRequestHeaders(net::HttpRequestHeaders headers); + // Various accessor methods. DataReductionProxyConfigurator* configurator() const { return configurator_.get();
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc index ef7d102..2be73a8 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
@@ -570,6 +570,17 @@ data_use_measurement::DataUseMeasurement::GetContentTypeForRequest( request), request.traffic_annotation().unique_id_hash_code); + + if (params::IsDataSaverSiteBreakdownUsingPLMEnabled() && + data_reduction_proxy_io_data_ && + data_reduction_proxy_io_data_->resource_type_provider() && + data_reduction_proxy_io_data_->resource_type_provider() + ->IsNonContentInitiatedRequest(request)) { + // Record non-content initiated traffic to the Other bucket for data saver + // site-breakdown. + data_reduction_proxy_io_data_->UpdateDataUseForHost( + data_used, original_size, util::GetSiteBreakdownOtherHostName()); + } } void DataReductionProxyNetworkDelegate::AccumulateDataUsage(
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc index 2c817e1a..05ad471 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
@@ -36,6 +36,7 @@ #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h" +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers_test_utils.h" @@ -45,6 +46,7 @@ #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h" #include "components/data_reduction_proxy/core/common/lofi_decider.h" #include "components/data_reduction_proxy/proto/client_config.pb.h" +#include "components/data_reduction_proxy/proto/data_store.pb.h" #include "components/previews/core/previews_experiments.h" #include "components/previews/core/previews_features.h" #include "components/previews/core/test_previews_decider.h" @@ -287,6 +289,28 @@ bool on_lofi_response_; }; +class TestResourceTypeProvider : public ResourceTypeProvider { + public: + void SetContentType(const net::URLRequest& request) override {} + + ContentType GetContentType(const GURL& url) const override { + return ResourceTypeProvider::CONTENT_TYPE_UNKNOWN; + } + + bool IsNonContentInitiatedRequest( + const net::URLRequest& request) const override { + return is_non_content_initiated_request_; + } + + void set_is_non_content_initiated_request( + bool is_non_content_initiated_request) { + is_non_content_initiated_request_ = is_non_content_initiated_request; + } + + private: + bool is_non_content_initiated_request_ = false; +}; + enum ProxyTestConfig { USE_SECURE_PROXY, USE_INSECURE_PROXY, BYPASS_PROXY }; class DataReductionProxyNetworkDelegateTest : public testing::Test { @@ -782,6 +806,23 @@ request, data_reduction_proxy_info, proxy_retry_info, headers); } + void EnableDataUsageReporting() { + test_context_->pref_service()->SetBoolean(prefs::kDataUsageReportingEnabled, + true); + // Give the setting notification a chance to propagate. + base::RunLoop().RunUntilIdle(); + } + + size_t GetOtherHostDataUsage() { + const auto& data_usage_map = test_context_->data_reduction_proxy_service() + ->compression_stats() + ->DataUsageMapForTesting(); + const auto& it = data_usage_map.find(util::GetSiteBreakdownOtherHostName()); + if (it != data_usage_map.end()) + return it->second->data_used(); + return 0; + } + net::MockClientSocketFactory* mock_socket_factory() { return mock_socket_factory_.get(); } @@ -2244,6 +2285,32 @@ 9 /* UNKNOWN_TRANSFORM_RECEIVED */, 1); } +TEST_F(DataReductionProxyNetworkDelegateTest, RecordNonContentToOtherHost) { + const std::string response_headers = + "HTTP/1.1 200 OK\r\n" + "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n" + "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n" + "\r\n"; + + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature( + data_reduction_proxy::features:: + kDataSaverSiteBreakdownUsingPageLoadMetrics); + Init(USE_INSECURE_PROXY, false); + EnableDataUsageReporting(); + auto test_resource_type_provider = + std::make_unique<TestResourceTypeProvider>(); + test_resource_type_provider->set_is_non_content_initiated_request(true); + io_data()->set_resource_type_provider(std::move(test_resource_type_provider)); + + FetchURLRequest(GURL(kTestURL), nullptr, response_headers, + kResponseContentLength, 0); + base::RunLoop().RunUntilIdle(); + DCHECK_EQ(response_headers.size() + kResponseContentLength, + GetOtherHostDataUsage()); +} + } // namespace } // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc index fc20bdc..ea80668 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc
@@ -297,6 +297,12 @@ headers.push_back(FormatOption(kExperimentsOption, experiment)); header_value_ = base::JoinString(headers, ", "); + + if (update_header_callback_) { + net::HttpRequestHeaders headers; + headers.SetHeader(chrome_proxy_header(), header_value_); + update_header_callback_.Run(std::move(headers)); + } } std::string DataReductionProxyRequestOptions::GetSessionKeyFromRequestHeaders(
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h index e0b3561..5f54832 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h
@@ -11,6 +11,7 @@ #include <string> #include <vector> +#include "base/callback.h" #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/optional.h" @@ -19,6 +20,7 @@ #include "base/time/time.h" #include "build/build_config.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h" +#include "net/http/http_request_headers.h" namespace net { class HttpRequestHeaders; @@ -40,6 +42,9 @@ class DataReductionProxyConfig; +typedef base::RepeatingCallback<void(net::HttpRequestHeaders)> + UpdateHeaderCallback; + class DataReductionProxyRequestOptions { public: static bool IsKeySetOnCommandLine(); @@ -74,6 +79,11 @@ // Sets the credentials for sending to the Data Reduction Proxy. void SetSecureSession(const std::string& secure_session); + // Set the callback to call when the proxy request headers are updated. + void SetUpdateHeaderCallback(UpdateHeaderCallback callback) { + update_header_callback_ = callback; + } + // Retrieves the credentials for sending to the Data Reduction Proxy. const std::string& GetSecureSession() const; @@ -166,6 +176,10 @@ // The page identifier that was last generated for data saver proxy server. uint64_t current_page_id_; + // Callback to expose the chrome_proxy header to the UI thread. Called + // whenever the chrome_proxy header value changes. Can be null. + UpdateHeaderCallback update_header_callback_; + // Enforce usage on the IO thread. base::ThreadChecker thread_checker_;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc index dcf0efb..9b786ddc 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc
@@ -9,11 +9,13 @@ #include <string> #include <vector> +#include "base/callback.h" #include "base/command_line.h" #include "base/md5.h" #include "base/message_loop/message_loop.h" #include "base/metrics/field_trial.h" #include "base/strings/string16.h" +#include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "build/build_config.h" @@ -153,6 +155,17 @@ request_options_->Init(); } + void CreateRequestOptionsWithCallback(const std::string& version) { + CreateRequestOptions(version); + request_options_->SetUpdateHeaderCallback(base::BindRepeating( + &DataReductionProxyRequestOptionsTest::UpdateHeaderCallback, + base::Unretained(this))); + } + + void UpdateHeaderCallback(net::HttpRequestHeaders headers) { + callback_headers_ = headers; + } + TestDataReductionProxyParams* params() { return test_context_->config()->test_params(); } @@ -161,6 +174,8 @@ return request_options_.get(); } + net::HttpRequestHeaders callback_headers() { return callback_headers_; } + void VerifyExpectedHeader(const std::string& expected_header, uint64_t page_id) { test_context_->RunUntilIdle(); @@ -179,6 +194,7 @@ base::MessageLoopForIO message_loop_; std::unique_ptr<TestDataReductionProxyRequestOptions> request_options_; std::unique_ptr<DataReductionProxyTestContext> test_context_; + net::HttpRequestHeaders callback_headers_; }; TEST_F(DataReductionProxyRequestOptionsTest, AuthHashForSalt) { @@ -245,6 +261,25 @@ VerifyExpectedHeader(expected_header, kPageIdValue); } +TEST_F(DataReductionProxyRequestOptionsTest, CallsHeaderCallback) { + std::string expected_header; + SetHeaderExpectations(std::string(), std::string(), kSecureSession, + kClientStr, kExpectedBuild, kExpectedPatch, kPageId, + std::vector<std::string>(), &expected_header); + + CreateRequestOptionsWithCallback(kVersion); + request_options()->SetSecureSession(kSecureSession); + VerifyExpectedHeader(expected_header, kPageIdValue); + + std::string callback_header; + callback_headers().GetHeader(kChromeProxyHeader, &callback_header); + // |callback_header| does not include a page id. Since the page id is always + // the last element in the header, check that |callback_header| is the prefix + // of |expected_header|. + EXPECT_TRUE(base::StartsWith(expected_header, callback_header, + base::CompareCase::SENSITIVE)); +} + TEST_F(DataReductionProxyRequestOptionsTest, ParseExperiments) { base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( data_reduction_proxy::switches::kDataReductionProxyExperiment,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h index d7e6810..ae70408 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h
@@ -21,6 +21,7 @@ #include "components/data_reduction_proxy/core/browser/db_data_owner.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_storage_delegate.h" #include "components/data_use_measurement/core/data_use_user_data.h" +#include "net/http/http_request_headers.h" class PrefService; @@ -137,6 +138,17 @@ // cleared. void OnCacheCleared(const base::Time start, const base::Time end); + // Sets |proxy_request_headers_| with a forwarded value from the IO thread. + void SetProxyRequestHeaders(net::HttpRequestHeaders headers) { + proxy_request_headers_ = headers; + } + + // Returns |proxy_request_headers_|. Note: The chrome-proxy header does not + // include the page id. + const net::HttpRequestHeaders GetProxyRequestHeaders() const { + return proxy_request_headers_; + } + // Accessor methods. DataReductionProxyCompressionStats* compression_stats() const { return compression_stats_.get(); @@ -191,6 +203,10 @@ base::ObserverList<DataReductionProxyServiceObserver> observer_list_; + // Authentication headers for the Data Reduction Proxy, if any. This is + // forwarded from the IO thread in PostTask. + net::HttpRequestHeaders proxy_request_headers_; + bool initialized_; SEQUENCE_CHECKER(sequence_checker_);
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.cc index b67be94..2deca8c 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.cc
@@ -35,6 +35,10 @@ const char kApiKeyName[] = "key"; #endif +// Hostname used for the other bucket which consists of chrome-services traffic. +// This should be in sync with the same in DataReductionSiteBreakdownView.java +const char kOtherHostName[] = "Other"; + // Scales |byte_count| by the ratio of |numerator|:|denomenator|. int64_t ScaleByteCountByRatio(int64_t byte_count, int64_t numerator, @@ -284,6 +288,10 @@ } } +const char* GetSiteBreakdownOtherHostName() { + return kOtherHostName; +} + } // namespace util namespace protobuf_parser {
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h index 5b3d97b..e8b534e8c 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h
@@ -122,6 +122,10 @@ // Converts net::ProxyServer::Scheme to type ProxyScheme. ProxyScheme ConvertNetProxySchemeToProxyScheme(net::ProxyServer::Scheme scheme); +// Returns the hostname used for the other bucket to record datause not scoped +// to a page load such as chrome-services traffic, service worker, Downloads. +const char* GetSiteBreakdownOtherHostName(); + } // namespace util namespace protobuf_parser {
diff --git a/components/data_reduction_proxy/core/common/resource_type_provider.h b/components/data_reduction_proxy/core/common/resource_type_provider.h index 60ec2faa..a507b7c 100644 --- a/components/data_reduction_proxy/core/common/resource_type_provider.h +++ b/components/data_reduction_proxy/core/common/resource_type_provider.h
@@ -32,6 +32,12 @@ virtual ContentType GetContentType(const GURL& url) const = 0; + // Returns if the request is initiated via non-content that cannot be scoped + // to a page load. These ResourceInfo-less requests can be issued by chrome + // services, service-worker, Downloads, etc. + virtual bool IsNonContentInitiatedRequest( + const net::URLRequest& request) const = 0; + protected: ResourceTypeProvider() {}
diff --git a/components/offline_pages/core/model/offline_page_model_taskified.cc b/components/offline_pages/core/model/offline_page_model_taskified.cc index 6f64980..6b3ffe5e 100644 --- a/components/offline_pages/core/model/offline_page_model_taskified.cc +++ b/components/offline_pages/core/model/offline_page_model_taskified.cc
@@ -561,6 +561,11 @@ const OfflinePageItem& offline_page, PublishArchiveResult publish_results) { if (publish_results.move_result != SavePageResult::SUCCESS) { + // Add UMA for the failure reason. + UMA_HISTOGRAM_ENUMERATION("OfflinePages.PublishPageResult", + publish_results.move_result, + SavePageResult::RESULT_COUNT); + std::move(save_page_callback).Run(publish_results.move_result, 0LL); return; }
diff --git a/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc b/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc index 37a26e20..239a09c 100644 --- a/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc +++ b/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
@@ -119,6 +119,13 @@ const std::string& request_origin, std::unique_ptr<OfflinePageArchiver> archiver, SavePageResult expected_result); + // Start a save page simulating a file move failure. + int64_t SavePageWithFileMoveFailure( + const GURL& url, + const ClientId& client_id, + const GURL& original_url, + const std::string& request_origin, + std::unique_ptr<OfflinePageArchiver> archiver); // Insert an offline page in to store, it does not rely on the model // implementation. void InsertPageIntoStore(const OfflinePageItem& offline_page); @@ -312,6 +319,20 @@ return offline_id; } +int64_t OfflinePageModelTaskifiedTest::SavePageWithFileMoveFailure( + const GURL& url, + const ClientId& client_id, + const GURL& original_url, + const std::string& request_origin, + std::unique_ptr<OfflinePageArchiver> archiver) { + int64_t offline_id = OfflinePageModel::kInvalidOfflineId; + base::MockCallback<SavePageCallback> callback; + + SavePageWithCallback(url, client_id, original_url, request_origin, + std::move(archiver), callback.Get()); + return offline_id; +} + void OfflinePageModelTaskifiedTest::InsertPageIntoStore( const OfflinePageItem& offline_page) { store_test_util()->InsertItem(offline_page); @@ -1261,6 +1282,27 @@ // This test is affected by https://crbug.com/725685, which only affects windows // platform. #if defined(OS_WIN) +#define MAYBE_PublishPageFailure DISABLED_PublishPageFailure +#else +#define MAYBE_PublishPageFailure PublishPageFailure +#endif +TEST_F(OfflinePageModelTaskifiedTest, MAYBE_PublishPageFailure) { + // Save a persistent page that will report failure to be copied to a public + // dir. + auto archiver = BuildArchiver(kTestUrl, ArchiverResult::SUCCESSFULLY_CREATED); + archiver->set_archive_attempt_failure(true); + SavePageWithFileMoveFailure(kTestUrl, kTestUserRequestedClientId, GURL(), + kEmptyRequestOrigin, std::move(archiver)); + + // Ensure that a histogram is emitted for the failure + histogram_tester()->ExpectUniqueSample( + "OfflinePages.PublishPageResult", + static_cast<int>(SavePageResult::FILE_MOVE_FAILED), 1); +} + +// This test is affected by https://crbug.com/725685, which only affects windows +// platform. +#if defined(OS_WIN) #define MAYBE_CheckPublishInternalArchive DISABLED_CheckPublishInternalArchive #else #define MAYBE_CheckPublishInternalArchive CheckPublishInternalArchive
diff --git a/components/offline_pages/core/offline_page_test_archiver.cc b/components/offline_pages/core/offline_page_test_archiver.cc index 84f060e..b87e12f5 100644 --- a/components/offline_pages/core/offline_page_test_archiver.cc +++ b/components/offline_pages/core/offline_page_test_archiver.cc
@@ -26,13 +26,15 @@ size_to_report_(size_to_report), create_archive_called_(false), publish_archive_called_(false), + archive_attempt_failure_(false), delayed_(false), result_title_(result_title), digest_to_report_(digest_to_report), task_runner_(task_runner) {} OfflinePageTestArchiver::~OfflinePageTestArchiver() { - EXPECT_TRUE(create_archive_called_ || publish_archive_called_); + EXPECT_TRUE(create_archive_called_ || publish_archive_called_ || + archive_attempt_failure_); } void OfflinePageTestArchiver::CreateArchive( @@ -60,6 +62,10 @@ publish_archive_result.new_file_path = offline_page.file_path; publish_archive_result.download_id = 0; + if (archive_attempt_failure_) { + publish_archive_result.move_result = SavePageResult::FILE_MOVE_FAILED; + } + // Note: once the |publish_done_callback| is invoked it is very likely that // this instance will be destroyed. So all parameters sent to it must not be // bound to the lifetime on this.
diff --git a/components/offline_pages/core/offline_page_test_archiver.h b/components/offline_pages/core/offline_page_test_archiver.h index 19ab5b0d..6cae827 100644 --- a/components/offline_pages/core/offline_page_test_archiver.h +++ b/components/offline_pages/core/offline_page_test_archiver.h
@@ -76,6 +76,10 @@ bool create_archive_called() const { return create_archive_called_; } + void set_archive_attempt_failure(bool fail) { + archive_attempt_failure_ = fail; + } + private: // Not owned. Outlives OfflinePageTestArchiver. Observer* observer_; @@ -87,6 +91,7 @@ int64_t size_to_report_; bool create_archive_called_; bool publish_archive_called_; + bool archive_attempt_failure_; bool delayed_; base::string16 result_title_; std::string digest_to_report_;
diff --git a/components/omnibox/browser/autocomplete_match.cc b/components/omnibox/browser/autocomplete_match.cc index 089776fe..fb36902 100644 --- a/components/omnibox/browser/autocomplete_match.cc +++ b/components/omnibox/browser/autocomplete_match.cc
@@ -775,6 +775,10 @@ return res; } +bool AutocompleteMatch::IsExceptedFromLineReversal() const { + return !!answer && answer->type() == SuggestionAnswer::ANSWER_TYPE_DICTIONARY; +} + #if DCHECK_IS_ON() void AutocompleteMatch::Validate() const { ValidateClassifications(contents, contents_class);
diff --git a/components/omnibox/browser/autocomplete_match.h b/components/omnibox/browser/autocomplete_match.h index dff64d40..d16054bf 100644 --- a/components/omnibox/browser/autocomplete_match.h +++ b/components/omnibox/browser/autocomplete_match.h
@@ -350,6 +350,10 @@ // See base/trace_event/memory_usage_estimator.h for more info. size_t EstimateMemoryUsage() const; + // Some types of matches (answers for dictionary definitions, e.g.) do not + // follow the common rules for reversing lines. + bool IsExceptedFromLineReversal() const; + // The provider of this match, used to remember which provider the user had // selected when the input changes. This may be NULL, in which case there is // no provider (or memory of the user's selection).
diff --git a/components/payments/content/BUILD.gn b/components/payments/content/BUILD.gn index fa744191..74faebc 100644 --- a/components/payments/content/BUILD.gn +++ b/components/payments/content/BUILD.gn
@@ -36,6 +36,7 @@ "//components/payments/mojom", "//components/prefs", "//components/strings:components_strings_grit", + "//components/ukm/content", "//components/url_formatter", "//content/public/browser", "//third_party/blink/public:blink_headers", @@ -119,6 +120,7 @@ "//components/strings:components_strings_grit", "//components/webdata/common", "//content/test:test_support", + "//services/metrics/public/cpp:metrics_cpp", "//sql", "//testing/gtest", "//third_party/blink/public:blink_headers",
diff --git a/components/payments/content/DEPS b/components/payments/content/DEPS index a1853f1b..b57f1c0 100644 --- a/components/payments/content/DEPS +++ b/components/payments/content/DEPS
@@ -5,12 +5,14 @@ "+components/keyed_service/core", "+components/prefs", "+components/strings", + "+components/ukm/content", "+components/url_formatter", "+components/webdata/common", "+content/public", "+mojo/public/cpp", "+net", "+services/data_decoder/public/cpp", + "+services/metrics/public/cpp", "+sql", "+third_party/blink/public/common", "+third_party/blink/public/platform/modules/payments",
diff --git a/components/payments/content/payment_request.cc b/components/payments/content/payment_request.cc index a791237..32464225 100644 --- a/components/payments/content/payment_request.cc +++ b/components/payments/content/payment_request.cc
@@ -21,6 +21,7 @@ #include "components/payments/core/payment_instrument.h" #include "components/payments/core/payment_prefs.h" #include "components/prefs/pref_service.h" +#include "components/ukm/content/source_url_recorder.h" #include "components/url_formatter/elide_url.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h" @@ -49,8 +50,7 @@ render_frame_host->GetLastCommittedURL())), observer_for_testing_(observer_for_testing), journey_logger_(delegate_->IsIncognito(), - web_contents_->GetLastCommittedURL(), - delegate_->GetUkmRecorder()), + ukm::GetSourceIdForWebContentsDocument(web_contents)), weak_ptr_factory_(this) { // OnConnectionTerminated will be called when the Mojo pipe is closed. This // will happen as a result of many renderer-side events (both successful and
diff --git a/components/payments/content/payment_request_state_unittest.cc b/components/payments/content/payment_request_state_unittest.cc index 3b4c618..d0a298a 100644 --- a/components/payments/content/payment_request_state_unittest.cc +++ b/components/payments/content/payment_request_state_unittest.cc
@@ -16,6 +16,7 @@ #include "components/payments/content/payment_request_spec.h" #include "components/payments/content/test_content_payment_request_delegate.h" #include "components/payments/core/journey_logger.h" +#include "services/metrics/public/cpp/ukm_recorder.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/platform/modules/payments/payment_request.mojom.h" @@ -29,8 +30,7 @@ : num_on_selected_information_changed_called_(0), test_payment_request_delegate_(&test_personal_data_manager_), journey_logger_(test_payment_request_delegate_.IsIncognito(), - GURL("http://www.test.com"), - test_payment_request_delegate_.GetUkmRecorder()), + ukm::UkmRecorder::GetNewSourceID()), address_(autofill::test::GetFullProfile()), credit_card_visa_(autofill::test::GetCreditCard()) { test_personal_data_manager_.SetAutofillCreditCardEnabled(true);
diff --git a/components/payments/core/journey_logger.cc b/components/payments/core/journey_logger.cc index b306f49..307337f6 100644 --- a/components/payments/core/journey_logger.cc +++ b/components/payments/core/journey_logger.cc
@@ -55,13 +55,10 @@ } // namespace -JourneyLogger::JourneyLogger(bool is_incognito, - const GURL& url, - ukm::UkmRecorder* ukm_recorder) +JourneyLogger::JourneyLogger(bool is_incognito, ukm::SourceId source_id) : is_incognito_(is_incognito), events_(EVENT_INITIATED), - url_(url), - ukm_recorder_(ukm_recorder) {} + source_id_(source_id) {} JourneyLogger::~JourneyLogger() { if (WasPaymentRequestTriggered()) @@ -241,16 +238,14 @@ // Record the events in UMA. base::UmaHistogramSparse("PaymentRequest.Events", events_); - if (!ukm_recorder_ || !url_.is_valid()) + if (source_id_ == ukm::kInvalidSourceId) return; // Record the events in UKM. - ukm::SourceId source_id = ukm_recorder_->GetNewSourceID(); - ukm_recorder_->UpdateSourceURL(source_id, url_); - ukm::builders::PaymentRequest_CheckoutEvents(source_id) + ukm::builders::PaymentRequest_CheckoutEvents(source_id_) .SetCompletionStatus(completion_status) .SetEvents(events_) - .Record(ukm_recorder_); + .Record(ukm::UkmRecorder::Get()); } bool JourneyLogger::WasPaymentRequestTriggered() {
diff --git a/components/payments/core/journey_logger.h b/components/payments/core/journey_logger.h index 85709fc..7db5ce3 100644 --- a/components/payments/core/journey_logger.h +++ b/components/payments/core/journey_logger.h
@@ -8,11 +8,7 @@ #include <string> #include "base/macros.h" -#include "url/gurl.h" - -namespace ukm { -class UkmRecorder; -} +#include "services/metrics/public/cpp/ukm_source_id.h" namespace payments { @@ -127,9 +123,7 @@ NOT_SHOWN_REASON_MAX = 4, }; - JourneyLogger(bool is_incognito, - const GURL& url, - ukm::UkmRecorder* ukm_recorder); + JourneyLogger(bool is_incognito, ukm::SourceId source_id); ~JourneyLogger(); // Increments the number of selection adds for the specified section. @@ -232,10 +226,7 @@ // Accumulates the many events that have happened during the Payment Request. int events_; - const GURL url_; - - // Not owned, will outlive this object. - ukm::UkmRecorder* ukm_recorder_; + ukm::SourceId source_id_; DISALLOW_COPY_AND_ASSIGN(JourneyLogger); };
diff --git a/components/payments/core/journey_logger_unittest.cc b/components/payments/core/journey_logger_unittest.cc index ba883f6f..8a30a1a 100644 --- a/components/payments/core/journey_logger_unittest.cc +++ b/components/payments/core/journey_logger_unittest.cc
@@ -23,8 +23,7 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_CanMakePaymentNotCalled_NoShow) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/false, ukm::kInvalidSourceId); logger.SetCompleted(); @@ -42,8 +41,7 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_CanMakePaymentNotCalled_ShowAndUserAbort) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/false, ukm::kInvalidSourceId); // The merchant does not query CanMakePayment, show the PaymentRequest and the // user aborts it. @@ -66,8 +64,7 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_CanMakePaymentNotCalled_ShowAndOtherAbort) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/false, ukm::kInvalidSourceId); // The merchant does not query CanMakePayment, show the PaymentRequest and // there is an abort not initiated by the user. @@ -90,8 +87,7 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_CanMakePaymentNotCalled_ShowAndComplete) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/false, ukm::kInvalidSourceId); // The merchant does not query CanMakePayment, show the PaymentRequest and the // user completes it. @@ -114,8 +110,7 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_CanMakePaymentCalled_FalseAndNoShow) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/false, ukm::kInvalidSourceId); // The user cannot make payment and the PaymentRequest is not shown. logger.SetCanMakePaymentValue(false); @@ -136,8 +131,7 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_CanMakePaymentCalled_TrueAndNoShow) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/false, ukm::kInvalidSourceId); // The user can make payment and the PaymentRequest is not shown. logger.SetCanMakePaymentValue(true); @@ -158,8 +152,7 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_CanMakePaymentCalled_FalseShowAndUserAbort) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/false, ukm::kInvalidSourceId); // The user cannot make payment, the Payment Request is shown but is aborted // by the user. @@ -183,8 +176,7 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_CanMakePaymentCalled_FalseShowAndOtherAbort) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/false, ukm::kInvalidSourceId); // The user cannot make payment, the Payment Request is shown but is aborted. logger.SetEventOccurred(JourneyLogger::EVENT_SHOWN); @@ -207,8 +199,7 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_CanMakePaymentCalled_FalseShowAndComplete) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/false, ukm::kInvalidSourceId); // The user cannot make payment, the payment request is shown and is // completed. @@ -232,8 +223,7 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_CanMakePaymentCalled_TrueShowAndUserAbort) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/false, ukm::kInvalidSourceId); // The user can make payment, the Payment Request is shown and aborted by the // user. @@ -257,8 +247,7 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_CanMakePaymentCalled_TrueShowAndOtherAbort) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/false, ukm::kInvalidSourceId); // The user can make a payment, the request is shown but the transaction is // aborted. @@ -282,8 +271,7 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_CanMakePaymentCalled_TrueShowAndComplete) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/false, ukm::kInvalidSourceId); // The user can make a payment, the request is shown and the user completes // the checkout. @@ -307,8 +295,7 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_CanMakePayment_IncognitoTab) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/true, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/true, ukm::kInvalidSourceId); // The user can make a payment, the request is shown and the user completes // the checkout. @@ -332,8 +319,7 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_SuggestionsForEverything_Completed) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/false, ukm::kInvalidSourceId); // The merchant only requests payment information. logger.SetRequestedInformation( @@ -378,8 +364,7 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_SuggestionsForEverything_UserAborted) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/false, ukm::kInvalidSourceId); // The merchant only requests payment information. logger.SetRequestedInformation( @@ -424,8 +409,7 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_SuggestionsForEverything_OtherAborted) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/false, ukm::kInvalidSourceId); // The merchant only requests payment information. logger.SetRequestedInformation( @@ -471,8 +455,7 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_SuggestionsForEverything_Incognito) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/true, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/true, ukm::kInvalidSourceId); // The merchant only requests payment information. logger.SetRequestedInformation( @@ -517,8 +500,7 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_NoSuggestionsForEverything_Completed) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/false, ukm::kInvalidSourceId); // The merchant only requests payment information. logger.SetRequestedInformation( @@ -563,8 +545,7 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_NoSuggestionsForEverything_UserAborted) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/false, ukm::kInvalidSourceId); // The merchant only requests payment information. logger.SetRequestedInformation( @@ -609,8 +590,7 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_NoSuggestionsForEverything_OtherAborted) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/false, ukm::kInvalidSourceId); // The merchant only requests payment information. logger.SetRequestedInformation( @@ -656,8 +636,7 @@ TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_NoSuggestionsForEverything_Incognito) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/true, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/true, ukm::kInvalidSourceId); // The merchant only requests payment information. logger.SetRequestedInformation( @@ -703,8 +682,7 @@ JourneyLoggerTest, RecordJourneyStatsHistograms_NoCompleteSuggestionsForEverything_OtherAborted) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/false, ukm::kInvalidSourceId); // The merchant only requests payment information. logger.SetRequestedInformation( @@ -751,8 +729,7 @@ JourneyLoggerTest, RecordJourneyStatsHistograms_NoCompleteSuggestionsForEverything_SomeComplete_OtherAborted) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/false, ukm::kInvalidSourceId); // The merchant only requests payment information. logger.SetRequestedInformation( @@ -801,8 +778,7 @@ JourneyLoggerTest, RecordJourneyStatsHistograms_CompleteSuggestionsForEverything_OtherAborted) { base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger(/*is_incognito=*/false, ukm::kInvalidSourceId); // The merchant only requests payment information. logger.SetRequestedInformation( @@ -849,10 +825,8 @@ // Requests. TEST(JourneyLoggerTest, RecordJourneyStatsHistograms_TwoPaymentRequests) { base::HistogramTester histogram_tester; - JourneyLogger logger1(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); - JourneyLogger logger2(/*is_incognito=*/false, /*url=*/GURL(""), - /*ukm_recorder=*/nullptr); + JourneyLogger logger1(/*is_incognito=*/false, ukm::kInvalidSourceId); + JourneyLogger logger2(/*is_incognito=*/false, ukm::kInvalidSourceId); // Make the two loggers have different data. logger1.SetEventOccurred(JourneyLogger::EVENT_SHOWN); @@ -933,8 +907,9 @@ char test_url[] = "http://www.google.com/"; base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/true, /*url=*/GURL(test_url), - /*ukm_recorder=*/&ukm_recorder); + ukm::SourceId source_id = ukm::UkmRecorder::GetNewSourceID(); + ukm_recorder.UpdateSourceURL(source_id, GURL(test_url)); + JourneyLogger logger(/*is_incognito=*/true, source_id); logger.SetRequestedInformation( /*requested_shipping=*/true, /*requested_email=*/true, /*requested_phone=*/false, /*requested_name=*/false); @@ -983,8 +958,9 @@ char test_url[] = "http://www.google.com/"; base::HistogramTester histogram_tester; - JourneyLogger logger(/*is_incognito=*/true, /*url=*/GURL(test_url), - /*ukm_recorder=*/&ukm_recorder); + ukm::SourceId source_id = ukm::UkmRecorder::GetNewSourceID(); + ukm_recorder.UpdateSourceURL(source_id, GURL(test_url)); + JourneyLogger logger(/*is_incognito=*/true, source_id); logger.SetRequestedInformation( /*requested_shipping=*/true, /*requested_email=*/true, /*requested_phone=*/false, /*requested_name=*/false);
diff --git a/components/safe_browsing/proto/csd.proto b/components/safe_browsing/proto/csd.proto index 41a07f0b..1079f03 100644 --- a/components/safe_browsing/proto/csd.proto +++ b/components/safe_browsing/proto/csd.proto
@@ -705,7 +705,12 @@ // How this navigation is initiated. optional NavigationInitiation navigation_initiation = 10; - // next available tag number: 11. + // Whether we think this entry may have been launched by an external + // application. This will have no false negatives, but some false positives + // are possible. + optional bool maybe_launched_by_external_application = 11; + + // next available tag number: 12. } // End of ReferrerChainEntry message ClientDownloadResponse {
diff --git a/components/safe_browsing/web_ui/safe_browsing_ui.cc b/components/safe_browsing/web_ui/safe_browsing_ui.cc index b15e183..c8cbbbae 100644 --- a/components/safe_browsing/web_ui/safe_browsing_ui.cc +++ b/components/safe_browsing/web_ui/safe_browsing_ui.cc
@@ -567,6 +567,10 @@ referrer_dict.SetKey("navigation_initiation", base::Value(navigation_initiation)); + referrer_dict.SetKey( + "maybe_launched_by_external_application", + base::Value(referrer.maybe_launched_by_external_application())); + return std::move(referrer_dict); }
diff --git a/components/search_engines/BUILD.gn b/components/search_engines/BUILD.gn index 90e00b4..b5c89d4f 100644 --- a/components/search_engines/BUILD.gn +++ b/components/search_engines/BUILD.gn
@@ -77,6 +77,7 @@ "//components/url_formatter", "//google_apis", "//net", + "//services/network/public/cpp", "//sql", "//third_party/libxml", "//ui/base", @@ -140,6 +141,8 @@ "//components/sync_preferences:test_support", "//components/webdata/common", "//net:net", + "//services/network:test_support", + "//services/network/public/cpp", "//sql", "//testing/gmock", "//testing/gtest",
diff --git a/components/search_engines/DEPS b/components/search_engines/DEPS index a5e5859c..5f550b12 100644 --- a/components/search_engines/DEPS +++ b/components/search_engines/DEPS
@@ -17,6 +17,8 @@ "+google_apis", "+libxml", "+net", + "+services/network/public/cpp", + "+services/network/test", "+sql", "+ui/base", "+ui/gfx",
diff --git a/components/search_engines/template_url_fetcher.cc b/components/search_engines/template_url_fetcher.cc index 47a8a79..a930d09b 100644 --- a/components/search_engines/template_url_fetcher.cc +++ b/components/search_engines/template_url_fetcher.cc
@@ -13,10 +13,8 @@ #include "components/search_engines/template_url_service.h" #include "net/base/load_flags.h" #include "net/traffic_annotation/network_traffic_annotation.h" -#include "net/url_request/url_fetcher.h" -#include "net/url_request/url_fetcher_delegate.h" -#include "net/url_request/url_request_context_getter.h" -#include "net/url_request/url_request_status.h" +#include "services/network/public/cpp/resource_request.h" +#include "services/network/public/cpp/simple_url_loader.h" namespace { @@ -46,19 +44,20 @@ } // namespace // RequestDelegate ------------------------------------------------------------ -class TemplateURLFetcher::RequestDelegate : public net::URLFetcherDelegate { +class TemplateURLFetcher::RequestDelegate { public: - RequestDelegate( - TemplateURLFetcher* fetcher, - const base::string16& keyword, - const GURL& osdd_url, - const GURL& favicon_url, - const URLFetcherCustomizeCallback& url_fetcher_customize_callback); + RequestDelegate(TemplateURLFetcher* fetcher, + const base::string16& keyword, + const GURL& osdd_url, + const GURL& favicon_url, + const url::Origin& initiator, + network::mojom::URLLoaderFactory* url_loader_factory, + int render_frame_id, + int resource_type); - // net::URLFetcherDelegate: // If data contains a valid OSDD, a TemplateURL is created and added to // the TemplateURLService. - void OnURLFetchComplete(const net::URLFetcher* source) override; + void OnSimpleLoaderComplete(std::unique_ptr<std::string> response_body); // URL of the OSDD. GURL url() const { return osdd_url_; } @@ -70,7 +69,7 @@ void OnLoaded(); void AddSearchProvider(); - std::unique_ptr<net::URLFetcher> url_fetcher_; + std::unique_ptr<network::SimpleURLLoader> simple_url_loader_; TemplateURLFetcher* fetcher_; std::unique_ptr<TemplateURL> template_url_; base::string16 keyword_; @@ -87,12 +86,11 @@ const base::string16& keyword, const GURL& osdd_url, const GURL& favicon_url, - const URLFetcherCustomizeCallback& url_fetcher_customize_callback) - : url_fetcher_(net::URLFetcher::Create(osdd_url, - net::URLFetcher::GET, - this, - kTrafficAnnotation)), - fetcher_(fetcher), + const url::Origin& initiator, + network::mojom::URLLoaderFactory* url_loader_factory, + int render_frame_id, + int resource_type) + : fetcher_(fetcher), keyword_(keyword), osdd_url_(osdd_url), favicon_url_(favicon_url) { @@ -107,14 +105,22 @@ model->Load(); } - if (!url_fetcher_customize_callback.is_null()) - url_fetcher_customize_callback.Run(url_fetcher_.get()); - - url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | - net::LOAD_DO_NOT_SAVE_COOKIES | - net::LOAD_DO_NOT_SEND_AUTH_DATA); - url_fetcher_->SetRequestContext(fetcher->request_context_.get()); - url_fetcher_->Start(); + auto resource_request = std::make_unique<network::ResourceRequest>(); + resource_request->url = osdd_url; + resource_request->request_initiator = initiator; + resource_request->render_frame_id = render_frame_id; + resource_request->resource_type = resource_type; + resource_request->load_flags = net::LOAD_DO_NOT_SEND_COOKIES | + net::LOAD_DO_NOT_SAVE_COOKIES | + net::LOAD_DO_NOT_SEND_AUTH_DATA; + simple_url_loader_ = network::SimpleURLLoader::Create( + std::move(resource_request), kTrafficAnnotation); + simple_url_loader_->DownloadToString( + url_loader_factory, + base::BindOnce( + &TemplateURLFetcher::RequestDelegate::OnSimpleLoaderComplete, + base::Unretained(this)), + 50000 /* max_body_size */); } void TemplateURLFetcher::RequestDelegate::OnLoaded() { @@ -125,27 +131,19 @@ // WARNING: AddSearchProvider deletes us. } -void TemplateURLFetcher::RequestDelegate::OnURLFetchComplete( - const net::URLFetcher* source) { +void TemplateURLFetcher::RequestDelegate::OnSimpleLoaderComplete( + std::unique_ptr<std::string> response_body) { // Validation checks. // Make sure we can still replace the keyword, i.e. the fetch was successful. - // If the OSDD file was loaded HTTP, we also have to check the response_code. - // For other schemes, e.g. when the OSDD file is bundled with an extension, - // the response_code is not applicable and should be -1. Also, ensure that - // the returned information results in a valid search URL. - std::string data; - if (!source->GetStatus().is_success() || - ((source->GetResponseCode() != -1) && - (source->GetResponseCode() != 200)) || - !source->GetResponseAsString(&data)) { + if (!response_body) { fetcher_->RequestCompleted(this); // WARNING: RequestCompleted deletes us. return; } template_url_ = TemplateURLParser::Parse( - fetcher_->template_url_service_->search_terms_data(), data.data(), - data.length(), nullptr); + fetcher_->template_url_service_->search_terms_data(), + response_body->data(), response_body->length(), nullptr); if (!template_url_ || !template_url_->url_ref().SupportsReplacement( fetcher_->template_url_service_->search_terms_data())) { @@ -198,12 +196,8 @@ // TemplateURLFetcher --------------------------------------------------------- -TemplateURLFetcher::TemplateURLFetcher( - TemplateURLService* template_url_service, - net::URLRequestContextGetter* request_context) - : template_url_service_(template_url_service), - request_context_(request_context) { -} +TemplateURLFetcher::TemplateURLFetcher(TemplateURLService* template_url_service) + : template_url_service_(template_url_service) {} TemplateURLFetcher::~TemplateURLFetcher() { } @@ -212,7 +206,10 @@ const base::string16& keyword, const GURL& osdd_url, const GURL& favicon_url, - const URLFetcherCustomizeCallback& url_fetcher_customize_callback) { + const url::Origin& initiator, + network::mojom::URLLoaderFactory* url_loader_factory, + int render_frame_id, + int resource_type) { DCHECK(osdd_url.is_valid()); DCHECK(!keyword.empty()); @@ -236,7 +233,8 @@ } requests_.push_back(std::make_unique<RequestDelegate>( - this, keyword, osdd_url, favicon_url, url_fetcher_customize_callback)); + this, keyword, osdd_url, favicon_url, initiator, url_loader_factory, + render_frame_id, resource_type)); } void TemplateURLFetcher::RequestCompleted(RequestDelegate* request) {
diff --git a/components/search_engines/template_url_fetcher.h b/components/search_engines/template_url_fetcher.h index 896c755..9944c70 100644 --- a/components/search_engines/template_url_fetcher.h +++ b/components/search_engines/template_url_fetcher.h
@@ -18,9 +18,14 @@ class TemplateURL; class TemplateURLService; -namespace net { -class URLFetcher; -class URLRequestContextGetter; +namespace network { +namespace mojom { +class URLLoaderFactory; +} +} // namespace network + +namespace url { +class Origin; } // TemplateURLFetcher is responsible for downloading OpenSearch description @@ -29,12 +34,8 @@ // class TemplateURLFetcher : public KeyedService { public: - typedef base::Callback<void( - net::URLFetcher* url_fetcher)> URLFetcherCustomizeCallback; - // Creates a TemplateURLFetcher. - TemplateURLFetcher(TemplateURLService* template_url_service, - net::URLRequestContextGetter* request_context); + explicit TemplateURLFetcher(TemplateURLService* template_url_service); ~TemplateURLFetcher() override; // If TemplateURLFetcher is not already downloading the OSDD for osdd_url, @@ -45,14 +46,13 @@ // TemplateURL in the model for |keyword|, or we're already downloading an // OSDD for this keyword, no download is started. // - // If |url_fetcher_customize_callback| is not null, it's run after a - // URLFetcher is created. This callback can be used to set additional - // parameters on the URLFetcher. - void ScheduleDownload( - const base::string16& keyword, - const GURL& osdd_url, - const GURL& favicon_url, - const URLFetcherCustomizeCallback& url_fetcher_customize_callback); + void ScheduleDownload(const base::string16& keyword, + const GURL& osdd_url, + const GURL& favicon_url, + const url::Origin& initiator, + network::mojom::URLLoaderFactory* url_loader_factory, + int render_frame_id, + int resource_type); // The current number of outstanding requests. int requests_count() const { return requests_.size(); } @@ -69,7 +69,6 @@ friend class RequestDelegate; TemplateURLService* template_url_service_; - scoped_refptr<net::URLRequestContextGetter> request_context_; // In progress requests. std::vector<std::unique_ptr<RequestDelegate>> requests_;
diff --git a/components/viz/service/display_embedder/DEPS b/components/viz/service/display_embedder/DEPS index 1d1ca6ac..1246dfd 100644 --- a/components/viz/service/display_embedder/DEPS +++ b/components/viz/service/display_embedder/DEPS
@@ -22,6 +22,7 @@ "+gpu/config", "+gpu/ipc", "+gpu/skia_bindings", + "+gpu/vulkan", "+mojo/public/cpp/bindings", "+mojo/public/cpp/system", "+skia",
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.cc b/components/viz/service/display_embedder/skia_output_surface_impl.cc index 58d6a05..f9633cf 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl.cc +++ b/components/viz/service/display_embedder/skia_output_surface_impl.cc
@@ -315,12 +315,31 @@ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(recorder_); - // Convert internal format from GLES2 to platform GL. - const auto* version_info = impl_on_gpu_->gl_version_info(); - metadata.backend_format = GrBackendFormat::MakeGL( - gl::GetInternalFormat(version_info, - *metadata.backend_format.getGLFormat()), - *metadata.backend_format.getGLTarget()); + if (!gpu_service_->is_using_vulkan()) { + // Convert internal format from GLES2 to platform GL. + const auto* version_info = impl_on_gpu_->gl_version_info(); + metadata.backend_format = GrBackendFormat::MakeGL( + gl::GetInternalFormat(version_info, + *metadata.backend_format.getGLFormat()), + *metadata.backend_format.getGLTarget()); + } else { +#if BUILDFLAG(ENABLE_VULKAN) + VkFormat format = VK_FORMAT_UNDEFINED; + switch (metadata.color_type) { + case kRGBA_8888_SkColorType: + format = VK_FORMAT_R8G8B8A8_UNORM; + break; + case kBGRA_8888_SkColorType: + format = VK_FORMAT_B8G8R8A8_UNORM; + break; + default: + NOTREACHED(); + } + metadata.backend_format = GrBackendFormat::MakeVk(format); +#else + NOTREACHED(); +#endif + } DCHECK(!metadata.mailbox.IsZero()); resource_sync_tokens_.push_back(metadata.sync_token); @@ -343,10 +362,19 @@ // supported by Skia. YUVResourceMetadata yuv_metadata(std::move(metadatas), yuv_color_space); - // Convert internal format from GLES2 to platform GL. - const auto* version_info = impl_on_gpu_->gl_version_info(); - auto backend_format = GrBackendFormat::MakeGL( - gl::GetInternalFormat(version_info, GL_BGRA8_EXT), GL_TEXTURE_2D); + GrBackendFormat backend_format; + if (!gpu_service_->is_using_vulkan()) { + // Convert internal format from GLES2 to platform GL. + const auto* version_info = impl_on_gpu_->gl_version_info(); + backend_format = GrBackendFormat::MakeGL( + gl::GetInternalFormat(version_info, GL_BGRA8_EXT), GL_TEXTURE_2D); + } else { +#if BUILDFLAG(ENABLE_VULKAN) + backend_format = GrBackendFormat::MakeVk(VK_FORMAT_B8G8R8A8_UNORM); +#else + NOTREACHED(); +#endif + } return PromiseTextureHelper<YUVResourceMetadata>::MakePromiseSkImage( this, &recorder_.value(), backend_format, yuv_metadata.size(), @@ -393,11 +421,21 @@ // TODO(penghuang): Figure out how to choose the right size. constexpr size_t kCacheMaxResourceBytes = 90 * 1024 * 1024; - const auto* version_info = impl_on_gpu_->gl_version_info(); - unsigned int texture_storage_format = TextureStorageFormat(format); - auto backend_format = GrBackendFormat::MakeGL( - gl::GetInternalFormat(version_info, texture_storage_format), - GL_TEXTURE_2D); + + GrBackendFormat backend_format; + if (!gpu_service_->is_using_vulkan()) { + const auto* version_info = impl_on_gpu_->gl_version_info(); + unsigned int texture_storage_format = TextureStorageFormat(format); + backend_format = GrBackendFormat::MakeGL( + gl::GetInternalFormat(version_info, texture_storage_format), + GL_TEXTURE_2D); + } else { +#if BUILDFLAG(ENABLE_VULKAN) + backend_format = GrBackendFormat::MakeVk(VK_FORMAT_B8G8R8A8_UNORM); +#else + NOTREACHED(); +#endif + } auto characterization = gr_context_thread_safe->createCharacterization( kCacheMaxResourceBytes, image_info, backend_format, msaa_sample_count, kTopLeft_GrSurfaceOrigin, surface_props, mipmap); @@ -441,14 +479,25 @@ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(recorder_); - // Convert internal format from GLES2 to platform GL. - const auto* version_info = impl_on_gpu_->gl_version_info(); - unsigned int texture_storage_format = TextureStorageFormat(format); - auto backend_format = GrBackendFormat::MakeGL( - gl::GetInternalFormat(version_info, texture_storage_format), - GL_TEXTURE_2D); - SkColorType color_type = - ResourceFormatToClosestSkColorType(true /*gpu_compositing */, format); + SkColorType color_type = kBGRA_8888_SkColorType; + GrBackendFormat backend_format; + + if (!gpu_service_->is_using_vulkan()) { + // Convert internal format from GLES2 to platform GL. + const auto* version_info = impl_on_gpu_->gl_version_info(); + unsigned int texture_storage_format = TextureStorageFormat(format); + backend_format = GrBackendFormat::MakeGL( + gl::GetInternalFormat(version_info, texture_storage_format), + GL_TEXTURE_2D); + color_type = + ResourceFormatToClosestSkColorType(true /*gpu_compositing */, format); + } else { +#if BUILDFLAG(ENABLE_VULKAN) + backend_format = GrBackendFormat::MakeVk(VK_FORMAT_B8G8R8A8_UNORM); +#else + NOTREACHED(); +#endif + } return PromiseTextureHelper<RenderPassId>::MakePromiseSkImage( this, &recorder_.value(), backend_format, size, mipmap ? GrMipMapped::kYes : GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin,
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc index 44840ec..10c3211 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc +++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -17,7 +17,9 @@ #include "gpu/command_buffer/service/texture_base.h" #include "gpu/command_buffer/service/texture_manager.h" #include "gpu/config/gpu_preferences.h" +#include "gpu/ipc/common/gpu_surface_lookup.h" #include "gpu/ipc/service/image_transport_surface.h" +#include "gpu/vulkan/buildflags.h" #include "third_party/skia/include/private/SkDeferredDisplayList.h" #include "ui/gfx/skia_util.h" #include "ui/gl/gl_bindings.h" @@ -26,6 +28,10 @@ #include "ui/gl/gl_version_info.h" #include "ui/gl/init/gl_factory.h" +#if BUILDFLAG(ENABLE_VULKAN) +#include "gpu/vulkan/vulkan_implementation.h" +#endif + namespace viz { namespace { @@ -67,52 +73,20 @@ gpu::CommandBufferNamespace::VIZ_OUTPUT_SURFACE, command_buffer_id_, gpu_service_->skia_output_surface_sequence_id()); - if (surface_handle_) { - surface_ = gpu::ImageTransportSurface::CreateNativeSurface( - weak_ptr_factory_.GetWeakPtr(), surface_handle_, gl::GLSurfaceFormat()); - } else { - // surface_ could be null for pixel tests. - surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size(1, 1)); - } - DCHECK(surface_); - - gl::GLContext* gl_context = nullptr; - if (!gpu_service_->GetGrContextForGLSurface(surface_.get(), &gr_context_, - &gl_context)) { - LOG(FATAL) << "Failed to create GrContext"; - // TODO(penghuang): handle the failure. - } - gl_context_ = gl_context; - DCHECK(gr_context_); - DCHECK(gl_context_); - - if (!gl_context_->MakeCurrent(surface_.get())) { - LOG(FATAL) << "Failed to make current."; - // TODO(penghuang): Handle the failure. - } - - gl_version_info_ = gl_context_->GetVersionInfo(); - - capabilities_.flipped_output_surface = surface_->FlipsVertically(); - - // Get stencil bits from the default frame buffer. - auto* current_gl = gl_context_->GetCurrentGL(); - const auto* version = current_gl->Version; - auto* api = current_gl->Api; - GLint stencil_bits = 0; - if (version->is_desktop_core_profile) { - api->glGetFramebufferAttachmentParameterivEXTFn( - GL_FRAMEBUFFER, GL_STENCIL, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, - &stencil_bits); - } else { - api->glGetIntegervFn(GL_STENCIL_BITS, &stencil_bits); - } - - capabilities_.supports_stencil = stencil_bits > 0; + if (gpu_service_->is_using_vulkan()) + InitializeForVulkan(); + else + InitializeForGL(); } SkiaOutputSurfaceImplOnGpu::~SkiaOutputSurfaceImplOnGpu() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +#if BUILDFLAG(ENABLE_VULKAN) + if (vulkan_surface_) { + vulkan_surface_->Destroy(); + vulkan_surface_ = nullptr; + } +#endif sync_point_client_state_->Destroy(); } @@ -132,36 +106,65 @@ base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(event))); } - if (!gl_context_->MakeCurrent(surface_.get())) { - LOG(FATAL) << "Failed to make current."; - // TODO(penghuang): Handle the failure. + if (!gpu_service_->is_using_vulkan()) { + if (!gl_context_->MakeCurrent(gl_surface_.get())) { + LOG(FATAL) << "Failed to make current."; + // TODO(penghuang): Handle the failure. + } + gl::GLSurface::ColorSpace surface_color_space = + color_space == gfx::ColorSpace::CreateSCRGBLinear() + ? gl::GLSurface::ColorSpace::SCRGB_LINEAR + : gl::GLSurface::ColorSpace::UNSPECIFIED; + if (!gl_surface_->Resize(size, device_scale_factor, surface_color_space, + has_alpha)) { + LOG(FATAL) << "Failed to resize."; + // TODO(penghuang): Handle the failure. + } + DCHECK(gl_context_->IsCurrent(gl_surface_.get())); + DCHECK(gr_context_); + + SkSurfaceProps surface_props = + SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType); + + GrGLFramebufferInfo framebuffer_info; + framebuffer_info.fFBOID = 0; + framebuffer_info.fFormat = + gl_version_info_->is_es ? GL_BGRA8_EXT : GL_RGBA8; + + GrBackendRenderTarget render_target(size.width(), size.height(), 0, 8, + framebuffer_info); + + sk_surface_ = SkSurface::MakeFromBackendRenderTarget( + gr_context_, render_target, kBottomLeft_GrSurfaceOrigin, + kBGRA_8888_SkColorType, nullptr, &surface_props); + DCHECK(sk_surface_); + } else { +#if BUILDFLAG(ENABLE_VULKAN) + if (vulkan_surface_) + vulkan_surface_->Destroy(); + gfx::AcceleratedWidget accelerated_widget = gfx::kNullAcceleratedWidget; +#if defined(OS_ANDROID) + accelerated_widget = + gpu::GpuSurfaceLookup::GetInstance()->AcquireNativeWidget( + surface_handle_); +#else + accelerated_widget = surface_handle_; +#endif + vulkan_surface_ = gpu_service_->vulkan_context_provider() + ->GetVulkanImplementation() + ->CreateViewSurface(accelerated_widget); + if (!vulkan_surface_) + LOG(FATAL) << "Failed to create vulkan surface."; + if (!vulkan_surface_->Initialize( + gpu_service_->vulkan_context_provider()->GetDeviceQueue(), + gpu::VulkanSurface::DEFAULT_SURFACE_FORMAT)) { + LOG(FATAL) << "Failed to initialize vulkan surface."; + } + CreateSkSurfaceForVulkan(size); +#else + NOTREACHED(); +#endif } - gl::GLSurface::ColorSpace surface_color_space = - color_space == gfx::ColorSpace::CreateSCRGBLinear() - ? gl::GLSurface::ColorSpace::SCRGB_LINEAR - : gl::GLSurface::ColorSpace::UNSPECIFIED; - if (!surface_->Resize(size, device_scale_factor, surface_color_space, - has_alpha)) { - LOG(FATAL) << "Failed to resize."; - // TODO(penghuang): Handle the failure. - } - DCHECK(gl_context_->IsCurrent(surface_.get())); - DCHECK(gr_context_); - - SkSurfaceProps surface_props = - SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType); - - GrGLFramebufferInfo framebuffer_info; - framebuffer_info.fFBOID = 0; - framebuffer_info.fFormat = gl_version_info_->is_es ? GL_BGRA8_EXT : GL_RGBA8; - - GrBackendRenderTarget render_target(size.width(), size.height(), 0, 8, - framebuffer_info); - - sk_surface_ = SkSurface::MakeFromBackendRenderTarget( - gr_context_, render_target, kBottomLeft_GrSurfaceOrigin, - kBGRA_8888_SkColorType, nullptr, &surface_props); - DCHECK(sk_surface_); if (characterization) { sk_surface_->characterize(characterization); @@ -177,13 +180,13 @@ DCHECK(ddl); DCHECK(sk_surface_); - if (!gl_context_->MakeCurrent(surface_.get())) { + if (!gpu_service_->is_using_vulkan() && + !gl_context_->MakeCurrent(gl_surface_.get())) { LOG(FATAL) << "Failed to make current."; // TODO(penghuang): Handle the failure. } PreprocessYUVResources(std::move(yuv_resource_metadatas)); - sk_surface_->draw(ddl.get()); gr_context_->flush(); sync_point_client_state_->ReleaseFenceSync(sync_fence_release); @@ -192,14 +195,30 @@ void SkiaOutputSurfaceImplOnGpu::SwapBuffers(OutputSurfaceFrame frame) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(sk_surface_); - if (!gl_context_->MakeCurrent(surface_.get())) { - LOG(FATAL) << "Failed to make current."; - // TODO(penghuang): Handle the failure. + if (!gpu_service_->is_using_vulkan()) { + if (!gl_context_->MakeCurrent(gl_surface_.get())) { + LOG(FATAL) << "Failed to make current."; + // TODO(penghuang): Handle the failure. + } + OnSwapBuffers(); + gl_surface_->SwapBuffers(frame.need_presentation_feedback + ? buffer_presented_callback_ + : base::DoNothing()); + } else { +#if BUILDFLAG(ENABLE_VULKAN) + OnSwapBuffers(); + gpu::SwapBuffersCompleteParams params; + params.swap_response.swap_start = base::TimeTicks::Now(); + params.swap_response.result = vulkan_surface_->SwapBuffers(); + params.swap_response.swap_end = base::TimeTicks::Now(); + DidSwapBuffersComplete(params); + + CreateSkSurfaceForVulkan( + gfx::Size(sk_surface_->width(), sk_surface_->height())); +#else + NOTREACHED(); +#endif } - OnSwapBuffers(); - surface_->SwapBuffers(frame.need_presentation_feedback - ? buffer_presented_callback_ - : base::DoNothing()); } void SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass( @@ -210,9 +229,10 @@ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(ddl); - if (!gl_context_->MakeCurrent(surface_.get())) { + if (!gpu_service_->is_using_vulkan() && + !gl_context_->MakeCurrent(gl_surface_.get())) { LOG(FATAL) << "Failed to make current."; - // TODO(penghuang): Handle resize failure. + // TODO(penghuang): Handle the failure. } PreprocessYUVResources(std::move(yuv_resource_metadatas)); @@ -272,6 +292,11 @@ const ResourceMetadata& metadata, GrBackendTexture* backend_texture) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (gpu_service_->is_using_vulkan()) { + // TODO(https://crbug.com/838899): Use SkSurface as raster decoder target. + // NOTIMPLEMENTED(); + return; + } auto* mailbox_manager = gpu_service_->mailbox_manager(); auto* texture_base = mailbox_manager->ConsumeTexture(metadata.mailbox); if (!texture_base) { @@ -365,6 +390,56 @@ return 0; } +void SkiaOutputSurfaceImplOnGpu::InitializeForGL() { + if (surface_handle_) { + gl_surface_ = gpu::ImageTransportSurface::CreateNativeSurface( + weak_ptr_factory_.GetWeakPtr(), surface_handle_, gl::GLSurfaceFormat()); + } else { + // surface_ could be null for pixel tests. + gl_surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size(1, 1)); + } + DCHECK(gl_surface_); + + gl::GLContext* gl_context = nullptr; + if (!gpu_service_->GetGrContextForGLSurface(gl_surface_.get(), &gr_context_, + &gl_context)) { + LOG(FATAL) << "Failed to create GrContext"; + // TODO(penghuang): handle the failure. + } + gl_context_ = gl_context; + DCHECK(gr_context_); + DCHECK(gl_context_); + + if (!gl_context_->MakeCurrent(gl_surface_.get())) { + LOG(FATAL) << "Failed to make current."; + // TODO(penghuang): Handle the failure. + } + + gl_version_info_ = gl_context_->GetVersionInfo(); + + capabilities_.flipped_output_surface = gl_surface_->FlipsVertically(); + + // Get stencil bits from the default frame buffer. + auto* current_gl = gl_context_->GetCurrentGL(); + const auto* version = current_gl->Version; + auto* api = current_gl->Api; + GLint stencil_bits = 0; + if (version->is_desktop_core_profile) { + api->glGetFramebufferAttachmentParameterivEXTFn( + GL_FRAMEBUFFER, GL_STENCIL, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, + &stencil_bits); + } else { + api->glGetIntegervFn(GL_STENCIL_BITS, &stencil_bits); + } + + capabilities_.supports_stencil = stencil_bits > 0; +} + +void SkiaOutputSurfaceImplOnGpu::InitializeForVulkan() { + gr_context_ = gpu_service_->GetGrContextForVulkan(); + DCHECK(gr_context_); +} + void SkiaOutputSurfaceImplOnGpu::BindOrCopyTextureIfNecessary( gpu::TextureBase* texture_base) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); @@ -392,6 +467,11 @@ void SkiaOutputSurfaceImplOnGpu::PreprocessYUVResources( std::vector<YUVResourceMetadata*> yuv_resource_metadatas) { + if (gpu_service_->is_using_vulkan()) { + // TODO(https://crbug.com/838899): Use VkImage for video. + // NOTIMPLEMENTED(); + return; + } // Create SkImage for fullfilling YUV promise image, before drawing the ddl. // TODO(penghuang): Remove the extra step when Skia supports drawing YUV // textures directly. @@ -440,4 +520,26 @@ pending_swap_completed_params_.emplace_back(swap_id, pixel_size); } +void SkiaOutputSurfaceImplOnGpu::CreateSkSurfaceForVulkan( + const gfx::Size& size) { +#if BUILDFLAG(ENABLE_VULKAN) + SkSurfaceProps surface_props = + SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType); + auto* swap_chain = vulkan_surface_->GetSwapChain(); + VkImage vk_image = swap_chain->GetCurrentImage(swap_chain->current_image()); + GrVkImageInfo vk_image_info; + vk_image_info.fImage = vk_image; + vk_image_info.fAlloc = {VK_NULL_HANDLE, 0, 0, 0}; + vk_image_info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + vk_image_info.fImageTiling = VK_IMAGE_TILING_OPTIMAL; + vk_image_info.fFormat = VK_FORMAT_B8G8R8A8_UNORM; + vk_image_info.fLevelCount = 1; + GrBackendRenderTarget render_target(size.width(), size.height(), 0, 0, + vk_image_info); + sk_surface_ = SkSurface::MakeFromBackendRenderTarget( + gr_context_, render_target, kTopLeft_GrSurfaceOrigin, + kBGRA_8888_SkColorType, nullptr, &surface_props); +#endif +} + } // namespace viz
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h index 38d0349..a124875 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h +++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
@@ -31,6 +31,10 @@ namespace gpu { class SyncPointClientState; + +#if BUILDFLAG(ENABLE_VULKAN) +class VulkanSurface; +#endif } namespace viz { @@ -140,6 +144,9 @@ void AddFilter(IPC::MessageFilter* message_filter) override; int32_t GetRouteID() const override; + void InitializeForGL(); + void InitializeForVulkan(); + void BindOrCopyTextureIfNecessary(gpu::TextureBase* texture_base); void PreprocessYUVResources( std::vector<YUVResourceMetadata*> yuv_resource_metadatas); @@ -147,6 +154,8 @@ // Generage the next swap ID and push it to our pending swap ID queues. void OnSwapBuffers(); + void CreateSkSurfaceForVulkan(const gfx::Size& size); + const gpu::CommandBufferId command_buffer_id_; GpuServiceImpl* const gpu_service_; const gpu::SurfaceHandle surface_handle_; @@ -154,13 +163,17 @@ BufferPresentedCallback buffer_presented_callback_; scoped_refptr<gpu::SyncPointClientState> sync_point_client_state_; gpu::GpuPreferences gpu_preferences_; - scoped_refptr<gl::GLSurface> surface_; + scoped_refptr<gl::GLSurface> gl_surface_; sk_sp<SkSurface> sk_surface_; GrContext* gr_context_ = nullptr; scoped_refptr<gl::GLContext> gl_context_; const gl::GLVersionInfo* gl_version_info_ = nullptr; OutputSurface::Capabilities capabilities_; +#if BUILDFLAG(ENABLE_VULKAN) + std::unique_ptr<gpu::VulkanSurface> vulkan_surface_; +#endif + // Offscreen surfaces for render passes. It can only be accessed on GPU // thread. base::flat_map<RenderPassId, sk_sp<SkSurface>> offscreen_surfaces_;
diff --git a/components/viz/service/gl/DEPS b/components/viz/service/gl/DEPS index 55cd3a7..1e459f8 100644 --- a/components/viz/service/gl/DEPS +++ b/components/viz/service/gl/DEPS
@@ -8,6 +8,7 @@ "+gpu/ipc", "+gpu/ipc/common", "+gpu/ipc/service", + "+gpu/vulkan", "+ipc", "+media/gpu", "+media/mojo",
diff --git a/components/viz/service/gl/gpu_service_impl.cc b/components/viz/service/gl/gpu_service_impl.cc index 3ed52c92..a9e578db 100644 --- a/components/viz/service/gl/gpu_service_impl.cc +++ b/components/viz/service/gl/gpu_service_impl.cc
@@ -18,6 +18,8 @@ #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "components/crash/core/common/crash_key.h" +#include "components/viz/common/gpu/vulkan_context_provider.h" +#include "components/viz/common/gpu/vulkan_in_process_context_provider.h" #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h" #include "gpu/command_buffer/service/gpu_switches.h" #include "gpu/command_buffer/service/scheduler.h" @@ -33,6 +35,7 @@ #include "gpu/ipc/service/gpu_channel_manager.h" #include "gpu/ipc/service/gpu_memory_buffer_factory.h" #include "gpu/ipc/service/gpu_watchdog_thread.h" +#include "gpu/vulkan/buildflags.h" #include "ipc/ipc_channel_handle.h" #include "ipc/ipc_sync_channel.h" #include "ipc/ipc_sync_message_filter.h" @@ -135,6 +138,7 @@ const base::Optional<gpu::GPUInfo>& gpu_info_for_hardware_gpu, const base::Optional<gpu::GpuFeatureInfo>& gpu_feature_info_for_hardware_gpu, + gpu::VulkanImplementation* vulkan_implementation, base::OnceClosure exit_callback) : main_runner_(base::ThreadTaskRunnerHandle::Get()), io_runner_(std::move(io_runner)), @@ -146,6 +150,9 @@ gpu_feature_info_(gpu_feature_info), gpu_info_for_hardware_gpu_(gpu_info_for_hardware_gpu), gpu_feature_info_for_hardware_gpu_(gpu_feature_info_for_hardware_gpu), +#if BUILDFLAG(ENABLE_VULKAN) + vulkan_implementation_(vulkan_implementation), +#endif exit_callback_(std::move(exit_callback)), bindings_(std::make_unique<mojo::BindingSet<mojom::GpuService>>()), weak_ptr_factory_(this) { @@ -153,6 +160,16 @@ #if defined(OS_CHROMEOS) protected_buffer_manager_ = new arc::ProtectedBufferManager(); #endif // defined(OS_CHROMEOS) + +#if BUILDFLAG(ENABLE_VULKAN) + if (vulkan_implementation_) { + vulkan_context_provider_ = + VulkanInProcessContextProvider::Create(vulkan_implementation_); + if (!vulkan_context_provider_) + DLOG(WARNING) << "Failed to create Vulkan context provider."; + } +#endif + weak_ptr_ = weak_ptr_factory_.GetWeakPtr(); } @@ -293,6 +310,7 @@ GrContext** gr_context, gl::GLContext** gl_context) { DCHECK(main_runner_->BelongsToCurrentThread()); + DCHECK(!is_using_vulkan()); DCHECK(surface); DCHECK(gr_context && !*gr_context); DCHECK(gl_context && !*gl_context); @@ -328,6 +346,17 @@ return !!gr_context; } +GrContext* GpuServiceImpl::GetGrContextForVulkan() { + DCHECK(main_runner_->BelongsToCurrentThread()); + DCHECK(is_using_vulkan()); +#if BUILDFLAG(ENABLE_VULKAN) + return vulkan_context_provider_->GetGrContext(); +#else + NOTREACHED(); + return nullptr; +#endif +} + gpu::ImageFactory* GpuServiceImpl::gpu_image_factory() { return gpu_memory_buffer_factory_ ? gpu_memory_buffer_factory_->AsImageFactory()
diff --git a/components/viz/service/gl/gpu_service_impl.h b/components/viz/service/gl/gpu_service_impl.h index 675534d..31e1b51 100644 --- a/components/viz/service/gl/gpu_service_impl.h +++ b/components/viz/service/gl/gpu_service_impl.h
@@ -25,6 +25,7 @@ #include "gpu/ipc/service/gpu_channel_manager_delegate.h" #include "gpu/ipc/service/gpu_config.h" #include "gpu/ipc/service/x_util.h" +#include "gpu/vulkan/buildflags.h" #include "mojo/public/cpp/bindings/binding_set.h" #include "services/viz/privileged/interfaces/gl/gpu_host.mojom.h" #include "services/viz/privileged/interfaces/gl/gpu_service.mojom.h" @@ -44,6 +45,7 @@ class GpuWatchdogThread; class Scheduler; class SyncPointManager; +class VulkanImplementation; } // namespace gpu namespace media { @@ -52,6 +54,8 @@ namespace viz { +class VulkanContextProvider; + // This runs in the GPU process, and communicates with the gpu host (which is // the window server) over the mojom APIs. This is responsible for setting up // the connection to clients, allocating/free'ing gpu memory etc. @@ -66,6 +70,7 @@ const base::Optional<gpu::GPUInfo>& gpu_info_for_hardware_gpu, const base::Optional<gpu::GpuFeatureInfo>& gpu_feature_info_for_hardware_gpu, + gpu::VulkanImplementation* vulkan_implementation, base::OnceClosure exit_callback); ~GpuServiceImpl() override; @@ -83,6 +88,8 @@ GrContext** gr_context, gl::GLContext** gl_context); + GrContext* GetGrContextForVulkan(); + // Notifies the GpuHost to stop using GPU compositing. This should be called // in response to an error in the GPU process that occurred after // InitializeWithHost() was called, otherwise GpuFeatureInfo should be set @@ -134,6 +141,16 @@ return skia_output_surface_sequence_id_; } +#if BUILDFLAG(ENABLE_VULKAN) + bool is_using_vulkan() const { return !!vulkan_context_provider_; } + VulkanContextProvider* vulkan_context_provider() { + return vulkan_context_provider_.get(); + } +#else + bool is_using_vulkan() const { return false; } + VulkanContextProvider* vulkan_context_provider() { return nullptr; } +#endif + void set_oopd_enabled() { oopd_enabled_ = true; } private: @@ -267,6 +284,11 @@ struct GrContextAndGLContext; base::flat_map<unsigned long, GrContextAndGLContext> contexts_for_gl_; +#if BUILDFLAG(ENABLE_VULKAN) + gpu::VulkanImplementation* vulkan_implementation_; + scoped_refptr<VulkanContextProvider> vulkan_context_provider_; +#endif + // An event that will be signalled when we shutdown. On some platforms it // comes from external sources. std::unique_ptr<base::WaitableEvent> owned_shutdown_event_;
diff --git a/components/viz/service/gl/gpu_service_impl_unittest.cc b/components/viz/service/gl/gpu_service_impl_unittest.cc index 7ac7f83..e988567 100644 --- a/components/viz/service/gl/gpu_service_impl_unittest.cc +++ b/components/viz/service/gl/gpu_service_impl_unittest.cc
@@ -50,9 +50,10 @@ void SetUp() override { ASSERT_TRUE(io_thread_.Start()); gpu_service_ = std::make_unique<GpuServiceImpl>( - gpu::GPUInfo(), /*watchdog_thread=*/nullptr, io_thread_.task_runner(), + gpu::GPUInfo(), nullptr /* watchdog_thread */, io_thread_.task_runner(), gpu::GpuFeatureInfo(), gpu::GpuPreferences(), gpu::GPUInfo(), - gpu::GpuFeatureInfo(), /*exit_callback=*/base::DoNothing()); + gpu::GpuFeatureInfo(), nullptr /* vulkan_implementation */, + base::DoNothing() /* exit_callback */); } void TearDown() override {
diff --git a/components/viz/service/main/viz_main_impl.cc b/components/viz/service/main/viz_main_impl.cc index c08e4619..2475623 100644 --- a/components/viz/service/main/viz_main_impl.cc +++ b/components/viz/service/main/viz_main_impl.cc
@@ -170,7 +170,8 @@ gpu_init_->gpu_info(), gpu_init_->TakeWatchdogThread(), io_task_runner(), gpu_init_->gpu_feature_info(), gpu_init_->gpu_preferences(), gpu_init_->gpu_info_for_hardware_gpu(), - gpu_init_->gpu_feature_info_for_hardware_gpu(), std::move(exit_callback)); + gpu_init_->gpu_feature_info_for_hardware_gpu(), + gpu_init_->vulkan_implementation(), std::move(exit_callback)); if (dependencies_.create_display_compositor) gpu_service_->set_oopd_enabled(); }
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index dbe98ed..dab1edb 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -1890,8 +1890,6 @@ "media/capture/cursor_renderer.h", "media/capture/desktop_capture_device.cc", "media/capture/desktop_capture_device.h", - "media/capture/fake_webcontent_capture_machine.cc", - "media/capture/fake_webcontent_capture_machine.h", "media/capture/frame_sink_video_capture_device.cc", "media/capture/frame_sink_video_capture_device.h", "media/capture/web_contents_video_capture_device.cc", @@ -1901,14 +1899,10 @@ deps += [ "//third_party/webrtc/modules/desktop_capture" ] if (use_aura) { sources += [ - "media/capture/aura_window_capture_machine.cc", - "media/capture/aura_window_capture_machine.h", "media/capture/aura_window_video_capture_device.cc", "media/capture/aura_window_video_capture_device.h", "media/capture/cursor_renderer_aura.cc", "media/capture/cursor_renderer_aura.h", - "media/capture/desktop_capture_device_aura.cc", - "media/capture/desktop_capture_device_aura.h", ] } if (is_chromeos) {
diff --git a/content/browser/DEPS b/content/browser/DEPS index 288e1043..afd8cb0 100644 --- a/content/browser/DEPS +++ b/content/browser/DEPS
@@ -65,9 +65,9 @@ # Limit visibility into Content Service internals. "-services/content", "+services/content/public", + "+services/content/navigable_contents_delegate.h", "+services/content/service.h", "+services/content/service_delegate.h", - "+services/content/view_delegate.h", # No inclusion of WebKit from the browser, other than the ones in # WebKit/public/{mojom,common}, or the ones that are strictly enum/POD,
diff --git a/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc b/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc index 1e4481e0..2f95096b 100644 --- a/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc +++ b/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc
@@ -1492,6 +1492,7 @@ GURL domain("https://google.com"); logging_service->OnHeader(url::Origin::Create(domain), + net::IPAddress(192, 168, 0, 1), "{\"report_to\":\"group\",\"max_age\":86400}"); ASSERT_EQ(1u, logging_service->GetPolicyOriginsForTesting().size()); @@ -1513,15 +1514,19 @@ GURL domain1("https://google.com"); logging_service->OnHeader(url::Origin::Create(domain1), + net::IPAddress(192, 168, 0, 1), "{\"report_to\":\"group\",\"max_age\":86400}"); GURL domain2("https://host2.com"); logging_service->OnHeader(url::Origin::Create(domain2), + net::IPAddress(192, 168, 0, 1), "{\"report_to\":\"group\",\"max_age\":86400}"); GURL domain3("https://host3.com"); logging_service->OnHeader(url::Origin::Create(domain3), + net::IPAddress(192, 168, 0, 1), "{\"report_to\":\"group\",\"max_age\":86400}"); GURL domain4("https://host4.com"); logging_service->OnHeader(url::Origin::Create(domain4), + net::IPAddress(192, 168, 0, 1), "{\"report_to\":\"group\",\"max_age\":86400}"); ASSERT_EQ(4u, logging_service->GetPolicyOriginsForTesting().size());
diff --git a/content/browser/content_service_browsertest.cc b/content/browser/content_service_browsertest.cc index db6558f..633ff83 100644 --- a/content/browser/content_service_browsertest.cc +++ b/content/browser/content_service_browsertest.cc
@@ -12,9 +12,9 @@ #include "content/public/common/content_paths.h" #include "content/public/test/content_browser_test.h" #include "content/shell/browser/shell.h" -#include "services/content/public/cpp/view.h" +#include "services/content/public/cpp/navigable_contents.h" #include "services/content/public/mojom/constants.mojom.h" -#include "services/content/public/mojom/view_factory.mojom.h" +#include "services/content/public/mojom/navigable_contents_factory.mojom.h" #include "services/service_manager/public/cpp/connector.h" namespace content { @@ -39,19 +39,19 @@ }; // Verifies that the embedded Content Service is reachable. Does a basic -// end-to-end sanity check to also verify that a ContentView client is backed -// by a WebContents instance in the browser. +// end-to-end sanity check to also verify that a NavigableContents is backed by +// a WebContents instance in the browser. IN_PROC_BROWSER_TEST_F(ContentServiceBrowserTest, EmbeddedContentService) { auto* browser_context = shell()->web_contents()->GetBrowserContext(); auto* connector = BrowserContext::GetConnectorFor(browser_context); - content::mojom::ViewFactoryPtr factory; + content::mojom::NavigableContentsFactoryPtr factory; connector->BindInterface(content::mojom::kServiceName, &factory); - auto view = std::make_unique<content::View>(factory.get()); + auto contents = std::make_unique<content::NavigableContents>(factory.get()); base::RunLoop loop; - view->set_did_stop_loading_callback_for_testing(loop.QuitClosure()); - view->Navigate(embedded_test_server()->GetURL("/hello.html")); + contents->set_did_stop_loading_callback_for_testing(loop.QuitClosure()); + contents->Navigate(embedded_test_server()->GetURL("/hello.html")); loop.Run(); }
diff --git a/content/browser/content_service_delegate_impl.cc b/content/browser/content_service_delegate_impl.cc index fa67d58..40eb806f11 100644 --- a/content/browser/content_service_delegate_impl.cc +++ b/content/browser/content_service_delegate_impl.cc
@@ -7,29 +7,32 @@ #include "base/macros.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_observer.h" +#include "services/content/navigable_contents_delegate.h" #include "services/content/service.h" -#include "services/content/view_delegate.h" namespace content { namespace { -// Bridge between Content Service view delegation API and a WebContentsImpl. -class ViewDelegateImpl : public content::ViewDelegate, - public WebContentsObserver { +// Bridge between Content Service navigable contents delegation API and a +// WebContentsImpl. +class NavigableContentsDelegateImpl : public content::NavigableContentsDelegate, + public WebContentsObserver { public: - explicit ViewDelegateImpl(BrowserContext* browser_context, - mojom::ViewClient* client) + explicit NavigableContentsDelegateImpl(BrowserContext* browser_context, + mojom::NavigableContentsClient* client) : client_(client) { WebContents::CreateParams params(browser_context); web_contents_ = WebContents::Create(params); WebContentsObserver::Observe(web_contents_.get()); } - ~ViewDelegateImpl() override { WebContentsObserver::Observe(nullptr); } + ~NavigableContentsDelegateImpl() override { + WebContentsObserver::Observe(nullptr); + } private: - // content::ViewDelegate: + // content::NavigableContentsDelegate: gfx::NativeView GetNativeView() override { return web_contents_->GetNativeView(); } @@ -44,9 +47,9 @@ void DidStopLoading() override { client_->DidStopLoading(); } std::unique_ptr<WebContents> web_contents_; - mojom::ViewClient* const client_; + mojom::NavigableContentsClient* const client_; - DISALLOW_COPY_AND_ASSIGN(ViewDelegateImpl); + DISALLOW_COPY_AND_ASSIGN(NavigableContentsDelegateImpl); }; } // namespace @@ -77,9 +80,11 @@ service_instances_.erase(service); } -std::unique_ptr<content::ViewDelegate> -ContentServiceDelegateImpl::CreateViewDelegate(mojom::ViewClient* client) { - return std::make_unique<ViewDelegateImpl>(browser_context_, client); +std::unique_ptr<content::NavigableContentsDelegate> +ContentServiceDelegateImpl::CreateNavigableContentsDelegate( + mojom::NavigableContentsClient* client) { + return std::make_unique<NavigableContentsDelegateImpl>(browser_context_, + client); } } // namespace content
diff --git a/content/browser/content_service_delegate_impl.h b/content/browser/content_service_delegate_impl.h index 6c37c19..70b2295f 100644 --- a/content/browser/content_service_delegate_impl.h +++ b/content/browser/content_service_delegate_impl.h
@@ -36,8 +36,8 @@ private: // content::ContentServiceDelegate: void WillDestroyServiceInstance(content::Service* service) override; - std::unique_ptr<ViewDelegate> CreateViewDelegate( - mojom::ViewClient* client) override; + std::unique_ptr<NavigableContentsDelegate> CreateNavigableContentsDelegate( + mojom::NavigableContentsClient* client) override; BrowserContext* const browser_context_;
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index 9cc32b63..12538a7 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -823,6 +823,35 @@ Send(new FrameMsg_MediaPlayerActionAt(routing_id_, point_in_view, action)); } +void RenderFrameHostImpl::CreateNetworkServiceDefaultFactory( + network::mojom::URLLoaderFactoryRequest default_factory_request) { + network::mojom::URLLoaderFactoryParamsPtr params = + network::mojom::URLLoaderFactoryParams::New(); + params->process_id = GetProcess()->GetID(); + SiteIsolationPolicy::PopulateURLLoaderFactoryParamsPtrForCORB(params.get()); + + auto* context = GetSiteInstance()->GetBrowserContext(); + GetContentClient()->browser()->WillCreateURLLoaderFactory( + context, this, false /* is_navigation */, &default_factory_request); + // Keep DevTools proxy lasy, i.e. closest to the network. + RenderFrameDevToolsAgentHost::WillCreateURLLoaderFactory( + this, false /* is_navigation */, false /* is_download */, + &default_factory_request); + StoragePartitionImpl* storage_partition = static_cast<StoragePartitionImpl*>( + BrowserContext::GetStoragePartition(context, GetSiteInstance())); + if (g_create_network_factory_callback_for_test.Get().is_null()) { + storage_partition->GetNetworkContext()->CreateURLLoaderFactory( + std::move(default_factory_request), std::move(params)); + } else { + network::mojom::URLLoaderFactoryPtr original_factory; + storage_partition->GetNetworkContext()->CreateURLLoaderFactory( + mojo::MakeRequest(&original_factory), std::move(params)); + g_create_network_factory_callback_for_test.Get().Run( + std::move(default_factory_request), GetProcess()->GetID(), + original_factory.PassInterface()); + } +} + gfx::NativeView RenderFrameHostImpl::GetNativeView() { RenderWidgetHostView* view = render_view_host_->GetWidget()->GetView(); if (!view) @@ -4626,40 +4655,21 @@ void RenderFrameHostImpl::CreateNetworkServiceDefaultFactoryAndObserve( network::mojom::URLLoaderFactoryRequest default_factory_request) { - network::mojom::URLLoaderFactoryParamsPtr params = - network::mojom::URLLoaderFactoryParams::New(); - params->process_id = GetProcess()->GetID(); - SiteIsolationPolicy::PopulateURLLoaderFactoryParamsPtrForCORB(params.get()); - network::mojom::URLLoaderFactoryParamsPtr params_for_error_monitoring = - params->Clone(); - - auto* context = GetSiteInstance()->GetBrowserContext(); - GetContentClient()->browser()->WillCreateURLLoaderFactory( - context, this, false /* is_navigation */, &default_factory_request); - // Keep DevTools proxy lasy, i.e. closest to the network. - RenderFrameDevToolsAgentHost::WillCreateURLLoaderFactory( - this, false /* is_navigation */, false /* is_download */, - &default_factory_request); - StoragePartitionImpl* storage_partition = static_cast<StoragePartitionImpl*>( - BrowserContext::GetStoragePartition(context, GetSiteInstance())); - if (g_create_network_factory_callback_for_test.Get().is_null()) { - storage_partition->GetNetworkContext()->CreateURLLoaderFactory( - std::move(default_factory_request), std::move(params)); - } else { - network::mojom::URLLoaderFactoryPtr original_factory; - storage_partition->GetNetworkContext()->CreateURLLoaderFactory( - mojo::MakeRequest(&original_factory), std::move(params)); - g_create_network_factory_callback_for_test.Get().Run( - std::move(default_factory_request), GetProcess()->GetID(), - original_factory.PassInterface()); - } + CreateNetworkServiceDefaultFactory(std::move(default_factory_request)); // Add connection error observer when Network Service is running // out-of-process. - if (IsOutOfProcessNetworkService()) { + if (IsOutOfProcessNetworkService() && + (!network_service_connection_error_handler_holder_ || + network_service_connection_error_handler_holder_.encountered_error())) { + StoragePartition* storage_partition = BrowserContext::GetStoragePartition( + GetSiteInstance()->GetBrowserContext(), GetSiteInstance()); + network::mojom::URLLoaderFactoryParamsPtr params = + network::mojom::URLLoaderFactoryParams::New(); + params->process_id = GetProcess()->GetID(); storage_partition->GetNetworkContext()->CreateURLLoaderFactory( mojo::MakeRequest(&network_service_connection_error_handler_holder_), - std::move(params_for_error_monitoring)); + std::move(params)); network_service_connection_error_handler_holder_ .set_connection_error_handler(base::BindOnce( &RenderFrameHostImpl::UpdateSubresourceLoaderFactories,
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h index a52c401..7d84b0f4 100644 --- a/content/browser/frame_host/render_frame_host_impl.h +++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -247,6 +247,8 @@ void ExecuteMediaPlayerActionAtLocation( const gfx::Point&, const blink::WebMediaPlayerAction& action) override; + void CreateNetworkServiceDefaultFactory( + network::mojom::URLLoaderFactoryRequest default_factory_request) override; // IPC::Sender bool Send(IPC::Message* msg) override;
diff --git a/content/browser/media/capture/aura_window_capture_machine.cc b/content/browser/media/capture/aura_window_capture_machine.cc deleted file mode 100644 index 2f6caae..0000000 --- a/content/browser/media/capture/aura_window_capture_machine.cc +++ /dev/null
@@ -1,485 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/media/capture/aura_window_capture_machine.h" - -#include <algorithm> -#include <utility> - -#include "base/logging.h" -#include "base/metrics/histogram_macros.h" -#include "components/viz/common/frame_sinks/copy_output_request.h" -#include "components/viz/common/frame_sinks/copy_output_result.h" -#include "components/viz/common/gl_helper.h" -#include "content/browser/compositor/image_transport_factory.h" -#include "content/browser/media/capture/desktop_capture_device_uma_types.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/common/service_manager_connection.h" -#include "media/base/video_util.h" -#include "media/capture/content/thread_safe_capture_oracle.h" -#include "media/capture/content/video_capture_oracle.h" -#include "media/capture/video_capture_types.h" -#include "services/device/public/mojom/constants.mojom.h" -#include "services/device/public/mojom/wake_lock_provider.mojom.h" -#include "services/service_manager/public/cpp/connector.h" -#include "skia/ext/image_operations.h" -#include "ui/aura/client/screen_position_client.h" -#include "ui/aura/env.h" -#include "ui/aura/window.h" -#include "ui/aura/window_observer.h" -#include "ui/aura/window_tree_host.h" -#include "ui/base/cursor/cursors_aura.h" -#include "ui/compositor/compositor.h" -#include "ui/compositor/dip_util.h" -#include "ui/compositor/layer.h" - -namespace content { - -AuraWindowCaptureMachine::AuraWindowCaptureMachine() - : desktop_window_(nullptr), - screen_capture_(false), - frame_capture_active_(true), - weak_factory_(this) {} - -AuraWindowCaptureMachine::~AuraWindowCaptureMachine() {} - -void AuraWindowCaptureMachine::Start( - const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy, - const media::VideoCaptureParams& params, - const base::Callback<void(bool)> callback) { - // Starts the capture machine asynchronously. - BrowserThread::PostTaskAndReplyWithResult( - BrowserThread::UI, - FROM_HERE, - base::Bind(&AuraWindowCaptureMachine::InternalStart, - base::Unretained(this), - oracle_proxy, - params), - callback); -} - -bool AuraWindowCaptureMachine::InternalStart( - const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy, - const media::VideoCaptureParams& params) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - // The window might be destroyed between SetWindow() and Start(). - if (!desktop_window_) - return false; - - // If the associated layer is already destroyed then return failure. - ui::Layer* layer = desktop_window_->layer(); - if (!layer) - return false; - - DCHECK(oracle_proxy); - oracle_proxy_ = oracle_proxy; - capture_params_ = params; - - // Update capture size. - UpdateCaptureSize(); - - // Start observing compositor updates. - aura::WindowTreeHost* const host = desktop_window_->GetHost(); - ui::Compositor* const compositor = host ? host->compositor() : nullptr; - if (!compositor) - return false; - compositor->AddAnimationObserver(this); - - // Start observing for GL context losses. - compositor->context_factory()->AddObserver(this); - - DCHECK(!wake_lock_); - // Request Wake Lock. In some testing contexts, the service manager - // connection isn't initialized. - if (ServiceManagerConnection::GetForProcess()) { - service_manager::Connector* connector = - ServiceManagerConnection::GetForProcess()->GetConnector(); - DCHECK(connector); - device::mojom::WakeLockProviderPtr wake_lock_provider; - connector->BindInterface(device::mojom::kServiceName, - mojo::MakeRequest(&wake_lock_provider)); - wake_lock_provider->GetWakeLockWithoutContext( - device::mojom::WakeLockType::kPreventDisplaySleep, - device::mojom::WakeLockReason::kOther, "Aura window or desktop capture", - mojo::MakeRequest(&wake_lock_)); - - wake_lock_->RequestWakeLock(); - } - - return true; -} - -void AuraWindowCaptureMachine::Suspend() { - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::BindOnce(&AuraWindowCaptureMachine::InternalSuspend, - base::Unretained(this))); -} - -void AuraWindowCaptureMachine::InternalSuspend() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - DVLOG(1) << "Suspending frame capture and delivery."; - frame_capture_active_ = false; -} - -void AuraWindowCaptureMachine::Resume() { - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::BindOnce(&AuraWindowCaptureMachine::InternalResume, - base::Unretained(this))); -} - -void AuraWindowCaptureMachine::InternalResume() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - DVLOG(1) << "Resuming frame capture and delivery."; - frame_capture_active_ = true; - // Whenever capture resumes, capture a refresh frame immediately to make sure - // no content updates are missing from the video stream. - MaybeCaptureForRefresh(); -} - -void AuraWindowCaptureMachine::Stop(const base::Closure& callback) { - // Stops the capture machine asynchronously. - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::BindOnce(&AuraWindowCaptureMachine::InternalStop, - base::Unretained(this), callback)); -} - -void AuraWindowCaptureMachine::InternalStop(const base::Closure& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - // Cancel any and all outstanding callbacks owned by external modules. - weak_factory_.InvalidateWeakPtrs(); - - if (wake_lock_) - wake_lock_->CancelWakeLock(); - // Stop observing compositor and window events. - if (desktop_window_) { - if (aura::WindowTreeHost* host = desktop_window_->GetHost()) { - if (ui::Compositor* compositor = host->compositor()) { - compositor->RemoveAnimationObserver(this); - compositor->context_factory()->RemoveObserver(this); - } - } - desktop_window_->RemoveObserver(this); - desktop_window_ = nullptr; - cursor_renderer_.reset(); - } - - OnLostResources(); - - callback.Run(); -} - -void AuraWindowCaptureMachine::MaybeCaptureForRefresh() { - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::BindOnce( - &AuraWindowCaptureMachine::Capture, - // Use of Unretained() is safe here since this task must run - // before InternalStop(). - base::Unretained(this), base::TimeTicks())); -} - -void AuraWindowCaptureMachine::SetWindow(aura::Window* window) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - DCHECK(!desktop_window_); - desktop_window_ = window; - cursor_renderer_.reset( - new CursorRendererAura(CursorRenderer::CURSOR_DISPLAYED_ALWAYS)); - cursor_renderer_->SetTargetView(window); - - // Start observing window events. - desktop_window_->AddObserver(this); - - // We must store this for the UMA reporting in DidCopyOutput() as - // desktop_window_ might be destroyed at that point. - screen_capture_ = window->IsRootWindow(); - IncrementDesktopCaptureCounter(screen_capture_ ? SCREEN_CAPTURER_CREATED - : WINDOW_CAPTURER_CREATED); -} - -void AuraWindowCaptureMachine::UpdateCaptureSize() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (oracle_proxy_ && desktop_window_) { - ui::Layer* layer = desktop_window_->layer(); - oracle_proxy_->UpdateCaptureSize(ui::ConvertSizeToPixel( - layer, layer->bounds().size())); - } -} - -void AuraWindowCaptureMachine::Capture(base::TimeTicks event_time) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - // Do not capture if the desktop window is already destroyed. - if (!desktop_window_) - return; - - scoped_refptr<media::VideoFrame> frame; - media::ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb; - - // TODO(miu): Need to fix this so the compositor is providing the presentation - // timestamps and damage regions, to leverage the frame timestamp rewriting - // logic. http://crbug.com/492839 - const base::TimeTicks start_time = base::TimeTicks::Now(); - media::VideoCaptureOracle::Event event; - if (event_time.is_null()) { - event = media::VideoCaptureOracle::kRefreshRequest; - event_time = start_time; - } else { - event = media::VideoCaptureOracle::kCompositorUpdate; - } - if (oracle_proxy_->ObserveEventAndDecideCapture( - event, gfx::Rect(), event_time, &frame, &capture_frame_cb)) { - std::unique_ptr<viz::CopyOutputRequest> request = - std::make_unique<viz::CopyOutputRequest>( - viz::CopyOutputRequest::ResultFormat::RGBA_TEXTURE, - base::BindOnce(&AuraWindowCaptureMachine::DidCopyOutput, - weak_factory_.GetWeakPtr(), std::move(frame), - event_time, start_time, capture_frame_cb)); - gfx::Rect window_rect = gfx::Rect(desktop_window_->bounds().width(), - desktop_window_->bounds().height()); - request->set_area(window_rect); - desktop_window_->layer()->RequestCopyOfOutput(std::move(request)); - } -} - -void AuraWindowCaptureMachine::DidCopyOutput( - scoped_refptr<media::VideoFrame> video_frame, - base::TimeTicks event_time, - base::TimeTicks start_time, - const CaptureFrameCallback& capture_frame_cb, - std::unique_ptr<viz::CopyOutputResult> result) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - static bool first_call = true; - - const bool succeeded = ProcessCopyOutputResponse( - video_frame, event_time, capture_frame_cb, std::move(result)); - - const base::TimeDelta capture_time = base::TimeTicks::Now() - start_time; - - // The two UMA_ blocks must be put in its own scope since it creates a static - // variable which expected constant histogram name. - if (screen_capture_) { - UMA_HISTOGRAM_TIMES(kUmaScreenCaptureTime, capture_time); - } else { - UMA_HISTOGRAM_TIMES(kUmaWindowCaptureTime, capture_time); - } - - if (first_call) { - first_call = false; - if (screen_capture_) { - IncrementDesktopCaptureCounter(succeeded ? FIRST_SCREEN_CAPTURE_SUCCEEDED - : FIRST_SCREEN_CAPTURE_FAILED); - } else { - IncrementDesktopCaptureCounter(succeeded - ? FIRST_WINDOW_CAPTURE_SUCCEEDED - : FIRST_WINDOW_CAPTURE_FAILED); - } - } - - // If ProcessCopyOutputResponse() failed, it will not run |capture_frame_cb|, - // so do that now. - if (!succeeded) - capture_frame_cb.Run(std::move(video_frame), event_time, false); -} - -bool AuraWindowCaptureMachine::ProcessCopyOutputResponse( - scoped_refptr<media::VideoFrame> video_frame, - base::TimeTicks event_time, - const CaptureFrameCallback& capture_frame_cb, - std::unique_ptr<viz::CopyOutputResult> result) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK_EQ(result->format(), viz::CopyOutputResult::Format::RGBA_TEXTURE); - - if (!desktop_window_) { - VLOG(1) << "Ignoring CopyOutputResult: Capture target has gone away."; - return false; - } - if (result->IsEmpty()) { - VLOG(1) << "CopyOutputRequest failed: Empty result."; - return false; - } - DCHECK(video_frame); - - // Compute the dest size we want after the letterboxing resize. Make the - // coordinates and sizes even because we letterbox in YUV space - // (see CopyRGBToVideoFrame). They need to be even for the UV samples to - // line up correctly. - // The video frame's visible_rect() and the result's size() are both physical - // pixels. - gfx::Rect region_in_frame = media::ComputeLetterboxRegion( - video_frame->visible_rect(), result->size()); - region_in_frame = gfx::Rect(region_in_frame.x() & ~1, - region_in_frame.y() & ~1, - region_in_frame.width() & ~1, - region_in_frame.height() & ~1); - if (region_in_frame.IsEmpty()) { - VLOG(1) << "Aborting capture: Computed empty letterboxed content region."; - return false; - } - - ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); - viz::GLHelper* gl_helper = factory->GetGLHelper(); - if (!gl_helper) { - VLOG(1) << "Aborting capture: No GLHelper available for YUV readback."; - return false; - } - - gpu::Mailbox mailbox = result->GetTextureResult()->mailbox; - gpu::SyncToken sync_token = result->GetTextureResult()->sync_token; - std::unique_ptr<viz::SingleReleaseCallback> release_callback = - result->TakeTextureOwnership(); - - if (!yuv_readback_pipeline_) - yuv_readback_pipeline_ = gl_helper->CreateReadbackPipelineYUV(true, true); - viz::GLHelper::ScalerInterface* const scaler = - yuv_readback_pipeline_->scaler(); - const gfx::Vector2d scale_from(result->size().width(), - result->size().height()); - const gfx::Vector2d scale_to(region_in_frame.width(), - region_in_frame.height()); - if (scale_from == scale_to) { - if (scaler) - yuv_readback_pipeline_->SetScaler(nullptr); - } else if (!scaler || !scaler->IsSameScaleRatio(scale_from, scale_to)) { - std::unique_ptr<viz::GLHelper::ScalerInterface> fast_scaler = - gl_helper->CreateScaler(viz::GLHelper::SCALER_QUALITY_FAST, scale_from, - scale_to, false, false, false); - DCHECK( - fast_scaler); // Arguments to CreateScaler() should never be invalid. - yuv_readback_pipeline_->SetScaler(std::move(fast_scaler)); - } - - yuv_readback_pipeline_->ReadbackYUV( - mailbox, sync_token, result->size(), gfx::Rect(region_in_frame.size()), - video_frame->stride(media::VideoFrame::kYPlane), - video_frame->data(media::VideoFrame::kYPlane), - video_frame->stride(media::VideoFrame::kUPlane), - video_frame->data(media::VideoFrame::kUPlane), - video_frame->stride(media::VideoFrame::kVPlane), - video_frame->data(media::VideoFrame::kVPlane), region_in_frame.origin(), - base::Bind(&CopyOutputFinishedForVideo, weak_factory_.GetWeakPtr(), - event_time, capture_frame_cb, video_frame, region_in_frame, - base::Passed(&release_callback))); - media::LetterboxVideoFrame(video_frame.get(), region_in_frame); - return true; -} - -using CaptureFrameCallback = - media::ThreadSafeCaptureOracle::CaptureFrameCallback; - -void AuraWindowCaptureMachine::CopyOutputFinishedForVideo( - base::WeakPtr<AuraWindowCaptureMachine> machine, - base::TimeTicks event_time, - const CaptureFrameCallback& capture_frame_cb, - scoped_refptr<media::VideoFrame> target, - const gfx::Rect& region_in_frame, - std::unique_ptr<viz::SingleReleaseCallback> release_callback, - bool result) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - release_callback->Run(gpu::SyncToken(), false); - - // Render the cursor and deliver the captured frame if the - // AuraWindowCaptureMachine has not been stopped (i.e., the WeakPtr is - // still valid). - if (machine) { - if (machine->cursor_renderer_ && result) - machine->cursor_renderer_->RenderOnVideoFrame(target.get(), - region_in_frame, nullptr); - } else { - VLOG(1) << "Aborting capture: AuraWindowCaptureMachine has gone away."; - result = false; - } - - capture_frame_cb.Run(std::move(target), event_time, result); -} - -void AuraWindowCaptureMachine::OnWindowBoundsChanged( - aura::Window* window, - const gfx::Rect& old_bounds, - const gfx::Rect& new_bounds, - ui::PropertyChangeReason reason) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK(desktop_window_ && window == desktop_window_); - - // Post a task to update capture size after first returning to the event loop. - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::BindOnce(&AuraWindowCaptureMachine::UpdateCaptureSize, - weak_factory_.GetWeakPtr())); -} - -void AuraWindowCaptureMachine::OnWindowDestroying(aura::Window* window) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - InternalStop(base::DoNothing()); - - oracle_proxy_->ReportError(FROM_HERE, "OnWindowDestroying()"); -} - -void AuraWindowCaptureMachine::OnWindowAddedToRootWindow( - aura::Window* window) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK(window == desktop_window_); - - if (aura::WindowTreeHost* host = window->GetHost()) { - if (ui::Compositor* compositor = host->compositor()) - compositor->AddAnimationObserver(this); - } -} - -void AuraWindowCaptureMachine::OnWindowRemovingFromRootWindow( - aura::Window* window, - aura::Window* new_root) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK(window == desktop_window_); - - if (aura::WindowTreeHost* host = window->GetHost()) { - if (ui::Compositor* compositor = host->compositor()) { - compositor->RemoveAnimationObserver(this); - compositor->context_factory()->RemoveObserver(this); - } - } -} - -void AuraWindowCaptureMachine::OnAnimationStep(base::TimeTicks timestamp) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK(!timestamp.is_null()); - - // HACK: The compositor invokes this observer method to step layer animation - // forward. Scheduling frame capture was not the intention, and so invoking - // this method does not actually indicate the content has changed. However, - // this is the only reliable way to ensure all screen changes are captured, as - // of this writing. - // http://crbug.com/600031 - // - // TODO(miu): Need a better observer callback interface from the compositor - // for this use case. The solution here will always capture frames at the - // maximum framerate, which means CPU/GPU is being wasted on redundant - // captures and quality/smoothness of animating content will suffer - // significantly. - // http://crbug.com/492839 - if (frame_capture_active_) - Capture(timestamp); -} - -void AuraWindowCaptureMachine::OnCompositingShuttingDown( - ui::Compositor* compositor) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - compositor->RemoveAnimationObserver(this); - compositor->context_factory()->RemoveObserver(this); -} - -void AuraWindowCaptureMachine::OnLostResources() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - yuv_readback_pipeline_.reset(); -} - -} // namespace content
diff --git a/content/browser/media/capture/aura_window_capture_machine.h b/content/browser/media/capture/aura_window_capture_machine.h deleted file mode 100644 index d606741..0000000 --- a/content/browser/media/capture/aura_window_capture_machine.h +++ /dev/null
@@ -1,150 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_AURA_WINDOW_CAPTURE_MACHINE_H_ -#define CONTENT_BROWSER_MEDIA_CAPTURE_AURA_WINDOW_CAPTURE_MACHINE_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "content/browser/media/capture/cursor_renderer_aura.h" -#include "media/capture/content/screen_capture_device_core.h" -#include "services/device/public/mojom/wake_lock.mojom.h" -#include "ui/aura/window.h" -#include "ui/aura/window_observer.h" -#include "ui/base/cursor/cursors_aura.h" -#include "ui/compositor/compositor.h" -#include "ui/compositor/compositor_animation_observer.h" - -namespace viz { -class CopyOutputResult; -class ReadbackYUVInterface; -} - -namespace content { - -// AuraWindowCaptureMachine uses the compositor to capture Aura windows. -// -// It is used for browser window capture on platforms that use Aura (Windows, -// Linux, and Chrome OS) and additionally for desktop capture on Chrome OS. -class AuraWindowCaptureMachine : public media::VideoCaptureMachine, - public aura::WindowObserver, - public ui::ContextFactoryObserver, - public ui::CompositorAnimationObserver { - public: - AuraWindowCaptureMachine(); - ~AuraWindowCaptureMachine() override; - - // VideoCaptureMachine overrides. - void Start(const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy, - const media::VideoCaptureParams& params, - const base::Callback<void(bool)> callback) override; - void Suspend() override; - void Resume() override; - void Stop(const base::Closure& callback) override; - void MaybeCaptureForRefresh() override; - - // Implements aura::WindowObserver. - void OnWindowBoundsChanged(aura::Window* window, - const gfx::Rect& old_bounds, - const gfx::Rect& new_bounds, - ui::PropertyChangeReason reason) override; - void OnWindowDestroying(aura::Window* window) override; - void OnWindowAddedToRootWindow(aura::Window* window) override; - void OnWindowRemovingFromRootWindow(aura::Window* window, - aura::Window* new_root) override; - - // ui::CompositorAnimationObserver implementation. - void OnAnimationStep(base::TimeTicks timestamp) override; - void OnCompositingShuttingDown(ui::Compositor* compositor) override; - - // Sets the window to use for capture. - void SetWindow(aura::Window* window); - - private: - bool InternalStart( - const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy, - const media::VideoCaptureParams& params); - void InternalSuspend(); - void InternalResume(); - void InternalStop(const base::Closure& callback); - - // Captures a frame. |event_time| is provided by the compositor, or is null - // for refresh requests. - void Capture(base::TimeTicks event_time); - - // Update capture size. Must be called on the UI thread. - void UpdateCaptureSize(); - - using CaptureFrameCallback = - media::ThreadSafeCaptureOracle::CaptureFrameCallback; - - // Response callback for cc::Layer::RequestCopyOfOutput(). - void DidCopyOutput(scoped_refptr<media::VideoFrame> video_frame, - base::TimeTicks event_time, - base::TimeTicks start_time, - const CaptureFrameCallback& capture_frame_cb, - std::unique_ptr<viz::CopyOutputResult> result); - - // A helper which does the real work for DidCopyOutput. Returns true if - // succeeded and |capture_frame_cb| will be run at some future point. Returns - // false on error, and |capture_frame_cb| should be run by the caller (with - // failure status). - bool ProcessCopyOutputResponse(scoped_refptr<media::VideoFrame> video_frame, - base::TimeTicks event_time, - const CaptureFrameCallback& capture_frame_cb, - std::unique_ptr<viz::CopyOutputResult> result); - - // ui::ContextFactoryObserver implementation. - void OnLostResources() override; - - // Renders the cursor if needed and then delivers the captured frame. - static void CopyOutputFinishedForVideo( - base::WeakPtr<AuraWindowCaptureMachine> machine, - base::TimeTicks event_time, - const CaptureFrameCallback& capture_frame_cb, - scoped_refptr<media::VideoFrame> target, - const gfx::Rect& region_in_frame, - std::unique_ptr<viz::SingleReleaseCallback> release_callback, - bool result); - - // The window associated with the desktop. - aura::Window* desktop_window_; - - // Whether screen capturing or window capture. - bool screen_capture_; - - // Makes all the decisions about which frames to copy, and how. - scoped_refptr<media::ThreadSafeCaptureOracle> oracle_proxy_; - - // The capture parameters for this capture. - media::VideoCaptureParams capture_params_; - - // YUV readback pipeline. - std::unique_ptr<viz::ReadbackYUVInterface> yuv_readback_pipeline_; - - // Renders mouse cursor on frame. - std::unique_ptr<content::CursorRendererAura> cursor_renderer_; - - // TODO(jiayl): Remove wake_lock_ when there is an API to keep the - // screen from sleeping for the drive-by web. - device::mojom::WakeLockPtr wake_lock_; - - // False while frame capture has been suspended. All other aspects of the - // machine are maintained. - bool frame_capture_active_; - - // WeakPtrs are used for the asynchronous capture callbacks passed to external - // modules. They are only valid on the UI thread and become invalidated - // immediately when InternalStop() is called to ensure that no more captured - // frames will be delivered to the client. - base::WeakPtrFactory<AuraWindowCaptureMachine> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(AuraWindowCaptureMachine); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_MEDIA_CAPTURE_AURA_WINDOW_CAPTURE_MACHINE_H_
diff --git a/content/browser/media/capture/desktop_capture_device_aura.cc b/content/browser/media/capture/desktop_capture_device_aura.cc deleted file mode 100644 index a80e012..0000000 --- a/content/browser/media/capture/desktop_capture_device_aura.cc +++ /dev/null
@@ -1,82 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/media/capture/desktop_capture_device_aura.h" - -#include <utility> - -#include "base/logging.h" -#include "base/memory/ptr_util.h" -#include "base/timer/timer.h" -#include "content/browser/media/capture/aura_window_capture_machine.h" -#include "content/browser/media/capture/desktop_capture_device_uma_types.h" -#include "content/public/browser/browser_thread.h" -#include "ui/aura/window.h" - -namespace content { - -namespace { - -void SetCaptureSource(AuraWindowCaptureMachine* machine, - const DesktopMediaID& source) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - aura::Window* window = DesktopMediaID::GetAuraWindowById(source); - if (window) { - machine->SetWindow(window); - if (source.type == DesktopMediaID::TYPE_SCREEN) { - if (source.audio_share) - IncrementDesktopCaptureCounter(SCREEN_CAPTURER_CREATED_WITH_AUDIO); - else - IncrementDesktopCaptureCounter(SCREEN_CAPTURER_CREATED_WITHOUT_AUDIO); - } - } -} - -} // namespace - -DesktopCaptureDeviceAura::DesktopCaptureDeviceAura( - const DesktopMediaID& source) { - AuraWindowCaptureMachine* machine = new AuraWindowCaptureMachine(); - core_.reset(new media::ScreenCaptureDeviceCore(base::WrapUnique(machine))); - // |core_| owns |machine| and deletes it on UI thread so passing the raw - // pointer to the UI thread is safe here. - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::BindOnce(&SetCaptureSource, machine, source)); -} - -DesktopCaptureDeviceAura::~DesktopCaptureDeviceAura() { - DVLOG(2) << "DesktopCaptureDeviceAura@" << this << " destroying."; -} - -// static -std::unique_ptr<media::VideoCaptureDevice> DesktopCaptureDeviceAura::Create( - const DesktopMediaID& source) { - if (source.aura_id == DesktopMediaID::kNullId) - return nullptr; - return std::unique_ptr<media::VideoCaptureDevice>( - new DesktopCaptureDeviceAura(source)); -} - -void DesktopCaptureDeviceAura::AllocateAndStart( - const media::VideoCaptureParams& params, - std::unique_ptr<Client> client) { - DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); - core_->AllocateAndStart(params, std::move(client)); -} - -void DesktopCaptureDeviceAura::RequestRefreshFrame() { - core_->RequestRefreshFrame(); -} - -void DesktopCaptureDeviceAura::StopAndDeAllocate() { - core_->StopAndDeAllocate(); -} - -void DesktopCaptureDeviceAura::OnUtilizationReport(int frame_feedback_id, - double utilization) { - core_->OnConsumerReportingUtilization(frame_feedback_id, utilization); -} - -} // namespace content
diff --git a/content/browser/media/capture/desktop_capture_device_aura.h b/content/browser/media/capture/desktop_capture_device_aura.h deleted file mode 100644 index 6eee43a..0000000 --- a/content/browser/media/capture/desktop_capture_device_aura.h +++ /dev/null
@@ -1,48 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_DESKTOP_CAPTURE_DEVICE_AURA_H_ -#define CONTENT_BROWSER_MEDIA_CAPTURE_DESKTOP_CAPTURE_DEVICE_AURA_H_ - -#include <memory> -#include <string> - -#include "base/macros.h" -#include "content/common/content_export.h" -#include "content/public/browser/desktop_media_id.h" -#include "media/capture/content/screen_capture_device_core.h" -#include "media/capture/video/video_capture_device.h" - -namespace content { - -// An implementation of VideoCaptureDevice that mirrors an Aura window. -class CONTENT_EXPORT DesktopCaptureDeviceAura - : public media::VideoCaptureDevice { - public: - // Creates a VideoCaptureDevice for the Aura desktop. If |source| does not - // reference a registered aura window, returns nullptr instead. - static std::unique_ptr<media::VideoCaptureDevice> Create( - const DesktopMediaID& source); - - ~DesktopCaptureDeviceAura() override; - - // VideoCaptureDevice implementation. - void AllocateAndStart(const media::VideoCaptureParams& params, - std::unique_ptr<Client> client) override; - void RequestRefreshFrame() override; - void StopAndDeAllocate() override; - void OnUtilizationReport(int frame_feedback_id, double utilization) override; - - private: - explicit DesktopCaptureDeviceAura(const DesktopMediaID& source); - - std::unique_ptr<media::ScreenCaptureDeviceCore> core_; - - DISALLOW_COPY_AND_ASSIGN(DesktopCaptureDeviceAura); -}; - - -} // namespace content - -#endif // CONTENT_BROWSER_MEDIA_CAPTURE_DESKTOP_CAPTURE_DEVICE_AURA_H_
diff --git a/content/browser/media/capture/desktop_capture_device_aura_unittest.cc b/content/browser/media/capture/desktop_capture_device_aura_unittest.cc deleted file mode 100644 index 7de25f8..0000000 --- a/content/browser/media/capture/desktop_capture_device_aura_unittest.cc +++ /dev/null
@@ -1,175 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/media/capture/desktop_capture_device_aura.h" - -#include <stddef.h> -#include <stdint.h> -#include <utility> - -#include "base/location.h" -#include "base/macros.h" -#include "base/run_loop.h" -#include "base/synchronization/waitable_event.h" -#include "content/browser/compositor/test/test_image_transport_factory.h" -#include "content/public/browser/desktop_media_id.h" -#include "content/public/test/test_browser_thread_bundle.h" -#include "media/capture/video_capture_types.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/aura/client/window_parenting_client.h" -#include "ui/aura/test/aura_test_helper.h" -#include "ui/aura/test/test_window_delegate.h" -#include "ui/aura/window.h" -#include "ui/wm/core/default_activation_client.h" - -using ::testing::_; -using ::testing::AnyNumber; -using ::testing::AtMost; -using ::testing::DoAll; -using ::testing::Expectation; -using ::testing::InvokeWithoutArgs; -using ::testing::SaveArg; - -namespace media { -class VideoFrame; -} // namespace media - -namespace content { -namespace { - -const int kFrameRate = 30; - -class MockDeviceClient : public media::VideoCaptureDevice::Client { - public: - MOCK_METHOD7(OnIncomingCapturedData, - void(const uint8_t* data, - int length, - const media::VideoCaptureFormat& frame_format, - int rotation, - base::TimeTicks reference_time, - base::TimeDelta tiemstamp, - int frame_feedback_id)); - MOCK_METHOD6(OnIncomingCapturedGfxBuffer, - void(gfx::GpuMemoryBuffer* buffer, - const media::VideoCaptureFormat& frame_format, - int clockwise_rotation, - base::TimeTicks reference_time, - base::TimeDelta timestamp, - int frame_feedback_id)); - MOCK_METHOD0(DoReserveOutputBuffer, void(void)); - MOCK_METHOD0(DoOnIncomingCapturedBuffer, void(void)); - MOCK_METHOD0(DoOnIncomingCapturedVideoFrame, void(void)); - MOCK_METHOD0(DoResurrectLastOutputBuffer, void(void)); - MOCK_METHOD2(OnError, - void(const base::Location& from_here, - const std::string& reason)); - MOCK_METHOD0(OnStarted, void(void)); - - // Trampoline methods to workaround GMOCK problems with std::unique_ptr<>. - Buffer ReserveOutputBuffer(const gfx::Size& dimensions, - media::VideoPixelFormat format, - int frame_feedback_id) override { - EXPECT_EQ(media::PIXEL_FORMAT_I420, format); - DoReserveOutputBuffer(); - return Buffer(); - } - void OnIncomingCapturedBuffer(Buffer buffer, - const media::VideoCaptureFormat& frame_format, - base::TimeTicks reference_time, - base::TimeDelta timestamp) override { - DoOnIncomingCapturedBuffer(); - } - void OnIncomingCapturedBufferExt( - Buffer buffer, - const media::VideoCaptureFormat& format, - base::TimeTicks reference_time, - base::TimeDelta timestamp, - gfx::Rect visible_rect, - const media::VideoFrameMetadata& additional_metadata) override { - DoOnIncomingCapturedVideoFrame(); - } - Buffer ResurrectLastOutputBuffer(const gfx::Size& dimensions, - media::VideoPixelFormat format, - int frame_feedback_id) override { - EXPECT_EQ(media::PIXEL_FORMAT_I420, format); - DoResurrectLastOutputBuffer(); - return Buffer(); - } - double GetBufferPoolUtilization() const override { return 0.0; } -}; - -// Test harness that sets up a minimal environment with necessary stubs. -class DesktopCaptureDeviceAuraTest : public testing::Test { - public: - DesktopCaptureDeviceAuraTest() = default; - ~DesktopCaptureDeviceAuraTest() override = default; - - protected: - void SetUp() override { - // The ContextFactory must exist before any Compositors are created. - ImageTransportFactory::SetFactory( - std::make_unique<TestImageTransportFactory>()); - helper_.reset(new aura::test::AuraTestHelper()); - helper_->SetUp( - ImageTransportFactory::GetInstance()->GetContextFactory(), - ImageTransportFactory::GetInstance()->GetContextFactoryPrivate()); - new wm::DefaultActivationClient(helper_->root_window()); - // We need a window to cover desktop area so that DesktopCaptureDeviceAura - // can use gfx::NativeWindow::GetWindowAtScreenPoint() to locate the - // root window associated with the primary display. - gfx::Rect desktop_bounds = root_window()->bounds(); - window_delegate_.reset(new aura::test::TestWindowDelegate()); - desktop_window_.reset(new aura::Window(window_delegate_.get())); - desktop_window_->Init(ui::LAYER_TEXTURED); - desktop_window_->SetBounds(desktop_bounds); - aura::client::ParentWindowWithContext( - desktop_window_.get(), root_window(), desktop_bounds); - desktop_window_->Show(); - } - - void TearDown() override { - helper_->RunAllPendingInMessageLoop(); - root_window()->RemoveChild(desktop_window_.get()); - desktop_window_.reset(); - window_delegate_.reset(); - helper_->TearDown(); - base::RunLoop().RunUntilIdle(); - ImageTransportFactory::Terminate(); - } - - aura::Window* root_window() { return helper_->root_window(); } - - private: - TestBrowserThreadBundle thread_bundle_; - std::unique_ptr<aura::test::AuraTestHelper> helper_; - std::unique_ptr<aura::Window> desktop_window_; - std::unique_ptr<aura::test::TestWindowDelegate> window_delegate_; - - DISALLOW_COPY_AND_ASSIGN(DesktopCaptureDeviceAuraTest); -}; - -TEST_F(DesktopCaptureDeviceAuraTest, StartAndStop) { - std::unique_ptr<media::VideoCaptureDevice> capture_device = - DesktopCaptureDeviceAura::Create( - content::DesktopMediaID::RegisterAuraWindow( - content::DesktopMediaID::TYPE_SCREEN, root_window())); - ASSERT_TRUE(capture_device); - - std::unique_ptr<MockDeviceClient> client(new MockDeviceClient()); - EXPECT_CALL(*client, OnError(_, _)).Times(0); - // |STARTED| is reported asynchronously, which may not be received if capture - // is stopped immediately. - EXPECT_CALL(*client, OnStarted()).Times(AtMost(1)); - - media::VideoCaptureParams capture_params; - capture_params.requested_format.frame_size.SetSize(640, 480); - capture_params.requested_format.frame_rate = kFrameRate; - capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420; - capture_device->AllocateAndStart(capture_params, std::move(client)); - capture_device->StopAndDeAllocate(); -} - -} // namespace -} // namespace content
diff --git a/content/browser/media/capture/fake_webcontent_capture_machine.cc b/content/browser/media/capture/fake_webcontent_capture_machine.cc deleted file mode 100644 index f18b8835..0000000 --- a/content/browser/media/capture/fake_webcontent_capture_machine.cc +++ /dev/null
@@ -1,35 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/media/capture/fake_webcontent_capture_machine.h" - -#include "base/logging.h" - -namespace content { - -FakeWebContentCaptureMachine::FakeWebContentCaptureMachine( - bool enable_auto_throttling) - : enable_auto_throttling_(enable_auto_throttling) { - DVLOG(2) << "FakeWebContentCaptureMachine"; -} - -FakeWebContentCaptureMachine::~FakeWebContentCaptureMachine() { - DVLOG(2) << "FakeWebContentCaptureMachine@" << this << " destroying."; -} - -void FakeWebContentCaptureMachine::Start( - const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy, - const media::VideoCaptureParams& params, - const base::Callback<void(bool)> callback) { - callback.Run(true); -} -void FakeWebContentCaptureMachine::Suspend() {} -void FakeWebContentCaptureMachine::Resume() {} -void FakeWebContentCaptureMachine::Stop(const base::Closure& callback) {} -bool FakeWebContentCaptureMachine::IsAutoThrottlingEnabled() const { - return enable_auto_throttling_; -} -void FakeWebContentCaptureMachine::MaybeCaptureForRefresh() {} - -} // namespace content \ No newline at end of file
diff --git a/content/browser/media/capture/fake_webcontent_capture_machine.h b/content/browser/media/capture/fake_webcontent_capture_machine.h deleted file mode 100644 index 92a5f84..0000000 --- a/content/browser/media/capture/fake_webcontent_capture_machine.h +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_FAKE_WEBCONTENT_CAPTURE_MACHINE_H_ -#define CONTENT_BROWSER_MEDIA_CAPTURE_FAKE_WEBCONTENT_CAPTURE_MACHINE_H_ - -#include "base/callback_helpers.h" -#include "content/common/content_export.h" -#include "media/capture/content/screen_capture_device_core.h" -#include "media/capture/content/thread_safe_capture_oracle.h" -#include "media/capture/video_capture_types.h" - -namespace content { - -// An implementation of VideoCaptureDevice that fakes a desktop capturer. -class CONTENT_EXPORT FakeWebContentCaptureMachine - : public media::VideoCaptureMachine { - public: - FakeWebContentCaptureMachine(bool enable_auto_throttling); - ~FakeWebContentCaptureMachine() override; - - // VideoCaptureMachine overrides. - void Start(const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy, - const media::VideoCaptureParams& params, - const base::Callback<void(bool)> callback) override; - void Suspend() override; - void Resume() override; - void Stop(const base::Closure& callback) override; - bool IsAutoThrottlingEnabled() const override; - void MaybeCaptureForRefresh() override; - - private: - bool enable_auto_throttling_; - - DISALLOW_COPY_AND_ASSIGN(FakeWebContentCaptureMachine); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_MEDIA_CAPTURE_DESKTOP_FAKE_CAPTURE_DEVICE_H_ \ No newline at end of file
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc index e30cb00..454ebca 100644 --- a/content/browser/renderer_host/compositor_impl_android.cc +++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -183,8 +183,10 @@ // http://crbug.com/657959. std::unique_ptr<viz::FrameSinkManagerImpl> frame_sink_manager_impl; +#if BUILDFLAG(ENABLE_VULKAN) std::unique_ptr<gpu::VulkanImplementation> vulkan_implementation; scoped_refptr<viz::VulkanContextProvider> vulkan_context_provider; +#endif private: friend class base::NoDestructor<CompositorDependencies>; @@ -240,6 +242,7 @@ const unsigned int kMaxDisplaySwapBuffers = 1U; +#if BUILDFLAG(ENABLE_VULKAN) scoped_refptr<viz::VulkanContextProvider> GetSharedVulkanContextProvider() { if (!base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableVulkan)) @@ -257,6 +260,7 @@ } return context_provider; } +#endif gpu::SharedMemoryLimits GetCompositorContextSharedMemoryLimits( gfx::NativeWindow window) { @@ -405,10 +409,12 @@ } } +#if BUILDFLAG(ENABLE_VULKAN) gpu::VulkanSurface* GetVulkanSurface() override { NOTIMPLEMENTED(); return nullptr; } +#endif void BindToClient(viz::OutputSurfaceClient* client) override { DCHECK(client); @@ -491,6 +497,7 @@ base::WeakPtrFactory<AndroidOutputSurface> weak_ptr_factory_; }; +#if BUILDFLAG(ENABLE_VULKAN) class VulkanOutputSurface : public viz::OutputSurface { public: explicit VulkanOutputSurface( @@ -600,6 +607,7 @@ DISALLOW_COPY_AND_ASSIGN(VulkanOutputSurface); }; +#endif // TODO(khushalsagar): These are being sent based on the CompositorImpl // visiblity which bakes in the assumption that there is a single CompositorImpl @@ -954,8 +962,10 @@ if (!host_->IsVisible()) return; +#if BUILDFLAG(ENABLE_VULKAN) if (CreateVulkanOutputSurface()) return; +#endif DCHECK(surface_handle_ != gpu::kNullSurfaceHandle); BrowserMainLoop::GetInstance() @@ -965,6 +975,7 @@ weak_factory_.GetWeakPtr())); } +#if BUILDFLAG(ENABLE_VULKAN) bool CompositorImpl::CreateVulkanOutputSurface() { if (!base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableVulkan)) @@ -985,6 +996,7 @@ return !!display_; } +#endif void CompositorImpl::OnGpuChannelEstablished( scoped_refptr<gpu::GpuChannelHost> gpu_channel_host) {
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h index f61c64dc..ad8f0ea 100644 --- a/content/browser/renderer_host/compositor_impl_android.h +++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -166,7 +166,9 @@ void HandlePendingLayerTreeFrameSinkRequest(); +#if BUILDFLAG(ENABLE_VULKAN) bool CreateVulkanOutputSurface(); +#endif void OnGpuChannelEstablished( scoped_refptr<gpu::GpuChannelHost> gpu_channel_host); void InitializeDisplay(
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index 5b7e2a1..7a862fa 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -1372,8 +1372,15 @@ if (delegated_frame_host_ && delegated_frame_host_->IsPrimarySurfaceEvicted()) { - SynchronizeVisualProperties(cc::DeadlinePolicy::UseDefaultDeadline(), - base::nullopt); + ui::WindowAndroidCompositor* compositor = + view_.GetWindowAndroid() ? view_.GetWindowAndroid()->GetCompositor() + : nullptr; + SynchronizeVisualProperties( + compositor && compositor->IsDrawingFirstVisibleFrame() + ? cc::DeadlinePolicy::UseSpecifiedDeadline( + ui::DelegatedFrameHostAndroid::FirstFrameTimeoutFrames()) + : cc::DeadlinePolicy::UseDefaultDeadline(), + base::nullopt); } host()->WasShown(false /* record_presentation_time */); @@ -1976,8 +1983,10 @@ StartObservingRootWindow(); if (resize) { - SynchronizeVisualProperties(cc::DeadlinePolicy::UseDefaultDeadline(), - base::nullopt); + SynchronizeVisualProperties( + cc::DeadlinePolicy::UseSpecifiedDeadline( + ui::DelegatedFrameHostAndroid::ResizeTimeoutFrames()), + base::nullopt); } if (!touch_selection_controller_) { @@ -2069,8 +2078,10 @@ void RenderWidgetHostViewAndroid::OnPhysicalBackingSizeChanged() { EvictFrameIfNecessary(); - SynchronizeVisualProperties(cc::DeadlinePolicy::UseDefaultDeadline(), - base::nullopt); + SynchronizeVisualProperties( + cc::DeadlinePolicy::UseSpecifiedDeadline( + ui::DelegatedFrameHostAndroid::ResizeTimeoutFrames()), + base::nullopt); } void RenderWidgetHostViewAndroid::OnRootWindowVisibilityChanged(bool visible) {
diff --git a/content/browser/renderer_host/web_database_host_impl.cc b/content/browser/renderer_host/web_database_host_impl.cc index a27dfea..99612d10 100644 --- a/content/browser/renderer_host/web_database_host_impl.cc +++ b/content/browser/renderer_host/web_database_host_impl.cc
@@ -91,8 +91,8 @@ // open handles to them in the database tracker to make sure they're // around for as long as needed. if (vfs_file_name.empty()) { - file = VfsBackend::OpenTempFileInDirectory(db_tracker_->DatabaseDirectory(), - desired_flags); + file = VfsBackend::OpenTempFileInDirectory( + db_tracker_->database_directory(), desired_flags); } else if (DatabaseUtil::CrackVfsFileName(vfs_file_name, &origin_identifier, &database_name, nullptr) && !db_tracker_->IsDatabaseScheduledForDeletion(origin_identifier,
diff --git a/content/browser/sandbox_parameters_mac.mm b/content/browser/sandbox_parameters_mac.mm index e9415b0d..a9227b8 100644 --- a/content/browser/sandbox_parameters_mac.mm +++ b/content/browser/sandbox_parameters_mac.mm
@@ -10,6 +10,7 @@ #include "base/files/file_util.h" #include "base/logging.h" #include "base/mac/bundle_locations.h" +#include "base/mac/foundation_util.h" #include "base/mac/mac_util.h" #include "base/numerics/checked_math.h" #include "base/strings/stringprintf.h" @@ -63,8 +64,8 @@ CHECK(client->SetParameter(service_manager::SandboxMac::kSandboxBundlePath, bundle_path)); - NSBundle* bundle = base::mac::OuterBundle(); - std::string bundle_id = base::SysNSStringToUTF8([bundle bundleIdentifier]); + std::string bundle_id = base::mac::BaseBundleID(); + DCHECK(!bundle_id.empty()) << "base::mac::OuterBundle is unset"; CHECK(client->SetParameter( service_manager::SandboxMac::kSandboxChromeBundleId, bundle_id));
diff --git a/content/browser/service_manager/service_manager_context.cc b/content/browser/service_manager/service_manager_context.cc index 35dba772..2daaf72 100644 --- a/content/browser/service_manager/service_manager_context.cc +++ b/content/browser/service_manager/service_manager_context.cc
@@ -295,15 +295,6 @@ DISALLOW_COPY_AND_ASSIGN(ServiceBinaryLauncherFactory); }; -// Helper to invoke GetGeolocationRequestContext on the currently-set -// ContentBrowserClient. -void GetGeolocationRequestContextFromContentClient( - base::OnceCallback<void(scoped_refptr<net::URLRequestContextGetter>)> - callback) { - GetContentClient()->browser()->GetGeolocationRequestContext( - std::move(callback)); -} - bool ShouldEnableVizService() { #if defined(USE_AURA) // aura::Env can be null in tests. @@ -530,7 +521,7 @@ device_info.factory = base::Bind( &device::CreateDeviceService, device_blocking_task_runner, service_manager_thread_task_runner_, - base::BindRepeating(&GetGeolocationRequestContextFromContentClient), + GetContentClient()->browser()->GetSystemSharedURLLoaderFactory(), GetContentClient()->browser()->GetGeolocationApiKey(), GetContentClient()->browser()->ShouldUseGmsCoreGeolocationProvider(), base::Bind(&WakeLockContextHost::GetNativeViewForContext), @@ -541,7 +532,7 @@ device_info.factory = base::Bind( &device::CreateDeviceService, device_blocking_task_runner, service_manager_thread_task_runner_, - base::BindRepeating(&GetGeolocationRequestContextFromContentClient), + GetContentClient()->browser()->GetSystemSharedURLLoaderFactory(), GetContentClient()->browser()->GetGeolocationApiKey(), base::Bind(&ContentBrowserClient::OverrideSystemLocationProvider, base::Unretained(GetContentClient()->browser())));
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc index 7537896e..aee47ae 100644 --- a/content/browser/site_per_process_hit_test_browsertest.cc +++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -921,11 +921,20 @@ } #endif // defined(USE_AURA) +#if defined(OS_CHROMEOS) +// Times out flakily on Chrome OS. crbug.com/833380 +#define MAYBE_CancelWheelScrollBubblingOnWheelTargetDeletion \ + DISABLED_CancelWheelScrollBubblingOnWheelTargetDeletion +#else +#define MAYBE_CancelWheelScrollBubblingOnWheelTargetDeletion \ + CancelWheelScrollBubblingOnWheelTargetDeletion +#endif + // Tests that wheel scroll bubbling gets cancelled when the wheel target view // gets destroyed in the middle of a wheel scroll seqeunce. This happens in // cases like overscroll navigation from inside an oopif. IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest, - CancelWheelScrollBubblingOnWheelTargetDeletion) { + MAYBE_CancelWheelScrollBubblingOnWheelTargetDeletion) { ui::GestureConfiguration::GetInstance()->set_scroll_debounce_interval_in_ms( 0); GURL main_url(embedded_test_server()->GetURL( @@ -1471,7 +1480,7 @@ // and is needed for trackpad scrolling on Chromebooks. #if defined(USE_AURA) -#if defined(THREAD_SANITIZER) +#if defined(THREAD_SANITIZER) || defined(OS_CHROMEOS) // Flaky: https://crbug.com/833380 #define MAYBE_ScrollEventToOOPIF DISABLED_ScrollEventToOOPIF #else @@ -1618,9 +1627,10 @@ // Test that mouse events are being routed to the correct RenderWidgetHostView // based on coordinates. -#if defined(THREAD_SANITIZER) +#if defined(THREAD_SANITIZER) || defined(OS_CHROMEOS) // The test times out often on TSAN bot. // https://crbug.com/591170. +// Also times out flakily on Chrome OS. crbug.com/833380 #define MAYBE_SurfaceHitTestTest DISABLED_SurfaceHitTestTest #else #define MAYBE_SurfaceHitTestTest SurfaceHitTestTest
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn index 2138a5fb..f592dc9 100644 --- a/content/common/BUILD.gn +++ b/content/common/BUILD.gn
@@ -217,7 +217,6 @@ "navigation_subresource_loader_params.h", "net/record_load_histograms.cc", "net/record_load_histograms.h", - "net/url_fetcher.cc", "net/url_request_service_worker_data.cc", "net/url_request_service_worker_data.h", "net/url_request_user_data.cc",
diff --git a/content/common/net/url_fetcher.cc b/content/common/net/url_fetcher.cc deleted file mode 100644 index 9af15ee..0000000 --- a/content/common/net/url_fetcher.cc +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/public/common/url_fetcher.h" - -#include "base/bind.h" -#include "content/common/net/url_request_user_data.h" -#include "net/url_request/url_fetcher.h" - -namespace content { - -namespace { - -std::unique_ptr<base::SupportsUserData::Data> CreateURLRequestUserData( - int render_process_id, - int render_frame_id) { - return std::make_unique<URLRequestUserData>(render_process_id, - render_frame_id); -} - -} // namespace - -void AssociateURLFetcherWithRenderFrame( - net::URLFetcher* url_fetcher, - const base::Optional<url::Origin>& initiator, - int render_process_id, - int render_frame_id) { - url_fetcher->SetInitiator(initiator); - url_fetcher->SetURLRequestUserData( - URLRequestUserData::kUserDataKey, - base::Bind(&CreateURLRequestUserData, render_process_id, - render_frame_id)); -} - -} // namespace content
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json index a332235..c14c0d3 100644 --- a/content/public/app/mojo/content_browser_manifest.json +++ b/content/public/app/mojo/content_browser_manifest.json
@@ -85,7 +85,7 @@ "testing_api" ], "cdm": [ "media:cdm" ], - "content": [ "view" ], + "content": [ "navigation" ], "content_gpu": [ "browser" ], "content_plugin": [ "browser" ], "content_renderer": [ "browser" ],
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc index ac20bf65b..bef2c6a 100644 --- a/content/public/browser/content_browser_client.cc +++ b/content/public/browser/content_browser_client.cc
@@ -370,10 +370,9 @@ return nullptr; } -void ContentBrowserClient::GetGeolocationRequestContext( - base::OnceCallback<void(scoped_refptr<net::URLRequestContextGetter>)> - callback) { - std::move(callback).Run(scoped_refptr<net::URLRequestContextGetter>(nullptr)); +scoped_refptr<network::SharedURLLoaderFactory> +ContentBrowserClient::GetSystemSharedURLLoaderFactory() { + return nullptr; } std::string ContentBrowserClient::GetGeolocationApiKey() {
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index d765060..88e9ab2 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h
@@ -87,6 +87,10 @@ class ScopedInterfaceEndpointHandle; } +namespace network { +class SharedURLLoaderFactory; +} + namespace service_manager { class Identity; class Service; @@ -582,14 +586,11 @@ virtual std::unique_ptr<device::LocationProvider> OverrideSystemLocationProvider(); - // Allows the embedder to provide a URLRequestContextGetter to use for network - // geolocation queries. - // * May be called from any thread. A URLRequestContextGetter is then provided - // by invoking |callback| on the calling thread. - // * Default implementation provides nullptr URLRequestContextGetter. - virtual void GetGeolocationRequestContext( - base::OnceCallback<void(scoped_refptr<net::URLRequestContextGetter>)> - callback); + // Returns a SharedURLLoaderFactory attached to the system network context. + // Must be called on the UI thread. The default implementation returns + // nullptr. + virtual scoped_refptr<network::SharedURLLoaderFactory> + GetSystemSharedURLLoaderFactory(); // Allows an embedder to provide a Google API Key to use for network // geolocation queries.
diff --git a/content/public/browser/gpu_utils.cc b/content/public/browser/gpu_utils.cc index fd8d511b..78d1c989 100644 --- a/content/public/browser/gpu_utils.cc +++ b/content/public/browser/gpu_utils.cc
@@ -95,6 +95,9 @@ gpu_preferences.disable_oop_rasterization = command_line->HasSwitch(switches::kDisableOopRasterization); + gpu_preferences.enable_vulkan = + command_line->HasSwitch(switches::kEnableVulkan); + // Some of these preferences are set or adjusted in // GpuDataManagerImplPrivate::AppendGpuCommandLine. return gpu_preferences;
diff --git a/content/public/browser/render_frame_host.h b/content/public/browser/render_frame_host.h index 74b1304..5a85535 100644 --- a/content/public/browser/render_frame_host.h +++ b/content/public/browser/render_frame_host.h
@@ -15,6 +15,7 @@ #include "content/public/common/file_chooser_params.h" #include "ipc/ipc_listener.h" #include "ipc/ipc_sender.h" +#include "services/network/public/mojom/url_loader_factory.mojom.h" #include "third_party/blink/public/mojom/loader/pause_subresource_loading_handle.mojom.h" #include "third_party/blink/public/mojom/page/page_visibility_state.mojom.h" #include "third_party/blink/public/platform/web_sudden_termination_disabler_type.h" @@ -314,6 +315,10 @@ const gfx::Point& location, const blink::WebMediaPlayerAction& action) = 0; + // Creates a Network Service-backed factory from appropriate |NetworkContext|. + virtual void CreateNetworkServiceDefaultFactory( + network::mojom::URLLoaderFactoryRequest default_factory_request) = 0; + private: // This interface should only be implemented inside content. friend class RenderFrameHostImpl;
diff --git a/content/public/common/BUILD.gn b/content/public/common/BUILD.gn index 19f059c..f0cad2d 100644 --- a/content/public/common/BUILD.gn +++ b/content/public/common/BUILD.gn
@@ -217,7 +217,6 @@ "three_d_api_types.h", "url_constants.cc", "url_constants.h", - "url_fetcher.h", "url_loader_throttle.cc", "url_loader_throttle.h", "url_utils.cc",
diff --git a/content/public/common/url_fetcher.h b/content/public/common/url_fetcher.h deleted file mode 100644 index bc9f1436..0000000 --- a/content/public/common/url_fetcher.h +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_PUBLIC_COMMON_URL_FETCHER_H_ -#define CONTENT_PUBLIC_COMMON_URL_FETCHER_H_ - -#include "base/optional.h" -#include "content/common/content_export.h" - -namespace net { -class URLFetcher; -} // namespace - -namespace url { -class Origin; -} // namespace - -namespace content { - -// Mark URLRequests started by the URLFetcher to stem from the given render -// frame. -CONTENT_EXPORT void AssociateURLFetcherWithRenderFrame( - net::URLFetcher* url_fetcher, - const base::Optional<url::Origin>& initiator, - int render_process_id, - int render_frame_id); - -} // namespace content - -#endif // CONTENT_PUBLIC_COMMON_URL_FETCHER_H_
diff --git a/content/public/test/test_launcher.cc b/content/public/test/test_launcher.cc index 2a7eaf53..3b3afff 100644 --- a/content/public/test/test_launcher.cc +++ b/content/public/test/test_launcher.cc
@@ -57,6 +57,7 @@ #include "services/service_manager/sandbox/win/sandbox_win.h" #elif defined(OS_MACOSX) #include "base/mac/scoped_nsautorelease_pool.h" +#include "sandbox/mac/seatbelt_exec.h" #endif namespace content { @@ -614,6 +615,13 @@ params.instance = GetModuleHandle(NULL); params.sandbox_info = &sandbox_info; +#elif defined(OS_MACOSX) + sandbox::SeatbeltExecServer::CreateFromArgumentsResult seatbelt = + sandbox::SeatbeltExecServer::CreateFromArguments( + command_line->GetProgram().value().c_str(), argc, argv); + if (seatbelt.sandbox_required) { + CHECK(seatbelt.server->InitializeSandbox()); + } #elif !defined(OS_ANDROID) params.argc = argc; params.argv = const_cast<const char**>(argv);
diff --git a/content/renderer/android/synchronous_layer_tree_frame_sink.cc b/content/renderer/android/synchronous_layer_tree_frame_sink.cc index eece5a8f..24c569e 100644 --- a/content/renderer/android/synchronous_layer_tree_frame_sink.cc +++ b/content/renderer/android/synchronous_layer_tree_frame_sink.cc
@@ -86,10 +86,12 @@ void BindFramebuffer() override {} void SetDrawRectangle(const gfx::Rect& rect) override {} void SwapBuffers(viz::OutputSurfaceFrame frame) override {} +#if BUILDFLAG(ENABLE_VULKAN) gpu::VulkanSurface* GetVulkanSurface() override { NOTIMPLEMENTED(); return nullptr; } +#endif void Reshape(const gfx::Size& size, float scale_factor, const gfx::ColorSpace& color_space,
diff --git a/content/renderer/media/webrtc/media_stream_remote_video_source.cc b/content/renderer/media/webrtc/media_stream_remote_video_source.cc index 44dac7b..0e810df 100644 --- a/content/renderer/media/webrtc/media_stream_remote_video_source.cc +++ b/content/renderer/media/webrtc/media_stream_remote_video_source.cc
@@ -160,6 +160,23 @@ const_cast<uint8_t*>(yuv_buffer->DataV()), elapsed_timestamp); break; } + case webrtc::VideoFrameBuffer::Type::kI010: { + webrtc::I010BufferInterface* yuv_buffer = buffer->GetI010(); + // WebRTC defines I010 data as uint16 whereas Chromium uses uint8 for all + // video formats, so conversion and cast is needed. + video_frame = media::VideoFrame::WrapExternalYuvData( + media::PIXEL_FORMAT_YUV420P10, size, gfx::Rect(size), size, + yuv_buffer->StrideY() * 2, yuv_buffer->StrideU() * 2, + yuv_buffer->StrideV() * 2, + const_cast<uint8_t*>( + reinterpret_cast<const uint8_t*>(yuv_buffer->DataY())), + const_cast<uint8_t*>( + reinterpret_cast<const uint8_t*>(yuv_buffer->DataU())), + const_cast<uint8_t*>( + reinterpret_cast<const uint8_t*>(yuv_buffer->DataV())), + elapsed_timestamp); + break; + } default: NOTREACHED(); }
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc index cea3cbe..af63abe 100644 --- a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc +++ b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
@@ -636,160 +636,6 @@ RTCStatsCollectorCallbackImpl::Create(main_thread, std::move(callback))); } -class PeerConnectionUMAObserver : public webrtc::UMAObserver { - public: - PeerConnectionUMAObserver() {} - ~PeerConnectionUMAObserver() override {} - void IncrementEnumCounter(webrtc::PeerConnectionEnumCounterType counter_type, - int counter, - int counter_max) override { - switch (counter_type) { - case webrtc::kEnumCounterAddressFamily: - UMA_HISTOGRAM_EXACT_LINEAR("WebRTC.PeerConnection.IPMetrics", counter, - counter_max); - break; - case webrtc::kEnumCounterIceCandidatePairTypeUdp: - UMA_HISTOGRAM_EXACT_LINEAR( - "WebRTC.PeerConnection.CandidatePairType_UDP", counter, - counter_max); - break; - case webrtc::kEnumCounterIceCandidatePairTypeTcp: - UMA_HISTOGRAM_EXACT_LINEAR( - "WebRTC.PeerConnection.CandidatePairType_TCP", counter, - counter_max); - break; - case webrtc::kEnumCounterDtlsHandshakeError: - UMA_HISTOGRAM_EXACT_LINEAR("WebRTC.PeerConnection.DtlsHandshakeError", - counter, counter_max); - break; - case webrtc::kEnumCounterIceRestart: - UMA_HISTOGRAM_EXACT_LINEAR("WebRTC.PeerConnection.IceRestartState", - counter, counter_max); - break; - case webrtc::kEnumCounterIceRegathering: - UMA_HISTOGRAM_EXACT_LINEAR("WebRTC.PeerConnection.IceRegatheringReason", - counter, counter_max); - break; - case webrtc::kEnumCounterKeyProtocol: - UMA_HISTOGRAM_ENUMERATION( - "WebRTC.PeerConnection.KeyProtocol", - static_cast<webrtc::KeyExchangeProtocolType>(counter), - webrtc::kEnumCounterKeyProtocolMax); - break; - case webrtc::kEnumCounterSdpSemanticNegotiated: - UMA_HISTOGRAM_ENUMERATION( - "WebRTC.PeerConnection.SdpSemanticNegotiated", - static_cast<webrtc::SdpSemanticNegotiated>(counter), - webrtc::kSdpSemanticNegotiatedMax); - break; - case webrtc::kEnumCounterKeyProtocolMediaType: - UMA_HISTOGRAM_ENUMERATION( - "WebRTC.PeerConnection.KeyProtocolByMedia", - static_cast<webrtc::KeyExchangeProtocolMedia>(counter), - webrtc::kEnumCounterKeyProtocolMediaTypeMax); - break; - case webrtc::kEnumCounterSdpFormatReceived: - UMA_HISTOGRAM_ENUMERATION( - "WebRTC.PeerConnection.SdpFormatReceived", - static_cast<webrtc::SdpFormatReceived>(counter), - webrtc::kSdpFormatReceivedMax); - break; - default: - // The default clause is expected to be reached when new enum types are - // added. Log, but only once. - { - static bool log_once = false; - LOG_IF(ERROR, !log_once) << "New WebRTC enum counter found: " - << static_cast<int>(counter_type); - log_once = true; - } - break; - } - } - - void IncrementSparseEnumCounter( - webrtc::PeerConnectionEnumCounterType counter_type, - int counter) override { - switch (counter_type) { - case webrtc::kEnumCounterAudioSrtpCipher: - base::UmaHistogramSparse("WebRTC.PeerConnection.SrtpCryptoSuite.Audio", - counter); - break; - case webrtc::kEnumCounterAudioSslCipher: - base::UmaHistogramSparse("WebRTC.PeerConnection.SslCipherSuite.Audio", - counter); - break; - case webrtc::kEnumCounterVideoSrtpCipher: - base::UmaHistogramSparse("WebRTC.PeerConnection.SrtpCryptoSuite.Video", - counter); - break; - case webrtc::kEnumCounterVideoSslCipher: - base::UmaHistogramSparse("WebRTC.PeerConnection.SslCipherSuite.Video", - counter); - break; - case webrtc::kEnumCounterDataSrtpCipher: - base::UmaHistogramSparse("WebRTC.PeerConnection.SrtpCryptoSuite.Data", - counter); - break; - case webrtc::kEnumCounterDataSslCipher: - base::UmaHistogramSparse("WebRTC.PeerConnection.SslCipherSuite.Data", - counter); - break; - case webrtc::kEnumCounterSrtpUnprotectError: - base::UmaHistogramSparse("WebRTC.PeerConnection.SrtpUnprotectError", - counter); - break; - case webrtc::kEnumCounterSrtcpUnprotectError: - base::UmaHistogramSparse("WebRTC.PeerConnection.SrtcpUnprotectError", - counter); - break; - case webrtc::kEnumCounterUsagePattern: - base::UmaHistogramSparse("WebRTC.PeerConnection.UsagePattern", counter); - break; - default: - // The default clause is expected to be reached when new enum types are - // added. Log, but only once. - { - static bool log_once = false; - LOG_IF(ERROR, !log_once) << "New WebRTC sparse enum counter found: " - << static_cast<int>(counter_type); - log_once = true; - } - break; - } - } - - void AddHistogramSample(webrtc::PeerConnectionUMAMetricsName type, - int value) override { - // Runs on libjingle's signaling thread. - switch (type) { - case webrtc::kTimeToConnect: - UMA_HISTOGRAM_MEDIUM_TIMES( - "WebRTC.PeerConnection.TimeToConnect", - base::TimeDelta::FromMilliseconds(value)); - break; - case webrtc::kNetworkInterfaces_IPv4: - UMA_HISTOGRAM_COUNTS_100("WebRTC.PeerConnection.IPv4Interfaces", - value); - break; - case webrtc::kNetworkInterfaces_IPv6: - UMA_HISTOGRAM_COUNTS_100("WebRTC.PeerConnection.IPv6Interfaces", - value); - break; - default: - // The default clause is expected to be reached when new enum types are - // added. Log, but only once. - { - static bool log_once = false; - LOG_IF(ERROR, !log_once) << "New WebRTC histogram counter found: " - << static_cast<int>(type); - log_once = true; - } - break; - } - } -}; - void ConvertOfferOptionsToWebrtcOfferOptions( const blink::WebRTCOfferOptions& options, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions* output) { @@ -1316,9 +1162,6 @@ options, frame_); } - uma_observer_ = new rtc::RefCountedObject<PeerConnectionUMAObserver>(); - native_peer_connection_->RegisterUMAObserver(uma_observer_.get()); - UMA_HISTOGRAM_ENUMERATION( "WebRTC.PeerConnection.SdpSemanticRequested", GetSdpSemanticRequested(server_configuration.sdp_semantics),
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler.h b/content/renderer/media/webrtc/rtc_peer_connection_handler.h index 0865b854..07562e8c 100644 --- a/content/renderer/media/webrtc/rtc_peer_connection_handler.h +++ b/content/renderer/media/webrtc/rtc_peer_connection_handler.h
@@ -300,7 +300,6 @@ // To make sure the observers are released after native_peer_connection_, // they have to come first. scoped_refptr<Observer> peer_connection_observer_; - scoped_refptr<webrtc::UMAObserver> uma_observer_; // |native_peer_connection_| is the libjingle native PeerConnection object. scoped_refptr<webrtc::PeerConnectionInterface> native_peer_connection_;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index cb17517..401eca8 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -483,7 +483,10 @@ } if (is_mac) { - deps += [ "//ui/accelerated_widget_mac" ] + deps += [ + "//sandbox/mac:seatbelt", + "//ui/accelerated_widget_mac", + ] } } @@ -1954,10 +1957,6 @@ if (is_mac) { sources += [ "../browser/media/capture/cursor_renderer_mac_unittest.mm" ] } - if (is_chromeos) { - sources += - [ "../browser/media/capture/desktop_capture_device_aura_unittest.cc" ] - } } if (is_linux) {
diff --git a/device/fido/fake_fido_discovery_unittest.cc b/device/fido/fake_fido_discovery_unittest.cc index 9858dcb..d3a8c37 100644 --- a/device/fido/fake_fido_discovery_unittest.cc +++ b/device/fido/fake_fido_discovery_unittest.cc
@@ -11,6 +11,7 @@ #include "base/test/scoped_task_environment.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" +#include "device/fido/fido_test_data.h" #include "device/fido/mock_fido_device.h" #include "device/fido/mock_fido_discovery_observer.h" #include "testing/gmock/include/gmock/gmock.h" @@ -117,8 +118,15 @@ auto device0 = std::make_unique<MockFidoDevice>(); EXPECT_CALL(*device0, GetId()).WillOnce(::testing::Return("device0")); - EXPECT_CALL(observer, DeviceAdded(&discovery, ::testing::_)); + device0->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, + test_data::kTestAuthenticatorGetInfoResponse); + base::RunLoop device0_done; + EXPECT_CALL(observer, DeviceAdded(&discovery, ::testing::_)) + .WillOnce(testing::InvokeWithoutArgs( + [&device0_done]() { device0_done.Quit(); })); discovery.AddDevice(std::move(device0)); + device0_done.Run(); ::testing::Mock::VerifyAndClearExpectations(&observer); EXPECT_CALL(observer, DiscoveryStarted(&discovery, true)); @@ -127,8 +135,15 @@ auto device1 = std::make_unique<MockFidoDevice>(); EXPECT_CALL(*device1, GetId()).WillOnce(::testing::Return("device1")); - EXPECT_CALL(observer, DeviceAdded(&discovery, ::testing::_)); + device1->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, + test_data::kTestAuthenticatorGetInfoResponse); + base::RunLoop device1_done; + EXPECT_CALL(observer, DeviceAdded(&discovery, ::testing::_)) + .WillOnce(testing::InvokeWithoutArgs( + [&device1_done]() { device1_done.Quit(); })); discovery.AddDevice(std::move(device1)); + device1_done.Run(); ::testing::Mock::VerifyAndClearExpectations(&observer); }
diff --git a/device/fido/fido_authenticator.h b/device/fido/fido_authenticator.h index 1eddfe5..258c9bf6 100644 --- a/device/fido/fido_authenticator.h +++ b/device/fido/fido_authenticator.h
@@ -16,7 +16,7 @@ namespace device { -class AuthenticatorSelectionCriteria; +class AuthenticatorSupportedOptions; class CtapGetAssertionRequest; class CtapMakeCredentialRequest; @@ -36,13 +36,13 @@ virtual ~FidoAuthenticator() = default; virtual void MakeCredential( - AuthenticatorSelectionCriteria authenticator_selection_criteria, CtapMakeCredentialRequest request, MakeCredentialCallback callback) = 0; virtual void GetAssertion(CtapGetAssertionRequest request, GetAssertionCallback callback) = 0; virtual void Cancel() = 0; virtual std::string GetId() const = 0; + virtual const AuthenticatorSupportedOptions& Options() const = 0; private: DISALLOW_COPY_AND_ASSIGN(FidoAuthenticator);
diff --git a/device/fido/fido_device.cc b/device/fido/fido_device.cc index 1646e652..e3f448c 100644 --- a/device/fido/fido_device.cc +++ b/device/fido/fido_device.cc
@@ -6,11 +6,56 @@ #include <utility> +#include "base/bind.h" +#include "base/stl_util.h" +#include "device/base/features.h" +#include "device/fido/ctap_empty_authenticator_request.h" +#include "device/fido/device_response_converter.h" +#include "device/fido/fido_constants.h" + namespace device { FidoDevice::FidoDevice() = default; FidoDevice::~FidoDevice() = default; +void FidoDevice::DiscoverSupportedProtocolAndDeviceInfo( + base::OnceClosure done) { + if (base::FeatureList::IsEnabled(kNewCtap2Device)) { + // Set the protocol version to CTAP2 for the purpose of sending the GetInfo + // request. The correct value will be set in the callback based on the + // device response. + supported_protocol_ = ProtocolVersion::kCtap; + DeviceTransact(AuthenticatorGetInfoRequest().Serialize(), + base::BindOnce(&FidoDevice::OnDeviceInfoReceived, + GetWeakPtr(), std::move(done))); + } else { + supported_protocol_ = ProtocolVersion::kU2f; + std::move(done).Run(); + } +} + +bool FidoDevice::SupportedProtocolIsInitialized() { + return (supported_protocol_ == ProtocolVersion::kU2f && !device_info_) || + (supported_protocol_ == ProtocolVersion::kCtap && device_info_); +} + +void FidoDevice::OnDeviceInfoReceived( + base::OnceClosure done, + base::Optional<std::vector<uint8_t>> response) { + state_ = FidoDevice::State::kReady; + + base::Optional<AuthenticatorGetInfoResponse> get_info_response = + response ? ReadCTAPGetInfoResponse(*response) : base::nullopt; + if (!get_info_response || !base::ContainsKey(get_info_response->versions(), + ProtocolVersion::kCtap)) { + supported_protocol_ = ProtocolVersion::kU2f; + } else { + supported_protocol_ = ProtocolVersion::kCtap; + device_info_ = std::move(*get_info_response); + } + std::move(done).Run(); +} + void FidoDevice::SetDeviceInfo(AuthenticatorGetInfoResponse device_info) { device_info_ = std::move(device_info); }
diff --git a/device/fido/fido_device.h b/device/fido/fido_device.h index 28ffef7..defeec5 100644 --- a/device/fido/fido_device.h +++ b/device/fido/fido_device.h
@@ -21,6 +21,11 @@ namespace device { // Device abstraction for an individual CTAP1.0/CTAP2.0 device. +// +// Devices are instantiated with an unknown protocol version. Users should call +// |DiscoverSupportedProtocolAndDeviceInfo| to determine a device's +// capabilities and initialize the instance accordingly. Instances returned by +// |FidoDiscovery| are already fully initialized. class COMPONENT_EXPORT(DEVICE_FIDO) FidoDevice { public: using WinkCallback = base::OnceClosure; @@ -41,11 +46,18 @@ virtual void Cancel() = 0; virtual std::string GetId() const = 0; - void SetDeviceInfo(AuthenticatorGetInfoResponse device_info); + // Sends a speculative AuthenticatorGetInfo request to determine whether the + // device supports the CTAP2 protocol, and initializes supported_protocol_ + // and device_info_ according to the result (unless the + // device::kNewCtap2Device feature is off, in which case U2F is assumed). + void DiscoverSupportedProtocolAndDeviceInfo(base::OnceClosure done); + // Returns whether supported_protocol has been correctly initialized (usually + // by calling DiscoverSupportedProtocolAndDeviceInfo). + bool SupportedProtocolIsInitialized(); + // TODO(martinkr): Rename to "SetSupportedProtocolForTesting". void set_supported_protocol(ProtocolVersion supported_protocol) { supported_protocol_ = supported_protocol; } - void set_state(State state) { state_ = state; } ProtocolVersion supported_protocol() const { return supported_protocol_; } const base::Optional<AuthenticatorGetInfoResponse>& device_info() const { @@ -56,6 +68,10 @@ protected: virtual base::WeakPtr<FidoDevice> GetWeakPtr() = 0; + void OnDeviceInfoReceived(base::OnceClosure done, + base::Optional<std::vector<uint8_t>> response); + void SetDeviceInfo(AuthenticatorGetInfoResponse device_info); + State state_ = State::kInit; ProtocolVersion supported_protocol_ = ProtocolVersion::kUnknown; base::Optional<AuthenticatorGetInfoResponse> device_info_;
diff --git a/device/fido/fido_device_authenticator.cc b/device/fido/fido_device_authenticator.cc index c8aa469..93071ce 100644 --- a/device/fido/fido_device_authenticator.cc +++ b/device/fido/fido_device_authenticator.cc
@@ -6,7 +6,8 @@ #include <utility> -#include "device/fido/authenticator_selection_criteria.h" +#include "base/logging.h" +#include "device/fido/authenticator_supported_options.h" #include "device/fido/ctap_get_assertion_request.h" #include "device/fido/ctap_make_credential_request.h" #include "device/fido/fido_device.h" @@ -16,19 +17,18 @@ namespace device { FidoDeviceAuthenticator::FidoDeviceAuthenticator(FidoDevice* device) - : device_(device) {} + : device_(device) { + DCHECK(device_->SupportedProtocolIsInitialized()); +} FidoDeviceAuthenticator::~FidoDeviceAuthenticator() = default; -void FidoDeviceAuthenticator::MakeCredential( - AuthenticatorSelectionCriteria authenticator_selection_criteria, - CtapMakeCredentialRequest request, - MakeCredentialCallback callback) { +void FidoDeviceAuthenticator::MakeCredential(CtapMakeCredentialRequest request, + MakeCredentialCallback callback) { DCHECK(!task_); // TODO(martinkr): Change FidoTasks to take all request parameters by const // reference, so we can avoid copying these from the RequestHandler. - task_ = std::make_unique<MakeCredentialTask>( - device_, std::move(request), std::move(authenticator_selection_criteria), - std::move(callback)); + task_ = std::make_unique<MakeCredentialTask>(device_, std::move(request), + std::move(callback)); } void FidoDeviceAuthenticator::GetAssertion(CtapGetAssertionRequest request, @@ -48,6 +48,21 @@ return device_->GetId(); } +const AuthenticatorSupportedOptions& FidoDeviceAuthenticator::Options() const { + static const AuthenticatorSupportedOptions default_options; + switch (device_->supported_protocol()) { + case ProtocolVersion::kU2f: + return default_options; + case ProtocolVersion::kCtap: + DCHECK(device_->device_info()) << "uninitialized device"; + return device_->device_info()->options(); + case ProtocolVersion::kUnknown: + NOTREACHED() << "uninitialized device"; + } + NOTREACHED(); + return default_options; +} + void FidoDeviceAuthenticator::SetTaskForTesting( std::unique_ptr<FidoTask> task) { task_ = std::move(task);
diff --git a/device/fido/fido_device_authenticator.h b/device/fido/fido_device_authenticator.h index 29db9d81..ec62fef 100644 --- a/device/fido/fido_device_authenticator.h +++ b/device/fido/fido_device_authenticator.h
@@ -15,7 +15,6 @@ namespace device { -class AuthenticatorSelectionCriteria; class CtapGetAssertionRequest; class CtapMakeCredentialRequest; class FidoDevice; @@ -32,13 +31,13 @@ // FidoAuthenticator: void MakeCredential( - AuthenticatorSelectionCriteria authenticator_selection_criteria, CtapMakeCredentialRequest request, MakeCredentialCallback callback) override; void GetAssertion(CtapGetAssertionRequest request, GetAssertionCallback callback) override; void Cancel() override; std::string GetId() const override; + const AuthenticatorSupportedOptions& Options() const override; protected: void OnCtapMakeCredentialResponseReceived(
diff --git a/device/fido/fido_discovery.cc b/device/fido/fido_discovery.cc index 299bbf05..98d4f67 100644 --- a/device/fido/fido_discovery.cc +++ b/device/fido/fido_discovery.cc
@@ -6,6 +6,7 @@ #include <utility> +#include "base/bind.h" #include "build/build_config.h" #include "device/fido/fido_ble_discovery.h" #include "device/fido/fido_device.h" @@ -67,7 +68,7 @@ } FidoDiscovery::FidoDiscovery(FidoTransportProtocol transport) - : transport_(transport) {} + : transport_(transport), weak_factory_(this) {} FidoDiscovery::~FidoDiscovery() = default; @@ -132,9 +133,15 @@ bool FidoDiscovery::AddDevice(std::unique_ptr<FidoDevice> device) { std::string device_id = device->GetId(); const auto result = devices_.emplace(std::move(device_id), std::move(device)); - if (result.second) - NotifyDeviceAdded(result.first->second.get()); - return result.second; + if (!result.second) { + return false; // Duplicate device id. + } + FidoDevice* device_ptr = result.first->second.get(); + // Determine the device protocol version before notifying observers. + device_ptr->DiscoverSupportedProtocolAndDeviceInfo( + base::BindOnce(&FidoDiscovery::NotifyDeviceAdded, + weak_factory_.GetWeakPtr(), device_ptr)); + return true; } bool FidoDiscovery::RemoveDevice(base::StringPiece device_id) {
diff --git a/device/fido/fido_discovery.h b/device/fido/fido_discovery.h index a3c31b5..68aadcc9 100644 --- a/device/fido/fido_discovery.h +++ b/device/fido/fido_discovery.h
@@ -49,6 +49,11 @@ // before the client of FidoDiscovery calls FidoDiscovery::Start(). However, // for devices already known to the system at that point, DeviceAdded() // might already be called to reported already known devices. + // + // The supplied FidoDevice instance is guaranteed to have its protocol + // version initialized. I.e., FidoDiscovery calls + // FidoDevice::DiscoverSupportedProtocolAndDeviceInfo() before notifying + // the Observer. virtual void DeviceAdded(FidoDiscovery* discovery, FidoDevice* device) = 0; virtual void DeviceRemoved(FidoDiscovery* discovery, FidoDevice* device) = 0; @@ -112,6 +117,7 @@ const FidoTransportProtocol transport_; State state_ = State::kIdle; + base::WeakPtrFactory<FidoDiscovery> weak_factory_; DISALLOW_COPY_AND_ASSIGN(FidoDiscovery); };
diff --git a/device/fido/fido_discovery_unittest.cc b/device/fido/fido_discovery_unittest.cc index 51b873e..922c559 100644 --- a/device/fido/fido_discovery_unittest.cc +++ b/device/fido/fido_discovery_unittest.cc
@@ -7,6 +7,9 @@ #include <utility> #include "base/macros.h" +#include "base/run_loop.h" +#include "base/test/scoped_task_environment.h" +#include "device/fido/fido_test_data.h" #include "device/fido/mock_fido_device.h" #include "device/fido/mock_fido_discovery_observer.h" #include "testing/gmock/include/gmock/gmock.h" @@ -90,6 +93,7 @@ } TEST(FidoDiscoveryTest, TestAddRemoveDevices) { + base::test::ScopedTaskEnvironment scoped_task_environment_; ConcreteFidoDiscovery discovery(FidoTransportProtocol::kBluetoothLowEnergy); MockFidoDiscoveryObserver observer; discovery.set_observer(&observer); @@ -98,18 +102,37 @@ // Expect successful insertion. auto device0 = std::make_unique<MockFidoDevice>(); auto* device0_raw = device0.get(); - EXPECT_CALL(observer, DeviceAdded(&discovery, device0_raw)); + device0->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, + test_data::kTestAuthenticatorGetInfoResponse); + base::RunLoop device0_done; + EXPECT_CALL(observer, DeviceAdded(&discovery, device0_raw)) + .WillOnce(testing::InvokeWithoutArgs( + [&device0_done]() { device0_done.Quit(); })); EXPECT_CALL(*device0, GetId()).WillOnce(Return("device0")); EXPECT_TRUE(discovery.AddDevice(std::move(device0))); + device0_done.Run(); ::testing::Mock::VerifyAndClearExpectations(&observer); + // Device should have been initialized as a CTAP device. + EXPECT_EQ(ProtocolVersion::kCtap, device0_raw->supported_protocol()); + EXPECT_TRUE(device0_raw->device_info()); - // // Expect successful insertion. + // Expect successful insertion. + base::RunLoop device1_done; auto device1 = std::make_unique<MockFidoDevice>(); auto* device1_raw = device1.get(); - EXPECT_CALL(observer, DeviceAdded(&discovery, device1_raw)); + device1->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, base::nullopt); + EXPECT_CALL(observer, DeviceAdded(&discovery, device1_raw)) + .WillOnce(testing::InvokeWithoutArgs( + [&device1_done]() { device1_done.Quit(); })); EXPECT_CALL(*device1, GetId()).WillOnce(Return("device1")); EXPECT_TRUE(discovery.AddDevice(std::move(device1))); + device1_done.Run(); ::testing::Mock::VerifyAndClearExpectations(&observer); + // Device should have been initialized as a U2F device. + EXPECT_EQ(ProtocolVersion::kU2f, device1_raw->supported_protocol()); + EXPECT_FALSE(device1_raw->device_info()); // Inserting a device with an already present id should be prevented. auto device1_dup = std::make_unique<MockFidoDevice>();
diff --git a/device/fido/fido_request_handler_base.cc b/device/fido/fido_request_handler_base.cc index 09a7905..7adbfdd 100644 --- a/device/fido/fido_request_handler_base.cc +++ b/device/fido/fido_request_handler_base.cc
@@ -92,10 +92,6 @@ void FidoRequestHandlerBase::DeviceAdded(FidoDiscovery* discovery, FidoDevice* device) { DCHECK(!base::ContainsKey(active_authenticators(), device->GetId())); - // All devices are initially assumed to support CTAP protocol and thus - // AuthenticatorGetInfo command is sent to all connected devices. If device - // errors out, then it is assumed to support U2F protocol. - device->set_supported_protocol(ProtocolVersion::kCtap); AddAuthenticator(CreateAuthenticatorFromDevice(device)); }
diff --git a/device/fido/fido_request_handler_unittest.cc b/device/fido/fido_request_handler_unittest.cc index a8fddbe0..c497d0a 100644 --- a/device/fido/fido_request_handler_unittest.cc +++ b/device/fido/fido_request_handler_unittest.cc
@@ -180,6 +180,8 @@ discovery()->WaitForCallToStartAndSimulateSuccess(); auto device = std::make_unique<MockFidoDevice>(); + device->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, base::nullopt); EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device0")); // Device returns success response. device->ExpectRequestAndRespondWith(std::vector<uint8_t>(), @@ -200,12 +202,16 @@ discovery()->WaitForCallToStartAndSimulateSuccess(); auto device0 = std::make_unique<MockFidoDevice>(); - device0->set_supported_protocol(ProtocolVersion::kCtap); + device0->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, + test_data::kTestAuthenticatorGetInfoResponse); EXPECT_CALL(*device0, GetId()).WillRepeatedly(testing::Return("device0")); device0->ExpectRequestAndDoNotRespond(std::vector<uint8_t>()); EXPECT_CALL(*device0, Cancel()); auto device1 = std::make_unique<MockFidoDevice>(); - device1->set_supported_protocol(ProtocolVersion::kCtap); + device1->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, + test_data::kTestAuthenticatorGetInfoResponse); EXPECT_CALL(*device1, GetId()).WillRepeatedly(testing::Return("device1")); device1->ExpectRequestAndDoNotRespond(std::vector<uint8_t>()); EXPECT_CALL(*device1, Cancel()); @@ -224,7 +230,9 @@ // Represents a connected device that hangs without a response. auto device0 = std::make_unique<MockFidoDevice>(); - device0->set_supported_protocol(ProtocolVersion::kCtap); + device0->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, + test_data::kTestAuthenticatorGetInfoResponse); EXPECT_CALL(*device0, GetId()).WillRepeatedly(testing::Return("device0")); // Device is unresponsive and cancel command is invoked afterwards. device0->ExpectRequestAndDoNotRespond(std::vector<uint8_t>()); @@ -232,7 +240,9 @@ // Represents a connected device that response successfully. auto device1 = std::make_unique<MockFidoDevice>(); - device1->set_supported_protocol(ProtocolVersion::kCtap); + device1->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, + test_data::kTestAuthenticatorGetInfoResponse); EXPECT_CALL(*device1, GetId()).WillRepeatedly(testing::Return("device1")); device1->ExpectRequestAndRespondWith(std::vector<uint8_t>(), CreateFakeSuccessDeviceResponse()); @@ -255,7 +265,9 @@ // Represents a connected device that responds successfully after small time // delay. auto device0 = std::make_unique<MockFidoDevice>(); - device0->set_supported_protocol(ProtocolVersion::kCtap); + device0->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, + test_data::kTestAuthenticatorGetInfoResponse); EXPECT_CALL(*device0, GetId()).WillRepeatedly(testing::Return("device0")); device0->ExpectRequestAndRespondWith(std::vector<uint8_t>(), CreateFakeSuccessDeviceResponse(), @@ -264,7 +276,9 @@ // Represents a device that returns a success response after a longer time // delay. auto device1 = std::make_unique<MockFidoDevice>(); - device1->set_supported_protocol(ProtocolVersion::kCtap); + device1->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, + test_data::kTestAuthenticatorGetInfoResponse); EXPECT_CALL(*device1, GetId()).WillRepeatedly(testing::Return("device1")); device1->ExpectRequestAndRespondWith(std::vector<uint8_t>(), CreateFakeSuccessDeviceResponse(), @@ -294,6 +308,9 @@ // Represents a connected device that immediately responds with a processing // error. auto device0 = std::make_unique<MockFidoDevice>(); + device0->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, + test_data::kTestAuthenticatorGetInfoResponse); EXPECT_CALL(*device0, GetId()).WillRepeatedly(testing::Return("device0")); device0->ExpectRequestAndRespondWith(std::vector<uint8_t>(), CreateFakeDeviceProcesssingError()); @@ -301,6 +318,9 @@ // Represents a device that returns an UP verified failure response after a // small time delay. auto device1 = std::make_unique<MockFidoDevice>(); + device1->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, + test_data::kTestAuthenticatorGetInfoResponse); EXPECT_CALL(*device1, GetId()).WillRepeatedly(testing::Return("device1")); device1->ExpectRequestAndRespondWith(std::vector<uint8_t>(), CreateFakeUserPresenceVerifiedError(), @@ -309,7 +329,9 @@ // Represents a device that returns an UP verified failure response after a // big time delay. auto device2 = std::make_unique<MockFidoDevice>(); - device2->set_supported_protocol(ProtocolVersion::kCtap); + device2->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, + test_data::kTestAuthenticatorGetInfoResponse); EXPECT_CALL(*device2, GetId()).WillRepeatedly(testing::Return("device2")); device2->ExpectRequestAndRespondWith(std::vector<uint8_t>(), CreateFakeDeviceProcesssingError(), @@ -333,7 +355,7 @@ // A platform authenticator usually wouldn't usually use a FidoDevice, but // that's not the point of the test here. The test is only trying to ensure // the authenticator gets injected and used. - auto device = std::make_unique<MockFidoDevice>(); + auto device = MockFidoDevice::MakeCtap(); EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device0")); // Device returns success response. device->ExpectRequestAndRespondWith(std::vector<uint8_t>(),
diff --git a/device/fido/fido_task.cc b/device/fido/fido_task.cc index 5debc7c..80ba6505 100644 --- a/device/fido/fido_task.cc +++ b/device/fido/fido_task.cc
@@ -9,14 +9,13 @@ #include "base/bind.h" #include "base/stl_util.h" #include "base/threading/sequenced_task_runner_handle.h" -#include "device/fido/ctap_empty_authenticator_request.h" -#include "device/fido/device_response_converter.h" #include "device/fido/fido_constants.h" namespace device { FidoTask::FidoTask(FidoDevice* device) : device_(device), weak_factory_(this) { DCHECK(device_); + DCHECK(device_->SupportedProtocolIsInitialized()); base::SequencedTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(&FidoTask::StartTask, weak_factory_.GetWeakPtr())); @@ -31,35 +30,4 @@ device()->Cancel(); } -void FidoTask::GetAuthenticatorInfo(base::OnceClosure ctap_callback, - base::OnceClosure u2f_callback) { - // When AuthenticatorInfo command is sent to authenticators, we first assume - // that the connected device is a CTAP2 device. - device_->set_supported_protocol(ProtocolVersion::kCtap); - device()->DeviceTransact( - AuthenticatorGetInfoRequest().Serialize(), - base::BindOnce(&FidoTask::OnAuthenticatorInfoReceived, - weak_factory_.GetWeakPtr(), std::move(ctap_callback), - std::move(u2f_callback))); -} - -void FidoTask::OnAuthenticatorInfoReceived( - base::OnceClosure ctap_callback, - base::OnceClosure u2f_callback, - base::Optional<std::vector<uint8_t>> response) { - device()->set_state(FidoDevice::State::kReady); - - base::Optional<AuthenticatorGetInfoResponse> get_info_response; - if (!response || !(get_info_response = ReadCTAPGetInfoResponse(*response)) || - !base::ContainsKey(get_info_response->versions(), - ProtocolVersion::kCtap)) { - device()->set_supported_protocol(ProtocolVersion::kU2f); - std::move(u2f_callback).Run(); - return; - } - - device()->SetDeviceInfo(std::move(*get_info_response)); - std::move(ctap_callback).Run(); -} - } // namespace device
diff --git a/device/fido/fido_task.h b/device/fido/fido_task.h index 773b145b..b2ca94b 100644 --- a/device/fido/fido_task.h +++ b/device/fido/fido_task.h
@@ -13,7 +13,6 @@ #include "base/component_export.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "device/fido/fido_device.h" namespace device { @@ -42,27 +41,12 @@ // Asynchronously initiates CTAP request operation for a single device. virtual void StartTask() = 0; - // Invokes the AuthenticatorGetInfo method on |device_|. If successful and a - // well formed response is received, then |device_| is deemed to support CTAP - // protocol and |ctap_callback| is invoked, which sends CBOR encoded command - // to the authenticator. For all failure cases, |device_| is assumed to - // support the U2F protocol as FidoDiscovery selects only devices that support - // either the U2F or CTAP protocols during discovery. Therefore |u2f_callback| - // is invoked, which sends APDU encoded request to authenticator. - void GetAuthenticatorInfo(base::OnceClosure ctap_callback, - base::OnceClosure u2f_callback); - FidoDevice* device() const { DCHECK(device_); return device_; } private: - void OnAuthenticatorInfoReceived( - base::OnceClosure ctap_callback, - base::OnceClosure u2f_callback, - base::Optional<std::vector<uint8_t>> response); - FidoDevice* const device_; base::WeakPtrFactory<FidoTask> weak_factory_;
diff --git a/device/fido/get_assertion_handler_unittest.cc b/device/fido/get_assertion_handler_unittest.cc index c97955e..ed8267e 100644 --- a/device/fido/get_assertion_handler_unittest.cc +++ b/device/fido/get_assertion_handler_unittest.cc
@@ -38,19 +38,24 @@ } std::unique_ptr<GetAssertionRequestHandler> CreateGetAssertionHandler() { - ForgeNextHidDiscovery(); - - CtapGetAssertionRequest request_param(test_data::kRelyingPartyId, - test_data::kClientDataHash); - request_param.SetAllowList( + CtapGetAssertionRequest request(test_data::kRelyingPartyId, + test_data::kClientDataHash); + request.SetAllowList( {{CredentialType::kPublicKey, fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle)}}); + return CreateGetAssertionHandlerWithRequest(std::move(request)); + } + + std::unique_ptr<GetAssertionRequestHandler> + CreateGetAssertionHandlerWithRequest(CtapGetAssertionRequest request) { + ForgeNextHidDiscovery(); + return std::make_unique<GetAssertionRequestHandler>( nullptr /* connector */, base::flat_set<FidoTransportProtocol>( {FidoTransportProtocol::kUsbHumanInterfaceDevice}), - std::move(request_param), get_assertion_cb_.callback()); + std::move(request), get_assertion_cb_.callback()); } void InitFeatureListAndDisableCtapFlag() { @@ -138,4 +143,47 @@ EXPECT_TRUE(request_handler->is_complete()); } +TEST_F(FidoGetAssertionHandlerTest, TestIncompatibleUserVerificationSetting) { + auto request = CtapGetAssertionRequest(test_data::kRelyingPartyId, + test_data::kClientDataHash); + request.SetUserVerification(UserVerificationRequirement::kRequired); + auto request_handler = + CreateGetAssertionHandlerWithRequest(std::move(request)); + discovery()->WaitForCallToStartAndSimulateSuccess(); + + auto device = std::make_unique<MockFidoDevice>(); + EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device0")); + device->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, + test_data::kTestGetInfoResponseWithoutUvSupport); + + discovery()->AddDevice(std::move(device)); + + scoped_task_environment_.FastForwardUntilNoTasksRemain(); + EXPECT_FALSE(get_assertion_callback().was_called()); +} + +TEST_F(FidoGetAssertionHandlerTest, + TestU2fSignRequestWithUserVerificationRequired) { + auto request = CtapGetAssertionRequest(test_data::kRelyingPartyId, + test_data::kClientDataHash); + request.SetAllowList( + {{CredentialType::kPublicKey, + fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle)}}); + request.SetUserVerification(UserVerificationRequirement::kRequired); + auto request_handler = + CreateGetAssertionHandlerWithRequest(std::move(request)); + discovery()->WaitForCallToStartAndSimulateSuccess(); + + auto device = std::make_unique<MockFidoDevice>(); + EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device0")); + device->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, base::nullopt); + + discovery()->AddDevice(std::move(device)); + + scoped_task_environment_.FastForwardUntilNoTasksRemain(); + EXPECT_FALSE(get_assertion_callback().was_called()); +} + } // namespace device
diff --git a/device/fido/get_assertion_request_handler.cc b/device/fido/get_assertion_request_handler.cc index 6e9ce8f5..dcf5aa0 100644 --- a/device/fido/get_assertion_request_handler.cc +++ b/device/fido/get_assertion_request_handler.cc
@@ -51,10 +51,54 @@ GetAssertionRequestHandler::~GetAssertionRequestHandler() = default; +namespace { + +// Checks UserVerificationRequirement enum passed from the relying party is +// compatible with the authenticator, and updates the request to the +// "effective" user verification requirement. +// https://w3c.github.io/webauthn/#effective-user-verification-requirement-for-assertion +bool CheckUserVerificationCompatible(FidoAuthenticator* authenticator, + CtapGetAssertionRequest* request) { + const auto uv_availability = + authenticator->Options().user_verification_availability(); + + switch (request->user_verification()) { + case UserVerificationRequirement::kRequired: + return uv_availability == + AuthenticatorSupportedOptions::UserVerificationAvailability:: + kSupportedAndConfigured; + + case UserVerificationRequirement::kDiscouraged: + return true; + + case UserVerificationRequirement::kPreferred: + if (uv_availability == + AuthenticatorSupportedOptions::UserVerificationAvailability:: + kSupportedAndConfigured) { + request->SetUserVerification(UserVerificationRequirement::kRequired); + } else { + request->SetUserVerification(UserVerificationRequirement::kDiscouraged); + } + return true; + } + + NOTREACHED(); + return false; +} + +} // namespace + void GetAssertionRequestHandler::DispatchRequest( FidoAuthenticator* authenticator) { + // The user verification field of the request may be adjusted to the + // authenticator, so we need to make a copy. + CtapGetAssertionRequest request_copy = request_; + if (!CheckUserVerificationCompatible(authenticator, &request_copy)) { + return; + } + authenticator->GetAssertion( - request_, + std::move(request_copy), base::BindOnce(&GetAssertionRequestHandler::OnAuthenticatorResponse, weak_factory_.GetWeakPtr(), authenticator)); }
diff --git a/device/fido/get_assertion_task.cc b/device/fido/get_assertion_task.cc index 7cae6313..e381b64 100644 --- a/device/fido/get_assertion_task.cc +++ b/device/fido/get_assertion_task.cc
@@ -43,23 +43,15 @@ GetAssertionTask::~GetAssertionTask() = default; void GetAssertionTask::StartTask() { - if (base::FeatureList::IsEnabled(kNewCtap2Device)) { - GetAuthenticatorInfo( - base::BindOnce(&GetAssertionTask::GetAssertion, - weak_factory_.GetWeakPtr()), - base::BindOnce(&GetAssertionTask::U2fSign, weak_factory_.GetWeakPtr())); + if (base::FeatureList::IsEnabled(kNewCtap2Device) && + device()->supported_protocol() == ProtocolVersion::kCtap) { + GetAssertion(); } else { U2fSign(); } } void GetAssertionTask::GetAssertion() { - if (!CheckUserVerificationCompatible()) { - std::move(callback_).Run(CtapDeviceResponseCode::kCtap2ErrOther, - base::nullopt); - return; - } - sign_operation_ = std::make_unique<Ctap2DeviceOperation<CtapGetAssertionRequest, AuthenticatorGetAssertionResponse>>( @@ -72,13 +64,7 @@ void GetAssertionTask::U2fSign() { DCHECK(!device()->device_info()); - device()->set_supported_protocol(ProtocolVersion::kU2f); - - if (!CheckUserVerificationCompatible()) { - std::move(callback_).Run(CtapDeviceResponseCode::kCtap2ErrOther, - base::nullopt); - return; - } + DCHECK_EQ(ProtocolVersion::kU2f, device()->supported_protocol()); sign_operation_ = std::make_unique<U2fSignOperation>( device(), request_, @@ -134,6 +120,8 @@ return; } + // TODO(martinkr): CheckRpIdHash invocation needs to move into the Request + // handler. See https://crbug.com/863988. if (!device_response || !device_response->CheckRpIdHash(request_.rp_id()) || !CheckRequirementsOnReturnedCredentialId(*device_response) || !CheckRequirementsOnReturnedUserEntities(*device_response)) { @@ -145,37 +133,4 @@ std::move(callback_).Run(response_code, std::move(device_response)); } -bool GetAssertionTask::CheckUserVerificationCompatible() { - if (!device()->device_info()) { - return request_.user_verification() != - UserVerificationRequirement::kRequired; - } - - const auto uv_availability = - device()->device_info()->options().user_verification_availability(); - - switch (request_.user_verification()) { - case UserVerificationRequirement::kRequired: - return uv_availability == - AuthenticatorSupportedOptions::UserVerificationAvailability:: - kSupportedAndConfigured; - - case UserVerificationRequirement::kDiscouraged: - return true; - - case UserVerificationRequirement::kPreferred: - if (uv_availability == - AuthenticatorSupportedOptions::UserVerificationAvailability:: - kSupportedAndConfigured) { - request_.SetUserVerification(UserVerificationRequirement::kRequired); - } else { - request_.SetUserVerification(UserVerificationRequirement::kDiscouraged); - } - return true; - } - - NOTREACHED(); - return false; -} - } // namespace device
diff --git a/device/fido/get_assertion_task.h b/device/fido/get_assertion_task.h index cc8d666..b993d84 100644 --- a/device/fido/get_assertion_task.h +++ b/device/fido/get_assertion_task.h
@@ -67,17 +67,6 @@ bool CheckRequirementsOnReturnedCredentialId( const AuthenticatorGetAssertionResponse& response); - // Checks UserVerificationRequirement enum passed from the relying party - // is compatible with the authenticator using the following logic: - // - If UserVerificationRequirement is set to kRequired, user verification - // option parameter should be set to true. - // - If UserVerificationRequirement is set to kPreferred, user verification - // option is set to true only if the authenticator supports UV. - // - If UserVerificationRequirement is set to kDiscouraged, user verification - // is set to false. - // https://w3c.github.io/webauthn/#enumdef-userverificationrequirement - bool CheckUserVerificationCompatible(); - void OnCtapGetAssertionResponseReceived( CtapDeviceResponseCode response_code, base::Optional<AuthenticatorGetAssertionResponse> device_response);
diff --git a/device/fido/get_assertion_task_unittest.cc b/device/fido/get_assertion_task_unittest.cc index fbc5792..87599e5 100644 --- a/device/fido/get_assertion_task_unittest.cc +++ b/device/fido/get_assertion_task_unittest.cc
@@ -17,6 +17,7 @@ #include "device/base/features.h" #include "device/fido/authenticator_get_assertion_response.h" #include "device/fido/ctap_get_assertion_request.h" +#include "device/fido/device_response_converter.h" #include "device/fido/fido_constants.h" #include "device/fido/fido_parsing_utils.h" #include "device/fido/fido_test_data.h" @@ -29,7 +30,6 @@ using ::testing::_; namespace device { - namespace { using TestGetAssertionTaskCallbackReceiver = @@ -37,13 +37,9 @@ CtapDeviceResponseCode, base::Optional<AuthenticatorGetAssertionResponse>>; -} // namespace - class FidoGetAssertionTaskTest : public testing::Test { public: - FidoGetAssertionTaskTest() { - scoped_feature_list_.emplace(); - } + FidoGetAssertionTaskTest() { scoped_feature_list_.emplace(); } TestGetAssertionTaskCallbackReceiver& get_assertion_callback_receiver() { return cb_; @@ -61,10 +57,7 @@ }; TEST_F(FidoGetAssertionTaskTest, TestGetAssertionSuccess) { - auto device = std::make_unique<MockFidoDevice>(); - device->ExpectCtap2CommandAndRespondWith( - CtapRequestCommand::kAuthenticatorGetInfo, - test_data::kTestAuthenticatorGetInfoResponse); + auto device = MockFidoDevice::MakeCtap(); device->ExpectCtap2CommandAndRespondWith( CtapRequestCommand::kAuthenticatorGetAssertion, test_data::kTestGetAssertionResponse); @@ -83,14 +76,10 @@ EXPECT_EQ(CtapDeviceResponseCode::kSuccess, get_assertion_callback_receiver().status()); EXPECT_TRUE(get_assertion_callback_receiver().value()); - EXPECT_EQ(device->supported_protocol(), ProtocolVersion::kCtap); - EXPECT_TRUE(device->device_info()); } TEST_F(FidoGetAssertionTaskTest, TestU2fSignSuccess) { - auto device = std::make_unique<MockFidoDevice>(); - device->ExpectCtap2CommandAndRespondWith( - CtapRequestCommand::kAuthenticatorGetInfo, base::nullopt); + auto device = MockFidoDevice::MakeU2f(); device->ExpectRequestAndRespondWith( test_data::kU2fCheckOnlySignCommandApdu, test_data::kApduEncodedNoErrorSignResponse); @@ -112,8 +101,6 @@ EXPECT_EQ(CtapDeviceResponseCode::kSuccess, get_assertion_callback_receiver().status()); EXPECT_TRUE(get_assertion_callback_receiver().value()); - EXPECT_EQ(device->supported_protocol(), ProtocolVersion::kU2f); - EXPECT_FALSE(device->device_info()); } TEST_F(FidoGetAssertionTaskTest, TestSignSuccessWithFake) { @@ -133,6 +120,9 @@ std::move(private_key), fido_parsing_utils::CreateSHA256Hash(test_data::kRelyingPartyId), 42 /* counter */)); + test::TestCallbackReceiver<> done; + device->DiscoverSupportedProtocolAndDeviceInfo(done.callback()); + done.WaitForCallback(); auto task = std::make_unique<GetAssertionTask>( device.get(), std::move(request_param), @@ -163,7 +153,7 @@ TEST_F(FidoGetAssertionTaskTest, TestU2fSignWithoutFlag) { RemoveCtapFlag(); - auto device = std::make_unique<MockFidoDevice>(); + auto device = MockFidoDevice::MakeU2f(); device->ExpectRequestAndRespondWith( test_data::kU2fCheckOnlySignCommandApdu, test_data::kApduEncodedNoErrorSignResponse); @@ -185,18 +175,12 @@ EXPECT_EQ(CtapDeviceResponseCode::kSuccess, get_assertion_callback_receiver().status()); EXPECT_TRUE(get_assertion_callback_receiver().value()); - EXPECT_EQ(device->supported_protocol(), ProtocolVersion::kU2f); - EXPECT_FALSE(device->device_info()); } // Tests a scenario where the authenticator responds with credential ID that // is not included in the allowed list. TEST_F(FidoGetAssertionTaskTest, TestGetAssertionInvalidCredential) { - auto device = std::make_unique<MockFidoDevice>(); - - device->ExpectCtap2CommandAndRespondWith( - CtapRequestCommand::kAuthenticatorGetInfo, - test_data::kTestAuthenticatorGetInfoResponse); + auto device = MockFidoDevice::MakeCtap(); device->ExpectCtap2CommandAndRespondWith( CtapRequestCommand::kAuthenticatorGetAssertion, test_data::kTestGetAssertionResponse); @@ -211,18 +195,12 @@ EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrOther, get_assertion_callback_receiver().status()); EXPECT_FALSE(get_assertion_callback_receiver().value()); - EXPECT_EQ(device->supported_protocol(), ProtocolVersion::kCtap); - EXPECT_TRUE(device->device_info()); } // Tests a scenario where authenticator responds without user entity in its // response but client is expecting a resident key credential. TEST_F(FidoGetAssertionTaskTest, TestGetAsserionIncorrectUserEntity) { - auto device = std::make_unique<MockFidoDevice>(); - - device->ExpectCtap2CommandAndRespondWith( - CtapRequestCommand::kAuthenticatorGetInfo, - test_data::kTestAuthenticatorGetInfoResponse); + auto device = MockFidoDevice::MakeCtap(); device->ExpectCtap2CommandAndRespondWith( CtapRequestCommand::kAuthenticatorGetAssertion, test_data::kTestGetAssertionResponse); @@ -234,19 +212,13 @@ get_assertion_callback_receiver().callback()); get_assertion_callback_receiver().WaitForCallback(); - EXPECT_EQ(device->supported_protocol(), ProtocolVersion::kCtap); - EXPECT_TRUE(device->device_info()); EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrOther, get_assertion_callback_receiver().status()); EXPECT_FALSE(get_assertion_callback_receiver().value()); } TEST_F(FidoGetAssertionTaskTest, TestGetAsserionIncorrectRpIdHash) { - auto device = std::make_unique<MockFidoDevice>(); - - device->ExpectCtap2CommandAndRespondWith( - CtapRequestCommand::kAuthenticatorGetInfo, - test_data::kTestAuthenticatorGetInfoResponse); + auto device = MockFidoDevice::MakeCtap(); device->ExpectCtap2CommandAndRespondWith( CtapRequestCommand::kAuthenticatorGetAssertion, test_data::kTestGetAssertionResponseWithIncorrectRpIdHash); @@ -258,19 +230,13 @@ get_assertion_callback_receiver().callback()); get_assertion_callback_receiver().WaitForCallback(); - EXPECT_EQ(device->supported_protocol(), ProtocolVersion::kCtap); - EXPECT_TRUE(device->device_info()); EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrOther, get_assertion_callback_receiver().status()); EXPECT_FALSE(get_assertion_callback_receiver().value()); } TEST_F(FidoGetAssertionTaskTest, TestIncorrectGetAssertionResponse) { - auto device = std::make_unique<MockFidoDevice>(); - - device->ExpectCtap2CommandAndRespondWith( - CtapRequestCommand::kAuthenticatorGetInfo, - test_data::kTestAuthenticatorGetInfoResponse); + auto device = MockFidoDevice::MakeCtap(); device->ExpectCtap2CommandAndRespondWith( CtapRequestCommand::kAuthenticatorGetAssertion, base::nullopt); @@ -281,54 +247,6 @@ get_assertion_callback_receiver().callback()); get_assertion_callback_receiver().WaitForCallback(); - EXPECT_EQ(device->supported_protocol(), ProtocolVersion::kCtap); - EXPECT_TRUE(device->device_info()); - EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrOther, - get_assertion_callback_receiver().status()); - EXPECT_FALSE(get_assertion_callback_receiver().value()); -} - -TEST_F(FidoGetAssertionTaskTest, TestIncompatibleUserVerificationSetting) { - auto device = std::make_unique<MockFidoDevice>(); - - device->ExpectCtap2CommandAndRespondWith( - CtapRequestCommand::kAuthenticatorGetInfo, - test_data::kTestGetInfoResponseWithoutUvSupport); - - auto request = CtapGetAssertionRequest(test_data::kRelyingPartyId, - test_data::kClientDataHash); - request.SetUserVerification(UserVerificationRequirement::kRequired); - - auto task = std::make_unique<GetAssertionTask>( - device.get(), std::move(request), - get_assertion_callback_receiver().callback()); - - get_assertion_callback_receiver().WaitForCallback(); - EXPECT_EQ(device->supported_protocol(), ProtocolVersion::kCtap); - EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrOther, - get_assertion_callback_receiver().status()); - EXPECT_FALSE(get_assertion_callback_receiver().value()); -} - -TEST_F(FidoGetAssertionTaskTest, - TestU2fSignRequestWithUserVerificationRequired) { - auto request = CtapGetAssertionRequest(test_data::kRelyingPartyId, - test_data::kClientDataHash); - request.SetAllowList( - {{CredentialType::kPublicKey, - fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle)}}); - request.SetUserVerification(UserVerificationRequirement::kRequired); - - auto device = std::make_unique<MockFidoDevice>(); - device->ExpectCtap2CommandAndRespondWith( - CtapRequestCommand::kAuthenticatorGetInfo, base::nullopt); - - auto task = std::make_unique<GetAssertionTask>( - device.get(), std::move(request), - get_assertion_callback_receiver().callback()); - - get_assertion_callback_receiver().WaitForCallback(); - EXPECT_EQ(device->supported_protocol(), ProtocolVersion::kU2f); EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrOther, get_assertion_callback_receiver().status()); EXPECT_FALSE(get_assertion_callback_receiver().value()); @@ -338,9 +256,7 @@ auto request = CtapGetAssertionRequest(test_data::kRelyingPartyId, test_data::kClientDataHash); - auto device = std::make_unique<MockFidoDevice>(); - device->ExpectCtap2CommandAndRespondWith( - CtapRequestCommand::kAuthenticatorGetInfo, base::nullopt); + auto device = MockFidoDevice::MakeU2f(); device->ExpectRequestAndRespondWith( test_data::kU2fFakeRegisterCommand, test_data::kApduEncodedNoErrorSignResponse); @@ -350,10 +266,10 @@ get_assertion_callback_receiver().callback()); get_assertion_callback_receiver().WaitForCallback(); - EXPECT_EQ(device->supported_protocol(), ProtocolVersion::kU2f); EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrCredentialNotValid, get_assertion_callback_receiver().status()); EXPECT_FALSE(get_assertion_callback_receiver().value()); } +} // namespace } // namespace device
diff --git a/device/fido/mac/authenticator.h b/device/fido/mac/authenticator.h index 4804525..5030f64 100644 --- a/device/fido/mac/authenticator.h +++ b/device/fido/mac/authenticator.h
@@ -37,13 +37,13 @@ // FidoAuthenticator void MakeCredential( - AuthenticatorSelectionCriteria authenticator_selection_criteria, CtapMakeCredentialRequest request, MakeCredentialCallback callback) override; void GetAssertion(CtapGetAssertionRequest request, GetAssertionCallback callback) override; void Cancel() override; std::string GetId() const override; + const AuthenticatorSupportedOptions& Options() const override; private: TouchIdAuthenticator(std::string keychain_access_group,
diff --git a/device/fido/mac/authenticator.mm b/device/fido/mac/authenticator.mm index acf005d..76f9d482 100644 --- a/device/fido/mac/authenticator.mm +++ b/device/fido/mac/authenticator.mm
@@ -7,11 +7,12 @@ #import <LocalAuthentication/LocalAuthentication.h> #include "base/feature_list.h" +#include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/optional.h" #include "base/strings/string_piece.h" #include "device/base/features.h" -#include "device/fido/authenticator_selection_criteria.h" +#include "device/fido/authenticator_supported_options.h" #include "device/fido/ctap_get_assertion_request.h" #include "device/fido/ctap_make_credential_request.h" #include "device/fido/fido_constants.h" @@ -57,10 +58,8 @@ TouchIdAuthenticator::~TouchIdAuthenticator() = default; -void TouchIdAuthenticator::MakeCredential( - AuthenticatorSelectionCriteria authenticator_selection_criteria, - CtapMakeCredentialRequest request, - MakeCredentialCallback callback) { +void TouchIdAuthenticator::MakeCredential(CtapMakeCredentialRequest request, + MakeCredentialCallback callback) { if (__builtin_available(macOS 10.12.2, *)) { DCHECK(!operation_); operation_ = std::make_unique<MakeCredentialOperation>( @@ -97,6 +96,27 @@ return "TouchIdAuthenticator"; } +namespace { + +AuthenticatorSupportedOptions TouchIdAuthenticatorOptions() { + AuthenticatorSupportedOptions options; + options.SetIsPlatformDevice(true); + options.SetSupportsResidentKey(true); + options.SetUserVerificationAvailability( + AuthenticatorSupportedOptions::UserVerificationAvailability:: + kSupportedAndConfigured); + options.SetUserPresenceRequired(true); + return options; +} + +} // namespace + +const AuthenticatorSupportedOptions& TouchIdAuthenticator::Options() const { + static const AuthenticatorSupportedOptions options = + TouchIdAuthenticatorOptions(); + return options; +} + TouchIdAuthenticator::TouchIdAuthenticator(std::string keychain_access_group, std::string metadata_secret) : keychain_access_group_(std::move(keychain_access_group)),
diff --git a/device/fido/mac/browsing_data_deletion_unittest.mm b/device/fido/mac/browsing_data_deletion_unittest.mm index 7950267..b6acba5 100644 --- a/device/fido/mac/browsing_data_deletion_unittest.mm +++ b/device/fido/mac/browsing_data_deletion_unittest.mm
@@ -14,7 +14,6 @@ #include "base/test/scoped_feature_list.h" #include "base/test/scoped_task_environment.h" #include "device/base/features.h" -#include "device/fido/authenticator_selection_criteria.h" #include "device/fido/ctap_make_credential_request.h" #include "device/fido/fido_constants.h" #include "device/fido/mac/authenticator.h" @@ -141,8 +140,7 @@ TestCallbackReceiver<CtapDeviceResponseCode, base::Optional<AuthenticatorMakeCredentialResponse>> callback_receiver; - authenticator->MakeCredential(AuthenticatorSelectionCriteria(), - MakeRequest(), callback_receiver.callback()); + authenticator->MakeCredential(MakeRequest(), callback_receiver.callback()); callback_receiver.WaitForCallback(); auto result = callback_receiver.TakeResult(); return std::get<0>(result) == CtapDeviceResponseCode::kSuccess;
diff --git a/device/fido/make_credential_handler_unittest.cc b/device/fido/make_credential_handler_unittest.cc index f884b1be..f5b277d 100644 --- a/device/fido/make_credential_handler_unittest.cc +++ b/device/fido/make_credential_handler_unittest.cc
@@ -42,6 +42,13 @@ } std::unique_ptr<MakeCredentialRequestHandler> CreateMakeCredentialHandler() { + return CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( + AuthenticatorSelectionCriteria()); + } + + std::unique_ptr<MakeCredentialRequestHandler> + CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( + AuthenticatorSelectionCriteria authenticator_selection_criteria) { ForgeNextHidDiscovery(); PublicKeyCredentialRpEntity rp(test_data::kRelyingPartyId); PublicKeyCredentialUserEntity user( @@ -57,8 +64,8 @@ nullptr, base::flat_set<FidoTransportProtocol>( {FidoTransportProtocol::kUsbHumanInterfaceDevice}), - std::move(request_parameter), AuthenticatorSelectionCriteria(), - cb_.callback()); + std::move(request_parameter), + std::move(authenticator_selection_criteria), cb_.callback()); } void InitFeatureListAndDisableCtapFlag() { @@ -134,4 +141,181 @@ EXPECT_TRUE(request_handler->is_complete()); } +TEST_F(FidoMakeCredentialHandlerTest, U2fRegisterWithUserVerificationRequired) { + auto request_handler = + CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( + AuthenticatorSelectionCriteria( + AuthenticatorSelectionCriteria::AuthenticatorAttachment::kAny, + false /* require_resident_key */, + UserVerificationRequirement::kRequired)); + discovery()->WaitForCallToStartAndSimulateSuccess(); + + auto device = std::make_unique<MockFidoDevice>(); + EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device0")); + device->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, base::nullopt); + + discovery()->AddDevice(std::move(device)); + + scoped_task_environment_.FastForwardUntilNoTasksRemain(); + EXPECT_FALSE(callback().was_called()); +} + +TEST_F(FidoMakeCredentialHandlerTest, + U2fRegisterWithPlatformDeviceRequirement) { + auto request_handler = + CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( + AuthenticatorSelectionCriteria( + AuthenticatorSelectionCriteria::AuthenticatorAttachment:: + kPlatform, + false /* require_resident_key */, + UserVerificationRequirement::kPreferred)); + discovery()->WaitForCallToStartAndSimulateSuccess(); + + auto device = std::make_unique<MockFidoDevice>(); + EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device0")); + device->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, base::nullopt); + + discovery()->AddDevice(std::move(device)); + + scoped_task_environment_.FastForwardUntilNoTasksRemain(); + EXPECT_FALSE(callback().was_called()); +} + +TEST_F(FidoMakeCredentialHandlerTest, U2fRegisterWithResidentKeyRequirement) { + auto request_handler = + CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( + AuthenticatorSelectionCriteria( + AuthenticatorSelectionCriteria::AuthenticatorAttachment::kAny, + true /* require_resident_key */, + UserVerificationRequirement::kPreferred)); + discovery()->WaitForCallToStartAndSimulateSuccess(); + + auto device = std::make_unique<MockFidoDevice>(); + EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device0")); + device->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, base::nullopt); + + discovery()->AddDevice(std::move(device)); + + scoped_task_environment_.FastForwardUntilNoTasksRemain(); + EXPECT_FALSE(callback().was_called()); +} + +TEST_F(FidoMakeCredentialHandlerTest, + UserVerificationAuthenticatorSelectionCriteria) { + auto request_handler = + CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( + AuthenticatorSelectionCriteria( + AuthenticatorSelectionCriteria::AuthenticatorAttachment::kAny, + false /* require_resident_key */, + UserVerificationRequirement::kRequired)); + discovery()->WaitForCallToStartAndSimulateSuccess(); + + auto device = std::make_unique<MockFidoDevice>(); + EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device0")); + device->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, + test_data::kTestGetInfoResponseWithoutUvSupport); + + discovery()->AddDevice(std::move(device)); + + scoped_task_environment_.FastForwardUntilNoTasksRemain(); + EXPECT_FALSE(callback().was_called()); +} + +TEST_F(FidoMakeCredentialHandlerTest, + PlatformDeviceAuthenticatorSelectionCriteria) { + auto request_handler = + CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( + AuthenticatorSelectionCriteria( + AuthenticatorSelectionCriteria::AuthenticatorAttachment:: + kPlatform, + false /* require_resident_key */, + UserVerificationRequirement::kRequired)); + discovery()->WaitForCallToStartAndSimulateSuccess(); + + auto device = std::make_unique<MockFidoDevice>(); + EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device0")); + device->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, + test_data::kTestGetInfoResponseCrossPlatformDevice); + + discovery()->AddDevice(std::move(device)); + + scoped_task_environment_.FastForwardUntilNoTasksRemain(); + EXPECT_FALSE(callback().was_called()); +} + +TEST_F(FidoMakeCredentialHandlerTest, + ResidentKeyAuthenticatorSelectionCriteria) { + auto request_handler = + CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( + AuthenticatorSelectionCriteria( + AuthenticatorSelectionCriteria::AuthenticatorAttachment::kAny, + true /* require_resident_key */, + UserVerificationRequirement::kPreferred)); + discovery()->WaitForCallToStartAndSimulateSuccess(); + + auto device = std::make_unique<MockFidoDevice>(); + EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device0")); + device->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, + test_data::kTestGetInfoResponseWithoutResidentKeySupport); + + discovery()->AddDevice(std::move(device)); + + scoped_task_environment_.FastForwardUntilNoTasksRemain(); + EXPECT_FALSE(callback().was_called()); +} + +TEST_F(FidoMakeCredentialHandlerTest, + SatisfyAllAuthenticatorSelectionCriteria) { + auto request_handler = + CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( + AuthenticatorSelectionCriteria( + AuthenticatorSelectionCriteria::AuthenticatorAttachment:: + kPlatform, + true /* require_resident_key */, + UserVerificationRequirement::kRequired)); + discovery()->WaitForCallToStartAndSimulateSuccess(); + + auto device = std::make_unique<MockFidoDevice>(); + EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device0")); + device->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, + test_data::kTestAuthenticatorGetInfoResponse); + device->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorMakeCredential, + test_data::kTestMakeCredentialResponse); + + discovery()->AddDevice(std::move(device)); + + scoped_task_environment_.FastForwardUntilNoTasksRemain(); + callback().WaitForCallback(); + EXPECT_EQ(FidoReturnCode::kSuccess, callback().status()); +} + +TEST_F(FidoMakeCredentialHandlerTest, IncompatibleUserVerificationSetting) { + auto request_handler = + CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( + AuthenticatorSelectionCriteria( + AuthenticatorSelectionCriteria::AuthenticatorAttachment::kAny, + false /* require_resident_key */, + UserVerificationRequirement::kRequired)); + discovery()->WaitForCallToStartAndSimulateSuccess(); + + auto device = std::make_unique<MockFidoDevice>(); + EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device0")); + device->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetInfo, + test_data::kTestGetInfoResponseWithoutUvSupport); + + discovery()->AddDevice(std::move(device)); + + scoped_task_environment_.FastForwardUntilNoTasksRemain(); + EXPECT_FALSE(callback().was_called()); +} + } // namespace device
diff --git a/device/fido/make_credential_request_handler.cc b/device/fido/make_credential_request_handler.cc index abe433e..804bb75 100644 --- a/device/fido/make_credential_request_handler.cc +++ b/device/fido/make_credential_request_handler.cc
@@ -47,10 +47,58 @@ MakeCredentialRequestHandler::~MakeCredentialRequestHandler() = default; +namespace { + +bool CheckIfAuthenticatorSelectionCriteriaAreSatisfied( + FidoAuthenticator* authenticator, + const AuthenticatorSelectionCriteria& authenticator_selection_criteria, + CtapMakeCredentialRequest* request) { + using AuthenticatorAttachment = + AuthenticatorSelectionCriteria::AuthenticatorAttachment; + using UvAvailability = + AuthenticatorSupportedOptions::UserVerificationAvailability; + + const auto& options = authenticator->Options(); + if ((authenticator_selection_criteria.authenticator_attachement() == + AuthenticatorAttachment::kPlatform && + !options.is_platform_device()) || + (authenticator_selection_criteria.authenticator_attachement() == + AuthenticatorAttachment::kCrossPlatform && + options.is_platform_device())) { + return false; + } + + if (authenticator_selection_criteria.require_resident_key() && + !options.supports_resident_key()) { + return false; + } + + const auto& user_verification_requirement = + authenticator_selection_criteria.user_verification_requirement(); + if (user_verification_requirement == UserVerificationRequirement::kRequired) { + request->SetUserVerificationRequired(true); + } + + return user_verification_requirement != + UserVerificationRequirement::kRequired || + options.user_verification_availability() == + UvAvailability::kSupportedAndConfigured; +} + +} // namespace + void MakeCredentialRequestHandler::DispatchRequest( FidoAuthenticator* authenticator) { - return authenticator->MakeCredential( - authenticator_selection_criteria_, request_parameter_, + // The user verification field of the request may be adjusted to the + // authenticator, so we need to make a copy. + CtapMakeCredentialRequest request_copy = request_parameter_; + if (!CheckIfAuthenticatorSelectionCriteriaAreSatisfied( + authenticator, authenticator_selection_criteria_, &request_copy)) { + return; + } + + authenticator->MakeCredential( + std::move(request_copy), base::BindOnce(&MakeCredentialRequestHandler::OnAuthenticatorResponse, weak_factory_.GetWeakPtr(), authenticator)); }
diff --git a/device/fido/make_credential_task.cc b/device/fido/make_credential_task.cc index 8f7cbc3..d609836 100644 --- a/device/fido/make_credential_task.cc +++ b/device/fido/make_credential_task.cc
@@ -19,35 +19,24 @@ MakeCredentialTask::MakeCredentialTask( FidoDevice* device, CtapMakeCredentialRequest request_parameter, - AuthenticatorSelectionCriteria authenticator_selection_criteria, MakeCredentialTaskCallback callback) : FidoTask(device), request_parameter_(std::move(request_parameter)), - authenticator_selection_criteria_( - std::move(authenticator_selection_criteria)), callback_(std::move(callback)), weak_factory_(this) {} MakeCredentialTask::~MakeCredentialTask() = default; void MakeCredentialTask::StartTask() { - if (base::FeatureList::IsEnabled(kNewCtap2Device)) { - GetAuthenticatorInfo(base::BindOnce(&MakeCredentialTask::MakeCredential, - weak_factory_.GetWeakPtr()), - base::BindOnce(&MakeCredentialTask::U2fRegister, - weak_factory_.GetWeakPtr())); + if (base::FeatureList::IsEnabled(kNewCtap2Device) && + device()->supported_protocol() == ProtocolVersion::kCtap) { + MakeCredential(); } else { U2fRegister(); } } void MakeCredentialTask::MakeCredential() { - if (!CheckIfAuthenticatorSelectionCriteriaAreSatisfied()) { - std::move(callback_).Run(CtapDeviceResponseCode::kCtap2ErrOther, - base::nullopt); - return; - } - register_operation_ = std::make_unique<Ctap2DeviceOperation< CtapMakeCredentialRequest, AuthenticatorMakeCredentialResponse>>( device(), request_parameter_, @@ -58,10 +47,7 @@ } void MakeCredentialTask::U2fRegister() { - device()->set_supported_protocol(ProtocolVersion::kU2f); - - if (!CheckIfAuthenticatorSelectionCriteriaAreSatisfied() || - !IsConvertibleToU2fRegisterCommand(request_parameter_)) { + if (!IsConvertibleToU2fRegisterCommand(request_parameter_)) { std::move(callback_).Run(CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt); return; @@ -82,6 +68,8 @@ return; } + // TODO(martinkr): CheckRpIdHash invocation needs to move into the Request + // handler. See https://crbug.com/863988. if (!response_data || !response_data->CheckRpIdHash(request_parameter_.rp().rp_id())) { std::move(callback_).Run(CtapDeviceResponseCode::kCtap2ErrOther, @@ -92,48 +80,4 @@ std::move(callback_).Run(return_code, std::move(response_data)); } -bool MakeCredentialTask::CheckIfAuthenticatorSelectionCriteriaAreSatisfied() { - using AuthenticatorAttachment = - AuthenticatorSelectionCriteria::AuthenticatorAttachment; - using UvAvailability = - AuthenticatorSupportedOptions::UserVerificationAvailability; - - // U2F authenticators are non-platform devices that do not support resident - // key or user verification. - const auto& device_info = device()->device_info(); - if (!device_info) { - return !authenticator_selection_criteria_.require_resident_key() && - authenticator_selection_criteria_.user_verification_requirement() != - UserVerificationRequirement::kRequired && - authenticator_selection_criteria_.authenticator_attachement() != - AuthenticatorAttachment::kPlatform; - } - - const auto& options = device_info->options(); - if ((authenticator_selection_criteria_.authenticator_attachement() == - AuthenticatorAttachment::kPlatform && - !options.is_platform_device()) || - (authenticator_selection_criteria_.authenticator_attachement() == - AuthenticatorAttachment::kCrossPlatform && - options.is_platform_device())) { - return false; - } - - if (authenticator_selection_criteria_.require_resident_key() && - !options.supports_resident_key()) { - return false; - } - - const auto user_verification_requirement = - authenticator_selection_criteria_.user_verification_requirement(); - if (user_verification_requirement == UserVerificationRequirement::kRequired) { - request_parameter_.SetUserVerificationRequired(true); - } - - return user_verification_requirement != - UserVerificationRequirement::kRequired || - options.user_verification_availability() == - UvAvailability::kSupportedAndConfigured; -} - } // namespace device
diff --git a/device/fido/make_credential_task.h b/device/fido/make_credential_task.h index 47fcb99..fc8ae97 100644 --- a/device/fido/make_credential_task.h +++ b/device/fido/make_credential_task.h
@@ -16,7 +16,6 @@ #include "base/memory/weak_ptr.h" #include "base/optional.h" #include "device/fido/authenticator_make_credential_response.h" -#include "device/fido/authenticator_selection_criteria.h" #include "device/fido/ctap_make_credential_request.h" #include "device/fido/device_operation.h" #include "device/fido/fido_constants.h" @@ -37,7 +36,6 @@ MakeCredentialTask(FidoDevice* device, CtapMakeCredentialRequest request_parameter, - AuthenticatorSelectionCriteria authenticator_criteria, MakeCredentialTaskCallback callback); ~MakeCredentialTask() override; @@ -51,14 +49,7 @@ CtapDeviceResponseCode return_code, base::Optional<AuthenticatorMakeCredentialResponse> response_data); - // Invoked after retrieving response to AuthenticatorGetInfo request. Filters - // out authenticators based on |authenticator_selection_criteria_| constraints - // provided by the relying party. If |device_| does not satisfy the - // constraints, then this request is silently dropped. - bool CheckIfAuthenticatorSelectionCriteriaAreSatisfied(); - CtapMakeCredentialRequest request_parameter_; - AuthenticatorSelectionCriteria authenticator_selection_criteria_; std::unique_ptr<RegisterOperation> register_operation_; MakeCredentialTaskCallback callback_; base::WeakPtrFactory<MakeCredentialTask> weak_factory_;
diff --git a/device/fido/make_credential_task_unittest.cc b/device/fido/make_credential_task_unittest.cc index b97aa9b..ee16b84 100644 --- a/device/fido/make_credential_task_unittest.cc +++ b/device/fido/make_credential_task_unittest.cc
@@ -14,6 +14,7 @@ #include "device/base/features.h" #include "device/fido/authenticator_make_credential_response.h" #include "device/fido/ctap_make_credential_request.h" +#include "device/fido/device_response_converter.h" #include "device/fido/fido_constants.h" #include "device/fido/fido_parsing_utils.h" #include "device/fido/fido_test_data.h" @@ -35,13 +36,9 @@ CtapDeviceResponseCode, base::Optional<AuthenticatorMakeCredentialResponse>>; -} // namespace - class FidoMakeCredentialTaskTest : public testing::Test { public: - FidoMakeCredentialTaskTest() { - scoped_feature_list_.emplace(); - } + FidoMakeCredentialTaskTest() { scoped_feature_list_.emplace(); } std::unique_ptr<MakeCredentialTask> CreateMakeCredentialTask( FidoDevice* device) { @@ -54,23 +51,7 @@ test_data::kClientDataHash, std::move(rp), std::move(user), PublicKeyCredentialParams( std::vector<PublicKeyCredentialParams::CredentialInfo>(1))), - AuthenticatorSelectionCriteria(), callback_receiver_.callback()); - } - - std::unique_ptr<MakeCredentialTask> - CreateMakeCredentialTaskWithAuthenticatorSelectionCriteria( - FidoDevice* device, - AuthenticatorSelectionCriteria criteria) { - PublicKeyCredentialRpEntity rp(test_data::kRelyingPartyId); - PublicKeyCredentialUserEntity user( - fido_parsing_utils::Materialize(test_data::kUserId)); - return std::make_unique<MakeCredentialTask>( - device, - CtapMakeCredentialRequest( - test_data::kClientDataHash, std::move(rp), std::move(user), - PublicKeyCredentialParams( - std::vector<PublicKeyCredentialParams::CredentialInfo>(1))), - std::move(criteria), callback_receiver_.callback()); + callback_receiver_.callback()); } void RemoveCtapFlag() { @@ -89,11 +70,7 @@ }; TEST_F(FidoMakeCredentialTaskTest, MakeCredentialSuccess) { - auto device = std::make_unique<MockFidoDevice>(); - - device->ExpectCtap2CommandAndRespondWith( - CtapRequestCommand::kAuthenticatorGetInfo, - test_data::kTestAuthenticatorGetInfoResponse); + auto device = MockFidoDevice::MakeCtap(); device->ExpectCtap2CommandAndRespondWith( CtapRequestCommand::kAuthenticatorMakeCredential, test_data::kTestMakeCredentialResponse); @@ -110,6 +87,9 @@ TEST_F(FidoMakeCredentialTaskTest, TestRegisterSuccessWithFake) { auto device = std::make_unique<VirtualCtap2Device>(); + test::TestCallbackReceiver<> done_init; + device->DiscoverSupportedProtocolAndDeviceInfo(done_init.callback()); + done_init.WaitForCallback(); const auto task = CreateMakeCredentialTask(device.get()); make_credential_callback_receiver().WaitForCallback(); @@ -124,11 +104,7 @@ } TEST_F(FidoMakeCredentialTaskTest, MakeCredentialWithIncorrectRpIdHash) { - auto device = std::make_unique<MockFidoDevice>(); - - device->ExpectCtap2CommandAndRespondWith( - CtapRequestCommand::kAuthenticatorGetInfo, - test_data::kTestAuthenticatorGetInfoResponse); + auto device = MockFidoDevice::MakeCtap(); device->ExpectCtap2CommandAndRespondWith( CtapRequestCommand::kAuthenticatorMakeCredential, test_data::kTestMakeCredentialResponseWithIncorrectRpIdHash); @@ -141,10 +117,7 @@ } TEST_F(FidoMakeCredentialTaskTest, FallbackToU2fRegisterSuccess) { - auto device = std::make_unique<MockFidoDevice>(); - - device->ExpectCtap2CommandAndRespondWith( - CtapRequestCommand::kAuthenticatorGetInfo, base::nullopt); + auto device = MockFidoDevice::MakeU2f(); device->ExpectRequestAndRespondWith( test_data::kU2fRegisterCommandApdu, test_data::kApduEncodedNoErrorRegisterResponse); @@ -159,7 +132,7 @@ TEST_F(FidoMakeCredentialTaskTest, TestDefaultU2fRegisterOperationWithoutFlag) { RemoveCtapFlag(); - auto device = std::make_unique<MockFidoDevice>(); + auto device = MockFidoDevice::MakeU2f(); device->ExpectRequestAndRespondWith( test_data::kU2fRegisterCommandApdu, test_data::kApduEncodedNoErrorRegisterResponse); @@ -171,182 +144,5 @@ make_credential_callback_receiver().status()); } -TEST_F(FidoMakeCredentialTaskTest, U2fRegisterWithUserVerificationRequired) { - auto device = std::make_unique<MockFidoDevice>(); - - device->ExpectCtap2CommandAndRespondWith( - CtapRequestCommand::kAuthenticatorGetInfo, base::nullopt); - - const auto task = CreateMakeCredentialTaskWithAuthenticatorSelectionCriteria( - device.get(), - AuthenticatorSelectionCriteria( - AuthenticatorSelectionCriteria::AuthenticatorAttachment::kAny, - false /* require_resident_key */, - UserVerificationRequirement::kRequired)); - make_credential_callback_receiver().WaitForCallback(); - - EXPECT_EQ(ProtocolVersion::kU2f, device->supported_protocol()); - EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrOther, - make_credential_callback_receiver().status()); -} - -TEST_F(FidoMakeCredentialTaskTest, U2fRegisterWithPlatformDeviceRequirement) { - auto device = std::make_unique<MockFidoDevice>(); - - device->ExpectCtap2CommandAndRespondWith( - CtapRequestCommand::kAuthenticatorGetInfo, base::nullopt); - - const auto task = CreateMakeCredentialTaskWithAuthenticatorSelectionCriteria( - device.get(), - AuthenticatorSelectionCriteria( - AuthenticatorSelectionCriteria::AuthenticatorAttachment::kPlatform, - false /* require_resident_key */, - UserVerificationRequirement::kPreferred)); - make_credential_callback_receiver().WaitForCallback(); - - EXPECT_EQ(ProtocolVersion::kU2f, device->supported_protocol()); - EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrOther, - make_credential_callback_receiver().status()); -} - -TEST_F(FidoMakeCredentialTaskTest, U2fRegisterWithResidentKeyRequirement) { - auto device = std::make_unique<MockFidoDevice>(); - - device->ExpectCtap2CommandAndRespondWith( - CtapRequestCommand::kAuthenticatorGetInfo, base::nullopt); - - const auto task = CreateMakeCredentialTaskWithAuthenticatorSelectionCriteria( - device.get(), - AuthenticatorSelectionCriteria( - AuthenticatorSelectionCriteria::AuthenticatorAttachment::kAny, - true /* require_resident_key */, - UserVerificationRequirement::kPreferred)); - make_credential_callback_receiver().WaitForCallback(); - - EXPECT_EQ(ProtocolVersion::kU2f, device->supported_protocol()); - EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrOther, - make_credential_callback_receiver().status()); -} - -TEST_F(FidoMakeCredentialTaskTest, - UserVerificationAuthenticatorSelectionCriteria) { - auto device = std::make_unique<MockFidoDevice>(); - - device->ExpectCtap2CommandAndRespondWith( - CtapRequestCommand::kAuthenticatorGetInfo, - test_data::kTestGetInfoResponseWithoutUvSupport); - - const auto task = CreateMakeCredentialTaskWithAuthenticatorSelectionCriteria( - device.get(), - AuthenticatorSelectionCriteria( - AuthenticatorSelectionCriteria::AuthenticatorAttachment::kAny, - false /* require_resident_key */, - UserVerificationRequirement::kRequired)); - make_credential_callback_receiver().WaitForCallback(); - - EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrOther, - make_credential_callback_receiver().status()); - EXPECT_EQ(ProtocolVersion::kCtap, device->supported_protocol()); - EXPECT_TRUE(device->device_info()); - EXPECT_EQ(AuthenticatorSupportedOptions::UserVerificationAvailability:: - kSupportedButNotConfigured, - device->device_info()->options().user_verification_availability()); -} - -TEST_F(FidoMakeCredentialTaskTest, - PlatformDeviceAuthenticatorSelectionCriteria) { - auto device = std::make_unique<MockFidoDevice>(); - - device->ExpectCtap2CommandAndRespondWith( - CtapRequestCommand::kAuthenticatorGetInfo, - test_data::kTestGetInfoResponseCrossPlatformDevice); - - const auto task = CreateMakeCredentialTaskWithAuthenticatorSelectionCriteria( - device.get(), - AuthenticatorSelectionCriteria( - AuthenticatorSelectionCriteria::AuthenticatorAttachment::kPlatform, - false /* require_resident_key */, - UserVerificationRequirement::kPreferred)); - make_credential_callback_receiver().WaitForCallback(); - - EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrOther, - make_credential_callback_receiver().status()); - EXPECT_EQ(ProtocolVersion::kCtap, device->supported_protocol()); - EXPECT_TRUE(device->device_info()); - EXPECT_FALSE(device->device_info()->options().is_platform_device()); -} - -TEST_F(FidoMakeCredentialTaskTest, ResidentKeyAuthenticatorSelectionCriteria) { - auto device = std::make_unique<MockFidoDevice>(); - - device->ExpectCtap2CommandAndRespondWith( - CtapRequestCommand::kAuthenticatorGetInfo, - test_data::kTestGetInfoResponseWithoutResidentKeySupport); - - const auto task = CreateMakeCredentialTaskWithAuthenticatorSelectionCriteria( - device.get(), - AuthenticatorSelectionCriteria( - AuthenticatorSelectionCriteria::AuthenticatorAttachment::kAny, - true /* require_resident_key */, - UserVerificationRequirement::kPreferred)); - make_credential_callback_receiver().WaitForCallback(); - - EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrOther, - make_credential_callback_receiver().status()); - EXPECT_EQ(ProtocolVersion::kCtap, device->supported_protocol()); - EXPECT_TRUE(device->device_info()); - EXPECT_FALSE(device->device_info()->options().supports_resident_key()); -} - -TEST_F(FidoMakeCredentialTaskTest, SatisfyAllAuthenticatorSelectionCriteria) { - auto device = std::make_unique<MockFidoDevice>(); - - device->ExpectCtap2CommandAndRespondWith( - CtapRequestCommand::kAuthenticatorGetInfo, - test_data::kTestAuthenticatorGetInfoResponse); - device->ExpectCtap2CommandAndRespondWith( - CtapRequestCommand::kAuthenticatorMakeCredential, - test_data::kTestMakeCredentialResponse); - - const auto task = CreateMakeCredentialTaskWithAuthenticatorSelectionCriteria( - device.get(), - AuthenticatorSelectionCriteria( - AuthenticatorSelectionCriteria::AuthenticatorAttachment::kPlatform, - true /* require_resident_key */, - UserVerificationRequirement::kRequired)); - make_credential_callback_receiver().WaitForCallback(); - - EXPECT_EQ(CtapDeviceResponseCode::kSuccess, - make_credential_callback_receiver().status()); - EXPECT_TRUE(make_credential_callback_receiver().value()); - EXPECT_EQ(ProtocolVersion::kCtap, device->supported_protocol()); - EXPECT_TRUE(device->device_info()); - const auto& device_options = device->device_info()->options(); - EXPECT_TRUE(device_options.is_platform_device()); - EXPECT_TRUE(device_options.supports_resident_key()); - EXPECT_EQ(AuthenticatorSupportedOptions::UserVerificationAvailability:: - kSupportedAndConfigured, - device_options.user_verification_availability()); -} - -TEST_F(FidoMakeCredentialTaskTest, IncompatibleUserVerificationSetting) { - auto device = std::make_unique<MockFidoDevice>(); - - device->ExpectCtap2CommandAndRespondWith( - CtapRequestCommand::kAuthenticatorGetInfo, - test_data::kTestGetInfoResponseWithoutUvSupport); - - const auto task = CreateMakeCredentialTaskWithAuthenticatorSelectionCriteria( - device.get(), - AuthenticatorSelectionCriteria( - AuthenticatorSelectionCriteria::AuthenticatorAttachment::kAny, - false /* require_resident_key */, - UserVerificationRequirement::kRequired)); - make_credential_callback_receiver().WaitForCallback(); - EXPECT_EQ(ProtocolVersion::kCtap, device->supported_protocol()); - EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrOther, - make_credential_callback_receiver().status()); - EXPECT_FALSE(make_credential_callback_receiver().value()); -} - +} // namespace } // namespace device
diff --git a/device/fido/mock_fido_device.cc b/device/fido/mock_fido_device.cc index 714950a..cf499d5b 100644 --- a/device/fido/mock_fido_device.cc +++ b/device/fido/mock_fido_device.cc
@@ -10,18 +10,49 @@ #include "base/location.h" #include "base/threading/thread_task_runner_handle.h" #include "components/apdu/apdu_response.h" +#include "device/fido/device_response_converter.h" #include "device/fido/fido_constants.h" #include "device/fido/fido_parsing_utils.h" #include "device/fido/fido_test_data.h" namespace device { +namespace { +AuthenticatorGetInfoResponse DefaultAuthenticatorInfo() { + return *ReadCTAPGetInfoResponse(test_data::kTestAuthenticatorGetInfoResponse); +} +} // namespace + +// static +std::unique_ptr<MockFidoDevice> MockFidoDevice::MakeU2f() { + return std::make_unique<MockFidoDevice>(ProtocolVersion::kU2f, base::nullopt); +} + +// static +std::unique_ptr<MockFidoDevice> MockFidoDevice::MakeCtap( + base::Optional<AuthenticatorGetInfoResponse> device_info) { + if (!device_info) { + device_info = DefaultAuthenticatorInfo(); + } + return std::make_unique<MockFidoDevice>(ProtocolVersion::kCtap, + std::move(*device_info)); +} + // Matcher to compare the fist byte of the incoming requests. MATCHER_P(IsCtap2Command, expected_command, "") { return !arg.empty() && arg[0] == base::strict_cast<uint8_t>(expected_command); } MockFidoDevice::MockFidoDevice() : weak_factory_(this) {} +MockFidoDevice::MockFidoDevice( + ProtocolVersion protocol_version, + base::Optional<AuthenticatorGetInfoResponse> device_info) + : MockFidoDevice() { + set_supported_protocol(protocol_version); + if (device_info) { + SetDeviceInfo(std::move(*device_info)); + } +} MockFidoDevice::~MockFidoDevice() = default; void MockFidoDevice::TryWink(WinkCallback cb) {
diff --git a/device/fido/mock_fido_device.h b/device/fido/mock_fido_device.h index cabfea9..0df85aa9 100644 --- a/device/fido/mock_fido_device.h +++ b/device/fido/mock_fido_device.h
@@ -23,7 +23,13 @@ class MockFidoDevice : public FidoDevice { public: + static std::unique_ptr<MockFidoDevice> MakeU2f(); + static std::unique_ptr<MockFidoDevice> MakeCtap( + base::Optional<AuthenticatorGetInfoResponse> device_info = base::nullopt); + MockFidoDevice(); + MockFidoDevice(ProtocolVersion protocol_version, + base::Optional<AuthenticatorGetInfoResponse> device_info); ~MockFidoDevice() override; // TODO(crbug.com/729950): Remove these workarounds once support for move-only
diff --git a/device/vr/android/gvr/gvr_delegate_provider.h b/device/vr/android/gvr/gvr_delegate_provider.h index 2e5f84f..9bd7708 100644 --- a/device/vr/android/gvr/gvr_delegate_provider.h +++ b/device/vr/android/gvr/gvr_delegate_provider.h
@@ -23,7 +23,7 @@ virtual void StartWebXRPresentation( mojom::VRDisplayInfoPtr display_info, mojom::XRDeviceRuntimeSessionOptionsPtr options, - device::mojom::VRDisplayHost::RequestSessionCallback callback) = 0; + base::OnceCallback<void(device::mojom::XRSessionPtr)> callback) = 0; virtual void ExitWebVRPresent() = 0; virtual void OnListeningForActivateChanged(bool listening) = 0;
diff --git a/device/vr/android/gvr/gvr_device.cc b/device/vr/android/gvr/gvr_device.cc index de2c12bc..20166c65 100644 --- a/device/vr/android/gvr/gvr_device.cc +++ b/device/vr/android/gvr/gvr_device.cc
@@ -186,27 +186,25 @@ } if (options->immersive) { - if (options->immersive) { - // StartWebXRPresentation is async as we may trigger a DON (Device ON) - // flow that pauses Chrome. - delegate_provider->StartWebXRPresentation( - GetVRDisplayInfo(), std::move(options), - base::BindOnce(&GvrDevice::OnRequestSessionResult, - weak_ptr_factory_.GetWeakPtr(), std::move(callback))); - } else { - // TODO(https://crbug.com/695937): This should be NOTREACHED() once - // orientation device handles non-immersive VR sessions. - // TODO(https://crbug.com/842025): Handle this when RequestSession is - // called for non-immersive sessions. - NOTREACHED(); - } + // StartWebXRPresentation is async as we may trigger a DON (Device ON) flow + // that pauses Chrome. + delegate_provider->StartWebXRPresentation( + GetVRDisplayInfo(), std::move(options), + base::BindOnce(&GvrDevice::OnStartPresentResult, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); + } else { + // TODO(https://crbug.com/695937): This should be NOTREACHED() once + // orientation device handles non-immersive VR sessions. + // TODO(https://crbug.com/842025): Handle this when RequestSession is called + // for non-immersive sessions. + NOTREACHED(); } } -void GvrDevice::OnRequestSessionResult( +void GvrDevice::OnStartPresentResult( mojom::XRRuntime::RequestSessionCallback callback, - mojom::XRPresentationConnectionPtr connection) { - if (!connection) { + mojom::XRSessionPtr session) { + if (!session || !session->connection) { std::move(callback).Run(nullptr, nullptr); return; } @@ -225,7 +223,8 @@ base::BindOnce(&GvrDevice::OnPresentingControllerMojoConnectionError, base::Unretained(this))); - std::move(callback).Run(std::move(connection), std::move(session_controller)); + std::move(callback).Run(std::move(session->connection), + std::move(session_controller)); } // XRSessionController
diff --git a/device/vr/android/gvr/gvr_device.h b/device/vr/android/gvr/gvr_device.h index ead1ab4..6061fcbe 100644 --- a/device/vr/android/gvr/gvr_device.h +++ b/device/vr/android/gvr/gvr_device.h
@@ -44,8 +44,8 @@ void OnMagicWindowFrameDataRequest( mojom::VRMagicWindowProvider::GetFrameDataCallback callback) override; - void OnRequestSessionResult(mojom::XRRuntime::RequestSessionCallback callback, - mojom::XRPresentationConnectionPtr connection); + void OnStartPresentResult(mojom::XRRuntime::RequestSessionCallback callback, + mojom::XRSessionPtr session); // XRSessionController void SetFrameDataRestricted(bool restricted) override;
diff --git a/device/vr/public/mojom/isolated_xr_service.mojom b/device/vr/public/mojom/isolated_xr_service.mojom index 5b33778..3e4c7955 100644 --- a/device/vr/public/mojom/isolated_xr_service.mojom +++ b/device/vr/public/mojom/isolated_xr_service.mojom
@@ -69,9 +69,9 @@ // Attempt to start a "magic window" session. Magic window sessions allow // Clients to obtain poses (device position and orientation), but rendering // goes through the standard Chrome compositor. - RequestMagicWindowSession(device.mojom.VRMagicWindowProvider& session, - device.mojom.XRSessionController& controller) => - (bool success); + RequestMagicWindowSession() => + (device.mojom.VRMagicWindowProvider? session, + device.mojom.XRSessionController? controller); // The browser may register for changes to a device. Initial VRDisplayInfo // will immediately be returned to the listener to prevent races.
diff --git a/device/vr/public/mojom/vr_service.mojom b/device/vr/public/mojom/vr_service.mojom index a5b87a7..f87b684 100644 --- a/device/vr/public/mojom/vr_service.mojom +++ b/device/vr/public/mojom/vr_service.mojom
@@ -40,6 +40,13 @@ bool use_legacy_webvr_render_path; }; +// TODO(offenwanger) Rearrange these two interfaces to merge duplicate +// functionality. +struct XRSession { + VRMagicWindowProvider? magic_window_provider; + XRPresentationConnection? connection; +}; + struct XRPresentationConnection { VRSubmitFrameClient& client_request; VRPresentationProvider provider; @@ -237,8 +244,7 @@ }; interface VRServiceClient { - OnDisplayConnected(VRMagicWindowProvider magic_window_provider, - VRDisplayHost display, VRDisplayClient& request, + OnDisplayConnected(VRDisplayHost display, VRDisplayClient& request, VRDisplayInfo display_info); }; @@ -285,7 +291,7 @@ // reflect WebXR. RequestSession( XRSessionOptions options, - bool triggered_by_displayactive) => (XRPresentationConnection? connection); + bool triggered_by_displayactive) => (XRSession? session); SupportsSession(XRSessionOptions options) => (bool supports_session); ExitPresent();
diff --git a/device/vr/test/fake_vr_service_client.cc b/device/vr/test/fake_vr_service_client.cc index 9644610..a46445f 100644 --- a/device/vr/test/fake_vr_service_client.cc +++ b/device/vr/test/fake_vr_service_client.cc
@@ -13,7 +13,6 @@ FakeVRServiceClient::~FakeVRServiceClient() {} void FakeVRServiceClient::OnDisplayConnected( - mojom::VRMagicWindowProviderPtr magic_window_provider, mojom::VRDisplayHostPtr display, mojom::VRDisplayClientRequest request, mojom::VRDisplayInfoPtr displayInfo) {
diff --git a/device/vr/test/fake_vr_service_client.h b/device/vr/test/fake_vr_service_client.h index 1524f3b..74fd128 100644 --- a/device/vr/test/fake_vr_service_client.h +++ b/device/vr/test/fake_vr_service_client.h
@@ -19,8 +19,7 @@ FakeVRServiceClient(mojom::VRServiceClientRequest request); ~FakeVRServiceClient() override; - void OnDisplayConnected(mojom::VRMagicWindowProviderPtr magic_window_provider, - mojom::VRDisplayHostPtr display, + void OnDisplayConnected(mojom::VRDisplayHostPtr display, mojom::VRDisplayClientRequest request, mojom::VRDisplayInfoPtr displayInfo) override; void SetLastDeviceId(unsigned int id);
diff --git a/device/vr/vr_device_base.cc b/device/vr/vr_device_base.cc index 686f5eb3..1c7703a 100644 --- a/device/vr/vr_device_base.cc +++ b/device/vr/vr_device_base.cc
@@ -111,12 +111,12 @@ } void VRDeviceBase::RequestMagicWindowSession( - mojom::VRMagicWindowProviderRequest provider_request, - mojom::XRSessionControllerRequest controller_request, mojom::XRRuntime::RequestMagicWindowSessionCallback callback) { + mojom::VRMagicWindowProviderPtr provider; + mojom::XRSessionControllerPtr controller; magic_window_sessions_.push_back(std::make_unique<VRDisplayImpl>( - this, std::move(provider_request), std::move(controller_request))); - std::move(callback).Run(true); + this, mojo::MakeRequest(&provider), mojo::MakeRequest(&controller))); + std::move(callback).Run(std::move(provider), std::move(controller)); } void VRDeviceBase::EndMagicWindowSession(VRDisplayImpl* session) {
diff --git a/device/vr/vr_device_base.h b/device/vr/vr_device_base.h index 370b0c9..04f6c506 100644 --- a/device/vr/vr_device_base.h +++ b/device/vr/vr_device_base.h
@@ -85,8 +85,6 @@ // XRRuntime void RequestMagicWindowSession( - mojom::VRMagicWindowProviderRequest provider_request, - mojom::XRSessionControllerRequest controller_request, mojom::XRRuntime::RequestMagicWindowSessionCallback callback) override; mojom::XRRuntimeEventListenerPtr listener_;
diff --git a/docs/sublime_ide.md b/docs/sublime_ide.md index 1e692d3..b0b904ae 100644 --- a/docs/sublime_ide.md +++ b/docs/sublime_ide.md
@@ -553,6 +553,36 @@ ] ``` +### More detailed stack traces + +Chrome's default stack traces don't have full file paths so Sublime can't +parse them. You can enable more detailed stack traces and use F4 to step right +to the crashing line of code. + +First, add `print_unsymbolized_stack_traces = true` to your gn args, and make +sure you have debug symbols enabled too (`symbol_level = 2`). Then, pipe +Chrome's stderr through the asan_symbolize.py script. Here's a suitable build +variant for Linux (with tweaked file_regex): + +```json +{ + "name": "Build and run with asan_symbolize", + "cmd": "ninja -j 1000 -C out/Debug chrome && out/Debug/chrome 2>&1 | ./tools/valgrind/asan/asan_symbolize.py", + "shell": true, + "file_regex": "(?:^|[)] )[.\\\\/]*([a-z]?:?[\\w.\\\\/]+)[(:]([0-9]+)[,:]?([0-9]+)?[)]?:?(.*)$" +} +``` + +You can test it by visiting chrome://crash. You should be able to step through +each line in the resulting stacktrace with F4. You can also get a stack trace +without crashing like so: + +```c++ +#include "base/debug/stack_trace.h" +[...] +base::debug::StackTrace().Print(); +``` + ### Assigning builds to keyboard shortcuts To assign a build to a keyboard shortcut, select `Preferences > Key Bindings -
diff --git a/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc b/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc index fd3092d..cbf8b12 100644 --- a/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc +++ b/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc
@@ -20,7 +20,6 @@ #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" #include "content/public/common/stop_find_action.h" -#include "content/public/common/url_fetcher.h" #include "extensions/browser/guest_view/web_view/web_view_constants.h" #include "extensions/browser/guest_view/web_view/web_view_content_script_manager.h" #include "extensions/common/api/web_view_internal.h"
diff --git a/extensions/browser/api/web_request/web_request_info.cc b/extensions/browser/api/web_request/web_request_info.cc index 5ad45a4..e1cbcbd 100644 --- a/extensions/browser/api/web_request/web_request_info.cc +++ b/extensions/browser/api/web_request/web_request_info.cc
@@ -23,6 +23,8 @@ #include "net/log/net_log_with_source.h" #include "net/url_request/url_request.h" #include "services/network/public/cpp/resource_response.h" +#include "services/network/public/mojom/network_context.mojom.h" +#include "services/network/url_loader.h" namespace keys = extension_web_request_api_constants; @@ -257,6 +259,16 @@ web_request_type = ToWebRequestResourceType(type.value()); is_async = info->IsAsync(); resource_context = info->GetContext(); + } else if (auto* url_loader = network::URLLoader::ForRequest(*url_request)) { + // This is reached only in the SimpleURLLoader case (since network service + // is disabled if we're in this constructor). Only set the IDs if they're + // non-zero, since almost all requests come from the browser and aren't + // associated with a frame. In the case that the browser wants this + // SimpleURLLoader associated with a frame, the process ID will be non-zero. + if (url_loader->GetProcessId() != network::mojom::kBrowserProcessId) { + render_process_id = url_loader->GetProcessId(); + frame_id = url_loader->GetRenderFrameId(); + } } else { // There may be basic process and frame info associated with the request // even when |info| is null. Attempt to grab it as a last ditch effort. If
diff --git a/extensions/browser/blob_reader.cc b/extensions/browser/blob_reader.cc index 6df12eb..f4f4156 100644 --- a/extensions/browser/blob_reader.cc +++ b/extensions/browser/blob_reader.cc
@@ -72,6 +72,8 @@ void BlobReader::OnDataComplete() { data_complete_ = true; + if (!blob_data_) + blob_data_ = std::make_unique<std::string>(); if (blob_length_) Succeeded(); }
diff --git a/gpu/config/gpu_preferences.h b/gpu/config/gpu_preferences.h index b0936f66..9261ac2 100644 --- a/gpu/config/gpu_preferences.h +++ b/gpu/config/gpu_preferences.h
@@ -204,6 +204,9 @@ // send a background/suspend signal. bool watchdog_starts_backgrounded = false; + // Use Vulkan for rasterization and display compositing. + bool enable_vulkan = false; + // Please update gpu_preferences_unittest.cc when making additions or // changes to this struct. };
diff --git a/gpu/config/gpu_preferences_unittest.cc b/gpu/config/gpu_preferences_unittest.cc index 67e9ff7..d5493e2 100644 --- a/gpu/config/gpu_preferences_unittest.cc +++ b/gpu/config/gpu_preferences_unittest.cc
@@ -74,6 +74,7 @@ right.use_gpu_fences_for_overlay_planes); EXPECT_EQ(left.watchdog_starts_backgrounded, right.watchdog_starts_backgrounded); + EXPECT_EQ(left.enable_vulkan, right.enable_vulkan); } } // namespace @@ -150,6 +151,7 @@ GPU_PREFERENCES_FIELD(disable_oop_rasterization, true) GPU_PREFERENCES_FIELD(use_gpu_fences_for_overlay_planes, true) GPU_PREFERENCES_FIELD(watchdog_starts_backgrounded, true) + GPU_PREFERENCES_FIELD(enable_vulkan, true) input_prefs.texture_target_exception_list.emplace_back( gfx::BufferUsage::SCANOUT, gfx::BufferFormat::RGBA_8888);
diff --git a/gpu/ipc/common/gpu_preferences.mojom b/gpu/ipc/common/gpu_preferences.mojom index 37f32a8..b467a10 100644 --- a/gpu/ipc/common/gpu_preferences.mojom +++ b/gpu/ipc/common/gpu_preferences.mojom
@@ -64,4 +64,5 @@ bool disable_oop_rasterization; bool use_gpu_fences_for_overlay_planes; bool watchdog_starts_backgrounded; + bool enable_vulkan; };
diff --git a/gpu/ipc/common/gpu_preferences_struct_traits.h b/gpu/ipc/common/gpu_preferences_struct_traits.h index 6bcf6536..265911c4 100644 --- a/gpu/ipc/common/gpu_preferences_struct_traits.h +++ b/gpu/ipc/common/gpu_preferences_struct_traits.h
@@ -121,6 +121,7 @@ out->use_gpu_fences_for_overlay_planes = prefs.use_gpu_fences_for_overlay_planes(); out->watchdog_starts_backgrounded = prefs.watchdog_starts_backgrounded(); + out->enable_vulkan = prefs.enable_vulkan(); return true; } @@ -261,6 +262,9 @@ static bool watchdog_starts_backgrounded(const gpu::GpuPreferences& prefs) { return prefs.watchdog_starts_backgrounded; } + static bool enable_vulkan(const gpu::GpuPreferences& prefs) { + return prefs.enable_vulkan; + } }; } // namespace mojo
diff --git a/gpu/ipc/service/BUILD.gn b/gpu/ipc/service/BUILD.gn index b226989..834eab22f 100644 --- a/gpu/ipc/service/BUILD.gn +++ b/gpu/ipc/service/BUILD.gn
@@ -4,6 +4,7 @@ import("//testing/test.gni") import("//build/config/ui.gni") +import("//gpu/vulkan/features.gni") if (is_mac) { import("//build/config/mac/mac_sdk.gni") } @@ -64,6 +65,7 @@ "//gpu/command_buffer/service:gles2", "//gpu/config", "//gpu/ipc/common", + "//gpu/vulkan:buildflags", ] libs = [] ldflags = [] @@ -129,6 +131,9 @@ if (is_fuchsia) { sources += [ "image_transport_surface_fuchsia.cc" ] } + if (enable_vulkan) { + deps += [ "//gpu/vulkan/init" ] + } } source_set("test_support") {
diff --git a/gpu/ipc/service/gpu_channel_manager.cc b/gpu/ipc/service/gpu_channel_manager.cc index 1c8818d6..eb2da596 100644 --- a/gpu/ipc/service/gpu_channel_manager.cc +++ b/gpu/ipc/service/gpu_channel_manager.cc
@@ -30,6 +30,7 @@ #include "gpu/ipc/service/gpu_channel.h" #include "gpu/ipc/service/gpu_channel_manager_delegate.h" #include "gpu/ipc/service/gpu_memory_buffer_factory.h" +#include "third_party/skia/include/core/SkGraphics.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_share_group.h" #include "ui/gl/gl_version_info.h" @@ -298,6 +299,8 @@ raster_decoder_context_state_->context_lost = true; raster_decoder_context_state_.reset(); } + + SkGraphics::PurgeAllCaches(); } #endif @@ -307,6 +310,9 @@ base::MemoryPressureListener::MemoryPressureLevel:: MEMORY_PRESSURE_LEVEL_CRITICAL); } + + // Release all skia caching when the application is backgrounded. + SkGraphics::PurgeAllCaches(); } void GpuChannelManager::HandleMemoryPressure(
diff --git a/gpu/ipc/service/gpu_init.cc b/gpu/ipc/service/gpu_init.cc index 98a1a44..4ba6ee24 100644 --- a/gpu/ipc/service/gpu_init.cc +++ b/gpu/ipc/service/gpu_init.cc
@@ -38,6 +38,11 @@ #include "ui/gl/gl_surface_egl.h" #endif +#if BUILDFLAG(ENABLE_VULKAN) +#include "gpu/vulkan/init/vulkan_factory.h" +#include "gpu/vulkan/vulkan_implementation.h" +#endif + namespace gpu { namespace { @@ -172,6 +177,20 @@ #endif // OS_WIN } +#if BUILDFLAG(ENABLE_VULKAN) + if (gpu_preferences_.enable_vulkan) { + vulkan_implementation_ = gpu::CreateVulkanImplementation(); + if (!vulkan_implementation_ || + !vulkan_implementation_->InitializeVulkanInstance()) { + DLOG(WARNING) << "Failed to create and initialize Vulkan implementation."; + vulkan_implementation_ = nullptr; + } + gpu_preferences_.enable_vulkan = !!vulkan_implementation_; + } +#else + gpu_preferences_.enable_vulkan = false; +#endif + sandbox_helper_->PreSandboxStartup(); bool attempted_startsandbox = false;
diff --git a/gpu/ipc/service/gpu_init.h b/gpu/ipc/service/gpu_init.h index a19f6cc..39ed71f 100644 --- a/gpu/ipc/service/gpu_init.h +++ b/gpu/ipc/service/gpu_init.h
@@ -12,6 +12,7 @@ #include "gpu/config/gpu_preferences.h" #include "gpu/ipc/service/gpu_ipc_service_export.h" #include "gpu/ipc/service/gpu_watchdog_thread.h" +#include "gpu/vulkan/buildflags.h" namespace base { class CommandLine; @@ -19,6 +20,8 @@ namespace gpu { +class VulkanImplementation; + class GPU_IPC_SERVICE_EXPORT GpuSandboxHelper { public: virtual ~GpuSandboxHelper() = default; @@ -60,6 +63,13 @@ return std::move(watchdog_thread_); } bool init_successful() const { return init_successful_; } +#if BUILDFLAG(ENABLE_VULKAN) + VulkanImplementation* vulkan_implementation() { + return vulkan_implementation_.get(); + } +#else + VulkanImplementation* vulkan_implementation() { return nullptr; } +#endif private: GpuSandboxHelper* sandbox_helper_ = nullptr; @@ -74,6 +84,10 @@ base::Optional<GPUInfo> gpu_info_for_hardware_gpu_; base::Optional<GpuFeatureInfo> gpu_feature_info_for_hardware_gpu_; +#if BUILDFLAG(ENABLE_VULKAN) + std::unique_ptr<VulkanImplementation> vulkan_implementation_; +#endif + void AdjustInfoToSwiftShader(); DISALLOW_COPY_AND_ASSIGN(GpuInit);
diff --git a/gpu/vulkan/features.gni b/gpu/vulkan/features.gni index 150f6156..1c11576f 100644 --- a/gpu/vulkan/features.gni +++ b/gpu/vulkan/features.gni
@@ -9,4 +9,10 @@ declare_args() { # Enable experimental vulkan backend. enable_vulkan = (is_linux && use_x11) || is_android + + # We want to temporarily disable Vulkan on Android to give us time to + # investigate ways to reduce its binary size. + if (is_android) { + enable_vulkan = false + } }
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg index 7adec62..4080ded 100644 --- a/infra/config/global/luci-scheduler.cfg +++ b/infra/config/global/luci-scheduler.cfg
@@ -78,6 +78,8 @@ triggers: "Android FYI Release (Nexus 6P)" triggers: "Android FYI Release (Nexus 9)" triggers: "Android FYI dEQP Release (Nexus 5X)" + triggers: "Android N5 Swarm" + triggers: "Android N5X Swarm" triggers: "Android Release (Nexus 5X)" triggers: "Android arm Builder (dbg)" triggers: "Android arm64 Builder (dbg)" @@ -87,6 +89,7 @@ triggers: "Cast Android (dbg)" triggers: "Cast Audio Linux" triggers: "Cast Linux" + triggers: "ChromeOS Swarm" triggers: "Chromium Linux Goma GCE Staging" triggers: "Chromium Linux Goma RBE Staging (clobber)" triggers: "Chromium Linux Goma RBE Staging (dbg) (clobber)" @@ -152,6 +155,7 @@ triggers: "Linux Clang Analyzer" triggers: "Linux FYI GPU TSAN Release" triggers: "Linux MSan Builder" + triggers: "Linux Swarm" triggers: "Linux TSan Builder" triggers: "Linux Viz" triggers: "Linux remote_run Builder" @@ -172,6 +176,7 @@ triggers: "Mac FYI GPU ASAN Release" triggers: "Mac Goma Canary (clobber)" triggers: "Mac Goma Canary LocalOutputCache" + triggers: "Mac Swarm" triggers: "Mac deterministic (dbg)" triggers: "Mac deterministic" triggers: "Mac" @@ -203,6 +208,7 @@ triggers: "Win7 Builder Goma Canary" triggers: "WinMSVC64 Goma Canary" triggers: "Windows Clang deterministic" + triggers: "Windows Swarm" triggers: "Windows deterministic" triggers: "android-kitkat-arm-rel" triggers: "android-marshmallow-arm64-rel"
diff --git a/ios/chrome/browser/experimental_flags.mm b/ios/chrome/browser/experimental_flags.mm index eb914622..2a5fe05 100644 --- a/ios/chrome/browser/experimental_flags.mm +++ b/ios/chrome/browser/experimental_flags.mm
@@ -143,7 +143,7 @@ } bool IsSettingsUIRebootEnabled() { - return base::FeatureList::IsEnabled(kCollectionsUIReboot); + return base::FeatureList::IsEnabled(kUIRefreshPhase1); } } // namespace experimental_flags
diff --git a/ios/chrome/browser/payments/BUILD.gn b/ios/chrome/browser/payments/BUILD.gn index e3c48928..588b77ad 100644 --- a/ios/chrome/browser/payments/BUILD.gn +++ b/ios/chrome/browser/payments/BUILD.gn
@@ -44,6 +44,7 @@ "//ios/chrome/browser", "//ios/chrome/browser/autofill", "//ios/chrome/browser/browser_state", + "//ios/chrome/browser/metrics", "//ios/chrome/browser/signin", "//ios/web", "//net",
diff --git a/ios/chrome/browser/payments/payment_request.mm b/ios/chrome/browser/payments/payment_request.mm index f9ae6baa..76495d9e2 100644 --- a/ios/chrome/browser/payments/payment_request.mm +++ b/ios/chrome/browser/payments/payment_request.mm
@@ -31,6 +31,7 @@ #include "ios/chrome/browser/autofill/address_normalizer_factory.h" #include "ios/chrome/browser/autofill/validation_rules_storage_factory.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" +#import "ios/chrome/browser/metrics/ukm_url_recorder.h" #import "ios/chrome/browser/payments/ios_payment_instrument.h" #import "ios/chrome/browser/payments/payment_request_util.h" #include "ios/chrome/browser/signin/signin_manager_factory.h" @@ -96,7 +97,8 @@ selected_payment_method_(nullptr), selected_shipping_option_(nullptr), profile_comparator_(GetApplicationLocale(), *this), - journey_logger_(IsIncognito(), GetLastCommittedURL(), GetUkmRecorder()), + journey_logger_(IsIncognito(), + ukm::GetSourceIdForWebStateDocument(web_state)), payment_instruments_ready_(false), ios_instrument_finder_( GetApplicationContext()->GetSharedURLLoaderFactory(),
diff --git a/media/base/bind_to_current_loop.h b/media/base/bind_to_current_loop.h index 8c07621..de69a63a 100644 --- a/media/base/bind_to_current_loop.h +++ b/media/base/bind_to_current_loop.h
@@ -13,18 +13,22 @@ #include "base/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" -// This is a helper utility for base::Bind()ing callbacks to the current -// MessageLoop. The typical use is when |a| (of class |A|) wants to hand a +// This is a helper utility for base::Bind()ing callbacks to a given +// TaskRunner. The typical use is when |a| (of class |A|) wants to hand a // callback such as base::Bind(&A::AMethod, a) to |b|, but needs to ensure that -// when |b| executes the callback, it does so on |a|'s current MessageLoop. +// when |b| executes the callback, it does so on |a|'s task_runner's +// MessageLoop. // // Typical usage: request to be called back on the current thread: // other->StartAsyncProcessAndCallMeBack( -// media::BindToCurrentLoop(base::BindOnce(&MyClass::MyMethod, this))); +// media::BindToLoop(task_runner, base::BindOnce(&MyClass::MyMethod, this))); // -// media::BindToCurrentLoop returns the same type of callback to the given +// media::BindToLoop returns the same type of callback to the given // callback. I.e. it returns a RepeatingCallback for a given RepeatingCallback, // and returns OnceCallback for a given OnceCallback. +// +// The function BindToCurrentLoop is shorthand to bind to the calling function's +// current MessageLoop. namespace media { namespace internal { @@ -81,7 +85,8 @@ } // namespace internal template <typename... Args> -inline base::RepeatingCallback<void(Args...)> BindToCurrentLoop( +inline base::RepeatingCallback<void(Args...)> BindToLoop( + scoped_refptr<base::SequencedTaskRunner> task_runner, base::RepeatingCallback<void(Args...)> cb) { using CallbackType = base::RepeatingCallback<void(Args...)>; using Helper = internal::TrampolineHelper<CallbackType>; @@ -89,12 +94,12 @@ RunnerType run = &Helper::Run; // TODO(tzik): Propagate FROM_HERE from the caller. return base::BindRepeating( - run, std::make_unique<Helper>( - FROM_HERE, base::ThreadTaskRunnerHandle::Get(), std::move(cb))); + run, std::make_unique<Helper>(FROM_HERE, task_runner, std::move(cb))); } template <typename... Args> -inline base::OnceCallback<void(Args...)> BindToCurrentLoop( +inline base::OnceCallback<void(Args...)> BindToLoop( + scoped_refptr<base::SequencedTaskRunner> task_runner, base::OnceCallback<void(Args...)> cb) { using CallbackType = base::OnceCallback<void(Args...)>; using Helper = internal::TrampolineHelper<CallbackType>; @@ -102,8 +107,19 @@ RunnerType run = &Helper::Run; // TODO(tzik): Propagate FROM_HERE from the caller. return base::BindOnce( - run, std::make_unique<Helper>( - FROM_HERE, base::ThreadTaskRunnerHandle::Get(), std::move(cb))); + run, std::make_unique<Helper>(FROM_HERE, task_runner, std::move(cb))); +} + +template <typename... Args> +inline base::RepeatingCallback<void(Args...)> BindToCurrentLoop( + base::RepeatingCallback<void(Args...)> cb) { + return BindToLoop(base::ThreadTaskRunnerHandle::Get(), std::move(cb)); +} + +template <typename... Args> +inline base::OnceCallback<void(Args...)> BindToCurrentLoop( + base::OnceCallback<void(Args...)> cb) { + return BindToLoop(base::ThreadTaskRunnerHandle::Get(), std::move(cb)); } } // namespace media
diff --git a/media/blink/DEPS b/media/blink/DEPS index c30001fa..efda6347 100644 --- a/media/blink/DEPS +++ b/media/blink/DEPS
@@ -1,5 +1,6 @@ include_rules = [ "+cc/layers/layer.h", + "+cc/layers/surface_layer.h", "+cc/layers/video_frame_provider.h", "+cc/layers/video_layer.h", "+components/scheduler", # Only allowed in tests.
diff --git a/media/blink/video_frame_compositor.cc b/media/blink/video_frame_compositor.cc index 99c2fb99..6b25bcb0 100644 --- a/media/blink/video_frame_compositor.cc +++ b/media/blink/video_frame_compositor.cc
@@ -9,6 +9,7 @@ #include "base/time/default_tick_clock.h" #include "base/trace_event/auto_open_close_event.h" #include "base/trace_event/trace_event.h" +#include "media/base/bind_to_current_loop.h" #include "media/base/media_switches.h" #include "media/base/video_frame.h" #include "media/blink/webmediaplayer_params.h" @@ -46,9 +47,23 @@ task_runner_->PostTask( FROM_HERE, base::Bind(&VideoFrameCompositor::InitializeSubmitter, weak_ptr_factory_.GetWeakPtr())); + update_submission_state_callback_ = media::BindToLoop( + task_runner_, + base::BindRepeating(&VideoFrameCompositor::UpdateSubmissionState, + weak_ptr_factory_.GetWeakPtr())); } } +cc::UpdateSubmissionStateCB +VideoFrameCompositor::GetUpdateSubmissionStateCallback() { + return update_submission_state_callback_; +} + +void VideoFrameCompositor::UpdateSubmissionState(bool state) { + DCHECK(task_runner_->BelongsToCurrentThread()); + submitter_->UpdateSubmissionState(state); +} + void VideoFrameCompositor::InitializeSubmitter() { DCHECK(task_runner_->BelongsToCurrentThread()); submitter_->Initialize(this); @@ -63,7 +78,7 @@ } void VideoFrameCompositor::EnableSubmission( - const viz::FrameSinkId& id, + const viz::SurfaceId& id, media::VideoRotation rotation, blink::WebFrameSinkDestroyedCallback frame_sink_destroyed_callback) { DCHECK(task_runner_->BelongsToCurrentThread());
diff --git a/media/blink/video_frame_compositor.h b/media/blink/video_frame_compositor.h index f0b49b5..f3959f8 100644 --- a/media/blink/video_frame_compositor.h +++ b/media/blink/video_frame_compositor.h
@@ -15,6 +15,7 @@ #include "base/time/tick_clock.h" #include "base/time/time.h" #include "base/timer/timer.h" +#include "cc/layers/surface_layer.h" #include "cc/layers/video_frame_provider.h" #include "media/base/video_renderer_sink.h" #include "media/blink/media_blink_export.h" @@ -29,7 +30,7 @@ } namespace viz { -class FrameSinkId; +class SurfaceId; } namespace media { @@ -76,10 +77,13 @@ // called before destruction starts. ~VideoFrameCompositor() override; + // Can be called from any thread. + cc::UpdateSubmissionStateCB GetUpdateSubmissionStateCallback(); + // Signals the VideoFrameSubmitter to prepare to receive BeginFrames and // submit video frames given by VideoFrameCompositor. virtual void EnableSubmission( - const viz::FrameSinkId& id, + const viz::SurfaceId& id, media::VideoRotation rotation, blink::WebFrameSinkDestroyedCallback frame_sink_destroyed_callback); @@ -150,9 +154,10 @@ // Ran on the |task_runner_| to initalize |submitter_|; void InitializeSubmitter(); + // Signals the VideoFrameSubmitter to stop submitting frames. + void UpdateSubmissionState(bool); + // Indicates whether the endpoint for the VideoFrame exists. - // TODO(lethalantidote): Update this function to read creation/destruction - // signals of the SurfaceLayerImpl. bool IsClientSinkAvailable(); // Called on the compositor thread in response to Start() or Stop() calls; @@ -201,6 +206,7 @@ base::TimeDelta last_interval_; base::TimeTicks last_background_render_; OnNewProcessedFrameCB new_processed_frame_cb_; + cc::UpdateSubmissionStateCB update_submission_state_callback_; // Set on the compositor thread, but also read on the media thread. base::Lock current_frame_lock_;
diff --git a/media/blink/video_frame_compositor_unittest.cc b/media/blink/video_frame_compositor_unittest.cc index 8585ce9..237be8d 100644 --- a/media/blink/video_frame_compositor_unittest.cc +++ b/media/blink/video_frame_compositor_unittest.cc
@@ -28,11 +28,12 @@ // blink::WebVideoFrameSubmitter implementation. void StopUsingProvider() override {} MOCK_METHOD2(EnableSubmission, - void(viz::FrameSinkId, blink::WebFrameSinkDestroyedCallback)); + void(viz::SurfaceId, blink::WebFrameSinkDestroyedCallback)); MOCK_METHOD0(StartRendering, void()); MOCK_METHOD0(StopRendering, void()); MOCK_METHOD1(Initialize, void(cc::VideoFrameProvider*)); MOCK_METHOD1(SetRotation, void(media::VideoRotation)); + MOCK_METHOD1(UpdateSubmissionState, void(bool)); void DidReceiveFrame() override { ++did_receive_frame_count_; } int did_receive_frame_count() { return did_receive_frame_count_; } @@ -69,8 +70,8 @@ base::RunLoop().RunUntilIdle(); EXPECT_CALL(*submitter_, SetRotation(Eq(media::VideoRotation::VIDEO_ROTATION_90))); - EXPECT_CALL(*submitter_, EnableSubmission(Eq(viz::FrameSinkId(1, 1)), _)); - compositor_->EnableSubmission(viz::FrameSinkId(1, 1), + EXPECT_CALL(*submitter_, EnableSubmission(Eq(viz::SurfaceId()), _)); + compositor_->EnableSubmission(viz::SurfaceId(), media::VideoRotation::VIDEO_ROTATION_90, base::BindRepeating([] {})); }
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc index d1a69db..49b1395 100644 --- a/media/blink/webmediaplayer_impl.cc +++ b/media/blink/webmediaplayer_impl.cc
@@ -1630,13 +1630,15 @@ } else { DCHECK(!bridge_); - bridge_ = std::move(create_bridge_callback_).Run(this); + bridge_ = std::move(create_bridge_callback_) + .Run(this, compositor_->GetUpdateSubmissionStateCallback()); bridge_->CreateSurfaceLayer(); + vfc_task_runner_->PostTask( FROM_HERE, base::BindOnce( &VideoFrameCompositor::EnableSubmission, - base::Unretained(compositor_.get()), bridge_->GetFrameSinkId(), + base::Unretained(compositor_.get()), bridge_->GetSurfaceId(), pipeline_metadata_.video_decoder_config.video_rotation(), BindToCurrentLoop(base::BindRepeating( &WebMediaPlayerImpl::OnFrameSinkDestroyed, AsWeakPtr()))));
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h index 3872617..5af1fefd 100644 --- a/media/blink/webmediaplayer_impl.h +++ b/media/blink/webmediaplayer_impl.h
@@ -24,6 +24,7 @@ #include "base/timer/elapsed_timer.h" #include "base/timer/timer.h" #include "build/build_config.h" +#include "cc/layers/surface_layer.h" #include "components/viz/common/gpu/context_provider.h" #include "media/base/media_observer.h" #include "media/base/media_tracks.h" @@ -866,7 +867,8 @@ bool surface_layer_for_video_enabled_ = false; base::OnceCallback<std::unique_ptr<blink::WebSurfaceLayerBridge>( - blink::WebSurfaceLayerBridgeObserver*)> + blink::WebSurfaceLayerBridgeObserver*, + cc::UpdateSubmissionStateCB)> create_bridge_callback_; base::CancelableOnceCallback<void(base::TimeTicks)> frame_time_report_cb_;
diff --git a/media/blink/webmediaplayer_impl_unittest.cc b/media/blink/webmediaplayer_impl_unittest.cc index 5d59dba..eb1bbe3 100644 --- a/media/blink/webmediaplayer_impl_unittest.cc +++ b/media/blink/webmediaplayer_impl_unittest.cc
@@ -294,10 +294,10 @@ public: MOCK_CONST_METHOD0(GetCcLayer, cc::Layer*()); MOCK_CONST_METHOD0(GetFrameSinkId, const viz::FrameSinkId&()); + MOCK_CONST_METHOD0(GetSurfaceId, const viz::SurfaceId&()); MOCK_METHOD0(ClearSurfaceId, void()); MOCK_METHOD1(SetContentsOpaque, void(bool)); MOCK_METHOD0(CreateSurfaceLayer, void()); - MOCK_CONST_METHOD0(GetSurfaceId, const viz::SurfaceId&()); }; class MockVideoFrameCompositor : public VideoFrameCompositor { @@ -311,7 +311,7 @@ void SetOnNewProcessedFrameCallback(OnNewProcessedFrameCB cb) override {} MOCK_METHOD0(GetCurrentFrameAndUpdateIfStale, scoped_refptr<VideoFrame>()); MOCK_METHOD3(EnableSubmission, - void(const viz::FrameSinkId&, + void(const viz::SurfaceId&, media::VideoRotation, blink::WebFrameSinkDestroyedCallback)); }; @@ -379,9 +379,8 @@ kMaxKeyframeDistanceToDisableBackgroundVideo, kMaxKeyframeDistanceToDisableBackgroundVideoMSE, false, false, std::move(provider), - base::BindRepeating( - &WebMediaPlayerImplTest::CreateMockSurfaceLayerBridge, - base::Unretained(this)), + base::BindOnce(&WebMediaPlayerImplTest::CreateMockSurfaceLayerBridge, + base::Unretained(this)), viz::TestContextProvider::Create(), base::FeatureList::IsEnabled(media::kUseSurfaceLayerForVideo)); @@ -416,7 +415,8 @@ protected: std::unique_ptr<blink::WebSurfaceLayerBridge> CreateMockSurfaceLayerBridge( - blink::WebSurfaceLayerBridgeObserver*) { + blink::WebSurfaceLayerBridgeObserver*, + cc::UpdateSubmissionStateCB) { return std::move(surface_layer_bridge_); } @@ -768,8 +768,8 @@ if (base::FeatureList::IsEnabled(kUseSurfaceLayerForVideo)) { EXPECT_CALL(*surface_layer_bridge_ptr_, CreateSurfaceLayer()); EXPECT_CALL(client_, SetCcLayer(_)).Times(0); - EXPECT_CALL(*surface_layer_bridge_ptr_, GetFrameSinkId()) - .WillOnce(ReturnRef(frame_sink_id_)); + EXPECT_CALL(*surface_layer_bridge_ptr_, GetSurfaceId()) + .WillOnce(ReturnRef(surface_id_)); EXPECT_CALL(*compositor_, EnableSubmission(_, _, _)); EXPECT_CALL(*surface_layer_bridge_ptr_, SetContentsOpaque(false)); } @@ -1166,7 +1166,7 @@ if (base::FeatureList::IsEnabled(media::kUseSurfaceLayerForVideo)) { EXPECT_CALL(*surface_layer_bridge_ptr_, CreateSurfaceLayer()).Times(0); - EXPECT_CALL(*surface_layer_bridge_ptr_, GetFrameSinkId()).Times(0); + EXPECT_CALL(*surface_layer_bridge_ptr_, GetSurfaceId()).Times(0); EXPECT_CALL(*compositor_, EnableSubmission(_, _, _)).Times(0); } @@ -1184,8 +1184,8 @@ if (base::FeatureList::IsEnabled(kUseSurfaceLayerForVideo)) { EXPECT_CALL(*surface_layer_bridge_ptr_, CreateSurfaceLayer()); EXPECT_CALL(client_, SetCcLayer(_)).Times(0); - EXPECT_CALL(*surface_layer_bridge_ptr_, GetFrameSinkId()) - .WillOnce(ReturnRef(frame_sink_id_)); + EXPECT_CALL(*surface_layer_bridge_ptr_, GetSurfaceId()) + .WillOnce(ReturnRef(surface_id_)); EXPECT_CALL(*compositor_, EnableSubmission(_, _, _)); EXPECT_CALL(*surface_layer_bridge_ptr_, SetContentsOpaque(false)); } else { @@ -1211,8 +1211,8 @@ if (base::FeatureList::IsEnabled(kUseSurfaceLayerForVideo)) { EXPECT_CALL(client_, SetCcLayer(_)).Times(0); EXPECT_CALL(*surface_layer_bridge_ptr_, CreateSurfaceLayer()); - EXPECT_CALL(*surface_layer_bridge_ptr_, GetFrameSinkId()) - .WillOnce(ReturnRef(frame_sink_id_)); + EXPECT_CALL(*surface_layer_bridge_ptr_, GetSurfaceId()) + .WillOnce(ReturnRef(surface_id_)); EXPECT_CALL(*compositor_, EnableSubmission(_, _, _)); EXPECT_CALL(*surface_layer_bridge_ptr_, SetContentsOpaque(false)); } else { @@ -1239,8 +1239,8 @@ if (base::FeatureList::IsEnabled(kUseSurfaceLayerForVideo)) { EXPECT_CALL(client_, SetCcLayer(_)).Times(0); EXPECT_CALL(*surface_layer_bridge_ptr_, CreateSurfaceLayer()); - EXPECT_CALL(*surface_layer_bridge_ptr_, GetFrameSinkId()) - .WillOnce(ReturnRef(frame_sink_id_)); + EXPECT_CALL(*surface_layer_bridge_ptr_, GetSurfaceId()) + .WillOnce(ReturnRef(surface_id_)); EXPECT_CALL(*compositor_, EnableSubmission(_, _, _)); EXPECT_CALL(*surface_layer_bridge_ptr_, SetContentsOpaque(false)); } else { @@ -1315,8 +1315,8 @@ if (base::FeatureList::IsEnabled(kUseSurfaceLayerForVideo)) { EXPECT_CALL(client_, SetCcLayer(_)).Times(0); EXPECT_CALL(*surface_layer_bridge_ptr_, CreateSurfaceLayer()); - EXPECT_CALL(*surface_layer_bridge_ptr_, GetFrameSinkId()) - .WillOnce(ReturnRef(frame_sink_id_)); + EXPECT_CALL(*surface_layer_bridge_ptr_, GetSurfaceId()) + .WillOnce(ReturnRef(surface_id_)); EXPECT_CALL(*compositor_, EnableSubmission(_, _, _)); EXPECT_CALL(*surface_layer_bridge_ptr_, SetContentsOpaque(false)); } else { @@ -1353,8 +1353,8 @@ EXPECT_CALL(client_, SetCcLayer(_)).Times(0); EXPECT_CALL(*surface_layer_bridge_ptr_, CreateSurfaceLayer()); - EXPECT_CALL(*surface_layer_bridge_ptr_, GetFrameSinkId()) - .WillOnce(ReturnRef(frame_sink_id_)); + EXPECT_CALL(*surface_layer_bridge_ptr_, GetSurfaceId()) + .WillOnce(ReturnRef(surface_id_)); EXPECT_CALL(*surface_layer_bridge_ptr_, SetContentsOpaque(false)); EXPECT_CALL(*compositor_, EnableSubmission(_, _, _)); @@ -1392,10 +1392,8 @@ InitializeWebMediaPlayerImpl(); EXPECT_CALL(*surface_layer_bridge_ptr_, CreateSurfaceLayer()); - EXPECT_CALL(*surface_layer_bridge_ptr_, GetFrameSinkId()) - .WillOnce(ReturnRef(frame_sink_id_)); EXPECT_CALL(*surface_layer_bridge_ptr_, GetSurfaceId()) - .WillOnce(ReturnRef(surface_id_)); + .WillRepeatedly(ReturnRef(surface_id_)); EXPECT_CALL(*compositor_, EnableSubmission(_, _, _)); EXPECT_CALL(*surface_layer_bridge_ptr_, SetContentsOpaque(false));
diff --git a/media/blink/webmediaplayer_params.cc b/media/blink/webmediaplayer_params.cc index 9b6a730..0436885 100644 --- a/media/blink/webmediaplayer_params.cc +++ b/media/blink/webmediaplayer_params.cc
@@ -29,7 +29,8 @@ bool embedded_media_experience_enabled, mojom::MediaMetricsProviderPtr metrics_provider, base::OnceCallback<std::unique_ptr<blink::WebSurfaceLayerBridge>( - blink::WebSurfaceLayerBridgeObserver*)> create_bridge_callback, + blink::WebSurfaceLayerBridgeObserver*, + cc::UpdateSubmissionStateCB)> create_bridge_callback, scoped_refptr<viz::ContextProvider> context_provider, bool use_surface_layer_for_video) : defer_load_cb_(defer_load_cb),
diff --git a/media/blink/webmediaplayer_params.h b/media/blink/webmediaplayer_params.h index 256532d80..0793f19 100644 --- a/media/blink/webmediaplayer_params.h +++ b/media/blink/webmediaplayer_params.h
@@ -13,6 +13,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/time/time.h" +#include "cc/layers/surface_layer.h" #include "components/viz/common/gpu/context_provider.h" #include "media/base/media_log.h" #include "media/base/media_observer.h" @@ -81,7 +82,8 @@ bool embedded_media_experience_enabled, mojom::MediaMetricsProviderPtr metrics_provider, base::OnceCallback<std::unique_ptr<blink::WebSurfaceLayerBridge>( - blink::WebSurfaceLayerBridgeObserver*)> bridge_callback, + blink::WebSurfaceLayerBridgeObserver*, + cc::UpdateSubmissionStateCB)> bridge_callback, scoped_refptr<viz::ContextProvider> context_provider, bool use_surface_layer_for_video); @@ -152,7 +154,8 @@ } base::OnceCallback<std::unique_ptr<blink::WebSurfaceLayerBridge>( - blink::WebSurfaceLayerBridgeObserver*)> + blink::WebSurfaceLayerBridgeObserver*, + cc::UpdateSubmissionStateCB)> create_bridge_callback() { return std::move(create_bridge_callback_); } @@ -185,7 +188,8 @@ const bool embedded_media_experience_enabled_; mojom::MediaMetricsProviderPtr metrics_provider_; base::OnceCallback<std::unique_ptr<blink::WebSurfaceLayerBridge>( - blink::WebSurfaceLayerBridgeObserver*)> + blink::WebSurfaceLayerBridgeObserver*, + cc::UpdateSubmissionStateCB)> create_bridge_callback_; scoped_refptr<viz::ContextProvider> context_provider_; bool use_surface_layer_for_video_;
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn index 9d9b3d14..b6cf674 100644 --- a/media/gpu/BUILD.gn +++ b/media/gpu/BUILD.gn
@@ -550,6 +550,12 @@ "jpeg_decode_accelerator_unittest.cc", "test/video_accelerator_unittest_helpers.h", ] + data = [ + "//media/test/data/peach_pi-1280x720.jpg", + "//media/test/data/peach_pi-40x23.jpg", + "//media/test/data/peach_pi-41x22.jpg", + "//media/test/data/peach_pi-41x23.jpg", + ] if (use_x11) { deps += [ "//ui/gfx/x" ] }
diff --git a/media/renderers/video_resource_updater.cc b/media/renderers/video_resource_updater.cc index efb9234..952c9a7 100644 --- a/media/renderers/video_resource_updater.cc +++ b/media/renderers/video_resource_updater.cc
@@ -872,14 +872,16 @@ size_t bytes_per_row = viz::ResourceSizes::CheckedWidthInBytes<size_t>( video_frame->coded_size().width(), viz::ResourceFormat::RGBA_8888); size_t needed_size = bytes_per_row * video_frame->coded_size().height(); - if (upload_pixels_.size() < needed_size) { - // Clear before resizing to avoid memcpy. - upload_pixels_.clear(); - upload_pixels_.resize(needed_size); + if (upload_pixels_size_ < needed_size) { + // Free the existing data first so that the memory can be reused, + // if possible. Note that the new array is purposely not initialized. + upload_pixels_.reset(); + upload_pixels_.reset(new uint8_t[needed_size]); + upload_pixels_size_ = needed_size; } PaintCanvasVideoRenderer::ConvertVideoFrameToRGBPixels( - video_frame.get(), &upload_pixels_[0], bytes_per_row); + video_frame.get(), upload_pixels_.get(), bytes_per_row); // Copy pixels into texture. auto* gl = context_provider_->ContextGL(); @@ -889,7 +891,7 @@ gl->TexSubImage2D( hardware_resource->texture_target(), 0, 0, 0, plane_size.width(), plane_size.height(), GLDataFormat(viz::ResourceFormat::RGBA_8888), - GLDataType(viz::ResourceFormat::RGBA_8888), &upload_pixels_[0]); + GLDataType(viz::ResourceFormat::RGBA_8888), upload_pixels_.get()); } plane_resource->SetUniqueId(video_frame->unique_id(), 0); } @@ -997,10 +999,12 @@ // Avoid malloc for each frame/plane if possible. const size_t needed_size = upload_image_stride * resource_size_pixels.height(); - if (upload_pixels_.size() < needed_size) { - // Clear before resizing to avoid memcpy. - upload_pixels_.clear(); - upload_pixels_.resize(needed_size); + if (upload_pixels_size_ < needed_size) { + // Free the existing data first so that the memory can be reused, + // if possible. Note that the new array is purposely not initialized. + upload_pixels_.reset(); + upload_pixels_.reset(new uint8_t[needed_size]); + upload_pixels_size_ = needed_size; } if (plane_resource_format == viz::LUMINANCE_F16) { @@ -1017,7 +1021,7 @@ const int scale = 0x10000 >> (bits_per_channel - 8); libyuv::Convert16To8Plane( reinterpret_cast<uint16_t*>(video_frame->data(i)), - video_stride_bytes / 2, upload_pixels_.data(), upload_image_stride, + video_stride_bytes / 2, upload_pixels_.get(), upload_image_stride, scale, bytes_per_row, resource_size_pixels.height()); } else { // Make a copy to reconcile stride, size and format being equal. @@ -1025,12 +1029,12 @@ DCHECK(plane_resource_format == viz::LUMINANCE_8 || plane_resource_format == viz::RED_8); libyuv::CopyPlane(video_frame->data(i), video_stride_bytes, - upload_pixels_.data(), upload_image_stride, + upload_pixels_.get(), upload_image_stride, resource_size_pixels.width(), resource_size_pixels.height()); } - pixels = &upload_pixels_[0]; + pixels = upload_pixels_.get(); } // Copy pixels into texture. TexSubImage2D() is applicable because
diff --git a/media/renderers/video_resource_updater.h b/media/renderers/video_resource_updater.h index 4a4e6a5..9ea3f50 100644 --- a/media/renderers/video_resource_updater.h +++ b/media/renderers/video_resource_updater.h
@@ -196,7 +196,8 @@ uint32_t next_plane_resource_id_ = 1; // Temporary pixel buffer when converting between formats. - std::vector<uint8_t> upload_pixels_; + std::unique_ptr<uint8_t[]> upload_pixels_; + size_t upload_pixels_size_ = 0; VideoFrameResourceType frame_resource_type_;
diff --git a/net/disk_cache/simple/simple_entry_impl.cc b/net/disk_cache/simple/simple_entry_impl.cc index e3345922..e6297a1 100644 --- a/net/disk_cache/simple/simple_entry_impl.cc +++ b/net/disk_cache/simple/simple_entry_impl.cc
@@ -391,8 +391,10 @@ return net::ERR_INVALID_ARGUMENT; } - // TODO(felipeg): Optimization: Add support for truly parallel read - // operations. + // If this is the only operation, bypass the queue, and also see if there is + // in-memory data to handle it synchronously. In principle, multiple reads can + // be parallelized, but past studies have shown that parallelizable ones + // happen <1% of the time, so it's probably not worth the effort. bool alone_in_queue = pending_operations_.size() == 0 && state_ == STATE_READY; @@ -402,8 +404,7 @@ } pending_operations_.push(SimpleEntryOperation::ReadOperation( - this, stream_index, offset, buf_len, buf, std::move(callback), - alone_in_queue)); + this, stream_index, offset, buf_len, buf, std::move(callback))); RunNextOperationIfNeeded(); return net::ERR_IO_PENDING; } @@ -453,7 +454,8 @@ // actually run the write operation that sets the stream size. It also // prevents from previous possibly-conflicting writes that could be stacked // in the |pending_operations_|. We could optimize this for when we have - // only read operations enqueued. + // only read operations enqueued, but past studies have shown that that such + // parallelizable cases are very rare. const bool optimistic = (use_optimistic_operations_ && state_ == STATE_READY && pending_operations_.size() == 0); @@ -567,7 +569,6 @@ // measured, but the ownership of SimpleSynchronousEntry isn't straightforward return sizeof(SimpleSynchronousEntry) + base::trace_event::EstimateMemoryUsage(pending_operations_) + - base::trace_event::EstimateMemoryUsage(executing_operation_) + (stream_0_data_ ? stream_0_data_->capacity() : 0) + (stream_1_prefetch_data_ ? stream_1_prefetch_data_->capacity() : 0); } @@ -665,13 +666,11 @@ CloseInternal(); break; case SimpleEntryOperation::TYPE_READ: - RecordReadIsParallelizable(*operation); ReadDataInternal(/* sync_possible= */ false, operation->index(), operation->offset(), operation->buf(), operation->length(), operation->ReleaseCallback()); break; case SimpleEntryOperation::TYPE_WRITE: - RecordWriteDependencyType(*operation); WriteDataInternal(operation->index(), operation->offset(), operation->buf(), operation->length(), operation->ReleaseCallback(), operation->truncate()); @@ -697,10 +696,6 @@ default: NOTREACHED(); } - // The operation is kept for histograms. Makes sure it does not leak - // resources. - executing_operation_.swap(operation); - executing_operation_->ReleaseReferences(); // |this| may have been deleted. } } @@ -1538,77 +1533,6 @@ return file_size; } -void SimpleEntryImpl::RecordReadIsParallelizable( - const SimpleEntryOperation& operation) const { - if (!executing_operation_) - return; - // Used in histograms, please only add entries at the end. - enum ReadDependencyType { - // READ_STANDALONE = 0, Deprecated. - READ_FOLLOWS_READ = 1, - READ_FOLLOWS_CONFLICTING_WRITE = 2, - READ_FOLLOWS_NON_CONFLICTING_WRITE = 3, - READ_FOLLOWS_OTHER = 4, - READ_ALONE_IN_QUEUE = 5, - READ_DEPENDENCY_TYPE_MAX = 6, - }; - - ReadDependencyType type = READ_FOLLOWS_OTHER; - if (operation.alone_in_queue()) { - type = READ_ALONE_IN_QUEUE; - } else if (executing_operation_->type() == SimpleEntryOperation::TYPE_READ) { - type = READ_FOLLOWS_READ; - } else if (executing_operation_->type() == SimpleEntryOperation::TYPE_WRITE) { - if (executing_operation_->ConflictsWith(operation)) - type = READ_FOLLOWS_CONFLICTING_WRITE; - else - type = READ_FOLLOWS_NON_CONFLICTING_WRITE; - } - SIMPLE_CACHE_UMA(ENUMERATION, - "ReadIsParallelizable", cache_type_, - type, READ_DEPENDENCY_TYPE_MAX); -} - -void SimpleEntryImpl::RecordWriteDependencyType( - const SimpleEntryOperation& operation) const { - if (!executing_operation_) - return; - // Used in histograms, please only add entries at the end. - enum WriteDependencyType { - WRITE_OPTIMISTIC = 0, - WRITE_FOLLOWS_CONFLICTING_OPTIMISTIC = 1, - WRITE_FOLLOWS_NON_CONFLICTING_OPTIMISTIC = 2, - WRITE_FOLLOWS_CONFLICTING_WRITE = 3, - WRITE_FOLLOWS_NON_CONFLICTING_WRITE = 4, - WRITE_FOLLOWS_CONFLICTING_READ = 5, - WRITE_FOLLOWS_NON_CONFLICTING_READ = 6, - WRITE_FOLLOWS_OTHER = 7, - WRITE_DEPENDENCY_TYPE_MAX = 8, - }; - - WriteDependencyType type = WRITE_FOLLOWS_OTHER; - if (operation.optimistic()) { - type = WRITE_OPTIMISTIC; - } else if (executing_operation_->type() == SimpleEntryOperation::TYPE_READ || - executing_operation_->type() == SimpleEntryOperation::TYPE_WRITE) { - bool conflicting = executing_operation_->ConflictsWith(operation); - - if (executing_operation_->type() == SimpleEntryOperation::TYPE_READ) { - type = conflicting ? WRITE_FOLLOWS_CONFLICTING_READ - : WRITE_FOLLOWS_NON_CONFLICTING_READ; - } else if (executing_operation_->optimistic()) { - type = conflicting ? WRITE_FOLLOWS_CONFLICTING_OPTIMISTIC - : WRITE_FOLLOWS_NON_CONFLICTING_OPTIMISTIC; - } else { - type = conflicting ? WRITE_FOLLOWS_CONFLICTING_WRITE - : WRITE_FOLLOWS_NON_CONFLICTING_WRITE; - } - } - SIMPLE_CACHE_UMA(ENUMERATION, - "WriteDependencyType", cache_type_, - type, WRITE_DEPENDENCY_TYPE_MAX); -} - int SimpleEntryImpl::ReadFromBuffer(net::GrowableIOBuffer* in_buf, int offset, int buf_len,
diff --git a/net/disk_cache/simple/simple_entry_impl.h b/net/disk_cache/simple/simple_entry_impl.h index c1323e7..f00f6902 100644 --- a/net/disk_cache/simple/simple_entry_impl.h +++ b/net/disk_cache/simple/simple_entry_impl.h
@@ -330,10 +330,6 @@ int64_t GetDiskUsage() const; - // Used to report histograms. - void RecordReadIsParallelizable(const SimpleEntryOperation& operation) const; - void RecordWriteDependencyType(const SimpleEntryOperation& operation) const; - // Completes a read from the stream data kept in memory, logging metrics // and updating metadata. Returns the # of bytes read successfully. // This asumes the caller has already range-checked offset and buf_len @@ -424,8 +420,6 @@ net::NetLogWithSource net_log_; - std::unique_ptr<SimpleEntryOperation> executing_operation_; - // Unlike other streams, stream 0 data is read from the disk when the entry is // opened, and then kept in memory. All read/write operations on stream 0 // affect the |stream_0_data_| buffer. When the entry is closed,
diff --git a/net/disk_cache/simple/simple_entry_operation.cc b/net/disk_cache/simple/simple_entry_operation.cc index 5e48343..e0c964e 100644 --- a/net/disk_cache/simple/simple_entry_operation.cc +++ b/net/disk_cache/simple/simple_entry_operation.cc
@@ -13,27 +13,6 @@ namespace disk_cache { -namespace { - -bool IsReadWriteType(unsigned int type) { - return type == SimpleEntryOperation::TYPE_READ || - type == SimpleEntryOperation::TYPE_WRITE || - type == SimpleEntryOperation::TYPE_READ_SPARSE || - type == SimpleEntryOperation::TYPE_WRITE_SPARSE; -} - -bool IsReadType(unsigned type) { - return type == SimpleEntryOperation::TYPE_READ || - type == SimpleEntryOperation::TYPE_READ_SPARSE; -} - -bool IsSparseType(unsigned type) { - return type == SimpleEntryOperation::TYPE_READ_SPARSE || - type == SimpleEntryOperation::TYPE_WRITE_SPARSE; -} - -} // anonymous namespace - SimpleEntryOperation::SimpleEntryOperation(SimpleEntryOperation&& other) : entry_(std::move(other.entry_)), buf_(std::move(other.buf_)), @@ -47,8 +26,7 @@ have_index_(other.have_index_), index_(other.index_), truncate_(other.truncate_), - optimistic_(other.optimistic_), - alone_in_queue_(other.alone_in_queue_) {} + optimistic_(other.optimistic_) {} SimpleEntryOperation::~SimpleEntryOperation() = default; @@ -59,8 +37,7 @@ net::CompletionOnceCallback callback, Entry** out_entry) { return SimpleEntryOperation(entry, NULL, std::move(callback), out_entry, 0, 0, - 0, NULL, TYPE_OPEN, have_index, 0, false, false, - false); + 0, NULL, TYPE_OPEN, have_index, 0, false, false); } // static @@ -70,7 +47,7 @@ net::CompletionOnceCallback callback, Entry** out_entry) { return SimpleEntryOperation(entry, NULL, std::move(callback), out_entry, 0, 0, - 0, NULL, TYPE_CREATE, have_index, 0, false, false, + 0, NULL, TYPE_CREATE, have_index, 0, false, false); } @@ -78,8 +55,7 @@ SimpleEntryOperation SimpleEntryOperation::CloseOperation( SimpleEntryImpl* entry) { return SimpleEntryOperation(entry, NULL, CompletionOnceCallback(), NULL, 0, 0, - 0, NULL, TYPE_CLOSE, false, 0, false, false, - false); + 0, NULL, TYPE_CLOSE, false, 0, false, false); } // static @@ -89,11 +65,10 @@ int offset, int length, net::IOBuffer* buf, - CompletionOnceCallback callback, - bool alone_in_queue) { + CompletionOnceCallback callback) { return SimpleEntryOperation(entry, buf, std::move(callback), NULL, offset, 0, length, NULL, TYPE_READ, false, index, false, - false, alone_in_queue); + false); } // static @@ -108,7 +83,7 @@ CompletionOnceCallback callback) { return SimpleEntryOperation(entry, buf, std::move(callback), NULL, offset, 0, length, NULL, TYPE_WRITE, false, index, truncate, - optimistic, false); + optimistic); } // static @@ -120,7 +95,7 @@ CompletionOnceCallback callback) { return SimpleEntryOperation(entry, buf, std::move(callback), NULL, 0, sparse_offset, length, NULL, TYPE_READ_SPARSE, - false, 0, false, false, false); + false, 0, false, false); } // static @@ -132,7 +107,7 @@ CompletionOnceCallback callback) { return SimpleEntryOperation(entry, buf, std::move(callback), NULL, 0, sparse_offset, length, NULL, TYPE_WRITE_SPARSE, - false, 0, false, false, false); + false, 0, false, false); } // static @@ -142,9 +117,9 @@ int length, int64_t* out_start, CompletionOnceCallback callback) { - return SimpleEntryOperation( - entry, NULL, std::move(callback), NULL, 0, sparse_offset, length, - out_start, TYPE_GET_AVAILABLE_RANGE, false, 0, false, false, false); + return SimpleEntryOperation(entry, NULL, std::move(callback), NULL, 0, + sparse_offset, length, out_start, + TYPE_GET_AVAILABLE_RANGE, false, 0, false, false); } // static @@ -161,53 +136,9 @@ const int index = 0; const bool truncate = false; const bool optimistic = false; - const bool alone_in_queue = false; - return SimpleEntryOperation(entry, buf, std::move(callback), out_entry, - offset, sparse_offset, length, out_start, - TYPE_DOOM, have_index, index, truncate, - optimistic, alone_in_queue); -} - -bool SimpleEntryOperation::ConflictsWith( - const SimpleEntryOperation& other_op) const { - EntryOperationType other_type = other_op.type(); - - // Non-read/write operations conflict with everything. - if (!IsReadWriteType(type_) || !IsReadWriteType(other_type)) - return true; - - // Reads (sparse or otherwise) conflict with nothing. - if (IsReadType(type_) && IsReadType(other_type)) - return false; - - // Sparse and non-sparse operations do not conflict with each other. - if (IsSparseType(type_) != IsSparseType(other_type)) { - return false; - } - - // There must be two read/write operations, at least one must be a write, and - // they must be either both non-sparse or both sparse. Compare the streams - // and offsets to see whether they overlap. - - if (IsSparseType(type_)) { - int64_t end = sparse_offset_ + length_; - int64_t other_op_end = other_op.sparse_offset() + other_op.length(); - return sparse_offset_ < other_op_end && other_op.sparse_offset() < end; - } - - if (index_ != other_op.index_) - return false; - int end = (type_ == TYPE_WRITE && truncate_) ? INT_MAX : offset_ + length_; - int other_op_end = (other_op.type() == TYPE_WRITE && other_op.truncate()) - ? INT_MAX - : other_op.offset() + other_op.length(); - return offset_ < other_op_end && other_op.offset() < end; -} - -void SimpleEntryOperation::ReleaseReferences() { - callback_ = CompletionOnceCallback(); - buf_ = NULL; - entry_ = NULL; + return SimpleEntryOperation( + entry, buf, std::move(callback), out_entry, offset, sparse_offset, length, + out_start, TYPE_DOOM, have_index, index, truncate, optimistic); } SimpleEntryOperation::SimpleEntryOperation(SimpleEntryImpl* entry, @@ -222,8 +153,7 @@ bool have_index, int index, bool truncate, - bool optimistic, - bool alone_in_queue) + bool optimistic) : entry_(entry), buf_(buf), callback_(std::move(callback)), @@ -236,7 +166,6 @@ have_index_(have_index), index_(index), truncate_(truncate), - optimistic_(optimistic), - alone_in_queue_(alone_in_queue) {} + optimistic_(optimistic) {} } // namespace disk_cache
diff --git a/net/disk_cache/simple/simple_entry_operation.h b/net/disk_cache/simple/simple_entry_operation.h index 15aa52f..564195ff 100644 --- a/net/disk_cache/simple/simple_entry_operation.h +++ b/net/disk_cache/simple/simple_entry_operation.h
@@ -55,8 +55,7 @@ int offset, int length, net::IOBuffer* buf, - CompletionOnceCallback callback, - bool alone_in_queue); + CompletionOnceCallback callback); static SimpleEntryOperation WriteOperation(SimpleEntryImpl* entry, int index, int offset, @@ -86,11 +85,6 @@ static SimpleEntryOperation DoomOperation(SimpleEntryImpl* entry, CompletionOnceCallback callback); - bool ConflictsWith(const SimpleEntryOperation& other_op) const; - // Releases all references. After calling this operation, SimpleEntryOperation - // will only hold POD members. - void ReleaseReferences(); - EntryOperationType type() const { return static_cast<EntryOperationType>(type_); } @@ -106,7 +100,6 @@ net::IOBuffer* buf() { return buf_.get(); } bool truncate() const { return truncate_; } bool optimistic() const { return optimistic_; } - bool alone_in_queue() const { return alone_in_queue_; } private: SimpleEntryOperation(SimpleEntryImpl* entry, @@ -121,8 +114,7 @@ bool have_index, int index, bool truncate, - bool optimistic, - bool alone_in_queue); + bool optimistic); // This ensures entry will not be deleted until the operation has ran. scoped_refptr<SimpleEntryImpl> entry_; @@ -148,8 +140,6 @@ // Used only in write operations. const bool truncate_; const bool optimistic_; - // Used only in SimpleCache.ReadIsParallelizable histogram. - const bool alone_in_queue_; }; } // namespace disk_cache
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json index 5a6fec7..1fbe018 100644 --- a/net/http/transport_security_state_static.json +++ b/net/http/transport_security_state_static.json
@@ -1251,7 +1251,6 @@ { "name": "s-c.se", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "security-carpet.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "sherbers.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "tittelbach.at", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "tomfisher.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wunderlist.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "zotero.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -11964,7 +11963,6 @@ { "name": "natenom.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ncpc.gov", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "netnodes.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "nepustil.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nerdtime.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "netsoins.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "netronix.be", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -13785,7 +13783,6 @@ { "name": "gopokego.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "gospelofmark.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "goto.world", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "gottcode.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "gracethrufaith.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "grademymac.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "grandwailea.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -14813,7 +14810,6 @@ { "name": "webduck.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "webeconomia.it", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "weblate.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "webmail.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "webmandesign.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "webtropia.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "weddywood.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -15943,14 +15939,12 @@ { "name": "mstiles92.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "migeeks.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "map4jena.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "muevetumundo.com.mx", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mistreaded.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "msh100.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "megamisja.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "muspla.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mkoppmann.at", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "manage4all.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "multimarques.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mainframeserver.space", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "miyoshi-kikaku.co.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mikek.work", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -15984,7 +15978,6 @@ { "name": "mostlyharmless.at", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "ndmath.club", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "mihnea.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "naturesharvestbread.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "megumico.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nanch.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "muonium.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -16107,7 +16100,6 @@ { "name": "pepsicoemployeepreferencesurvey.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nnote.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "open-mx.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "paradiselost.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "partyvan.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "opensource-cms.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "parckwart.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -16129,11 +16121,9 @@ { "name": "pe-kyousai.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "papygeek.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "photoancestry.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "peetah.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "npm.li", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "perezdecastro.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pe-bank.co.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "paper-republic.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "paul-kerebel.pro", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pnut.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "paulshir.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -27037,7 +27027,6 @@ { "name": "patsytoforyou.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "paulbramhall.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "paulbunyanmls.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "paulscustomauto.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "paulus-foto.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pautadiaria.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pavando.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -28390,7 +28379,6 @@ { "name": "7f-wgg.cf", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "7733445.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "44scc.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "00881919.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "5kraceforals.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "22scc.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "55scc.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -28765,7 +28753,6 @@ { "name": "arfad.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "beyond-infinity.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "beraru.tk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "bewegungsfluss.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "birdbrowser.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "bestwarezone.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "biletua.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -29879,65 +29866,30 @@ { "name": "herzig.cc", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hansmund.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "heribe-maruo.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71806.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71801.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71812.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "headlinepublishing.be", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg718.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71803.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71802.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71809.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71807.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71835.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "heimatverein-eitensheim.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg0088.vip", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71811.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71819.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71815.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "helber-it-services.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hickorywinecellar.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71836.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71833.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hermanbrouwer.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hingle.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71822.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71858.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71805.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71813.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hg71839.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hindmanfuneralhomes.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "herrderzeit.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hitrek.ml", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71857.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71837.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hiraku.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71852.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71851.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71860.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "holytransaction.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hga8687.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "goiaspropaganda.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71856.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hga8685.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71863.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hl7999.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hightower.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hga8587.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hga8758.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hatarisecurity.co.ke", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71861.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "highland-webcams.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "houraiteahouse.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hga8689.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "holodeck.us", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hokify.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "happyagain.se", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hokify.at", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hga8586.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hokify.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hga8757.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "highlegshop.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "hg71850.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "honeyhaw.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hollo.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "hootworld.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -30954,7 +30906,6 @@ { "name": "pdfconvert.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "noc.wang", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "party-kneipe-bar.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "patadanabouca.pw", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "paf-events.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pawelnazaruk.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "paranoidpenguin.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -32046,7 +31997,6 @@ { "name": "wesayyesprogram.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "widdleguy.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "whilsttraveling.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "wellies.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wasielewski.com.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "werhatunsverraten.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "wertheimer-burgrock.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -33626,7 +33576,6 @@ { "name": "nba2k.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nba2k.live", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nba2k.download", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "murmel.it", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "myliveupdates.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "microbiote-insectes-vecteurs.group", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "nba2k.tw", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -35567,7 +35516,6 @@ { "name": "pagedesignhub.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pagedesignpro.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pagedesignshop.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, - { "name": "paichai.space", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "passionatehorsemanship.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "pastorsuico.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, { "name": "paul-bronski.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true }, @@ -40933,7 +40881,6 @@ { "name": "fluteandpianoteaching.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "flygon.pink", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "formadmin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "freespace.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "freizeitplaza.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fuckyoupaypal.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fwdx.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -41933,7 +41880,6 @@ { "name": "546802.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "598598598.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "788da.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "7bwin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "81uc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "8888esb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "8901178.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -41967,7 +41913,6 @@ { "name": "aceanswering.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "acroso.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "actom.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "actom.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "adamcoffee.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "adhd-inattentive.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "admin-forms.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -42770,7 +42715,6 @@ { "name": "fireworkcoaching.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fitfitup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fiveboosts.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "fixvoltage.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "flamero.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "flangaapis.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "fleurenplume.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -50387,12 +50331,6 @@ { "name": "btsapem.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bttorj45.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bullshitmail.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "by2230.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "by2238.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "by2239.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "by2251.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "by2253.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "by2254.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "bytesign.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cad-noerdlingen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "cangku.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -50647,7 +50585,6 @@ { "name": "iambozboz.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "iankmusic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ibaq.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "ibwin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "iftarsaati.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ifttl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "ignacjanskiednimlodziezy.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -53293,7 +53230,6 @@ { "name": "windsorite.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "workmart.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "wumai-p.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "www-hg718.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xiecongan.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "xrwracing-france.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "yassine-ayari.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -54055,7 +53991,6 @@ { "name": "taoways.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tasks.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "tearoomlints.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "techcenturion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "techniclab.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "techniclab.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "technik-boeckmann.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, @@ -54211,6 +54146,358 @@ { "name": "zlaty-tyden.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zlatytyden.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "zq789.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "1288fc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "12photos.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "20zq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "319k3.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "3ank.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "5518k3.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "5986fc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "64970.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "6616fc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "6666yh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "72ty.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "74th.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "82ty.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "8688fc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "8818k3.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "8989k3.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "a0print.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "absolutehosting.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ace.media", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "acquistareviagragenericoitalia.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "afeefzarapackages.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "albertonplumber24-7.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "allthecryptonews.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "alquiaga.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amcangroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "amyfoundhermann.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "andrewbdesign.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "anegabawa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "angelesydemonios.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "animan.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aoaprograms.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "aperim.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "autoschadeschreuder.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "axtudo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "balilingo.ooo", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "banes.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bardiel.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "behindthethrills.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "benjaminkopelke.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "benz-hikaku.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bettertechinterviews.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bielefailed.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bigbendguide.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blockchain.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blogdeyugioh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bluemtnrentalmanagement.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "blyth.me.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bondank.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "brazenfol.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "breitband.bz.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bryansmith.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bscc.support", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bsdlab.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "busit.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "busuttil.org.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "bwfc.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "c3wien.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "campbellapplianceheatingandair.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cashbook.co.tz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "catchhimandkeephim.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "catl.st", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ccavenue.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cccwien.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ceoptique.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ch47f.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "chaoswars.ddns.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clad.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "clangwarnings.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "classroomconductor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "colorfuldots.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "consultimedia.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cordep.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "createme.com.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cromefire.myds.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "cyberexplained.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "damghaem.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "danielgorr.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "danielt.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "danslan.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "deepz.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "degosoft.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "digital1world.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dipalma.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dissieux.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "drchrislivingston.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dsanraffleshangbai.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "duocircle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dwi-sued.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "dziary.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "e-colle.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ecacollege.nsw.edu.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eduroam.uy", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "eihaikyo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elbohlyart.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "elevatoraptitudetest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emperola.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "emporioonline.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "erperium.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "escape2rooms.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "estate360.co.tz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "estudioamazonico.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "etresmant.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "everpcpc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "exsora.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "exultcosmetics.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ezzhole.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fedvan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fee-hosting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fjordboge.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "flyingspaghettimonsterdonationsfund.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "freesoft-board.to", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "froehliche-hessen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "fulfilmentcrowd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "futuretimes.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gallifreyapp.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "garage-abri-chalet.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gcgeeks.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "genome.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gigin.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "go-dutch.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "godaxen.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "golighthouse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "gratisgamecards.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "guidebook.co.tz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hamcocc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "happndin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "havetherelationshipyouwant.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "herbhuang.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hotels4teams.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hrbl.lc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "html.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "humorcaliente.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "hurleyhomestead.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ibericaderedes.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ickerseashop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "icmshoptrend.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ico500.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iliastsi.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "imanageproducts.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "imedes.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "immobilien-zirm.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "importsagt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "indoorcomfortteam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "infranotes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ing-buero-junk.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "internacao.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iochen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iomedia.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iowaschoolofbeauty.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ipad.li", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iran-geo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "iranjeunesse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "islamonline.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "it-service24.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "izaakbeekman.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jadchaar.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jericamacmillan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jeroldirvin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jessicahrehor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jisha.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "joaoaugusto.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jockbusuttil.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jockbusuttil.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jockbusuttil.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jodaniels.photography", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jordhy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "josephbleroy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "jsnfwlr.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "k7azx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kaany.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kantv1.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kissmycreative.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kolbeck.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "kzar.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "labtest.ltd", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lai.is", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lgbt.ventures", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lgbtqventures.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lgbtventures.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lifegrip.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "linzyjx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "litebit.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "livesheep.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lovelychalets-peisey.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "luan.ma", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "lykai.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "maggie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "malezan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "manuel7espejo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "markholden.guru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "marycliffpress.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mcgaccountancy.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "med360.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "meeco.kr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "megasystem.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "menhera.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mentesemprendedoras.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "meo.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "messenger.co.tz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "michael.band", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "michaelband.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "michaelhrehor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mollaretsmeningitis.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "moneybird.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monzo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "monzo.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "mr-designer-oman.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "muell-weg.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "munduch.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "munwr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "napisdata.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nazigol.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nebenbeiblog.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nevergreen.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nexril.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nextcloud.nerdpol.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nhgteam.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ninverse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "noofficewalls.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nootronerd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nosqlzoo.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nutpanda.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nwuss.okinawa", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nylevemusic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "nyuusannkinn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "omar.yt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "omlmetal.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "openre.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "orientravelmacas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "parav.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paul-schmidt.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "paybook.co.tz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pdfpassword.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pdfpasswort.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pearlsenroses.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pesyun.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "physicpezeshki.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pictureguy.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "plumbingman.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "polkhealthforanewyou.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pos.co.tz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "precept.uk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "pregono.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "prioritylawyers.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "protobetatest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "puq.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "q-technologies.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "qicomidadeverdade.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "radyabkhodro.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "railtoo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rajivshah.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "restaurantmaan.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rexskz.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "riku.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "robotkvarnen.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "romatrip.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ronniegane.kiwi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rossmacphee.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "rustralasia.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "saastopankki.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sac-shop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sacrome.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "saleduck.co.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "saleduck.co.th", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "saleduck.com.my", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "saleduck.com.ph", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "saleduck.com.sg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "saleduck.com.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "samtalen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sannesfotklinikk.no", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "saol.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sattamatkachart.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sattamatkadpboss.mobi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sattamatkamobi.mobi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "scroll.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "secretsdujeu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "semsec.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sexoyrelax.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sgsp.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shadowstack.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "shugo.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "siel.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sioeckes.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sjsmith.id.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sl899.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sl998.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "slate.to", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "solentbasketball.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spacinov.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spacivox.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "spectreattack.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "ss.lazio.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "starinvestors.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stijncrevits.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "strafensau.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stroeerdigital.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "studiopop.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "stumeta2019.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "sudo-i.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "superstropdas.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "swiftpk.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "swisstechassociation.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tabhui.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tambre.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tamposign.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "teengirl.pub", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tehrankey.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "theguitarcompany.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "thehairrepublic.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "timeless-photostudio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tkirch.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tobiaspahlings.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tomy.icu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tradik.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "travis.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trucchibellezza.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "trustocean.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tugers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tunity.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tunnelbear.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "tvipper.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "twinztech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "uhappy30.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "uhurl.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "unp.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "urbansurvival.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vedma-praktik.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vegetariantokyo.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "viljatori.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "vir2.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "webalert.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "werbeagentur.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "willvision.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wood-crafted.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wood-crafted.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "workforce.co.tz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wpsmackdown.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "wtpdive.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xendo.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xiaocg.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn----zmcaltpp1mdh16i.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--fs5ak3f.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--gfrrli-yxa.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--hgbk4a00a.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--kckd0bd4a8tp27yee2e.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xn--mgbpkc7fz3awhe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "xuanmeishe.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "youngpeopleunited.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "youtuberis.lt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zengdong.ren", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zny.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, + { "name": "zone403.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, // END OF 1-YEAR BULK HSTS ENTRIES // Only eTLD+1 domains can be submitted automatically to hstspreload.org,
diff --git a/net/network_error_logging/network_error_logging_service.cc b/net/network_error_logging/network_error_logging_service.cc index 34cf8900..762b185 100644 --- a/net/network_error_logging/network_error_logging_service.cc +++ b/net/network_error_logging/network_error_logging_service.cc
@@ -61,6 +61,8 @@ const char kApplicationPhase[] = "application"; const char kConnectionPhase[] = "connection"; const char kDnsPhase[] = "dns"; + +const char kDnsAddressChangedType[] = "dns.address_changed"; const char kHttpErrorType[] = "http.error"; const struct { @@ -147,6 +149,8 @@ REMOVED = 12, SET = 13, + DISCARDED_MISSING_REMOTE_ENDPOINT = 14, + MAX }; @@ -188,7 +192,9 @@ // NetworkErrorLoggingService implementation: - void OnHeader(const url::Origin& origin, const std::string& value) override { + void OnHeader(const url::Origin& origin, + const IPAddress& received_ip_address, + const std::string& value) override { // NEL is only available to secure origins, so don't permit insecure origins // to set policies. if (!origin.GetURL().SchemeIsCryptographic()) { @@ -197,6 +203,7 @@ } OriginPolicy policy; + policy.received_ip_address = received_ip_address; HeaderOutcome outcome = ParseHeader(value, tick_clock_->NowTicks(), &policy); RecordHeaderOutcome(outcome); @@ -217,7 +224,7 @@ MaybeAddWildcardPolicy(origin, &inserted.first->second); } - void OnRequest(const RequestDetails& details) override { + void OnRequest(RequestDetails details) override { if (!reporting_service_) { RecordRequestOutcome(RequestOutcome::DISCARDED_NO_REPORTING_SERVICE); return; @@ -270,6 +277,18 @@ return; } + // If the server that handled the request is different than the server that + // delivered the NEL policy (as determined by their IP address), then we + // have to "downgrade" the NEL report, so that it only includes information + // about DNS resolution. + if (phase_string != kDnsPhase && details.server_ip.IsValid() && + details.server_ip != policy->received_ip_address) { + phase_string = kDnsPhase; + type_string = kDnsAddressChangedType; + details.elapsed_time = base::TimeDelta(); + details.status_code = 0; + } + // include_subdomains policies are only allowed to report on DNS resolution // errors. if (phase_string != kDnsPhase && policy->include_subdomains) { @@ -351,6 +370,8 @@ private: // NEL Policy set by an origin. struct OriginPolicy { + IPAddress received_ip_address; + // Reporting API endpoint group to which reports should be sent. std::string report_to; @@ -594,6 +615,12 @@ // static void NetworkErrorLoggingService:: + RecordHeaderDiscardedForMissingRemoteEndpoint() { + RecordHeaderOutcome(HeaderOutcome::DISCARDED_MISSING_REMOTE_ENDPOINT); +} + +// static +void NetworkErrorLoggingService:: RecordRequestDiscardedForNoNetworkErrorLoggingService() { RecordRequestOutcome( RequestOutcome::DISCARDED_NO_NETWORK_ERROR_LOGGING_SERVICE);
diff --git a/net/network_error_logging/network_error_logging_service.h b/net/network_error_logging/network_error_logging_service.h index b024b31..2354a8c 100644 --- a/net/network_error_logging/network_error_logging_service.h +++ b/net/network_error_logging/network_error_logging_service.h
@@ -90,6 +90,7 @@ static void RecordHeaderDiscardedForNoNetworkErrorLoggingService(); static void RecordHeaderDiscardedForInvalidSSLInfo(); static void RecordHeaderDiscardedForCertStatusError(); + static void RecordHeaderDiscardedForMissingRemoteEndpoint(); static void RecordRequestDiscardedForNoNetworkErrorLoggingService(); @@ -98,16 +99,24 @@ virtual ~NetworkErrorLoggingService(); - // Ingests a "NEL:" header received from |orogin| with normalized value - // |value|. May or may not actually set a policy for that origin. + // Ingests a "NEL:" header received for |origin| from |received_ip_address| + // with normalized value |value|. May or may not actually set a policy for + // that origin. virtual void OnHeader(const url::Origin& origin, + const IPAddress& received_ip_address, const std::string& value) = 0; // Considers queueing a network error report for the request described in - // |details|. Note that Network Error Logging can report a fraction of - // successful requests as well (to calculate error rates), so this should be - // called on *all* requests. - virtual void OnRequest(const RequestDetails& details) = 0; + // |details|. The contents of |details| might be changed, depending on the + // NEL policy associated with the request's origin. Note that |details| is + // passed by value, so that it doesn't need to be copied in this function if + // it needs to be changed. Consider using std::move to pass this parameter if + // the caller doesn't need to access it after this method call. + // + // Note that Network Error Logging can report a fraction of successful + // requests as well (to calculate error rates), so this should be called on + // *all* requests. + virtual void OnRequest(RequestDetails details) = 0; // Removes browsing data (origin policies) associated with any origin for // which |origin_filter| returns true.
diff --git a/net/network_error_logging/network_error_logging_service_unittest.cc b/net/network_error_logging/network_error_logging_service_unittest.cc index 438bf7f..fdff16a9c 100644 --- a/net/network_error_logging/network_error_logging_service_unittest.cc +++ b/net/network_error_logging/network_error_logging_service_unittest.cc
@@ -129,13 +129,16 @@ reporting_service_.reset(); } - NetworkErrorLoggingService::RequestDetails - MakeRequestDetails(GURL url, Error error_type, int status_code = 0) { + NetworkErrorLoggingService::RequestDetails MakeRequestDetails( + GURL url, + Error error_type, + int status_code = 0, + IPAddress server_ip = IPAddress()) { NetworkErrorLoggingService::RequestDetails details; details.uri = url; details.referrer = kReferrer_; - details.server_ip = IPAddress::IPv4AllZeros(); + details.server_ip = server_ip.IsValid() ? server_ip : kServerIP_; details.status_code = status_code; details.elapsed_time = base::TimeDelta::FromSeconds(1); details.type = error_type; @@ -154,6 +157,8 @@ const GURL kUrlSubdomain_ = GURL("https://subdomain.example.com/path"); const GURL kUrlDifferentHost_ = GURL("https://example2.com/path"); + const IPAddress kServerIP_ = IPAddress(192, 168, 0, 1); + const IPAddress kOtherServerIP_ = IPAddress(192, 168, 0, 2); const url::Origin kOrigin_ = url::Origin::Create(kUrl_); const url::Origin kOriginDifferentPort_ = url::Origin::Create(kUrlDifferentPort_); @@ -199,7 +204,7 @@ TEST_F(NetworkErrorLoggingServiceTest, NoReportingService) { DestroyReportingService(); - service()->OnHeader(kOrigin_, kHeader_); + service()->OnHeader(kOrigin_, kServerIP_, kHeader_); service()->OnRequest(MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED)); } @@ -208,7 +213,7 @@ const GURL kInsecureUrl("http://insecure.com/"); const url::Origin kInsecureOrigin = url::Origin::Create(kInsecureUrl); - service()->OnHeader(kInsecureOrigin, kHeader_); + service()->OnHeader(kInsecureOrigin, kServerIP_, kHeader_); service()->OnRequest( MakeRequestDetails(kInsecureUrl, ERR_CONNECTION_REFUSED)); @@ -223,7 +228,7 @@ } TEST_F(NetworkErrorLoggingServiceTest, JsonTooLong) { - service()->OnHeader(kOrigin_, kHeaderTooLong_); + service()->OnHeader(kOrigin_, kServerIP_, kHeaderTooLong_); service()->OnRequest(MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED)); @@ -231,7 +236,7 @@ } TEST_F(NetworkErrorLoggingServiceTest, JsonTooDeep) { - service()->OnHeader(kOrigin_, kHeaderTooDeep_); + service()->OnHeader(kOrigin_, kServerIP_, kHeaderTooDeep_); service()->OnRequest(MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED)); @@ -241,7 +246,7 @@ TEST_F(NetworkErrorLoggingServiceTest, SuccessReportQueued) { static const std::string kHeaderSuccessFraction1 = "{\"report_to\":\"group\",\"max_age\":86400,\"success_fraction\":1.0}"; - service()->OnHeader(kOrigin_, kHeaderSuccessFraction1); + service()->OnHeader(kOrigin_, kServerIP_, kHeaderSuccessFraction1); service()->OnRequest(MakeRequestDetails(kUrl_, OK)); @@ -260,7 +265,7 @@ // TODO(juliatuttle): Extract these constants. ExpectDictDoubleValue(1.0, *body, NetworkErrorLoggingService::kSamplingFractionKey); - base::ExpectDictStringValue("0.0.0.0", *body, + base::ExpectDictStringValue(kServerIP_.ToString(), *body, NetworkErrorLoggingService::kServerIpKey); base::ExpectDictStringValue("", *body, NetworkErrorLoggingService::kProtocolKey); @@ -277,7 +282,7 @@ TEST_F(NetworkErrorLoggingServiceTest, FailureReportQueued) { static const std::string kHeaderFailureFraction1 = "{\"report_to\":\"group\",\"max_age\":86400,\"failure_fraction\":1.0}"; - service()->OnHeader(kOrigin_, kHeaderFailureFraction1); + service()->OnHeader(kOrigin_, kServerIP_, kHeaderFailureFraction1); service()->OnRequest(MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED)); @@ -296,7 +301,7 @@ // TODO(juliatuttle): Extract these constants. ExpectDictDoubleValue(1.0, *body, NetworkErrorLoggingService::kSamplingFractionKey); - base::ExpectDictStringValue("0.0.0.0", *body, + base::ExpectDictStringValue(kServerIP_.ToString(), *body, NetworkErrorLoggingService::kServerIpKey); base::ExpectDictStringValue("", *body, NetworkErrorLoggingService::kProtocolKey); @@ -313,7 +318,7 @@ TEST_F(NetworkErrorLoggingServiceTest, HttpErrorReportQueued) { static const std::string kHeaderFailureFraction1 = "{\"report_to\":\"group\",\"max_age\":86400,\"failure_fraction\":1.0}"; - service()->OnHeader(kOrigin_, kHeaderFailureFraction1); + service()->OnHeader(kOrigin_, kServerIP_, kHeaderFailureFraction1); service()->OnRequest(MakeRequestDetails(kUrl_, OK, 504)); @@ -332,7 +337,7 @@ // TODO(juliatuttle): Extract these constants. ExpectDictDoubleValue(1.0, *body, NetworkErrorLoggingService::kSamplingFractionKey); - base::ExpectDictStringValue("0.0.0.0", *body, + base::ExpectDictStringValue(kServerIP_.ToString(), *body, NetworkErrorLoggingService::kServerIpKey); base::ExpectDictStringValue("", *body, NetworkErrorLoggingService::kProtocolKey); @@ -346,10 +351,152 @@ NetworkErrorLoggingService::kTypeKey); } -TEST_F(NetworkErrorLoggingServiceTest, MaxAge0) { - service()->OnHeader(kOrigin_, kHeader_); +TEST_F(NetworkErrorLoggingServiceTest, SuccessReportDowngraded) { + static const std::string kHeaderSuccessFraction1 = + "{\"report_to\":\"group\",\"max_age\":86400,\"success_fraction\":1.0}"; + service()->OnHeader(kOrigin_, kServerIP_, kHeaderSuccessFraction1); - service()->OnHeader(kOrigin_, kHeaderMaxAge0_); + service()->OnRequest(MakeRequestDetails(kUrl_, OK, 200, kOtherServerIP_)); + + ASSERT_EQ(1u, reports().size()); + EXPECT_EQ(kUrl_, reports()[0].url); + EXPECT_EQ(kGroup_, reports()[0].group); + EXPECT_EQ(kType_, reports()[0].type); + EXPECT_EQ(0, reports()[0].depth); + + const base::DictionaryValue* body; + ASSERT_TRUE(reports()[0].body->GetAsDictionary(&body)); + base::ExpectDictStringValue(kUrl_.spec(), *body, + NetworkErrorLoggingService::kUriKey); + base::ExpectDictStringValue(kReferrer_.spec(), *body, + NetworkErrorLoggingService::kReferrerKey); + ExpectDictDoubleValue(1.0, *body, + NetworkErrorLoggingService::kSamplingFractionKey); + base::ExpectDictStringValue(kOtherServerIP_.ToString(), *body, + NetworkErrorLoggingService::kServerIpKey); + base::ExpectDictStringValue("", *body, + NetworkErrorLoggingService::kProtocolKey); + base::ExpectDictIntegerValue(0, *body, + NetworkErrorLoggingService::kStatusCodeKey); + base::ExpectDictIntegerValue(0, *body, + NetworkErrorLoggingService::kElapsedTimeKey); + base::ExpectDictStringValue("dns", *body, + NetworkErrorLoggingService::kPhaseKey); + base::ExpectDictStringValue("dns.address_changed", *body, + NetworkErrorLoggingService::kTypeKey); +} + +TEST_F(NetworkErrorLoggingServiceTest, FailureReportDowngraded) { + static const std::string kHeaderSuccessFraction1 = + "{\"report_to\":\"group\",\"max_age\":86400,\"success_fraction\":1.0}"; + service()->OnHeader(kOrigin_, kServerIP_, kHeaderSuccessFraction1); + + service()->OnRequest( + MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED, 200, kOtherServerIP_)); + + ASSERT_EQ(1u, reports().size()); + EXPECT_EQ(kUrl_, reports()[0].url); + EXPECT_EQ(kGroup_, reports()[0].group); + EXPECT_EQ(kType_, reports()[0].type); + EXPECT_EQ(0, reports()[0].depth); + + const base::DictionaryValue* body; + ASSERT_TRUE(reports()[0].body->GetAsDictionary(&body)); + base::ExpectDictStringValue(kUrl_.spec(), *body, + NetworkErrorLoggingService::kUriKey); + base::ExpectDictStringValue(kReferrer_.spec(), *body, + NetworkErrorLoggingService::kReferrerKey); + ExpectDictDoubleValue(1.0, *body, + NetworkErrorLoggingService::kSamplingFractionKey); + base::ExpectDictStringValue(kOtherServerIP_.ToString(), *body, + NetworkErrorLoggingService::kServerIpKey); + base::ExpectDictStringValue("", *body, + NetworkErrorLoggingService::kProtocolKey); + base::ExpectDictIntegerValue(0, *body, + NetworkErrorLoggingService::kStatusCodeKey); + base::ExpectDictIntegerValue(0, *body, + NetworkErrorLoggingService::kElapsedTimeKey); + base::ExpectDictStringValue("dns", *body, + NetworkErrorLoggingService::kPhaseKey); + base::ExpectDictStringValue("dns.address_changed", *body, + NetworkErrorLoggingService::kTypeKey); +} + +TEST_F(NetworkErrorLoggingServiceTest, HttpErrorReportDowngraded) { + static const std::string kHeaderSuccessFraction1 = + "{\"report_to\":\"group\",\"max_age\":86400,\"success_fraction\":1.0}"; + service()->OnHeader(kOrigin_, kServerIP_, kHeaderSuccessFraction1); + + service()->OnRequest(MakeRequestDetails(kUrl_, OK, 504, kOtherServerIP_)); + + ASSERT_EQ(1u, reports().size()); + EXPECT_EQ(kUrl_, reports()[0].url); + EXPECT_EQ(kGroup_, reports()[0].group); + EXPECT_EQ(kType_, reports()[0].type); + EXPECT_EQ(0, reports()[0].depth); + + const base::DictionaryValue* body; + ASSERT_TRUE(reports()[0].body->GetAsDictionary(&body)); + base::ExpectDictStringValue(kUrl_.spec(), *body, + NetworkErrorLoggingService::kUriKey); + base::ExpectDictStringValue(kReferrer_.spec(), *body, + NetworkErrorLoggingService::kReferrerKey); + ExpectDictDoubleValue(1.0, *body, + NetworkErrorLoggingService::kSamplingFractionKey); + base::ExpectDictStringValue(kOtherServerIP_.ToString(), *body, + NetworkErrorLoggingService::kServerIpKey); + base::ExpectDictStringValue("", *body, + NetworkErrorLoggingService::kProtocolKey); + base::ExpectDictIntegerValue(0, *body, + NetworkErrorLoggingService::kStatusCodeKey); + base::ExpectDictIntegerValue(0, *body, + NetworkErrorLoggingService::kElapsedTimeKey); + base::ExpectDictStringValue("dns", *body, + NetworkErrorLoggingService::kPhaseKey); + base::ExpectDictStringValue("dns.address_changed", *body, + NetworkErrorLoggingService::kTypeKey); +} + +TEST_F(NetworkErrorLoggingServiceTest, DNSFailureReportNotDowngraded) { + static const std::string kHeaderSuccessFraction1 = + "{\"report_to\":\"group\",\"max_age\":86400,\"success_fraction\":1.0}"; + service()->OnHeader(kOrigin_, kServerIP_, kHeaderSuccessFraction1); + + service()->OnRequest( + MakeRequestDetails(kUrl_, ERR_NAME_NOT_RESOLVED, 0, kOtherServerIP_)); + + ASSERT_EQ(1u, reports().size()); + EXPECT_EQ(kUrl_, reports()[0].url); + EXPECT_EQ(kGroup_, reports()[0].group); + EXPECT_EQ(kType_, reports()[0].type); + EXPECT_EQ(0, reports()[0].depth); + + const base::DictionaryValue* body; + ASSERT_TRUE(reports()[0].body->GetAsDictionary(&body)); + base::ExpectDictStringValue(kUrl_.spec(), *body, + NetworkErrorLoggingService::kUriKey); + base::ExpectDictStringValue(kReferrer_.spec(), *body, + NetworkErrorLoggingService::kReferrerKey); + ExpectDictDoubleValue(1.0, *body, + NetworkErrorLoggingService::kSamplingFractionKey); + base::ExpectDictStringValue(kOtherServerIP_.ToString(), *body, + NetworkErrorLoggingService::kServerIpKey); + base::ExpectDictStringValue("", *body, + NetworkErrorLoggingService::kProtocolKey); + base::ExpectDictIntegerValue(0, *body, + NetworkErrorLoggingService::kStatusCodeKey); + base::ExpectDictIntegerValue(1000, *body, + NetworkErrorLoggingService::kElapsedTimeKey); + base::ExpectDictStringValue("dns", *body, + NetworkErrorLoggingService::kPhaseKey); + base::ExpectDictStringValue("dns.name_not_resolved", *body, + NetworkErrorLoggingService::kTypeKey); +} + +TEST_F(NetworkErrorLoggingServiceTest, MaxAge0) { + service()->OnHeader(kOrigin_, kServerIP_, kHeader_); + + service()->OnHeader(kOrigin_, kServerIP_, kHeaderMaxAge0_); service()->OnRequest(MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED)); @@ -359,7 +506,7 @@ TEST_F(NetworkErrorLoggingServiceTest, SuccessFraction0) { static const std::string kHeaderSuccessFraction0 = "{\"report_to\":\"group\",\"max_age\":86400,\"success_fraction\":0.0}"; - service()->OnHeader(kOrigin_, kHeaderSuccessFraction0); + service()->OnHeader(kOrigin_, kServerIP_, kHeaderSuccessFraction0); // Each network error has a 0% chance of being reported. Fire off several and // verify that no reports are produced. @@ -376,7 +523,7 @@ static const std::string kHeaderSuccessFractionHalf = "{\"report_to\":\"group\",\"max_age\":86400,\"success_fraction\":0.5," "\"failure_fraction\":0.25}"; - service()->OnHeader(kOrigin_, kHeaderSuccessFractionHalf); + service()->OnHeader(kOrigin_, kServerIP_, kHeaderSuccessFractionHalf); // Each network error has a 50% chance of being reported. Fire off several // and verify that some requests were reported and some weren't. (We can't @@ -407,7 +554,7 @@ TEST_F(NetworkErrorLoggingServiceTest, FailureFraction0) { static const std::string kHeaderFailureFraction0 = "{\"report_to\":\"group\",\"max_age\":86400,\"failure_fraction\":0.0}"; - service()->OnHeader(kOrigin_, kHeaderFailureFraction0); + service()->OnHeader(kOrigin_, kServerIP_, kHeaderFailureFraction0); // Each network error has a 0% chance of being reported. Fire off several and // verify that no reports are produced. @@ -424,7 +571,7 @@ static const std::string kHeaderFailureFractionHalf = "{\"report_to\":\"group\",\"max_age\":86400,\"failure_fraction\":0.5," "\"success_fraction\":0.25}"; - service()->OnHeader(kOrigin_, kHeaderFailureFractionHalf); + service()->OnHeader(kOrigin_, kServerIP_, kHeaderFailureFractionHalf); // Each network error has a 50% chance of being reported. Fire off several // and verify that some requests were reported and some weren't. (We can't @@ -452,7 +599,7 @@ TEST_F(NetworkErrorLoggingServiceTest, ExcludeSubdomainsDoesntMatchDifferentPort) { - service()->OnHeader(kOrigin_, kHeader_); + service()->OnHeader(kOrigin_, kServerIP_, kHeader_); service()->OnRequest( MakeRequestDetails(kUrlDifferentPort_, ERR_CONNECTION_REFUSED)); @@ -461,7 +608,7 @@ } TEST_F(NetworkErrorLoggingServiceTest, ExcludeSubdomainsDoesntMatchSubdomain) { - service()->OnHeader(kOrigin_, kHeader_); + service()->OnHeader(kOrigin_, kServerIP_, kHeader_); service()->OnRequest( MakeRequestDetails(kUrlSubdomain_, ERR_CONNECTION_REFUSED)); @@ -470,7 +617,7 @@ } TEST_F(NetworkErrorLoggingServiceTest, IncludeSubdomainsMatchesDifferentPort) { - service()->OnHeader(kOrigin_, kHeaderIncludeSubdomains_); + service()->OnHeader(kOrigin_, kServerIP_, kHeaderIncludeSubdomains_); service()->OnRequest( MakeRequestDetails(kUrlDifferentPort_, ERR_NAME_NOT_RESOLVED)); @@ -480,7 +627,7 @@ } TEST_F(NetworkErrorLoggingServiceTest, IncludeSubdomainsMatchesSubdomain) { - service()->OnHeader(kOrigin_, kHeaderIncludeSubdomains_); + service()->OnHeader(kOrigin_, kServerIP_, kHeaderIncludeSubdomains_); service()->OnRequest( MakeRequestDetails(kUrlSubdomain_, ERR_NAME_NOT_RESOLVED)); @@ -490,7 +637,7 @@ TEST_F(NetworkErrorLoggingServiceTest, IncludeSubdomainsDoesntMatchSuperdomain) { - service()->OnHeader(kOriginSubdomain_, kHeaderIncludeSubdomains_); + service()->OnHeader(kOriginSubdomain_, kServerIP_, kHeaderIncludeSubdomains_); service()->OnRequest(MakeRequestDetails(kUrl_, ERR_NAME_NOT_RESOLVED)); @@ -499,7 +646,7 @@ TEST_F(NetworkErrorLoggingServiceTest, IncludeSubdomainsDoesntReportConnectionError) { - service()->OnHeader(kOrigin_, kHeaderIncludeSubdomains_); + service()->OnHeader(kOrigin_, kServerIP_, kHeaderIncludeSubdomains_); service()->OnRequest( MakeRequestDetails(kUrlSubdomain_, ERR_CONNECTION_REFUSED)); @@ -509,7 +656,7 @@ TEST_F(NetworkErrorLoggingServiceTest, IncludeSubdomainsDoesntReportApplicationError) { - service()->OnHeader(kOrigin_, kHeaderIncludeSubdomains_); + service()->OnHeader(kOrigin_, kServerIP_, kHeaderIncludeSubdomains_); service()->OnRequest( MakeRequestDetails(kUrlSubdomain_, ERR_INVALID_HTTP_RESPONSE)); @@ -518,7 +665,7 @@ } TEST_F(NetworkErrorLoggingServiceTest, IncludeSubdomainsDoesntReportSuccess) { - service()->OnHeader(kOrigin_, kHeaderIncludeSubdomains_); + service()->OnHeader(kOrigin_, kServerIP_, kHeaderIncludeSubdomains_); service()->OnRequest(MakeRequestDetails(kUrlSubdomain_, OK)); @@ -526,7 +673,7 @@ } TEST_F(NetworkErrorLoggingServiceTest, RemoveAllBrowsingData) { - service()->OnHeader(kOrigin_, kHeader_); + service()->OnHeader(kOrigin_, kServerIP_, kHeader_); service()->RemoveAllBrowsingData(); @@ -536,8 +683,8 @@ } TEST_F(NetworkErrorLoggingServiceTest, RemoveSomeBrowsingData) { - service()->OnHeader(kOrigin_, kHeader_); - service()->OnHeader(kOriginDifferentHost_, kHeader_); + service()->OnHeader(kOrigin_, kServerIP_, kHeader_); + service()->OnHeader(kOriginDifferentHost_, kServerIP_, kHeader_); service()->RemoveBrowsingData( base::BindRepeating([](const GURL& origin) -> bool { @@ -555,7 +702,7 @@ } TEST_F(NetworkErrorLoggingServiceTest, Nested) { - service()->OnHeader(kOrigin_, kHeader_); + service()->OnHeader(kOrigin_, kServerIP_, kHeader_); NetworkErrorLoggingService::RequestDetails details = MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED); @@ -569,7 +716,7 @@ } TEST_F(NetworkErrorLoggingServiceTest, NestedTooDeep) { - service()->OnHeader(kOrigin_, kHeader_); + service()->OnHeader(kOrigin_, kServerIP_, kHeader_); NetworkErrorLoggingService::RequestDetails details = MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED); @@ -586,9 +733,9 @@ static const std::string kHeaderSuccessFraction1 = "{\"report_to\":\"group\",\"max_age\":86400,\"success_fraction\":1.0}"; - service()->OnHeader(kOrigin_, kHeaderSuccessFraction1); - service()->OnHeader(kOriginDifferentHost_, kHeader_); - service()->OnHeader(kOriginSubdomain_, kHeaderIncludeSubdomains_); + service()->OnHeader(kOrigin_, kServerIP_, kHeaderSuccessFraction1); + service()->OnHeader(kOriginDifferentHost_, kServerIP_, kHeader_); + service()->OnHeader(kOriginSubdomain_, kServerIP_, kHeaderIncludeSubdomains_); base::Value actual = service()->StatusAsValue(); std::unique_ptr<base::Value> expected = base::test::ParseJson(R"json(
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc index b18ea93..7ef5874 100644 --- a/net/url_request/url_request.cc +++ b/net/url_request/url_request.cc
@@ -1210,7 +1210,7 @@ details.reporting_upload_depth = 0; } - service->OnRequest(details); + service->OnRequest(std::move(details)); } #endif // BUILDFLAG(ENABLE_REPORTING)
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc index af57b41ed..ff0bb02 100644 --- a/net/url_request/url_request_http_job.cc +++ b/net/url_request/url_request_http_job.cc
@@ -953,7 +953,14 @@ return; } - service->OnHeader(url::Origin::Create(request_info_.url), value); + IPEndPoint endpoint; + if (!GetRemoteEndpoint(&endpoint)) { + NetworkErrorLoggingService::RecordHeaderDiscardedForMissingRemoteEndpoint(); + return; + } + + service->OnHeader(url::Origin::Create(request_info_.url), endpoint.address(), + value); } #endif // BUILDFLAG(ENABLE_REPORTING)
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index a231d7d..ec987ea 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <algorithm> #include <utility> // This must be before Windows headers @@ -7631,7 +7632,17 @@ Header() = default; ~Header() = default; + // Returns whether the |received_ip_address| field matches any of the + // addresses in |address_list|. + bool MatchesAddressList(const AddressList& address_list) const { + return std::any_of(address_list.begin(), address_list.end(), + [this](const IPEndPoint& endpoint) { + return endpoint.address() == received_ip_address; + }); + } + url::Origin origin; + IPAddress received_ip_address; std::string value; }; @@ -7642,15 +7653,18 @@ ~TestNetworkErrorLoggingService() override = default; - void OnHeader(const url::Origin& origin, const std::string& value) override { + void OnHeader(const url::Origin& origin, + const IPAddress& received_ip_address, + const std::string& value) override { Header header; header.origin = origin; + header.received_ip_address = received_ip_address; header.value = value; headers_.push_back(header); } - void OnRequest(const RequestDetails& details) override { - errors_.push_back(details); + void OnRequest(RequestDetails details) override { + errors_.push_back(std::move(details)); } void RemoveBrowsingData(const base::RepeatingCallback<bool(const GURL&)>& @@ -7743,6 +7757,9 @@ ASSERT_EQ(1u, nel_service.headers().size()); EXPECT_EQ(url::Origin::Create(request_url), nel_service.headers()[0].origin); + AddressList address_list; + EXPECT_TRUE(https_test_server.GetAddressList(&address_list)); + EXPECT_TRUE(nel_service.headers()[0].MatchesAddressList(address_list)); EXPECT_EQ("foo", nel_service.headers()[0].value); }
diff --git a/remoting/protocol/webrtc_transport.cc b/remoting/protocol/webrtc_transport.cc index 5e48c07..04b0f94 100644 --- a/remoting/protocol/webrtc_transport.cc +++ b/remoting/protocol/webrtc_transport.cc
@@ -52,6 +52,13 @@ // XML namespace for the transport elements. const char kTransportNamespace[] = "google:remoting:webrtc"; +// Bitrate cap applied to relay connections. This is done to prevent +// large amounts of packet loss, since the Google TURN/relay server drops +// packets to limit the connection to ~10Mbps. The rate-limiting behavior works +// badly with WebRTC's bandwidth-estimation, which results in the host process +// trying to send frames too rapidly over the connection. +constexpr int kMaxBitrateOnRelayKbps = 8000; + #if !defined(NDEBUG) // Command line switch used to disable signature verification. // TODO(sergeyu): Remove this flag. @@ -742,6 +749,32 @@ bool is_relay = local_candidate_type == "relay" || remote_candidate_type == "relay"; VLOG(0) << "Relay connection: " << (is_relay ? "true" : "false"); + + if (is_relay) { + auto senders = peer_connection()->GetSenders(); + for (rtc::scoped_refptr<webrtc::RtpSenderInterface> sender : senders) { + // x-google-max-bitrate is only set for video codecs in the SDP exchange. + // So avoid setting a very large bitrate cap on the audio sender. + if (sender->media_type() != cricket::MediaType::MEDIA_TYPE_VIDEO) { + continue; + } + + webrtc::RtpParameters parameters = sender->GetParameters(); + if (parameters.encodings.empty()) { + LOG(ERROR) << "No encodings found for sender " << sender->id(); + continue; + } + + if (parameters.encodings.size() != 1) { + LOG(ERROR) << "Unexpected number of encodings (" + << parameters.encodings.size() << ") for sender " + << sender->id(); + } + + parameters.encodings[0].max_bitrate_bps = kMaxBitrateOnRelayKbps * 1000; + sender->SetParameters(parameters); + } + } } void WebrtcTransport::EnsurePendingTransportInfoMessage() {
diff --git a/services/content/BUILD.gn b/services/content/BUILD.gn index bd57f62a..f2fbe6f 100644 --- a/services/content/BUILD.gn +++ b/services/content/BUILD.gn
@@ -12,17 +12,17 @@ ] public = [ + "navigable_contents_delegate.h", "service.h", "service_delegate.h", - "view_delegate.h", ] sources = [ + "navigable_contents_factory_impl.cc", + "navigable_contents_factory_impl.h", + "navigable_contents_impl.cc", + "navigable_contents_impl.h", "service.cc", - "view_factory_impl.cc", - "view_factory_impl.h", - "view_impl.cc", - "view_impl.h", ] public_deps = [
diff --git a/services/content/manifest.json b/services/content/manifest.json index 19bba2ee..c47c4be 100644 --- a/services/content/manifest.json +++ b/services/content/manifest.json
@@ -4,11 +4,12 @@ "interface_provider_specs": { "service_manager:connector": { "provides": { - // The |view| capability allows a service to access embeddable, navigable content views. - // For now, access to this capability should be restricted only to services which are - // at least as trusted as the Chrome browser process (e.g., Ash). - "view": [ - "content.mojom.ViewFactory" + // The |navigation| capability allows a service to acquire embeddable, + // navigable contents. for now, access to this capability should be + // restricted only to services which are at least as trusted as the + // Chrome browser process (e.g., Ash). + "navigation": [ + "content.mojom.NavigableContentsFactory" ] } }
diff --git a/services/content/navigable_contents_delegate.h b/services/content/navigable_contents_delegate.h new file mode 100644 index 0000000..9e8208b --- /dev/null +++ b/services/content/navigable_contents_delegate.h
@@ -0,0 +1,39 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SERVICES_CONTENT_NAVIGABLE_CONTENTS_DELEGATE_H_ +#define SERVICES_CONTENT_NAVIGABLE_CONTENTS_DELEGATE_H_ + +#include "ui/gfx/native_widget_types.h" + +class GURL; + +namespace content { + +// A virtual interface which must be implemented as a backing for +// NavigableContentsImpl instances. +// +// This is the primary interface by which the Content Service delegates +// NavigableContentsImpl behavior out to WebContentsImpl in src/content. As such +// it is a transitional API which will be removed as soon as WebContentsImpl +// itself can be fully migrated into Content Service. +// +// Each instance of this interface is constructed by the ContentServiceDelegate +// implementation and owned by a NavigableContentsImpl. +class NavigableContentsDelegate { + public: + virtual ~NavigableContentsDelegate() {} + + // Returns a NativeView that can be embedded into a client application's + // window tree to display the web contents navigated by the delegate's + // NavigableContents. + virtual gfx::NativeView GetNativeView() = 0; + + // Navigates the content object to a new URL. + virtual void Navigate(const GURL& url) = 0; +}; + +} // namespace content + +#endif // SERVICES_CONTENT_NAVIGABLE_CONTENTS_DELEGATE_H_
diff --git a/services/content/navigable_contents_factory_impl.cc b/services/content/navigable_contents_factory_impl.cc new file mode 100644 index 0000000..179164b --- /dev/null +++ b/services/content/navigable_contents_factory_impl.cc
@@ -0,0 +1,35 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/content/navigable_contents_factory_impl.h" + +#include <memory> +#include <utility> + +#include "base/bind.h" +#include "services/content/navigable_contents_impl.h" +#include "services/content/service.h" + +namespace content { + +NavigableContentsFactoryImpl::NavigableContentsFactoryImpl( + Service* service, + mojom::NavigableContentsFactoryRequest request) + : service_(service), binding_(this, std::move(request)) { + binding_.set_connection_error_handler( + base::BindOnce(&Service::RemoveNavigableContentsFactory, + base::Unretained(service_), this)); +} + +NavigableContentsFactoryImpl::~NavigableContentsFactoryImpl() = default; + +void NavigableContentsFactoryImpl::CreateContents( + mojom::NavigableContentsParamsPtr params, + mojom::NavigableContentsRequest request, + mojom::NavigableContentsClientPtr client) { + service_->AddNavigableContents(std::make_unique<NavigableContentsImpl>( + service_, std::move(params), std::move(request), std::move(client))); +} + +} // namespace content
diff --git a/services/content/navigable_contents_factory_impl.h b/services/content/navigable_contents_factory_impl.h new file mode 100644 index 0000000..0232781 --- /dev/null +++ b/services/content/navigable_contents_factory_impl.h
@@ -0,0 +1,42 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SERVICES_CONTENT_NAVIGABLE_CONTENTS_FACTORY_IMPL_H_ +#define SERVICES_CONTENT_NAVIGABLE_CONTENTS_FACTORY_IMPL_H_ + +#include "base/macros.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "services/content/public/mojom/navigable_contents_factory.mojom.h" + +namespace content { + +class Service; + +// An implementation of the NavigableContentsFactory which backs every connected +// NavigableContentsFactory interface in a Content Service client. This creates +// instances of NavigableContentsImpl to fulfill |CreateContents()| requests. +// +// Instances of this class, and of the NavigableContentsImpls it creates, are +// all managed by the Service instance. +class NavigableContentsFactoryImpl : public mojom::NavigableContentsFactory { + public: + NavigableContentsFactoryImpl(Service* service, + mojom::NavigableContentsFactoryRequest request); + ~NavigableContentsFactoryImpl() override; + + private: + // mojom::NavigableContentsFactory: + void CreateContents(mojom::NavigableContentsParamsPtr params, + mojom::NavigableContentsRequest request, + mojom::NavigableContentsClientPtr client) override; + + Service* const service_; + mojo::Binding<mojom::NavigableContentsFactory> binding_; + + DISALLOW_COPY_AND_ASSIGN(NavigableContentsFactoryImpl); +}; + +} // namespace content + +#endif // SERVICES_CONTENT_NAVIGABLE_CONTENTS_FACTORY_IMPL_H_
diff --git a/services/content/view_impl.cc b/services/content/navigable_contents_impl.cc similarity index 62% rename from services/content/view_impl.cc rename to services/content/navigable_contents_impl.cc index 208616a..df8ce6c9 100644 --- a/services/content/view_impl.cc +++ b/services/content/navigable_contents_impl.cc
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "services/content/view_impl.h" +#include "services/content/navigable_contents_impl.h" #include "base/bind.h" +#include "services/content/navigable_contents_delegate.h" #include "services/content/public/cpp/buildflags.h" #include "services/content/service.h" #include "services/content/service_delegate.h" -#include "services/content/view_delegate.h" #if BUILDFLAG(ENABLE_AURA_CONTENT_VIEW_EMBEDDING) #include "ui/aura/window.h" // nogncheck @@ -17,17 +17,19 @@ namespace content { -ViewImpl::ViewImpl(Service* service, - mojom::ViewParamsPtr params, - mojom::ViewRequest request, - mojom::ViewClientPtr client) +NavigableContentsImpl::NavigableContentsImpl( + Service* service, + mojom::NavigableContentsParamsPtr params, + mojom::NavigableContentsRequest request, + mojom::NavigableContentsClientPtr client) : service_(service), binding_(this, std::move(request)), client_(std::move(client)), - delegate_(service_->delegate()->CreateViewDelegate(client_.get())), + delegate_( + service_->delegate()->CreateNavigableContentsDelegate(client_.get())), native_content_view_(delegate_->GetNativeView()) { binding_.set_connection_error_handler(base::BindRepeating( - &Service::RemoveView, base::Unretained(service_), this)); + &Service::RemoveNavigableContents, base::Unretained(service_), this)); #if BUILDFLAG(ENABLE_AURA_CONTENT_VIEW_EMBEDDING) if (native_content_view_) { @@ -38,14 +40,22 @@ #endif } -ViewImpl::~ViewImpl() = default; +NavigableContentsImpl::~NavigableContentsImpl() = default; -void ViewImpl::PrepareToEmbed(PrepareToEmbedCallback callback) { +void NavigableContentsImpl::Navigate(const GURL& url) { + // Ignore non-HTTP/HTTPS requests for now. + if (!url.SchemeIsHTTPOrHTTPS()) + return; + + delegate_->Navigate(url); +} + +void NavigableContentsImpl::CreateView(CreateViewCallback callback) { #if BUILDFLAG(ENABLE_AURA_CONTENT_VIEW_EMBEDDING) if (remote_view_provider_) { remote_view_provider_->GetEmbedToken( - base::BindOnce(&ViewImpl::OnEmbedTokenReceived, base::Unretained(this), - std::move(callback))); + base::BindOnce(&NavigableContentsImpl::OnEmbedTokenReceived, + base::Unretained(this), std::move(callback))); return; } #endif @@ -54,16 +64,9 @@ std::move(callback).Run(base::UnguessableToken::Create()); } -void ViewImpl::Navigate(const GURL& url) { - // Ignore non-HTTP/HTTPS requests for now. - if (!url.SchemeIsHTTPOrHTTPS()) - return; - - delegate_->Navigate(url); -} - -void ViewImpl::OnEmbedTokenReceived(PrepareToEmbedCallback callback, - const base::UnguessableToken& token) { +void NavigableContentsImpl::OnEmbedTokenReceived( + CreateViewCallback callback, + const base::UnguessableToken& token) { #if BUILDFLAG(ENABLE_AURA_CONTENT_VIEW_EMBEDDING) if (native_content_view_) native_content_view_->Show();
diff --git a/services/content/navigable_contents_impl.h b/services/content/navigable_contents_impl.h new file mode 100644 index 0000000..38b0b1f --- /dev/null +++ b/services/content/navigable_contents_impl.h
@@ -0,0 +1,60 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SERVICES_CONTENT_NAVIGABLE_CONTENTS_IMPL_H_ +#define SERVICES_CONTENT_NAVIGABLE_CONTENTS_IMPL_H_ + +#include "base/macros.h" +#include "base/unguessable_token.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "services/content/public/cpp/buildflags.h" +#include "services/content/public/mojom/navigable_contents.mojom.h" +#include "services/content/public/mojom/navigable_contents_factory.mojom.h" +#include "ui/gfx/native_widget_types.h" + +namespace views { +class RemoteViewProvider; +} + +namespace content { + +class Service; +class NavigableContentsDelegate; + +// This is the state which backs an individual NavigableContents owned by some +// client of the Content Service. In terms of the classical Content API, this is +// roughly analogous to a WebContentsImpl. +class NavigableContentsImpl : public mojom::NavigableContents { + public: + NavigableContentsImpl(Service* service, + mojom::NavigableContentsParamsPtr params, + mojom::NavigableContentsRequest request, + mojom::NavigableContentsClientPtr client); + ~NavigableContentsImpl() override; + + private: + // mojom::NavigableContents: + void Navigate(const GURL& url) override; + void CreateView(CreateViewCallback callback) override; + + void OnEmbedTokenReceived(CreateViewCallback callback, + const base::UnguessableToken& token); + + Service* const service_; + + mojo::Binding<mojom::NavigableContents> binding_; + mojom::NavigableContentsClientPtr client_; + std::unique_ptr<NavigableContentsDelegate> delegate_; + gfx::NativeView native_content_view_; + +#if BUILDFLAG(ENABLE_AURA_CONTENT_VIEW_EMBEDDING) + std::unique_ptr<views::RemoteViewProvider> remote_view_provider_; +#endif + + DISALLOW_COPY_AND_ASSIGN(NavigableContentsImpl); +}; + +} // namespace content + +#endif // SERVICES_CONTENT_NAVIGABLE_CONTENTS_IMPL_H_
diff --git a/services/content/public/cpp/BUILD.gn b/services/content/public/cpp/BUILD.gn index 5a031ff..1926c73 100644 --- a/services/content/public/cpp/BUILD.gn +++ b/services/content/public/cpp/BUILD.gn
@@ -15,11 +15,11 @@ output_name = "content_service_cpp" public = [ - "view.h", + "navigable_contents.h", ] sources = [ - "view.cc", + "navigable_contents.cc", ] defines = [ "IS_CONTENT_SERVICE_CPP_IMPL" ]
diff --git a/services/content/public/cpp/navigable_contents.cc b/services/content/public/cpp/navigable_contents.cc new file mode 100644 index 0000000..2fd041ed --- /dev/null +++ b/services/content/public/cpp/navigable_contents.cc
@@ -0,0 +1,66 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/content/public/cpp/navigable_contents.h" + +#include "services/content/public/cpp/buildflags.h" + +#if BUILDFLAG(ENABLE_AURA_CONTENT_VIEW_EMBEDDING) +#include "services/ui/public/interfaces/window_tree_constants.mojom.h" // nogncheck +#include "ui/views/layout/fill_layout.h" // nogncheck +#include "ui/views/mus/remote_view/remote_view_host.h" // nogncheck +#include "ui/views/view.h" // nogncheck +#endif + +namespace content { + +NavigableContents::NavigableContents(mojom::NavigableContentsFactory* factory) + : client_binding_(this) { + mojom::NavigableContentsClientPtr client; + client_binding_.Bind(mojo::MakeRequest(&client)); + factory->CreateContents(mojom::NavigableContentsParams::New(), + mojo::MakeRequest(&contents_), std::move(client)); +} + +NavigableContents::~NavigableContents() = default; + +views::View* NavigableContents::GetView() { +#if BUILDFLAG(ENABLE_AURA_CONTENT_VIEW_EMBEDDING) + if (!view_) { + view_ = std::make_unique<views::View>(); + view_->set_owned_by_client(); + view_->SetLayoutManager(std::make_unique<views::FillLayout>()); + + DCHECK(!remote_view_host_); + remote_view_host_ = new views::RemoteViewHost; + view_->AddChildView(remote_view_host_); + + contents_->CreateView(base::BindOnce( + &NavigableContents::OnEmbedTokenReceived, base::Unretained(this))); + } + return view_.get(); +#else + return nullptr; +#endif +} + +void NavigableContents::Navigate(const GURL& url) { + contents_->Navigate(url); +} + +void NavigableContents::DidStopLoading() { + if (did_stop_loading_callback_) + did_stop_loading_callback_.Run(); +} + +void NavigableContents::OnEmbedTokenReceived( + const base::UnguessableToken& token) { +#if BUILDFLAG(ENABLE_AURA_CONTENT_VIEW_EMBEDDING) + const uint32_t kEmbedFlags = ui::mojom::kEmbedFlagEmbedderInterceptsEvents | + ui::mojom::kEmbedFlagEmbedderControlsVisibility; + remote_view_host_->EmbedUsingToken(token, kEmbedFlags, base::DoNothing()); +#endif // defined(USE_AURA) +} + +} // namespace content
diff --git a/services/content/public/cpp/navigable_contents.h b/services/content/public/cpp/navigable_contents.h new file mode 100644 index 0000000..57a5d26 --- /dev/null +++ b/services/content/public/cpp/navigable_contents.h
@@ -0,0 +1,77 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SERVICES_CONTENT_PUBLIC_CPP_NAVIGABLE_CONTENTS_H_ +#define SERVICES_CONTENT_PUBLIC_CPP_NAVIGABLE_CONTENTS_H_ + +#include <memory> + +#include "base/callback.h" +#include "base/component_export.h" +#include "base/macros.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "services/content/public/cpp/buildflags.h" +#include "services/content/public/mojom/navigable_contents.mojom.h" +#include "services/content/public/mojom/navigable_contents_factory.mojom.h" + +namespace views { +class RemoteViewHost; +class View; +} // namespace views + +namespace content { + +// A NavigableContents controls a single dedicated instance of a top-level, +// navigable content frame hosted by the Content Service. In addition to +// maintaining its own navigation state, a NavigableContents may be used to +// acquire an embeddable Views widget to display renderered content within a +// client application's own UI. +class COMPONENT_EXPORT(CONTENT_SERVICE_CPP) NavigableContents + : public mojom::NavigableContentsClient { + public: + // Constructs a new NavigableContents using |factory|. + explicit NavigableContents(mojom::NavigableContentsFactory* factory); + ~NavigableContents() override; + + // Returns a View which renders this NavigableContents's currently navigated + // contents. This widget can be parented and displayed anywhere within the + // application's own window tree. + // + // Note that this View is created lazily on first call, and by default + // NavigableContents does not otherwise create or manipulate UI objects. + views::View* GetView(); + + // Begins an attempt to asynchronously navigate this NavigableContents to + // |url|. + void Navigate(const GURL& url); + + void set_did_stop_loading_callback_for_testing( + base::RepeatingClosure callback) { + did_stop_loading_callback_ = std::move(callback); + } + + private: + // mojom::NavigableContentsClient: + void DidStopLoading() override; + + void OnEmbedTokenReceived(const base::UnguessableToken& token); + + mojom::NavigableContentsPtr contents_; + mojo::Binding<mojom::NavigableContentsClient> client_binding_; + +#if BUILDFLAG(ENABLE_AURA_CONTENT_VIEW_EMBEDDING) + // This NavigableContents's View. Only initialized if |GetView()| is called, + // and only on platforms which support View embedding via Aura. + std::unique_ptr<views::View> view_; + views::RemoteViewHost* remote_view_host_ = nullptr; +#endif + + base::RepeatingClosure did_stop_loading_callback_; + + DISALLOW_COPY_AND_ASSIGN(NavigableContents); +}; + +} // namespace content + +#endif // SERVICES_CONTENT_PUBLIC_CPP_NAVIGABLE_CONTENTS_H_
diff --git a/services/content/public/cpp/view.cc b/services/content/public/cpp/view.cc deleted file mode 100644 index 15574a2..0000000 --- a/services/content/public/cpp/view.cc +++ /dev/null
@@ -1,62 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "services/content/public/cpp/view.h" - -#include "services/content/public/cpp/buildflags.h" - -#if BUILDFLAG(ENABLE_AURA_CONTENT_VIEW_EMBEDDING) -#include "services/ui/public/interfaces/window_tree_constants.mojom.h" // nogncheck -#include "ui/views/layout/fill_layout.h" // nogncheck -#include "ui/views/mus/remote_view/remote_view_host.h" // nogncheck -#include "ui/views/view.h" // nogncheck -#endif - -namespace content { - -View::View(mojom::ViewFactory* factory) : client_binding_(this) { - mojom::ViewClientPtr client; - client_binding_.Bind(mojo::MakeRequest(&client)); - factory->CreateView(mojom::ViewParams::New(), mojo::MakeRequest(&view_), - std::move(client)); -} - -View::~View() = default; - -views::View* View::CreateUI() { - view_->PrepareToEmbed( - base::BindOnce(&View::OnEmbedTokenReceived, base::Unretained(this))); -#if BUILDFLAG(ENABLE_AURA_CONTENT_VIEW_EMBEDDING) - DCHECK(!ui_view_); - ui_view_ = std::make_unique<views::View>(); - ui_view_->set_owned_by_client(); - ui_view_->SetLayoutManager(std::make_unique<views::FillLayout>()); - - DCHECK(!remote_view_host_); - remote_view_host_ = new views::RemoteViewHost; - ui_view_->AddChildView(remote_view_host_); - return ui_view_.get(); -#else - return nullptr; -#endif -} - -void View::Navigate(const GURL& url) { - view_->Navigate(url); -} - -void View::DidStopLoading() { - if (did_stop_loading_callback_) - did_stop_loading_callback_.Run(); -} - -void View::OnEmbedTokenReceived(const base::UnguessableToken& token) { -#if BUILDFLAG(ENABLE_AURA_CONTENT_VIEW_EMBEDDING) - const uint32_t kEmbedFlags = ui::mojom::kEmbedFlagEmbedderInterceptsEvents | - ui::mojom::kEmbedFlagEmbedderControlsVisibility; - remote_view_host_->EmbedUsingToken(token, kEmbedFlags, base::DoNothing()); -#endif // defined(USE_AURA) -} - -} // namespace content
diff --git a/services/content/public/cpp/view.h b/services/content/public/cpp/view.h deleted file mode 100644 index 9a62f2b..0000000 --- a/services/content/public/cpp/view.h +++ /dev/null
@@ -1,75 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SERVICES_CONTENT_PUBLIC_CPP_VIEW_H_ -#define SERVICES_CONTENT_PUBLIC_CPP_VIEW_H_ - -#include <memory> - -#include "base/callback.h" -#include "base/component_export.h" -#include "base/macros.h" -#include "mojo/public/cpp/bindings/binding.h" -#include "services/content/public/cpp/buildflags.h" -#include "services/content/public/mojom/view.mojom.h" -#include "services/content/public/mojom/view_factory.mojom.h" - -namespace views { -class RemoteViewHost; -class View; -} // namespace views - -namespace content { - -// A View is a navigable, top-level view of web content which applications can -// embed within their own UI. -// -// A View does not need to be used only for displaying visually renderable web -// contents, so by default it has no graphical presence. Call |CreateUI()| to -// get a usable Views widget which displays the navigated web contents and which -// can be attached to an existing window tree. -class COMPONENT_EXPORT(CONTENT_SERVICE_CPP) View : public mojom::ViewClient { - public: - // Constructs a new View using |factory|. - explicit View(mojom::ViewFactory* factory); - ~View() override; - - // Initialize's this View for use within a window tree. Returns the - // corresponding |views::View|, which the caller may parent to some other - // widget. This widget will display the web content navigated by the Content - // Service on this View's behalf. - views::View* CreateUI(); - - // Begins an attempt to asynchronously navigate this View to |url|. - void Navigate(const GURL& url); - - void set_did_stop_loading_callback_for_testing( - base::RepeatingClosure callback) { - did_stop_loading_callback_ = std::move(callback); - } - - private: - // mojom::ViewClient: - void DidStopLoading() override; - - void OnEmbedTokenReceived(const base::UnguessableToken& token); - - mojom::ViewPtr view_; - mojo::Binding<mojom::ViewClient> client_binding_; - -#if BUILDFLAG(ENABLE_AURA_CONTENT_VIEW_EMBEDDING) - // This View's node in the client's window tree. Non-existent by default, but - // may be initialized by calling InitializeUI. - std::unique_ptr<views::View> ui_view_; - views::RemoteViewHost* remote_view_host_ = nullptr; -#endif - - base::RepeatingClosure did_stop_loading_callback_; - - DISALLOW_COPY_AND_ASSIGN(View); -}; - -} // namespace content - -#endif // SERVICES_CONTENT_PUBLIC_CPP_VIEW_H_
diff --git a/services/content/public/mojom/BUILD.gn b/services/content/public/mojom/BUILD.gn index bbcac09..8308295 100644 --- a/services/content/public/mojom/BUILD.gn +++ b/services/content/public/mojom/BUILD.gn
@@ -13,8 +13,8 @@ sources = [ "constants.mojom", - "view.mojom", - "view_factory.mojom", + "navigable_contents.mojom", + "navigable_contents_factory.mojom", ] public_deps = [
diff --git a/services/content/public/mojom/navigable_contents.mojom b/services/content/public/mojom/navigable_contents.mojom new file mode 100644 index 0000000..dd9b5e1a --- /dev/null +++ b/services/content/public/mojom/navigable_contents.mojom
@@ -0,0 +1,31 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module content.mojom; + +import "mojo/public/mojom/base/unguessable_token.mojom"; +import "url/mojom/url.mojom"; + +// The primary interface an application uses to drive a top-level, navigable +// content object. Typically this would correspond to e.g. a browser tab, but +// it is not strictly necessary that the contents have any graphical presence +// within the client application. +interface NavigableContents { + // Initiates a navigation to |url|. + Navigate(url.mojom.Url url); + + // Creates a visual representation of the navigated contents, which is + // maintained by the Content Service. Responds with a |embed_token| which can + // be given to Mus in order to authorize embedding of that visual + // representation within the client application's own window tree. + CreateView() => (mojo_base.mojom.UnguessableToken embed_token); +}; + +// A client interface used by the Content Service to push contents-scoped events +// back to the application. +interface NavigableContentsClient { + // Notifies the client that the NavigableContents has stopped loading + // resources pertaining to a prior navigation request. + DidStopLoading(); +};
diff --git a/services/content/public/mojom/navigable_contents_factory.mojom b/services/content/public/mojom/navigable_contents_factory.mojom new file mode 100644 index 0000000..b79c633 --- /dev/null +++ b/services/content/public/mojom/navigable_contents_factory.mojom
@@ -0,0 +1,23 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module content.mojom; + +import "services/content/public/mojom/navigable_contents.mojom"; + +// Parameters used to configure a newly created NavigableContents. +struct NavigableContentsParams {}; + +// NavigableContentsFactory is the primary interface through which a new +// NavigableContents interface is bound to a new concrete navigable contents +// within the Content Service. +interface NavigableContentsFactory { + // Creates a new NavigableContents configured according to |params|. |request| + // is bound to the contents implementation, and |client| is used to push + // notifications of events relevant to the state of that context throughout + // its lifetime. + CreateContents(NavigableContentsParams params, + NavigableContents& request, + NavigableContentsClient client); +};
diff --git a/services/content/public/mojom/view.mojom b/services/content/public/mojom/view.mojom deleted file mode 100644 index b19b720e..0000000 --- a/services/content/public/mojom/view.mojom +++ /dev/null
@@ -1,28 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -module content.mojom; - -import "mojo/public/mojom/base/unguessable_token.mojom"; -import "url/mojom/url.mojom"; - -// The primary interface driving a navigable content view embedded by an -// application which wants to display web contents. -interface View { - // Prepares the visible content frame associated with this View to be embedded - // within another Mus window tree. The response's |token| can be passed to the - // desired embedder once received. - PrepareToEmbed() => (mojo_base.mojom.UnguessableToken token); - - // Initiates a navigation to |url|. - Navigate(url.mojom.Url url); -}; - -// A client interface used by the Content Service to push view-scoped events -// back to the application. -interface ViewClient { - // Notifies the client that the View has stopped loading resources pertaining - // to a navigation. - DidStopLoading(); -};
diff --git a/services/content/public/mojom/view_factory.mojom b/services/content/public/mojom/view_factory.mojom deleted file mode 100644 index fd7d98c..0000000 --- a/services/content/public/mojom/view_factory.mojom +++ /dev/null
@@ -1,20 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -module content.mojom; - -import "services/content/public/mojom/view.mojom"; - -// Parameters used to configure a newly created View. -struct ViewParams {}; - -// ViewFactory is the primary interface through which a new View interface is -// bound to a new concrete content view. -interface ViewFactory { - // Creates a new content view configured according to |params|. |request| is - // bound to the view implementation, and |client| is used to push - // notifications of events relevant to the state of the new view throughout - // its lifetime. - CreateView(ViewParams params, View& request, ViewClient client); -};
diff --git a/services/content/service.cc b/services/content/service.cc index dcbb091..f8be8865 100644 --- a/services/content/service.cc +++ b/services/content/service.cc
@@ -9,19 +9,20 @@ #include "base/bind.h" #include "base/macros.h" #include "mojo/public/cpp/bindings/binding.h" -#include "services/content/public/mojom/view_factory.mojom.h" +#include "services/content/navigable_contents_factory_impl.h" +#include "services/content/navigable_contents_impl.h" +#include "services/content/public/mojom/navigable_contents_factory.mojom.h" #include "services/content/service_delegate.h" -#include "services/content/view_factory_impl.h" -#include "services/content/view_impl.h" #include "services/service_manager/public/cpp/service_context.h" namespace content { Service::Service(ServiceDelegate* delegate) : delegate_(delegate) { binders_.AddInterface(base::BindRepeating( - [](Service* service, mojom::ViewFactoryRequest request) { - service->AddViewFactory( - std::make_unique<ViewFactoryImpl>(service, std::move(request))); + [](Service* service, mojom::NavigableContentsFactoryRequest request) { + service->AddNavigableContentsFactory( + std::make_unique<NavigableContentsFactoryImpl>(service, + std::move(request))); }, this)); } @@ -33,31 +34,34 @@ void Service::ForceQuit() { // Ensure that all bound interfaces are disconnected and no further interface // requests will be handled. - view_factories_.clear(); - views_.clear(); - binders_.RemoveInterface<mojom::ViewFactory>(); + navigable_contents_factories_.clear(); + navigable_contents_.clear(); + binders_.RemoveInterface<mojom::NavigableContentsFactory>(); // Force-disconnect from the Service Mangager. Under normal circumstances // (i.e. in non-test code), the call below destroys |this|. context()->QuitNow(); } -void Service::AddViewFactory(std::unique_ptr<ViewFactoryImpl> factory) { +void Service::AddNavigableContentsFactory( + std::unique_ptr<NavigableContentsFactoryImpl> factory) { auto* raw_factory = factory.get(); - view_factories_.emplace(raw_factory, std::move(factory)); + navigable_contents_factories_.emplace(raw_factory, std::move(factory)); } -void Service::RemoveViewFactory(ViewFactoryImpl* factory) { - view_factories_.erase(factory); +void Service::RemoveNavigableContentsFactory( + NavigableContentsFactoryImpl* factory) { + navigable_contents_factories_.erase(factory); } -void Service::AddView(std::unique_ptr<ViewImpl> view) { - auto* raw_view = view.get(); - views_.emplace(raw_view, std::move(view)); +void Service::AddNavigableContents( + std::unique_ptr<NavigableContentsImpl> contents) { + auto* raw_contents = contents.get(); + navigable_contents_.emplace(raw_contents, std::move(contents)); } -void Service::RemoveView(ViewImpl* view) { - views_.erase(view); +void Service::RemoveNavigableContents(NavigableContentsImpl* contents) { + navigable_contents_.erase(contents); } void Service::OnBindInterface(const service_manager::BindSourceInfo& source,
diff --git a/services/content/service.h b/services/content/service.h index 2a38a16..551cbd1 100644 --- a/services/content/service.h +++ b/services/content/service.h
@@ -14,8 +14,8 @@ namespace content { class ServiceDelegate; -class ViewFactoryImpl; -class ViewImpl; +class NavigableContentsFactoryImpl; +class NavigableContentsImpl; // The core Service implementation of the Content Service. This takes // responsibility for owning top-level state for an instance of the service, @@ -38,14 +38,15 @@ void ForceQuit(); private: - friend class ViewFactoryImpl; - friend class ViewImpl; + friend class NavigableContentsFactoryImpl; + friend class NavigableContentsImpl; - void AddViewFactory(std::unique_ptr<ViewFactoryImpl> factory); - void RemoveViewFactory(ViewFactoryImpl* factory); + void AddNavigableContentsFactory( + std::unique_ptr<NavigableContentsFactoryImpl> factory); + void RemoveNavigableContentsFactory(NavigableContentsFactoryImpl* factory); - void AddView(std::unique_ptr<ViewImpl> view); - void RemoveView(ViewImpl* view); + void AddNavigableContents(std::unique_ptr<NavigableContentsImpl> contents); + void RemoveNavigableContents(NavigableContentsImpl* contents); // service_manager::Service: void OnBindInterface(const service_manager::BindSourceInfo& source, @@ -55,8 +56,11 @@ ServiceDelegate* const delegate_; service_manager::BinderRegistry binders_; - std::map<ViewFactoryImpl*, std::unique_ptr<ViewFactoryImpl>> view_factories_; - std::map<ViewImpl*, std::unique_ptr<ViewImpl>> views_; + std::map<NavigableContentsFactoryImpl*, + std::unique_ptr<NavigableContentsFactoryImpl>> + navigable_contents_factories_; + std::map<NavigableContentsImpl*, std::unique_ptr<NavigableContentsImpl>> + navigable_contents_; DISALLOW_COPY_AND_ASSIGN(Service); };
diff --git a/services/content/service_delegate.h b/services/content/service_delegate.h index 7d96dccb..650a2e1 100644 --- a/services/content/service_delegate.h +++ b/services/content/service_delegate.h
@@ -5,12 +5,12 @@ #ifndef SERVICES_CONTENT_SERVICE_DELEGATE_H_ #define SERVICES_CONTENT_SERVICE_DELEGATE_H_ -#include "services/content/public/mojom/view.mojom.h" +#include "services/content/public/mojom/navigable_contents.mojom.h" namespace content { +class NavigableContentsDelegate; class Service; -class ViewDelegate; // This is a delegate interface which allows the Content Service implementation // to delegate out to private src/content code without a circular dependency @@ -28,12 +28,12 @@ // delegate) is about to be destroyed. virtual void WillDestroyServiceInstance(Service* service) = 0; - // Constructs a new ViewDelegate implementation to back a new ContentViewImpl - // instance, servicing a client's ContentView. |client| is a ViewClient - // interface the implementation can use to communicate with the client of this - // view. - virtual std::unique_ptr<ViewDelegate> CreateViewDelegate( - mojom::ViewClient* client) = 0; + // Constructs a new NavigableContentsDelegate implementation to back a new + // NavigableContentsImpl instance, servicing a client's NavigableContents. + // |client| is a NavigableContentsClient interface the implementation can use + // to communicate with the client of this contents. + virtual std::unique_ptr<NavigableContentsDelegate> + CreateNavigableContentsDelegate(mojom::NavigableContentsClient* client) = 0; }; }; // namespace content
diff --git a/services/content/service_unittest.cc b/services/content/service_unittest.cc index 928ee1f..d0e08da 100644 --- a/services/content/service_unittest.cc +++ b/services/content/service_unittest.cc
@@ -11,11 +11,11 @@ #include "base/test/bind_test_util.h" #include "base/test/scoped_task_environment.h" #include "mojo/public/cpp/bindings/binding.h" +#include "services/content/navigable_contents_delegate.h" #include "services/content/public/mojom/constants.mojom.h" -#include "services/content/public/mojom/view.mojom.h" -#include "services/content/public/mojom/view_factory.mojom.h" +#include "services/content/public/mojom/navigable_contents.mojom.h" +#include "services/content/public/mojom/navigable_contents_factory.mojom.h" #include "services/content/service_delegate.h" -#include "services/content/view_delegate.h" #include "services/service_manager/public/cpp/test/test_connector_factory.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" @@ -23,22 +23,22 @@ namespace content { namespace { -class TestViewClient : public mojom::ViewClient { +class TestNavigableContentsClient : public mojom::NavigableContentsClient { public: - TestViewClient() = default; - ~TestViewClient() override = default; + TestNavigableContentsClient() = default; + ~TestNavigableContentsClient() override = default; private: - // mojom::ViewClient: + // mojom::NavigableContentsClient: void DidStopLoading() override {} - DISALLOW_COPY_AND_ASSIGN(TestViewClient); + DISALLOW_COPY_AND_ASSIGN(TestNavigableContentsClient); }; -class TestViewDelegate : public ViewDelegate { +class TestNavigableContentsDelegate : public NavigableContentsDelegate { public: - TestViewDelegate() = default; - ~TestViewDelegate() override = default; + TestNavigableContentsDelegate() = default; + ~TestNavigableContentsDelegate() override = default; const GURL& last_navigated_url() const { return last_navigated_url_; } @@ -46,7 +46,7 @@ navigation_callback_ = std::move(callback); } - // ViewDelegate: + // NavigableContentsDelegate: void Navigate(const GURL& url) override { last_navigated_url_ = url; if (navigation_callback_) @@ -59,7 +59,7 @@ GURL last_navigated_url_; base::RepeatingClosure navigation_callback_; - DISALLOW_COPY_AND_ASSIGN(TestViewDelegate); + DISALLOW_COPY_AND_ASSIGN(TestNavigableContentsDelegate); }; class TestServiceDelegate : public ServiceDelegate { @@ -67,25 +67,25 @@ TestServiceDelegate() = default; ~TestServiceDelegate() override = default; - void set_view_delegate_created_callback( - base::RepeatingCallback<void(TestViewDelegate*)> callback) { - view_delegate_created_callback_ = std::move(callback); + void set_navigable_contents_delegate_created_callback( + base::RepeatingCallback<void(TestNavigableContentsDelegate*)> callback) { + navigable_contents_delegate_created_callback_ = std::move(callback); } // ServiceDelegate: void WillDestroyServiceInstance(Service* service) override {} - std::unique_ptr<ViewDelegate> CreateViewDelegate( - mojom::ViewClient* client) override { - auto object = std::make_unique<TestViewDelegate>(); - if (view_delegate_created_callback_) - view_delegate_created_callback_.Run(object.get()); - return object; + std::unique_ptr<NavigableContentsDelegate> CreateNavigableContentsDelegate( + mojom::NavigableContentsClient* client) override { + auto delegate = std::make_unique<TestNavigableContentsDelegate>(); + if (navigable_contents_delegate_created_callback_) + navigable_contents_delegate_created_callback_.Run(delegate.get()); + return delegate; } private: - base::RepeatingCallback<void(TestViewDelegate*)> - view_delegate_created_callback_; + base::RepeatingCallback<void(TestNavigableContentsDelegate*)> + navigable_contents_delegate_created_callback_; DISALLOW_COPY_AND_ASSIGN(TestServiceDelegate); }; @@ -119,38 +119,39 @@ DISALLOW_COPY_AND_ASSIGN(ContentServiceTest); }; -TEST_F(ContentServiceTest, ViewCreation) { - mojom::ViewFactoryPtr factory; +TEST_F(ContentServiceTest, NavigableContentsCreation) { + mojom::NavigableContentsFactoryPtr factory; BindInterface(mojo::MakeRequest(&factory)); base::RunLoop loop; - TestViewDelegate* view_delegate = nullptr; - delegate().set_view_delegate_created_callback( - base::BindLambdaForTesting([&](TestViewDelegate* delegate) { - EXPECT_FALSE(view_delegate); - view_delegate = delegate; + TestNavigableContentsDelegate* navigable_contents_delegate = nullptr; + delegate().set_navigable_contents_delegate_created_callback( + base::BindLambdaForTesting([&](TestNavigableContentsDelegate* delegate) { + EXPECT_FALSE(navigable_contents_delegate); + navigable_contents_delegate = delegate; loop.Quit(); })); - mojom::ViewPtr view; - TestViewClient client_impl; - mojom::ViewClientPtr client; - mojo::Binding<mojom::ViewClient> client_binding(&client_impl, - mojo::MakeRequest(&client)); - factory->CreateView(mojom::ViewParams::New(), mojo::MakeRequest(&view), - std::move(client)); + mojom::NavigableContentsPtr contents; + TestNavigableContentsClient client_impl; + mojom::NavigableContentsClientPtr client; + mojo::Binding<mojom::NavigableContentsClient> client_binding( + &client_impl, mojo::MakeRequest(&client)); + factory->CreateContents(mojom::NavigableContentsParams::New(), + mojo::MakeRequest(&contents), std::move(client)); loop.Run(); base::RunLoop navigation_loop; - ASSERT_TRUE(view_delegate); - view_delegate->set_navigation_callback(navigation_loop.QuitClosure()); + ASSERT_TRUE(navigable_contents_delegate); + navigable_contents_delegate->set_navigation_callback( + navigation_loop.QuitClosure()); const GURL kTestUrl("https://example.com/"); - view->Navigate(kTestUrl); + contents->Navigate(kTestUrl); navigation_loop.Run(); - EXPECT_EQ(kTestUrl, view_delegate->last_navigated_url()); + EXPECT_EQ(kTestUrl, navigable_contents_delegate->last_navigated_url()); } } // namespace
diff --git a/services/content/simple_browser/manifest.json b/services/content/simple_browser/manifest.json index 5d8332a..44ca599 100644 --- a/services/content/simple_browser/manifest.json +++ b/services/content/simple_browser/manifest.json
@@ -9,7 +9,7 @@ "app": [] }, "requires": { - "content": [ "view" ], + "content": [ "navigation" ], "font_service": [ "font_service" ], "ui": [ "app" ] }
diff --git a/services/content/simple_browser/window.cc b/services/content/simple_browser/window.cc index 4dc31d9d..4b9b5cf 100644 --- a/services/content/simple_browser/window.cc +++ b/services/content/simple_browser/window.cc
@@ -8,9 +8,9 @@ #include <utility> #include "base/strings/utf_string_conversions.h" -#include "services/content/public/cpp/view.h" +#include "services/content/public/cpp/navigable_contents.h" #include "services/content/public/mojom/constants.mojom.h" -#include "services/content/public/mojom/view_factory.mojom.h" +#include "services/content/public/mojom/navigable_contents_factory.mojom.h" #include "services/service_manager/public/cpp/connector.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" @@ -35,11 +35,12 @@ AddChildView(location_bar_); connector_->BindInterface(content::mojom::kServiceName, - MakeRequest(&view_factory_)); - view_ = std::make_unique<content::View>(view_factory_.get()); - content_area_ = view_->CreateUI(); - content_area_->SetBorder(views::CreateSolidBorder(2, SK_ColorGREEN)); - AddChildView(content_area_); + MakeRequest(&navigable_contents_factory_)); + navigable_contents_ = std::make_unique<content::NavigableContents>( + navigable_contents_factory_.get()); + content_view_ = navigable_contents_->GetView(); + content_view_->SetBorder(views::CreateSolidBorder(2, SK_ColorGREEN)); + AddChildView(content_view_); } ~SimpleBrowserUI() override = default; @@ -56,9 +57,9 @@ location_bar_bounds.Inset(5, 0); location_bar_->SetBoundsRect(location_bar_bounds); - gfx::Rect content_area_bounds = GetLocalBounds(); - content_area_bounds.Inset(5, 25, 5, 5); - content_area_->SetBoundsRect(content_area_bounds); + gfx::Rect content_view_bounds = GetLocalBounds(); + content_view_bounds.Inset(5, 25, 5, 5); + content_view_->SetBoundsRect(content_view_bounds); } gfx::Size CalculatePreferredSize() const override { @@ -71,19 +72,21 @@ if (key_event.type() != ui::ET_KEY_PRESSED) return false; - if (key_event.key_code() == ui::VKEY_RETURN) - view_->Navigate(GURL(base::UTF16ToUTF8(location_bar_->text()))); + if (key_event.key_code() == ui::VKEY_RETURN) { + navigable_contents_->Navigate( + GURL(base::UTF16ToUTF8(location_bar_->text()))); + } return false; } service_manager::Connector* const connector_; - content::mojom::ViewFactoryPtr view_factory_; - std::unique_ptr<content::View> view_; + content::mojom::NavigableContentsFactoryPtr navigable_contents_factory_; + std::unique_ptr<content::NavigableContents> navigable_contents_; views::Textfield* location_bar_; - views::View* content_area_; + views::View* content_view_; DISALLOW_COPY_AND_ASSIGN(SimpleBrowserUI); };
diff --git a/services/content/view_delegate.h b/services/content/view_delegate.h deleted file mode 100644 index 5c3364b..0000000 --- a/services/content/view_delegate.h +++ /dev/null
@@ -1,38 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SERVICES_CONTENT_VIEW_DELEGATE_H_ -#define SERVICES_CONTENT_VIEW_DELEGATE_H_ - -#include "ui/gfx/native_widget_types.h" - -class GURL; - -namespace content { - -// A virtual interface which must be implemented as a backing for ViewImpl -// instances. -// -// This is the primary interface by which the Content Service delegates ViewImpl -// behavior out to WebContentsImpl in src/content. As such it is a transitional -// API which will be removed as soon as WebContentsImpl itself can be fully -// migrated into Content Service. -// -// Each instance of this interface is constructed by the ContentServiceDelegate -// implementation and owned by a ViewImpl. -class ViewDelegate { - public: - virtual ~ViewDelegate() {} - - // Returns a NativeView that can be embedded into a client application's - // window tree to display the web contents navigated by the delegate's View. - virtual gfx::NativeView GetNativeView() = 0; - - // Navigates the content object to a new URL. - virtual void Navigate(const GURL& url) = 0; -}; - -} // namespace content - -#endif // SERVICES_CONTENT_VIEW_DELEGATE_H_
diff --git a/services/content/view_factory_impl.cc b/services/content/view_factory_impl.cc deleted file mode 100644 index cb1b74b..0000000 --- a/services/content/view_factory_impl.cc +++ /dev/null
@@ -1,32 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "services/content/view_factory_impl.h" - -#include <memory> -#include <utility> - -#include "base/bind.h" -#include "services/content/service.h" -#include "services/content/view_impl.h" - -namespace content { - -ViewFactoryImpl::ViewFactoryImpl(Service* service, - mojom::ViewFactoryRequest request) - : service_(service), binding_(this, std::move(request)) { - binding_.set_connection_error_handler(base::BindOnce( - &Service::RemoveViewFactory, base::Unretained(service_), this)); -} - -ViewFactoryImpl::~ViewFactoryImpl() = default; - -void ViewFactoryImpl::CreateView(mojom::ViewParamsPtr params, - mojom::ViewRequest request, - mojom::ViewClientPtr client) { - service_->AddView(std::make_unique<ViewImpl>( - service_, std::move(params), std::move(request), std::move(client))); -} - -} // namespace content
diff --git a/services/content/view_factory_impl.h b/services/content/view_factory_impl.h deleted file mode 100644 index 9c44c3ac..0000000 --- a/services/content/view_factory_impl.h +++ /dev/null
@@ -1,35 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SERVICES_CONTENT_VIEW_FACTORY_IMPL_H_ -#define SERVICES_CONTENT_VIEW_FACTORY_IMPL_H_ - -#include "base/macros.h" -#include "mojo/public/cpp/bindings/binding.h" -#include "services/content/public/mojom/view_factory.mojom.h" - -namespace content { - -class Service; - -class ViewFactoryImpl : public mojom::ViewFactory { - public: - ViewFactoryImpl(Service* service, mojom::ViewFactoryRequest request); - ~ViewFactoryImpl() override; - - private: - // mojom::ViewFactory: - void CreateView(mojom::ViewParamsPtr params, - mojom::ViewRequest request, - mojom::ViewClientPtr client) override; - - Service* const service_; - mojo::Binding<mojom::ViewFactory> binding_; - - DISALLOW_COPY_AND_ASSIGN(ViewFactoryImpl); -}; - -} // namespace content - -#endif // SERVICES_CONTENT_VIEW_FACTORY_IMPL_H_
diff --git a/services/content/view_impl.h b/services/content/view_impl.h deleted file mode 100644 index dfac642..0000000 --- a/services/content/view_impl.h +++ /dev/null
@@ -1,57 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SERVICES_CONTENT_VIEW_IMPL_H_ -#define SERVICES_CONTENT_VIEW_IMPL_H_ - -#include "base/macros.h" -#include "base/unguessable_token.h" -#include "mojo/public/cpp/bindings/binding.h" -#include "services/content/public/cpp/buildflags.h" -#include "services/content/public/mojom/view.mojom.h" -#include "services/content/public/mojom/view_factory.mojom.h" -#include "ui/gfx/native_widget_types.h" - -namespace views { -class RemoteViewProvider; -} - -namespace content { - -class Service; -class ViewDelegate; - -class ViewImpl : public mojom::View { - public: - ViewImpl(Service* service, - mojom::ViewParamsPtr params, - mojom::ViewRequest request, - mojom::ViewClientPtr client); - ~ViewImpl() override; - - private: - // mojom::View: - void PrepareToEmbed(PrepareToEmbedCallback callback) override; - void Navigate(const GURL& url) override; - - void OnEmbedTokenReceived(PrepareToEmbedCallback callback, - const base::UnguessableToken& token); - - Service* const service_; - - mojo::Binding<mojom::View> binding_; - mojom::ViewClientPtr client_; - std::unique_ptr<ViewDelegate> delegate_; - gfx::NativeView native_content_view_; - -#if BUILDFLAG(ENABLE_AURA_CONTENT_VIEW_EMBEDDING) - std::unique_ptr<views::RemoteViewProvider> remote_view_provider_; -#endif - - DISALLOW_COPY_AND_ASSIGN(ViewImpl); -}; - -} // namespace content - -#endif // SERVICES_CONTENT_VIEW_IMPL_H_
diff --git a/services/device/BUILD.gn b/services/device/BUILD.gn index ecbd41c2..83dce91 100644 --- a/services/device/BUILD.gn +++ b/services/device/BUILD.gn
@@ -117,6 +117,7 @@ "//services/device/public/cpp/power_monitor", "//services/device/public/mojom", "//services/device/wake_lock", + "//services/network:test_support", "//testing/gmock", "//testing/gtest", ] @@ -237,6 +238,7 @@ "//net:test_support", "//services/device/public/cpp/geolocation", "//services/device/public/mojom:constants", + "//services/network:test_support", "//services/service_manager/public/cpp", "//services/service_manager/public/cpp:service_test_support", ]
diff --git a/services/device/DEPS b/services/device/DEPS index ae6faf02..35d0c5e4 100644 --- a/services/device/DEPS +++ b/services/device/DEPS
@@ -1,6 +1,7 @@ include_rules = [ "+device", "+jni", - "+net/url_request", + "+services/network/public/cpp", + "+services/network/test", "+ui/gfx/native_widget_types.h", ]
diff --git a/services/device/device_service.cc b/services/device/device_service.cc index 44cacfed..0c55aa9 100644 --- a/services/device/device_service.cc +++ b/services/device/device_service.cc
@@ -24,6 +24,7 @@ #include "services/device/serial/serial_io_handler_impl.h" #include "services/device/time_zone_monitor/time_zone_monitor.h" #include "services/device/wake_lock/wake_lock_provider.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" #include "ui/gfx/native_widget_types.h" #if defined(OS_ANDROID) @@ -47,35 +48,33 @@ std::unique_ptr<service_manager::Service> CreateDeviceService( scoped_refptr<base::SingleThreadTaskRunner> file_task_runner, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, - const GeolocationProvider::RequestContextProducer - geolocation_request_context_producer, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& geolocation_api_key, bool use_gms_core_location_provider, const WakeLockContextCallback& wake_lock_context_callback, const CustomLocationProviderCallback& custom_location_provider_callback, const base::android::JavaRef<jobject>& java_nfc_delegate) { GeolocationProviderImpl::SetGeolocationConfiguration( - geolocation_request_context_producer, geolocation_api_key, + url_loader_factory, geolocation_api_key, custom_location_provider_callback, use_gms_core_location_provider); return std::make_unique<DeviceService>( std::move(file_task_runner), std::move(io_task_runner), - std::move(geolocation_request_context_producer), geolocation_api_key, + std::move(url_loader_factory), geolocation_api_key, wake_lock_context_callback, java_nfc_delegate); } #else std::unique_ptr<service_manager::Service> CreateDeviceService( scoped_refptr<base::SingleThreadTaskRunner> file_task_runner, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, - const GeolocationProvider::RequestContextProducer - geolocation_request_context_producer, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& geolocation_api_key, const CustomLocationProviderCallback& custom_location_provider_callback) { GeolocationProviderImpl::SetGeolocationConfiguration( - geolocation_request_context_producer, geolocation_api_key, + url_loader_factory, geolocation_api_key, custom_location_provider_callback); return std::make_unique<DeviceService>( std::move(file_task_runner), std::move(io_task_runner), - std::move(geolocation_request_context_producer), geolocation_api_key); + std::move(url_loader_factory), geolocation_api_key); } #endif @@ -83,15 +82,13 @@ DeviceService::DeviceService( scoped_refptr<base::SingleThreadTaskRunner> file_task_runner, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, - const GeolocationProvider::RequestContextProducer - geolocation_request_context_producer, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& geolocation_api_key, const WakeLockContextCallback& wake_lock_context_callback, const base::android::JavaRef<jobject>& java_nfc_delegate) : file_task_runner_(std::move(file_task_runner)), io_task_runner_(std::move(io_task_runner)), - geolocation_request_context_producer_( - geolocation_request_context_producer), + url_loader_factory_(std::move(url_loader_factory)), geolocation_api_key_(geolocation_api_key), wake_lock_context_callback_(wake_lock_context_callback), java_interface_provider_initialized_(false) { @@ -101,13 +98,11 @@ DeviceService::DeviceService( scoped_refptr<base::SingleThreadTaskRunner> file_task_runner, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, - const GeolocationProvider::RequestContextProducer - geolocation_request_context_producer, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& geolocation_api_key) : file_task_runner_(std::move(file_task_runner)), io_task_runner_(std::move(io_task_runner)), - geolocation_request_context_producer_( - geolocation_request_context_producer), + url_loader_factory_(std::move(url_loader_factory)), geolocation_api_key_(geolocation_api_key) {} #endif @@ -267,7 +262,7 @@ if (!public_ip_address_geolocation_provider_) { public_ip_address_geolocation_provider_ = std::make_unique<PublicIpAddressGeolocationProvider>( - geolocation_request_context_producer_, geolocation_api_key_); + url_loader_factory_, geolocation_api_key_); } public_ip_address_geolocation_provider_->Bind(std::move(request));
diff --git a/services/device/device_service.h b/services/device/device_service.h index 12146f3..2eae9a4 100644 --- a/services/device/device_service.h +++ b/services/device/device_service.h
@@ -51,6 +51,10 @@ class SingleThreadTaskRunner; } +namespace network { +class SharedURLLoaderFactory; +} // namespace network + namespace device { #if !defined(OS_ANDROID) @@ -68,8 +72,7 @@ std::unique_ptr<service_manager::Service> CreateDeviceService( scoped_refptr<base::SingleThreadTaskRunner> file_task_runner, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, - GeolocationProvider::RequestContextProducer - geolocation_request_context_producer, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& geolocation_api_key, bool use_gms_core_location_provider, const WakeLockContextCallback& wake_lock_context_callback, @@ -79,8 +82,7 @@ std::unique_ptr<service_manager::Service> CreateDeviceService( scoped_refptr<base::SingleThreadTaskRunner> file_task_runner, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, - GeolocationProvider::RequestContextProducer - geolocation_request_context_producer, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& geolocation_api_key, const CustomLocationProviderCallback& custom_location_provider_callback); #endif @@ -88,19 +90,19 @@ class DeviceService : public service_manager::Service { public: #if defined(OS_ANDROID) - DeviceService(scoped_refptr<base::SingleThreadTaskRunner> file_task_runner, - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, - GeolocationProvider::RequestContextProducer - geolocation_request_context_producer, - const std::string& geolocation_api_key, - const WakeLockContextCallback& wake_lock_context_callback, - const base::android::JavaRef<jobject>& java_nfc_delegate); + DeviceService( + scoped_refptr<base::SingleThreadTaskRunner> file_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + const std::string& geolocation_api_key, + const WakeLockContextCallback& wake_lock_context_callback, + const base::android::JavaRef<jobject>& java_nfc_delegate); #else - DeviceService(scoped_refptr<base::SingleThreadTaskRunner> file_task_runner, - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, - GeolocationProvider::RequestContextProducer - geolocation_request_context_producer, - const std::string& geolocation_api_key); + DeviceService( + scoped_refptr<base::SingleThreadTaskRunner> file_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + const std::string& geolocation_api_key); #endif ~DeviceService() override; @@ -157,9 +159,8 @@ std::unique_ptr<TimeZoneMonitor> time_zone_monitor_; scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_; scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; - GeolocationProvider::RequestContextProducer - geolocation_request_context_producer_; const std::string geolocation_api_key_; WakeLockContextCallback wake_lock_context_callback_;
diff --git a/services/device/device_service_test_base.cc b/services/device/device_service_test_base.cc index 0acf452..0e7a7f12 100644 --- a/services/device/device_service_test_base.cc +++ b/services/device/device_service_test_base.cc
@@ -6,14 +6,15 @@ #include <memory> +#include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/message_loop/message_loop.h" #include "base/single_thread_task_runner.h" #include "mojo/public/cpp/bindings/binding_set.h" -#include "net/url_request/url_request_test_util.h" #include "services/device/device_service.h" #include "services/device/public/cpp/geolocation/location_provider.h" #include "services/device/public/mojom/constants.mojom.h" +#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/service_manager/public/cpp/binder_registry.h" #include "services/service_manager/public/cpp/service_context.h" #include "services/service_manager/public/mojom/service_factory.mojom.h" @@ -24,17 +25,6 @@ const char kTestServiceName[] = "device_unittests"; -// Simple request context producer that immediately produces a -// TestURLRequestContextGetter. -void TestRequestContextProducer( - const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner, - base::OnceCallback<void(scoped_refptr<net::URLRequestContextGetter>)> - response_callback) { - std::move(response_callback) - .Run(base::MakeRefCounted<net::TestURLRequestContextGetter>( - network_task_runner)); -} - // Simply return a nullptr which means no CustomLocationProvider from embedder. std::unique_ptr<LocationProvider> GetCustomLocationProviderForTest() { return nullptr; @@ -47,10 +37,12 @@ explicit ServiceTestClient( service_manager::test::ServiceTest* test, scoped_refptr<base::SingleThreadTaskRunner> file_task_runner, - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) : service_manager::test::ServiceTestClient(test), file_task_runner_(std::move(file_task_runner)), - io_task_runner_(std::move(io_task_runner)) { + io_task_runner_(std::move(io_task_runner)), + url_loader_factory_(std::move(url_loader_factory)) { registry_.AddInterface<service_manager::mojom::ServiceFactory>( base::Bind(&ServiceTestClient::Create, base::Unretained(this))); } @@ -71,18 +63,16 @@ #if defined(OS_ANDROID) device_service_context_.reset(new service_manager::ServiceContext( CreateDeviceService( - file_task_runner_, io_task_runner_, - base::Bind(&TestRequestContextProducer, io_task_runner_), + file_task_runner_, io_task_runner_, url_loader_factory_, kTestGeolocationApiKey, false, wake_lock_context_callback_, - base::Bind(&GetCustomLocationProviderForTest), nullptr), + base::BindRepeating(&GetCustomLocationProviderForTest), nullptr), std::move(request))); #else device_service_context_.reset(new service_manager::ServiceContext( CreateDeviceService( - file_task_runner_, io_task_runner_, - base::Bind(&TestRequestContextProducer, io_task_runner_), + file_task_runner_, io_task_runner_, url_loader_factory_, kTestGeolocationApiKey, - base::Bind(&GetCustomLocationProviderForTest)), + base::BindRepeating(&GetCustomLocationProviderForTest)), std::move(request))); #endif } @@ -97,10 +87,13 @@ mojo::BindingSet<service_manager::mojom::ServiceFactory> service_factory_bindings_; std::unique_ptr<service_manager::ServiceContext> device_service_context_; - scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_; - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; + const scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_; + const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; + const scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; WakeLockContextCallback wake_lock_context_callback_; + + DISALLOW_COPY_AND_ASSIGN(ServiceTestClient); }; } // namespace @@ -118,8 +111,10 @@ std::unique_ptr<service_manager::Service> DeviceServiceTestBase::CreateService() { - return std::make_unique<ServiceTestClient>(this, file_thread_.task_runner(), - io_thread_.task_runner()); + return std::make_unique<ServiceTestClient>( + this, file_thread_.task_runner(), io_thread_.task_runner(), + base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( + &test_url_loader_factory_)); } } // namespace device
diff --git a/services/device/device_service_test_base.h b/services/device/device_service_test_base.h index 27938538..e7e35a7 100644 --- a/services/device/device_service_test_base.h +++ b/services/device/device_service_test_base.h
@@ -7,6 +7,7 @@ #include "base/macros.h" #include "base/threading/thread.h" +#include "services/network/test/test_url_loader_factory.h" #include "services/service_manager/public/cpp/service_test.h" namespace device { @@ -22,6 +23,7 @@ protected: base::Thread file_thread_; base::Thread io_thread_; + network::TestURLLoaderFactory test_url_loader_factory_; private: // service_manager::test::ServiceTest:
diff --git a/services/device/geolocation/BUILD.gn b/services/device/geolocation/BUILD.gn index 03e7230..0a139b7 100644 --- a/services/device/geolocation/BUILD.gn +++ b/services/device/geolocation/BUILD.gn
@@ -75,6 +75,7 @@ public_deps = [ "//services/device/public/cpp/geolocation", "//services/device/public/mojom", + "//services/network/public/cpp", ] if (is_android) { sources -= [
diff --git a/services/device/geolocation/DEPS b/services/device/geolocation/DEPS index d3e3a8c..0687f47a 100644 --- a/services/device/geolocation/DEPS +++ b/services/device/geolocation/DEPS
@@ -2,6 +2,9 @@ "+chromeos", "+dbus", "+jni", - "+net", + "+net/base", + "+net/traffic_annotation", + "+services/network/public/cpp", + "+services/network/test", "+third_party/cros_system_api/dbus", ]
diff --git a/services/device/geolocation/geolocation_provider.h b/services/device/geolocation/geolocation_provider.h index 1201e06..04ce5a1 100644 --- a/services/device/geolocation/geolocation_provider.h +++ b/services/device/geolocation/geolocation_provider.h
@@ -8,7 +8,6 @@ #include <memory> #include "base/callback_list.h" -#include "net/url_request/url_request_context_getter.h" #include "services/device/public/mojom/geoposition.mojom.h" namespace device { @@ -33,11 +32,6 @@ public: static GeolocationProvider* GetInstance(); - // Callback type for a function that asynchronously produces a - // URLRequestContextGetter. - using RequestContextProducer = base::RepeatingCallback<void( - base::OnceCallback<void(scoped_refptr<net::URLRequestContextGetter>)>)>; - typedef base::Callback<void(const mojom::Geoposition&)> LocationUpdateCallback; typedef base::CallbackList<void(const mojom::Geoposition&)>::Subscription
diff --git a/services/device/geolocation/geolocation_provider_impl.cc b/services/device/geolocation/geolocation_provider_impl.cc index 0482c486..49b700a4 100644 --- a/services/device/geolocation/geolocation_provider_impl.cc +++ b/services/device/geolocation/geolocation_provider_impl.cc
@@ -18,6 +18,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "services/device/geolocation/location_arbitrator.h" #include "services/device/public/cpp/geolocation/geoposition.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" #if defined(OS_ANDROID) #include "base/android/jni_android.h" @@ -29,8 +30,8 @@ namespace { base::LazyInstance<CustomLocationProviderCallback>::Leaky g_custom_location_provider_callback = LAZY_INSTANCE_INITIALIZER; -base::LazyInstance<GeolocationProvider::RequestContextProducer>::Leaky - g_request_context_producer = LAZY_INSTANCE_INITIALIZER; +base::LazyInstance<std::unique_ptr<network::SharedURLLoaderFactoryInfo>>::Leaky + g_url_loader_factory_info = LAZY_INSTANCE_INITIALIZER; base::LazyInstance<std::string>::Leaky g_api_key = LAZY_INSTANCE_INITIALIZER; } // namespace @@ -41,11 +42,12 @@ // static void GeolocationProviderImpl::SetGeolocationConfiguration( - const GeolocationProvider::RequestContextProducer request_context_producer, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& api_key, const CustomLocationProviderCallback& custom_location_provider_getter, bool use_gms_core_location_provider) { - g_request_context_producer.Get() = request_context_producer; + if (url_loader_factory) + g_url_loader_factory_info.Get() = url_loader_factory->Clone(); g_api_key.Get() = api_key; g_custom_location_provider_callback.Get() = custom_location_provider_getter; if (use_gms_core_location_provider) { @@ -226,9 +228,15 @@ LocationProvider::LocationProviderUpdateCallback callback = base::Bind( &GeolocationProviderImpl::OnLocationUpdate, base::Unretained(this)); + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory; + if (g_url_loader_factory_info.Get()) { + url_loader_factory = network::SharedURLLoaderFactory::Create( + std::move(g_url_loader_factory_info.Get())); + } + arbitrator_ = std::make_unique<LocationArbitrator>( - g_custom_location_provider_callback.Get(), - g_request_context_producer.Get(), g_api_key.Get()); + g_custom_location_provider_callback.Get(), std::move(url_loader_factory), + g_api_key.Get()); arbitrator_->SetUpdateCallback(callback); }
diff --git a/services/device/geolocation/geolocation_provider_impl.h b/services/device/geolocation/geolocation_provider_impl.h index b4564e4..79cf0af 100644 --- a/services/device/geolocation/geolocation_provider_impl.h +++ b/services/device/geolocation/geolocation_provider_impl.h
@@ -26,6 +26,10 @@ class SingleThreadTaskRunner; } // namespace base +namespace network { +class SharedURLLoaderFactory; +} + namespace device { // Callback that returns the embedder's custom location provider. This callback @@ -56,16 +60,14 @@ // Optional: Provide global configuration to Geolocation. Should be called // before using Init() on the singleton GetInstance(). - // |request_context_producer| : a callback to produce a request context for - // network geolocation requests. + // |url_loader_factory| : a factory to use for network geolocation requests. // |api_key| : a Google API key for network geolocation requests. // |custom_location_provider_getter| : a callback which returns a custom // location provider from embedder. // |use_gms_core_location_provider| : For android only, a flag indicates // whether using the GMS core location provider. static void SetGeolocationConfiguration( - const GeolocationProvider::RequestContextProducer - request_context_producer, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& api_key, const CustomLocationProviderCallback& custom_location_provider_getter, bool use_gms_core_location_provider = false);
diff --git a/services/device/geolocation/geolocation_service_unittest.cc b/services/device/geolocation/geolocation_service_unittest.cc index e727e98..18b19ae3 100644 --- a/services/device/geolocation/geolocation_service_unittest.cc +++ b/services/device/geolocation/geolocation_service_unittest.cc
@@ -3,13 +3,13 @@ // found in the LICENSE file. #include "base/run_loop.h" +#include "base/test/bind_test_util.h" #include "build/build_config.h" #if defined(OS_CHROMEOS) #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/network/geolocation_handler.h" #endif #include "mojo/public/cpp/bindings/interface_ptr.h" -#include "net/url_request/test_url_fetcher_factory.h" #include "services/device/device_service_test_base.h" #include "services/device/geolocation/geolocation_provider_impl.h" #include "services/device/geolocation/network_location_request.h" @@ -30,39 +30,6 @@ std::move(quit_closure).Run(); } -// Observer that waits until a TestURLFetcher with the specified fetcher_id -// starts, after which it is made available through .fetcher(). -class TestURLFetcherObserver : public net::TestURLFetcher::DelegateForTests { - public: - explicit TestURLFetcherObserver(int expected_fetcher_id) - : expected_fetcher_id_(expected_fetcher_id) { - factory_.SetDelegateForTests(this); - } - virtual ~TestURLFetcherObserver() {} - - void Wait() { loop_.Run(); } - - net::TestURLFetcher* fetcher() { return fetcher_; } - - // net::TestURLFetcher::DelegateForTests: - void OnRequestStart(int fetcher_id) override { - if (fetcher_id == expected_fetcher_id_) { - fetcher_ = factory_.GetFetcherByID(fetcher_id); - fetcher_->SetDelegateForTests(nullptr); - factory_.SetDelegateForTests(nullptr); - loop_.Quit(); - } - } - void OnChunkUpload(int fetcher_id) override {} - void OnRequestEnd(int fetcher_id) override {} - - private: - const int expected_fetcher_id_; - net::TestURLFetcher* fetcher_ = nullptr; - net::TestURLFetcherFactory factory_; - base::RunLoop loop_; -}; - class GeolocationServiceUnitTest : public DeviceServiceTestBase { public: GeolocationServiceUnitTest() = default; @@ -118,23 +85,20 @@ // detected in a scan: https://crbug.com/767300. #else TEST_F(GeolocationServiceUnitTest, UrlWithApiKey) { - // Unique ID (derived from Gerrit CL number): - device::NetworkLocationRequest::url_fetcher_id_for_tests = 675023; + base::RunLoop loop; + test_url_loader_factory_.SetInterceptor(base::BindLambdaForTesting( + [&loop](const network::ResourceRequest& request) { + // Verify the full URL including a fake Google API key. + std::string expected_url = + "https://www.googleapis.com/geolocation/v1/geolocate?key="; + expected_url.append(kTestGeolocationApiKey); - // Intercept the URLFetcher from network geolocation request. - TestURLFetcherObserver observer( - device::NetworkLocationRequest::url_fetcher_id_for_tests); + if (request.url == expected_url) + loop.Quit(); + })); geolocation_->SetHighAccuracy(true); - observer.Wait(); - DCHECK(observer.fetcher()); - - // Verify full URL including a fake Google API key. - std::string expected_url = - "https://www.googleapis.com/geolocation/v1/" - "geolocate?key="; - expected_url.append(kTestGeolocationApiKey); - EXPECT_EQ(expected_url, observer.fetcher()->GetOriginalURL()); + loop.Run(); } #endif
diff --git a/services/device/geolocation/location_arbitrator.cc b/services/device/geolocation/location_arbitrator.cc index a1a07a3..21ea659 100644 --- a/services/device/geolocation/location_arbitrator.cc +++ b/services/device/geolocation/location_arbitrator.cc
@@ -15,6 +15,7 @@ #include "services/device/geolocation/network_location_provider.h" #include "services/device/geolocation/wifi_polling_policy.h" #include "services/device/public/cpp/geolocation/geoposition.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" namespace device { @@ -25,10 +26,10 @@ LocationArbitrator::LocationArbitrator( const CustomLocationProviderCallback& custom_location_provider_getter, - GeolocationProvider::RequestContextProducer request_context_producer, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& api_key) : custom_location_provider_getter_(custom_location_provider_getter), - request_context_producer_(request_context_producer), + url_loader_factory_(url_loader_factory), api_key_(api_key), position_provider_(nullptr), is_permission_granted_(false), @@ -64,18 +65,7 @@ if (providers_.empty()) { RegisterSystemProvider(); - - // Request a URLRequestContextGetter to use for network geolocation. - if (!request_context_producer_.is_null()) { - // Note: .Reset() will cancel any previous callback. - request_context_response_callback_.Reset( - base::Bind(&LocationArbitrator::OnRequestContextResponse, - base::Unretained(this))); - // Invoke callback to obtain a URL request context. - request_context_producer_.Run( - request_context_response_callback_.callback()); - return; - } + RegisterNetworkProvider(); } DoStartProviders(); } @@ -105,16 +95,6 @@ is_running_ = false; } -void LocationArbitrator::OnRequestContextResponse( - scoped_refptr<net::URLRequestContextGetter> context_getter) { - if (context_getter != nullptr) { - // Create a NetworkLocationProvider using the provided request context. - RegisterProvider( - NewNetworkLocationProvider(std::move(context_getter), api_key_)); - } - DoStartProviders(); -} - void LocationArbitrator::RegisterProvider( std::unique_ptr<LocationProvider> provider) { if (!provider) @@ -137,6 +117,13 @@ RegisterProvider(std::move(provider)); } +void LocationArbitrator::RegisterNetworkProvider() { + if (!url_loader_factory_) + return; + + RegisterProvider(NewNetworkLocationProvider(url_loader_factory_, api_key_)); +} + void LocationArbitrator::OnLocationUpdate( const LocationProvider* provider, const mojom::Geoposition& new_position) { @@ -162,15 +149,15 @@ std::unique_ptr<LocationProvider> LocationArbitrator::NewNetworkLocationProvider( - scoped_refptr<net::URLRequestContextGetter> context, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& api_key) { - DCHECK(context != nullptr); + DCHECK(url_loader_factory); #if defined(OS_ANDROID) // Android uses its own SystemLocationProvider. return nullptr; #else - return std::make_unique<NetworkLocationProvider>(std::move(context), api_key, - this); + return std::make_unique<NetworkLocationProvider>( + std::move(url_loader_factory), api_key, this); #endif }
diff --git a/services/device/geolocation/location_arbitrator.h b/services/device/geolocation/location_arbitrator.h index 750de88..5d89450 100644 --- a/services/device/geolocation/location_arbitrator.h +++ b/services/device/geolocation/location_arbitrator.h
@@ -14,15 +14,14 @@ #include "base/macros.h" #include "base/strings/string16.h" #include "base/time/time.h" -#include "net/url_request/url_request_context_getter.h" #include "services/device/geolocation/geolocation_provider_impl.h" #include "services/device/geolocation/network_location_provider.h" #include "services/device/public/cpp/geolocation/location_provider.h" #include "services/device/public/mojom/geoposition.mojom.h" #include "url/gurl.h" -namespace net { -class URLRequestContextGetter; +namespace network { +class SharedURLLoaderFactory; } namespace device { @@ -42,8 +41,7 @@ // LocationArbitrator uses the default system location provider. LocationArbitrator( const CustomLocationProviderCallback& custom_location_provider_getter, - const GeolocationProvider::RequestContextProducer - request_context_producer, + const scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& api_key); ~LocationArbitrator() override; @@ -66,7 +64,7 @@ // These functions are useful for injection of dependencies in derived // testing classes. virtual std::unique_ptr<LocationProvider> NewNetworkLocationProvider( - scoped_refptr<net::URLRequestContextGetter> context, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& api_key); virtual std::unique_ptr<LocationProvider> NewSystemLocationProvider(); virtual base::Time GetTimeNow() const; @@ -78,6 +76,7 @@ // deleted on error (e.g. it fails to start). void RegisterProvider(std::unique_ptr<LocationProvider> provider); void RegisterSystemProvider(); + void RegisterNetworkProvider(); // Tells all registered providers to start. // If |providers_| is empty, immediately provides @@ -85,10 +84,6 @@ // |arbitrator_update_callback_|. void DoStartProviders(); - // Response callback for request_context_callback_. - void OnRequestContextResponse( - scoped_refptr<net::URLRequestContextGetter> context_getter); - // Gets called when a provider has a new position. void OnLocationUpdate(const LocationProvider* provider, const mojom::Geoposition& new_position); @@ -101,16 +96,11 @@ bool from_same_provider) const; const CustomLocationProviderCallback custom_location_provider_getter_; - const GeolocationProvider::RequestContextProducer request_context_producer_; + const scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; const std::string api_key_; LocationProvider::LocationProviderUpdateCallback arbitrator_update_callback_; - // CancelableCallback to prevent OnRequestContextReponse from being called - // multiple times in case request_context_callback_ is invoked multiple times. - base::CancelableCallback<void(scoped_refptr<net::URLRequestContextGetter>)> - request_context_response_callback_; - std::vector<std::unique_ptr<LocationProvider>> providers_; bool enable_high_accuracy_; // The provider which supplied the current |position_|
diff --git a/services/device/geolocation/location_arbitrator_unittest.cc b/services/device/geolocation/location_arbitrator_unittest.cc index 2a998c3..08c61f5 100644 --- a/services/device/geolocation/location_arbitrator_unittest.cc +++ b/services/device/geolocation/location_arbitrator_unittest.cc
@@ -10,11 +10,11 @@ #include "base/bind.h" #include "base/memory/ptr_util.h" #include "base/test/scoped_task_environment.h" -#include "net/url_request/url_request_test_util.h" #include "services/device/geolocation/fake_location_provider.h" #include "services/device/public/cpp/geolocation/geoposition.h" #include "services/device/public/cpp/geolocation/location_provider.h" #include "services/device/public/mojom/geoposition.mojom.h" +#include "services/network/test/test_shared_url_loader_factory.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -77,37 +77,16 @@ SetPositionFix(provider, 51.0, -0.1, 400); } -// Simple request context producer that immediately produces a -// TestURLRequestContextGetter. -void TestRequestContextProducer( - const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner, - base::OnceCallback<void(scoped_refptr<net::URLRequestContextGetter>)> - response_callback) { - std::move(response_callback) - .Run(base::MakeRefCounted<net::TestURLRequestContextGetter>( - network_task_runner)); -} - } // namespace -// Simple request context producer that immediately produces a nullptr -// URLRequestContextGetter, indicating that network geolocation should not be -// used. -void NullRequestContextProducer( - base::OnceCallback<void(scoped_refptr<net::URLRequestContextGetter>)> - response_callback) { - std::move(response_callback) - .Run(scoped_refptr<net::URLRequestContextGetter>(nullptr)); -} - class TestingLocationArbitrator : public LocationArbitrator { public: TestingLocationArbitrator( const LocationProviderUpdateCallback& callback, const CustomLocationProviderCallback& provider_getter, - GeolocationProvider::RequestContextProducer request_context_producer) + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) : LocationArbitrator(provider_getter, - request_context_producer, + std::move(url_loader_factory), std::string() /* api_key */), cell_(nullptr), gps_(nullptr) { @@ -117,7 +96,7 @@ base::Time GetTimeNow() const override { return GetTimeNowForTest(); } std::unique_ptr<LocationProvider> NewNetworkLocationProvider( - scoped_refptr<net::URLRequestContextGetter> context, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& api_key) override { cell_ = new FakeLocationProvider; return base::WrapUnique(cell_); @@ -140,17 +119,20 @@ class GeolocationLocationArbitratorTest : public testing::Test { protected: - GeolocationLocationArbitratorTest() : observer_(new MockLocationObserver) {} + GeolocationLocationArbitratorTest() + : observer_(new MockLocationObserver), + url_loader_factory_(new network::TestSharedURLLoaderFactory()) {} - // Initializes |arbitrator_| with the specified |provider|, which may be null. + // Initializes |arbitrator_| with the specified |url_loader_factory|, which + // may be null. void InitializeArbitrator( const CustomLocationProviderCallback& provider_getter, - GeolocationProvider::RequestContextProducer request_context_producer) { + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) { const LocationProvider::LocationProviderUpdateCallback callback = - base::Bind(&MockLocationObserver::OnLocationUpdate, - base::Unretained(observer_.get())); - arbitrator_.reset(new TestingLocationArbitrator(callback, provider_getter, - request_context_producer)); + base::BindRepeating(&MockLocationObserver::OnLocationUpdate, + base::Unretained(observer_.get())); + arbitrator_.reset(new TestingLocationArbitrator( + callback, provider_getter, std::move(url_loader_factory))); } // testing::Test @@ -179,12 +161,13 @@ const std::unique_ptr<MockLocationObserver> observer_; std::unique_ptr<TestingLocationArbitrator> arbitrator_; base::test::ScopedTaskEnvironment scoped_task_environment_; + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; }; // Basic test of the text fixture. TEST_F(GeolocationLocationArbitratorTest, CreateDestroy) { - InitializeArbitrator(base::Bind(&GetCustomLocationProviderForTest, nullptr), - base::Bind(&NullRequestContextProducer)); + InitializeArbitrator( + base::BindRepeating(&GetCustomLocationProviderForTest, nullptr), nullptr); EXPECT_TRUE(arbitrator_); arbitrator_.reset(); SUCCEED(); @@ -192,8 +175,8 @@ // Tests OnPermissionGranted(). TEST_F(GeolocationLocationArbitratorTest, OnPermissionGranted) { - InitializeArbitrator(base::Bind(&GetCustomLocationProviderForTest, nullptr), - base::Bind(&NullRequestContextProducer)); + InitializeArbitrator( + base::BindRepeating(&GetCustomLocationProviderForTest, nullptr), nullptr); EXPECT_FALSE(arbitrator_->HasPermissionBeenGrantedForTest()); arbitrator_->OnPermissionGranted(); EXPECT_TRUE(arbitrator_->HasPermissionBeenGrantedForTest()); @@ -207,9 +190,8 @@ // providers and system location provider. TEST_F(GeolocationLocationArbitratorTest, NormalUsage) { InitializeArbitrator( - base::Bind(&GetCustomLocationProviderForTest, nullptr), - base::Bind(&TestRequestContextProducer, - scoped_task_environment_.GetMainThreadTaskRunner())); + base::BindRepeating(&GetCustomLocationProviderForTest, nullptr), + url_loader_factory_); ASSERT_TRUE(arbitrator_); EXPECT_FALSE(cell()); @@ -244,9 +226,9 @@ TEST_F(GeolocationLocationArbitratorTest, CustomSystemProviderOnly) { auto provider = std::make_unique<FakeLocationProvider>(); FakeLocationProvider* fake_location_provider = provider.get(); - InitializeArbitrator( - base::Bind(&GetCustomLocationProviderForTest, base::Passed(&provider)), - base::Bind(&NullRequestContextProducer)); + InitializeArbitrator(base::BindRepeating(&GetCustomLocationProviderForTest, + base::Passed(&provider)), + nullptr); ASSERT_TRUE(arbitrator_); EXPECT_FALSE(cell()); @@ -281,10 +263,9 @@ CustomSystemAndDefaultNetworkProviders) { auto provider = std::make_unique<FakeLocationProvider>(); FakeLocationProvider* fake_location_provider = provider.get(); - InitializeArbitrator( - base::Bind(&GetCustomLocationProviderForTest, base::Passed(&provider)), - base::Bind(&TestRequestContextProducer, - scoped_task_environment_.GetMainThreadTaskRunner())); + InitializeArbitrator(base::BindRepeating(&GetCustomLocationProviderForTest, + base::Passed(&provider)), + url_loader_factory_); ASSERT_TRUE(arbitrator_); EXPECT_FALSE(cell()); @@ -318,9 +299,8 @@ // observer. TEST_F(GeolocationLocationArbitratorTest, SetObserverOptions) { InitializeArbitrator( - base::Bind(&GetCustomLocationProviderForTest, nullptr), - base::Bind(&TestRequestContextProducer, - scoped_task_environment_.GetMainThreadTaskRunner())); + base::BindRepeating(&GetCustomLocationProviderForTest, nullptr), + url_loader_factory_); arbitrator_->StartProvider(false); ASSERT_TRUE(cell()); ASSERT_TRUE(gps()); @@ -338,9 +318,8 @@ // multiple sources, with varying accuracy, across a period of time. TEST_F(GeolocationLocationArbitratorTest, Arbitration) { InitializeArbitrator( - base::Bind(&GetCustomLocationProviderForTest, nullptr), - base::Bind(&TestRequestContextProducer, - scoped_task_environment_.GetMainThreadTaskRunner())); + base::BindRepeating(&GetCustomLocationProviderForTest, nullptr), + url_loader_factory_); arbitrator_->StartProvider(false); ASSERT_TRUE(cell()); ASSERT_TRUE(gps()); @@ -419,9 +398,8 @@ // it has stopped and then restarted (crbug.com/240956). TEST_F(GeolocationLocationArbitratorTest, TwoOneShotsIsNewPositionBetter) { InitializeArbitrator( - base::Bind(&GetCustomLocationProviderForTest, nullptr), - base::Bind(&TestRequestContextProducer, - scoped_task_environment_.GetMainThreadTaskRunner())); + base::BindRepeating(&GetCustomLocationProviderForTest, nullptr), + url_loader_factory_); arbitrator_->StartProvider(false); ASSERT_TRUE(cell()); ASSERT_TRUE(gps());
diff --git a/services/device/geolocation/network_location_provider.cc b/services/device/geolocation/network_location_provider.cc index 5b12f45..c2f1ccd 100644 --- a/services/device/geolocation/network_location_provider.cc +++ b/services/device/geolocation/network_location_provider.cc
@@ -13,8 +13,8 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" #include "net/traffic_annotation/network_traffic_annotation.h" -#include "net/url_request/url_request_context_getter.h" #include "services/device/public/cpp/geolocation/geoposition.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" namespace device { namespace { @@ -101,7 +101,7 @@ // NetworkLocationProvider NetworkLocationProvider::NetworkLocationProvider( - scoped_refptr<net::URLRequestContextGetter> url_context_getter, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& api_key, LastPositionCache* last_position_cache) : wifi_data_provider_manager_(nullptr), @@ -113,7 +113,7 @@ is_permission_granted_(false), is_new_data_available_(false), request_(new NetworkLocationRequest( - std::move(url_context_getter), + std::move(url_loader_factory), api_key, base::Bind(&NetworkLocationProvider::OnLocationResponse, base::Unretained(this)))),
diff --git a/services/device/geolocation/network_location_provider.h b/services/device/geolocation/network_location_provider.h index e14937b2..75878bb 100644 --- a/services/device/geolocation/network_location_provider.h +++ b/services/device/geolocation/network_location_provider.h
@@ -73,9 +73,10 @@ CacheAgeList cache_age_list_; // Oldest first. }; - NetworkLocationProvider(scoped_refptr<net::URLRequestContextGetter> context, - const std::string& api_key, - LastPositionCache* last_position_cache); + NetworkLocationProvider( + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + const std::string& api_key, + LastPositionCache* last_position_cache); ~NetworkLocationProvider() override; // LocationProvider implementation
diff --git a/services/device/geolocation/network_location_provider_unittest.cc b/services/device/geolocation/network_location_provider_unittest.cc index 39124171..139b36da 100644 --- a/services/device/geolocation/network_location_provider_unittest.cc +++ b/services/device/geolocation/network_location_provider_unittest.cc
@@ -21,11 +21,12 @@ #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "net/base/net_errors.h" -#include "net/url_request/test_url_fetcher_factory.h" -#include "net/url_request/url_request_status.h" #include "services/device/geolocation/location_arbitrator.h" #include "services/device/geolocation/wifi_data_provider.h" #include "services/device/public/cpp/geolocation/geoposition.h" +#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" +#include "services/network/test/test_url_loader_factory.h" +#include "services/network/test/test_utils.h" #include "testing/gtest/include/gtest/gtest.h" namespace device { @@ -131,10 +132,8 @@ LocationProvider* CreateProvider(bool set_permission_granted, const std::string& api_key = std::string()) { - // No URLContextGetter needed: The request within the provider is tested - // directly using TestURLFetcherFactory. LocationProvider* provider = new NetworkLocationProvider( - nullptr, api_key, last_position_cache_.get()); + shared_url_loader_factory_, api_key, last_position_cache_.get()); if (set_permission_granted) provider->OnPermissionGranted(); return provider; @@ -142,7 +141,10 @@ protected: GeolocationNetworkProviderTest() - : wifi_data_provider_(MockWifiDataProvider::CreateInstance()), + : shared_url_loader_factory_( + new network::WeakWrapperSharedURLLoaderFactory( + &test_url_loader_factory_)), + wifi_data_provider_(MockWifiDataProvider::CreateInstance()), last_position_cache_(std::make_unique<TestLastPositionCache>()) { // TODO(joth): Really these should be in SetUp, not here, but they take no // effect on Mac OS Release builds if done there. I kid not. Figure out why. @@ -150,14 +152,8 @@ MockWifiDataProvider::GetInstance); } - // Returns the current url fetcher (if any) and advances the id ready for the - // next test step. - net::TestURLFetcher* get_url_fetcher_and_advance_id() { - net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID( - NetworkLocationRequest::url_fetcher_id_for_tests); - if (fetcher) - ++NetworkLocationRequest::url_fetcher_id_for_tests; - return fetcher; + ~GeolocationNetworkProviderTest() override { + shared_url_loader_factory_->Detach(); } static int IndexToChannel(int index) { return index + 4; } @@ -244,15 +240,18 @@ return testing::AssertionSuccess(); } - // Checks that |request| contains valid JSON upload data. The Wifi access - // points specified in the JSON are validated against the first + // Checks that current pending request contains valid JSON upload data. The + // WiFi access points specified in the JSON are validated against the first // |expected_wifi_aps| access points, starting from position // |wifi_start_index|, that are generated by CreateReferenceWifiScanDataJson. - void CheckRequestIsValid(const net::TestURLFetcher& request, - int expected_wifi_aps, - int wifi_start_index) { - const std::string& upload_data = request.upload_data(); + void CheckRequestIsValid(int expected_wifi_aps, int wifi_start_index) { + ASSERT_EQ(1, test_url_loader_factory_.NumPending()); + const network::TestURLLoaderFactory::PendingRequest& pending_request = + test_url_loader_factory_.pending_requests()->back(); + EXPECT_FALSE(pending_request.client.encountered_error()); + std::string upload_data = network::GetUploadData(pending_request.request); ASSERT_FALSE(upload_data.empty()); + std::string json_parse_error_msg; std::unique_ptr<base::Value> parsed_json = base::JSONReader::ReadAndReturnError(upload_data, base::JSON_PARSE_RFC, @@ -291,7 +290,9 @@ } const base::MessageLoop main_message_loop_; - const net::TestURLFetcherFactory url_fetcher_factory_; + network::TestURLLoaderFactory test_url_loader_factory_; + const scoped_refptr<network::WeakWrapperSharedURLLoaderFactory> + shared_url_loader_factory_; const scoped_refptr<MockWifiDataProvider> wifi_data_provider_; std::unique_ptr<NetworkLocationProvider::LastPositionCache> last_position_cache_; @@ -312,9 +313,11 @@ const std::string api_key = ""; std::unique_ptr<LocationProvider> provider(CreateProvider(true, api_key)); provider->StartProvider(false); - net::TestURLFetcher* fetcher = get_url_fetcher_and_advance_id(); - ASSERT_TRUE(fetcher); - EXPECT_FALSE(fetcher->GetOriginalURL().has_query()); + + ASSERT_EQ(1, test_url_loader_factory_.NumPending()); + const GURL& request_url = + test_url_loader_factory_.pending_requests()->back().request.url; + EXPECT_FALSE(request_url.has_query()); } // Tests that, with non-empty api_key, a "key" query string parameter is @@ -323,10 +326,12 @@ const std::string api_key = "something"; std::unique_ptr<LocationProvider> provider(CreateProvider(true, api_key)); provider->StartProvider(false); - net::TestURLFetcher* fetcher = get_url_fetcher_and_advance_id(); - ASSERT_TRUE(fetcher); - EXPECT_TRUE(fetcher->GetOriginalURL().has_query()); - EXPECT_TRUE(fetcher->GetOriginalURL().query_piece().starts_with("key=")); + + ASSERT_EQ(1, test_url_loader_factory_.NumPending()); + const GURL& request_url = + test_url_loader_factory_.pending_requests()->back().request.url; + EXPECT_TRUE(request_url.has_query()); + EXPECT_TRUE(request_url.query_piece().starts_with("key=")); } // Tests that, after StartProvider(), a TestURLFetcher can be extracted, @@ -334,9 +339,8 @@ TEST_F(GeolocationNetworkProviderTest, StartProvider) { std::unique_ptr<LocationProvider> provider(CreateProvider(true)); provider->StartProvider(false); - net::TestURLFetcher* fetcher = get_url_fetcher_and_advance_id(); - ASSERT_TRUE(fetcher); - CheckRequestIsValid(*fetcher, 0, 0); + + CheckRequestIsValid(0, 0); } // Tests that, with a very large number of access points, the set of access @@ -348,14 +352,16 @@ const int kFirstScanAps = 20; wifi_data_provider_->SetData(CreateReferenceWifiScanData(kFirstScanAps)); base::RunLoop().RunUntilIdle(); - net::TestURLFetcher* fetcher = get_url_fetcher_and_advance_id(); - ASSERT_TRUE(fetcher); + + ASSERT_EQ(1, test_url_loader_factory_.NumPending()); + const std::string& request_url = + test_url_loader_factory_.pending_requests()->back().request.url.spec(); // The request url should have been shortened to less than 2048 characters // in length by not including access points with the lowest signal strength // in the request. - EXPECT_LT(fetcher->GetOriginalURL().spec().size(), size_t(2048)); + EXPECT_LT(request_url.size(), size_t(2048)); // Expect only 16 out of 20 original access points. - CheckRequestIsValid(*fetcher, 16, 4); + CheckRequestIsValid(16, 4); } // Tests that the provider issues the right requests, and provides the right @@ -371,19 +377,18 @@ TEST_F(GeolocationNetworkProviderTest, MultipleWifiScansComplete) { std::unique_ptr<LocationProvider> provider(CreateProvider(true)); provider->StartProvider(false); - - net::TestURLFetcher* fetcher = get_url_fetcher_and_advance_id(); - ASSERT_TRUE(fetcher); + ASSERT_EQ(1, test_url_loader_factory_.NumPending()); // 1. Complete the network request with bad position fix. + const std::string& request_url_1 = + test_url_loader_factory_.pending_requests()->back().request.url.spec(); const char* kNoFixNetworkResponse = "{" " \"status\": \"ZERO_RESULTS\"" "}"; - fetcher->set_status(net::URLRequestStatus()); - fetcher->set_response_code(200); // OK - fetcher->SetResponseString(kNoFixNetworkResponse); - fetcher->delegate()->OnURLFetchComplete(fetcher); + test_url_loader_factory_.AddResponse(request_url_1, kNoFixNetworkResponse); + base::RunLoop().RunUntilIdle(); + test_url_loader_factory_.ClearResponses(); mojom::Geoposition position = provider->GetPosition(); EXPECT_FALSE(ValidateGeoposition(position)); @@ -392,12 +397,14 @@ const int kFirstScanAps = 6; wifi_data_provider_->SetData(CreateReferenceWifiScanData(kFirstScanAps)); base::RunLoop().RunUntilIdle(); - fetcher = get_url_fetcher_and_advance_id(); - ASSERT_TRUE(fetcher); + // The request should have the wifi data. - CheckRequestIsValid(*fetcher, kFirstScanAps, 0); + CheckRequestIsValid(kFirstScanAps, 0); // 3. Send a reply with good position fix. + ASSERT_EQ(1, test_url_loader_factory_.NumPending()); + const std::string& request_url_2 = + test_url_loader_factory_.pending_requests()->back().request.url.spec(); const char* kReferenceNetworkResponse = "{" " \"accuracy\": 1200.4," @@ -406,10 +413,10 @@ " \"lng\": -0.1" " }" "}"; - fetcher->set_status(net::URLRequestStatus()); - fetcher->set_response_code(200); // OK - fetcher->SetResponseString(kReferenceNetworkResponse); - fetcher->delegate()->OnURLFetchComplete(fetcher); + test_url_loader_factory_.AddResponse(request_url_2, + kReferenceNetworkResponse); + base::RunLoop().RunUntilIdle(); + test_url_loader_factory_.ClearResponses(); position = provider->GetPosition(); EXPECT_EQ(51.0, position.latitude); @@ -423,8 +430,7 @@ const int kSecondScanAps = kFirstScanAps - 1; wifi_data_provider_->SetData(CreateReferenceWifiScanData(kSecondScanAps)); base::RunLoop().RunUntilIdle(); - fetcher = get_url_fetcher_and_advance_id(); - EXPECT_FALSE(fetcher); + EXPECT_EQ(0, test_url_loader_factory_.NumPending()); position = provider->GetPosition(); EXPECT_EQ(51.0, position.latitude); @@ -435,15 +441,16 @@ const int kThirdScanAps = kFirstScanAps * 2 + 1; wifi_data_provider_->SetData(CreateReferenceWifiScanData(kThirdScanAps)); base::RunLoop().RunUntilIdle(); - fetcher = get_url_fetcher_and_advance_id(); - EXPECT_TRUE(fetcher); - CheckRequestIsValid(*fetcher, kThirdScanAps, 0); + CheckRequestIsValid(kThirdScanAps, 0); // 6. ...reply with a network error. - fetcher->set_status(net::URLRequestStatus::FromError(net::ERR_FAILED)); - fetcher->set_response_code(200); // should be ignored - fetcher->SetResponseString(std::string()); - fetcher->delegate()->OnURLFetchComplete(fetcher); + ASSERT_EQ(1, test_url_loader_factory_.NumPending()); + const GURL& request_url_3 = + test_url_loader_factory_.pending_requests()->back().request.url; + test_url_loader_factory_.AddResponse( + request_url_3, network::ResourceResponseHead(), std::string(), + network::URLLoaderCompletionStatus(net::ERR_FAILED)); + base::RunLoop().RunUntilIdle(); // Error means we now no longer have a fix. position = provider->GetPosition(); @@ -452,7 +459,7 @@ // 7. Wifi scan returns to original set: should be serviced from cache. wifi_data_provider_->SetData(CreateReferenceWifiScanData(kFirstScanAps)); base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(get_url_fetcher_and_advance_id()); // No new request created. + EXPECT_EQ(0, test_url_loader_factory_.NumPending()); position = provider->GetPosition(); EXPECT_EQ(51.0, position.latitude); @@ -471,14 +478,14 @@ provider->SetUpdateCallback(listener.callback); base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(get_url_fetcher_and_advance_id()) + EXPECT_EQ(0, test_url_loader_factory_.NumPending()) << "Network request should not be created right away on startup when " "wifi data has not yet arrived"; // Now Wifi data becomes available. wifi_data_provider_->SetData(CreateReferenceWifiScanData(1)); base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(get_url_fetcher_and_advance_id()); + EXPECT_EQ(1, test_url_loader_factory_.NumPending()); } // Tests that, even if a request is already in flight, new wifi data results in @@ -487,14 +494,12 @@ // Send initial request with empty data std::unique_ptr<LocationProvider> provider(CreateProvider(true)); provider->StartProvider(false); - net::TestURLFetcher* fetcher = get_url_fetcher_and_advance_id(); - EXPECT_TRUE(fetcher); + CheckRequestIsValid(0, 0); // Now wifi data arrives; new request should be sent. wifi_data_provider_->SetData(CreateReferenceWifiScanData(4)); base::RunLoop().RunUntilIdle(); - fetcher = get_url_fetcher_and_advance_id(); - EXPECT_TRUE(fetcher); + CheckRequestIsValid(4, 0); } // Tests that, if user geolocation permission hasn't been granted during @@ -503,12 +508,10 @@ TEST_F(GeolocationNetworkProviderTest, NetworkRequestDeferredForPermission) { std::unique_ptr<LocationProvider> provider(CreateProvider(false)); provider->StartProvider(false); - net::TestURLFetcher* fetcher = get_url_fetcher_and_advance_id(); - EXPECT_FALSE(fetcher); - provider->OnPermissionGranted(); + EXPECT_EQ(0, test_url_loader_factory_.NumPending()); - fetcher = get_url_fetcher_and_advance_id(); - ASSERT_TRUE(fetcher); + provider->OnPermissionGranted(); + EXPECT_EQ(1, test_url_loader_factory_.NumPending()); } // Tests that, even if new Wifi data arrives, the provider doesn't initiate its @@ -517,22 +520,15 @@ NetworkRequestWithWifiDataDeferredForPermission) { std::unique_ptr<LocationProvider> provider(CreateProvider(false)); provider->StartProvider(false); - net::TestURLFetcher* fetcher = get_url_fetcher_and_advance_id(); - EXPECT_FALSE(fetcher); + EXPECT_EQ(0, test_url_loader_factory_.NumPending()); static const int kScanCount = 4; wifi_data_provider_->SetData(CreateReferenceWifiScanData(kScanCount)); base::RunLoop().RunUntilIdle(); - - fetcher = get_url_fetcher_and_advance_id(); - EXPECT_FALSE(fetcher); + EXPECT_EQ(0, test_url_loader_factory_.NumPending()); provider->OnPermissionGranted(); - - fetcher = get_url_fetcher_and_advance_id(); - ASSERT_TRUE(fetcher); - - CheckRequestIsValid(*fetcher, kScanCount, 0); + CheckRequestIsValid(kScanCount, 0); } // Tests that the provider's position cache correctly caches each item, and @@ -580,12 +576,13 @@ const int kFirstScanAps = 6; wifi_data_provider_->SetData(CreateReferenceWifiScanData(kFirstScanAps)); base::RunLoop().RunUntilIdle(); - net::TestURLFetcher* fetcher = get_url_fetcher_and_advance_id(); - ASSERT_TRUE(fetcher); // The request should have the wifi data. - CheckRequestIsValid(*fetcher, kFirstScanAps, 0); + CheckRequestIsValid(kFirstScanAps, 0); // Send a reply with good position fix. + ASSERT_EQ(1, test_url_loader_factory_.NumPending()); + const std::string& request_url = + test_url_loader_factory_.pending_requests()->back().request.url.spec(); const char* kReferenceNetworkResponse = "{" " \"accuracy\": 1200.4," @@ -594,10 +591,8 @@ " \"lng\": -0.1" " }" "}"; - fetcher->set_status(net::URLRequestStatus()); - fetcher->set_response_code(200); // OK - fetcher->SetResponseString(kReferenceNetworkResponse); - fetcher->delegate()->OnURLFetchComplete(fetcher); + test_url_loader_factory_.AddResponse(request_url, kReferenceNetworkResponse); + base::RunLoop().RunUntilIdle(); // The provider should return the position as the current best estimate. position = provider->GetPosition(); @@ -747,7 +742,7 @@ EXPECT_FALSE(ValidateGeoposition(listener.last_position)); // Check that there is no pending network request. - EXPECT_FALSE(get_url_fetcher_and_advance_id()); + EXPECT_EQ(0, test_url_loader_factory_.NumPending()); // Simulate no new wifi data. wifi_data_provider_->set_got_data(false); @@ -763,7 +758,7 @@ EXPECT_FALSE(ValidateGeoposition(listener.last_position)); // Check that a network request is pending. - EXPECT_TRUE(get_url_fetcher_and_advance_id()); + EXPECT_EQ(1, test_url_loader_factory_.NumPending()); } } // namespace device
diff --git a/services/device/geolocation/network_location_request.cc b/services/device/geolocation/network_location_request.cc index deff99ce..c5cd5bd 100644 --- a/services/device/geolocation/network_location_request.cc +++ b/services/device/geolocation/network_location_request.cc
@@ -23,11 +23,10 @@ #include "net/base/escape.h" #include "net/base/load_flags.h" #include "net/traffic_annotation/network_traffic_annotation.h" -#include "net/url_request/url_fetcher.h" -#include "net/url_request/url_request_context_getter.h" -#include "net/url_request/url_request_status.h" #include "services/device/geolocation/location_arbitrator.h" #include "services/device/public/cpp/geolocation/geoposition.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" +#include "services/network/public/cpp/simple_url_loader.h" namespace device { namespace { @@ -87,9 +86,9 @@ // Attempts to extract a position from the response. Detects and indicates // various failure cases. -void GetLocationFromResponse(bool http_post_result, +void GetLocationFromResponse(int net_error, int status_code, - const std::string& response_body, + std::unique_ptr<std::string> response_body, const base::Time& wifi_timestamp, const GURL& server_url, mojom::Geoposition* position); @@ -105,15 +104,13 @@ base::DictionaryValue* request); } // namespace -int NetworkLocationRequest::url_fetcher_id_for_tests = 0; - NetworkLocationRequest::NetworkLocationRequest( - scoped_refptr<net::URLRequestContextGetter> context, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& api_key, LocationResponseCallback callback) - : url_context_(std::move(context)), + : url_loader_factory_(std::move(url_loader_factory)), api_key_(api_key), - location_response_callback_(callback) {} + location_response_callback_(std::move(callback)) {} NetworkLocationRequest::~NetworkLocationRequest() = default; @@ -123,10 +120,10 @@ const net::PartialNetworkTrafficAnnotationTag& partial_traffic_annotation) { RecordUmaEvent(NETWORK_LOCATION_REQUEST_EVENT_REQUEST_START); RecordUmaAccessPoints(wifi_data.access_point_data.size()); - if (url_fetcher_ != NULL) { + if (url_loader_) { DVLOG(1) << "NetworkLocationRequest : Cancelling pending request"; RecordUmaEvent(NETWORK_LOCATION_REQUEST_EVENT_REQUEST_CANCEL); - url_fetcher_.reset(); + url_loader_.reset(); } wifi_data_ = wifi_data; wifi_timestamp_ = wifi_timestamp; @@ -147,41 +144,48 @@ policy { cookies_allowed: NO })"); - const GURL request_url = FormRequestURL(api_key_); - DCHECK(request_url.is_valid()); - url_fetcher_ = - net::URLFetcher::Create(url_fetcher_id_for_tests, request_url, - net::URLFetcher::POST, this, traffic_annotation); - url_fetcher_->SetRequestContext(url_context_.get()); + + auto resource_request = std::make_unique<network::ResourceRequest>(); + resource_request->method = "POST"; + resource_request->url = FormRequestURL(api_key_); + DCHECK(resource_request->url.is_valid()); + resource_request->load_flags = + net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE | + net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES | + net::LOAD_DO_NOT_SEND_AUTH_DATA; + + url_loader_ = network::SimpleURLLoader::Create(std::move(resource_request), + traffic_annotation); + std::string upload_data; FormUploadData(wifi_data, wifi_timestamp, &upload_data); - url_fetcher_->SetUploadData("application/json", upload_data); - url_fetcher_->SetLoadFlags(net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE | - net::LOAD_DO_NOT_SAVE_COOKIES | - net::LOAD_DO_NOT_SEND_COOKIES | - net::LOAD_DO_NOT_SEND_AUTH_DATA); + url_loader_->AttachStringForUpload(upload_data, "application/json"); request_start_time_ = base::TimeTicks::Now(); - url_fetcher_->Start(); + url_loader_->DownloadToString( + url_loader_factory_.get(), + base::BindOnce(&NetworkLocationRequest::OnRequestComplete, + base::Unretained(this)), + 1024 * 1024 /* 1 MiB */); return true; } -void NetworkLocationRequest::OnURLFetchComplete(const net::URLFetcher* source) { - DCHECK_EQ(url_fetcher_.get(), source); +void NetworkLocationRequest::OnRequestComplete( + std::unique_ptr<std::string> data) { + int net_error = url_loader_->NetError(); - net::URLRequestStatus status = source->GetStatus(); - int response_code = source->GetResponseCode(); + int response_code = 0; + if (url_loader_->ResponseInfo()) + response_code = url_loader_->ResponseInfo()->headers->response_code(); RecordUmaResponseCode(response_code); mojom::Geoposition position; - std::string data; - source->GetResponseAsString(&data); - GetLocationFromResponse(status.is_success(), response_code, data, - wifi_timestamp_, source->GetURL(), &position); - const bool server_error = - !status.is_success() || (response_code >= 500 && response_code < 600); - url_fetcher_.reset(); + GetLocationFromResponse(net_error, response_code, std::move(data), + wifi_timestamp_, url_loader_->GetFinalURL(), + &position); + bool server_error = + net_error != net::OK || (response_code >= 500 && response_code < 600); if (!server_error) { const base::TimeDelta request_time = base::TimeTicks::Now() - request_start_time_; @@ -191,6 +195,8 @@ base::TimeDelta::FromSeconds(10), 100); } + url_loader_.reset(); + DVLOG(1) << "NetworkLocationRequest::OnURLFetchComplete() : run callback."; location_response_callback_.Run(position, server_error, wifi_data_); } @@ -294,9 +300,9 @@ << position->error_message; } -void GetLocationFromResponse(bool http_post_result, +void GetLocationFromResponse(int net_error, int status_code, - const std::string& response_body, + std::unique_ptr<std::string> response_body, const base::Time& wifi_timestamp, const GURL& server_url, mojom::Geoposition* position) { @@ -304,11 +310,12 @@ // HttpPost can fail for a number of reasons. Most likely this is because // we're offline, or there was no response. - if (!http_post_result) { + if (net_error != net::OK) { FormatPositionError(server_url, "No response received", position); RecordUmaEvent(NETWORK_LOCATION_REQUEST_EVENT_RESPONSE_EMPTY); return; } + if (status_code != 200) { // HTTP OK. std::string message = "Returned error code "; message += base::IntToString(status_code); @@ -316,14 +323,17 @@ RecordUmaEvent(NETWORK_LOCATION_REQUEST_EVENT_RESPONSE_NOT_OK); return; } + // We use the timestamp from the wifi data that was used to generate // this position fix. - if (!ParseServerResponse(response_body, wifi_timestamp, position)) { + DCHECK(response_body); + if (!ParseServerResponse(*response_body, wifi_timestamp, position)) { // We failed to parse the repsonse. FormatPositionError(server_url, "Response was malformed", position); RecordUmaEvent(NETWORK_LOCATION_REQUEST_EVENT_RESPONSE_MALFORMED); return; } + // The response was successfully parsed, but it may not be a valid // position fix. if (!ValidateGeoposition(*position)) { @@ -332,6 +342,7 @@ RecordUmaEvent(NETWORK_LOCATION_REQUEST_EVENT_RESPONSE_INVALID_FIX); return; } + RecordUmaEvent(NETWORK_LOCATION_REQUEST_EVENT_RESPONSE_SUCCESS); }
diff --git a/services/device/geolocation/network_location_request.h b/services/device/geolocation/network_location_request.h index c544960..885abf39 100644 --- a/services/device/geolocation/network_location_request.h +++ b/services/device/geolocation/network_location_request.h
@@ -11,39 +11,38 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/strings/string16.h" -#include "net/url_request/url_fetcher_delegate.h" #include "services/device/geolocation/wifi_data_provider.h" #include "services/device/public/mojom/geoposition.mojom.h" #include "url/gurl.h" namespace net { -class URLFetcher; -class URLRequestContextGetter; - struct PartialNetworkTrafficAnnotationTag; } // namespace net +namespace network { +class SharedURLLoaderFactory; +class SimpleURLLoader; +} // namespace network + namespace device { // Takes wifi data and sends it to a server to get a position fix. // It performs formatting of the request and interpretation of the response. -class NetworkLocationRequest : private net::URLFetcherDelegate { +class NetworkLocationRequest { public: - // ID passed to URLFetcher::Create(). Used for testing. - static int url_fetcher_id_for_tests; - // Called when a new geo position is available. The second argument indicates // whether there was a server error or not. It is true when there was a // server or network error - either no response or a 500 error code. using LocationResponseCallback = - base::Callback<void(const mojom::Geoposition& /* position */, - bool /* server_error */, - const WifiData& /* wifi_data */)>; + base::RepeatingCallback<void(const mojom::Geoposition& /* position */, + bool /* server_error */, + const WifiData& /* wifi_data */)>; - NetworkLocationRequest(scoped_refptr<net::URLRequestContextGetter> context, - const std::string& api_key, - LocationResponseCallback callback); - ~NetworkLocationRequest() override; + NetworkLocationRequest( + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + const std::string& api_key, + LocationResponseCallback callback); + ~NetworkLocationRequest(); // Makes a new request using the specified |wifi_data|. Returns true if the // new request was successfully started. In all cases, any currently pending @@ -56,16 +55,15 @@ const net::PartialNetworkTrafficAnnotationTag& partial_traffic_annotation); - bool is_request_pending() const { return url_fetcher_ != NULL; } + bool is_request_pending() const { return bool(url_loader_); } private: - // net::URLFetcherDelegate - void OnURLFetchComplete(const net::URLFetcher* source) override; + void OnRequestComplete(std::unique_ptr<std::string> data); - const scoped_refptr<net::URLRequestContextGetter> url_context_; + const scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; const std::string api_key_; const LocationResponseCallback location_response_callback_; - std::unique_ptr<net::URLFetcher> url_fetcher_; + std::unique_ptr<network::SimpleURLLoader> url_loader_; // Keep a copy of the data sent in the request, so we can refer back to it // when the response arrives.
diff --git a/services/device/geolocation/public_ip_address_geolocation_provider.cc b/services/device/geolocation/public_ip_address_geolocation_provider.cc index 207556e..2ad162e 100644 --- a/services/device/geolocation/public_ip_address_geolocation_provider.cc +++ b/services/device/geolocation/public_ip_address_geolocation_provider.cc
@@ -5,18 +5,19 @@ #include "services/device/geolocation/public_ip_address_geolocation_provider.h" #include "services/device/geolocation/public_ip_address_geolocator.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" namespace device { PublicIpAddressGeolocationProvider::PublicIpAddressGeolocationProvider( - GeolocationProvider::RequestContextProducer request_context_producer, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& api_key) { // Bind sequence_checker_ to the initialization sequence. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); public_ip_address_location_notifier_ = std::make_unique<PublicIpAddressLocationNotifier>( - request_context_producer, api_key); + std::move(url_loader_factory), api_key); } PublicIpAddressGeolocationProvider::~PublicIpAddressGeolocationProvider() {}
diff --git a/services/device/geolocation/public_ip_address_geolocation_provider.h b/services/device/geolocation/public_ip_address_geolocation_provider.h index 8888c95..06dd4fa6 100644 --- a/services/device/geolocation/public_ip_address_geolocation_provider.h +++ b/services/device/geolocation/public_ip_address_geolocation_provider.h
@@ -29,10 +29,9 @@ : public mojom::PublicIpAddressGeolocationProvider { public: // Initialize PublicIpAddressGeolocationProvider using the specified Google - // |api_key| and a URL request context produced by |request_context_producer| - // for network location requests. + // |api_key| and |url_loader_factory| for network location requests. PublicIpAddressGeolocationProvider( - GeolocationProvider::RequestContextProducer request_context_producer, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& api_key); ~PublicIpAddressGeolocationProvider() override;
diff --git a/services/device/geolocation/public_ip_address_geolocator_unittest.cc b/services/device/geolocation/public_ip_address_geolocator_unittest.cc index 2449938..795a3325 100644 --- a/services/device/geolocation/public_ip_address_geolocator_unittest.cc +++ b/services/device/geolocation/public_ip_address_geolocator_unittest.cc
@@ -5,11 +5,13 @@ #include "services/device/geolocation/public_ip_address_geolocator.h" #include "base/run_loop.h" +#include "base/strings/string_util.h" #include "base/test/scoped_task_environment.h" #include "mojo/core/embedder/embedder.h" #include "mojo/public/cpp/bindings/strong_binding_set.h" -#include "net/url_request/test_url_fetcher_factory.h" -#include "net/url_request/url_request_test_util.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" +#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" +#include "services/network/test/test_url_loader_factory.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -18,29 +20,18 @@ const char kTestGeolocationApiKey[] = ""; -// Simple request context producer that immediately produces a -// TestURLRequestContextGetter. -void TestRequestContextProducer( - const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner, - base::OnceCallback<void(scoped_refptr<net::URLRequestContextGetter>)> - response_callback) { - std::move(response_callback) - .Run(base::MakeRefCounted<net::TestURLRequestContextGetter>( - network_task_runner)); -} - class PublicIpAddressGeolocatorTest : public testing::Test { public: PublicIpAddressGeolocatorTest() : scoped_task_environment_( base::test::ScopedTaskEnvironment::MainThreadType::IO) { notifier_.reset(new PublicIpAddressLocationNotifier( - base::Bind(&TestRequestContextProducer, - scoped_task_environment_.GetMainThreadTaskRunner()), + base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( + &test_url_loader_factory_), kTestGeolocationApiKey)); } - ~PublicIpAddressGeolocatorTest() override = default; + ~PublicIpAddressGeolocatorTest() override {} protected: void SetUp() override { @@ -107,73 +98,33 @@ // The object under test. mojom::GeolocationPtr public_ip_address_geolocator_; - // PublicIpAddressGeolocator implementation. - // std::unique_ptr<PublicIpAddressGeolocator> impl_; + // Test URLLoaderFactory for handling requests to the geolocation API. + network::TestURLLoaderFactory test_url_loader_factory_; DISALLOW_COPY_AND_ASSIGN(PublicIpAddressGeolocatorTest); }; -// Observer that waits until a TestURLFetcher with the specified fetcher_id -// starts, after which it is made available through .fetcher(). -class TestURLFetcherObserver : public net::TestURLFetcher::DelegateForTests { - public: - explicit TestURLFetcherObserver(int expected_fetcher_id) - : expected_fetcher_id_(expected_fetcher_id) { - factory_.SetDelegateForTests(this); - } - virtual ~TestURLFetcherObserver() {} - - void Wait() { loop_.Run(); } - - net::TestURLFetcher* fetcher() { return fetcher_; } - - // net::TestURLFetcher::DelegateForTests: - void OnRequestStart(int fetcher_id) override { - if (fetcher_id == expected_fetcher_id_) { - fetcher_ = factory_.GetFetcherByID(fetcher_id); - fetcher_->SetDelegateForTests(nullptr); - factory_.SetDelegateForTests(nullptr); - loop_.Quit(); - } - } - void OnChunkUpload(int fetcher_id) override {} - void OnRequestEnd(int fetcher_id) override {} - - private: - const int expected_fetcher_id_; - net::TestURLFetcher* fetcher_ = nullptr; - net::TestURLFetcherFactory factory_; - base::RunLoop loop_; -}; - // Basic test of a client invoking QueryNextPosition. TEST_F(PublicIpAddressGeolocatorTest, BindAndQuery) { - // Intercept the URLFetcher from network geolocation request. - TestURLFetcherObserver observer( - device::NetworkLocationRequest::url_fetcher_id_for_tests); - - // Invoke QueryNextPosition and wait for a URLFetcher. + // Invoke QueryNextPosition. base::RunLoop loop; QueryNextPosition(loop.QuitClosure()); - observer.Wait(); - DCHECK(observer.fetcher()); - // Issue a valid response to the URLFetcher. - observer.fetcher()->set_url(observer.fetcher()->GetOriginalURL()); - observer.fetcher()->set_status(net::URLRequestStatus()); - observer.fetcher()->set_response_code(200); - observer.fetcher()->SetResponseString(R"({ + ASSERT_EQ(1, test_url_loader_factory_.NumPending()); + const std::string& request_url = + test_url_loader_factory_.pending_requests()->back().request.url.spec(); + EXPECT_TRUE( + base::StartsWith("https://www.googleapis.com/geolocation/v1/geolocate", + request_url, base::CompareCase::SENSITIVE)); + + // Issue a valid response. + test_url_loader_factory_.AddResponse(request_url, R"({ "accuracy": 100.0, "location": { "lat": 10.0, "lng": 20.0 } - })"); - scoped_task_environment_.GetMainThreadTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(&net::URLFetcherDelegate::OnURLFetchComplete, - base::Unretained(observer.fetcher()->delegate()), - base::Unretained(observer.fetcher()))); + })", net::HTTP_OK); // Wait for QueryNextPosition to return. loop.Run();
diff --git a/services/device/geolocation/public_ip_address_location_notifier.cc b/services/device/geolocation/public_ip_address_location_notifier.cc index 906bf98..207a08f8 100644 --- a/services/device/geolocation/public_ip_address_location_notifier.cc +++ b/services/device/geolocation/public_ip_address_location_notifier.cc
@@ -6,6 +6,7 @@ #include "net/traffic_annotation/network_traffic_annotation.h" #include "services/device/geolocation/wifi_data.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" namespace device { @@ -17,11 +18,11 @@ } // namespace PublicIpAddressLocationNotifier::PublicIpAddressLocationNotifier( - GeolocationProvider::RequestContextProducer request_context_producer, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& api_key) : network_changed_since_last_request_(true), api_key_(api_key), - request_context_producer_(request_context_producer), + url_loader_factory_(url_loader_factory), network_traffic_annotation_tag_(nullptr), weak_ptr_factory_(this) { // Subscribe to notifications of changes in network configuration. @@ -98,21 +99,11 @@ void PublicIpAddressLocationNotifier::MakeNetworkLocationRequest() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); network_changed_since_last_request_ = false; - // Obtain URL request context using provided producer callback, then continue - // request in MakeNetworkLocationRequestWithRequestContext. - request_context_producer_.Run(base::BindOnce( - &PublicIpAddressLocationNotifier::MakeNetworkLocationRequestWithContext, - weak_ptr_factory_.GetWeakPtr())); -} - -void PublicIpAddressLocationNotifier::MakeNetworkLocationRequestWithContext( - scoped_refptr<net::URLRequestContextGetter> context_getter) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!context_getter) + if (!url_loader_factory_) return; network_location_request_ = std::make_unique<NetworkLocationRequest>( - std::move(context_getter), api_key_, + url_loader_factory_, api_key_, base::BindRepeating( &PublicIpAddressLocationNotifier::OnNetworkLocationResponse, weak_ptr_factory_.GetWeakPtr()));
diff --git a/services/device/geolocation/public_ip_address_location_notifier.h b/services/device/geolocation/public_ip_address_location_notifier.h index 5272f50e..c304a61 100644 --- a/services/device/geolocation/public_ip_address_location_notifier.h +++ b/services/device/geolocation/public_ip_address_location_notifier.h
@@ -31,11 +31,10 @@ class PublicIpAddressLocationNotifier : public net::NetworkChangeNotifier::NetworkChangeObserver { public: - // Creates a notifier that uses the specified Google |api_key| and a URL - // request context produced by |request_context_producer| for network location - // requests. + // Creates a notifier that uses the specified Google |api_key| and + // |url_loader_factory| for network location requests. PublicIpAddressLocationNotifier( - GeolocationProvider::RequestContextProducer request_context_producer, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const std::string& api_key); ~PublicIpAddressLocationNotifier() override; @@ -69,15 +68,9 @@ // if any clients are waiting. void ReactToNetworkChange(); - // Begins a network location request, by first obtaining a - // URLRequestContextGetter, then continuing in - // MakeNetworkLocationRequestWithContext. - void MakeNetworkLocationRequest(); - - // Creates network_location_request_ and starts the network request, which + // Creates |network_location_request_| and starts the network request, which // will invoke OnNetworkLocationResponse when done. - void MakeNetworkLocationRequestWithContext( - scoped_refptr<net::URLRequestContextGetter> context_getter); + void MakeNetworkLocationRequest(); // Completion callback for network_location_request_. void OnNetworkLocationResponse(const mojom::Geoposition& position, @@ -98,8 +91,8 @@ // Google API key for network geolocation requests. const std::string api_key_; - // Callback to produce a URL request context for network geolocation requests. - const GeolocationProvider::RequestContextProducer request_context_producer_; + // SharedURLLoaderFactory for network geolocation requests. + const scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; // Used to make calls to the Maps geolocate API. // Empty unless a call is currently in progress.
diff --git a/services/device/geolocation/public_ip_address_location_notifier_unittest.cc b/services/device/geolocation/public_ip_address_location_notifier_unittest.cc index a4b8ce0..12bb806c 100644 --- a/services/device/geolocation/public_ip_address_location_notifier_unittest.cc +++ b/services/device/geolocation/public_ip_address_location_notifier_unittest.cc
@@ -9,27 +9,15 @@ #include "base/strings/stringprintf.h" #include "base/test/test_mock_time_task_runner.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_request_test_util.h" +#include "services/device/device_service_test_base.h" #include "services/device/public/cpp/geolocation/geoposition.h" #include "services/device/public/mojom/geoposition.mojom.h" +#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" +#include "services/network/test/test_url_loader_factory.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" namespace device { -namespace { -// Simple request context producer that immediately produces a -// TestURLRequestContextGetter. -void TestRequestContextProducer( - const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner, - base::OnceCallback<void(scoped_refptr<net::URLRequestContextGetter>)> - response_callback) { - std::move(response_callback) - .Run(base::MakeRefCounted<net::TestURLRequestContextGetter>( - network_task_runner)); -} - -} // namespace class PublicIpAddressLocationNotifierTest : public testing::Test { protected: @@ -64,31 +52,28 @@ : mock_time_task_runner_( base::MakeRefCounted<base::TestMockTimeTaskRunner>( base::TestMockTimeTaskRunner::Type::kBoundToThread)), - mock_time_scoped_context_(mock_time_task_runner_.get()), network_change_notifier_(net::NetworkChangeNotifier::CreateMock()), notifier_( - base::Bind(&TestRequestContextProducer, mock_time_task_runner_), - std::string() /* api_key */) {} + base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( + &test_url_loader_factory_), + kTestGeolocationApiKey) {} - // Returns the current TestURLFetcher (if any) and advances the test fetcher - // id for disambiguation from subsequent tests. - net::TestURLFetcher* GetTestUrlFetcher() { - net::TestURLFetcher* const fetcher = url_fetcher_factory_.GetFetcherByID( - NetworkLocationRequest::url_fetcher_id_for_tests); - if (fetcher) - ++NetworkLocationRequest::url_fetcher_id_for_tests; - return fetcher; - } + ~PublicIpAddressLocationNotifierTest() override {} // Gives a valid JSON reponse to the specified URLFetcher. // For disambiguation purposes, the specified |latitude| is included in the // response. - void RespondToFetchWithLatitude(net::TestURLFetcher* const fetcher, - const float latitude) { + void RespondToFetchWithLatitude(const float latitude) { + ASSERT_EQ(1, test_url_loader_factory_.NumPending()); + const std::string& request_url = + test_url_loader_factory_.pending_requests()->back().request.url.spec(); + std::string expected_url = + "https://www.googleapis.com/geolocation/v1/" + "geolocate?key="; + expected_url.append(kTestGeolocationApiKey); + EXPECT_EQ(expected_url, request_url); + // Issue a valid response including the specified latitude. - fetcher->set_url(fetcher->GetOriginalURL()); - fetcher->set_status(net::URLRequestStatus()); - fetcher->set_response_code(200); const char kNetworkResponseFormatString[] = R"({ "accuracy": 100.0, @@ -97,16 +82,28 @@ "lng": 90.0 } })"; - fetcher->SetResponseString( - base::StringPrintf(kNetworkResponseFormatString, latitude)); - fetcher->delegate()->OnURLFetchComplete(fetcher); + std::string body = + base::StringPrintf(kNetworkResponseFormatString, latitude); + test_url_loader_factory_.AddResponse(request_url, body, net::HTTP_OK); + mock_time_task_runner_->RunUntilIdle(); + test_url_loader_factory_.ClearResponses(); } - void RespondToFetchWithServerError(net::TestURLFetcher* const fetcher) { - fetcher->set_url(fetcher->GetOriginalURL()); - fetcher->set_status(net::URLRequestStatus()); - fetcher->set_response_code(500); - fetcher->delegate()->OnURLFetchComplete(fetcher); + void RespondToFetchWithServerError() { + ASSERT_EQ(1, test_url_loader_factory_.NumPending()); + const std::string& request_url = + test_url_loader_factory_.pending_requests()->back().request.url.spec(); + + std::string expected_url = + "https://www.googleapis.com/geolocation/v1/" + "geolocate?key="; + expected_url.append(kTestGeolocationApiKey); + EXPECT_EQ(expected_url, request_url); + + test_url_loader_factory_.AddResponse(request_url, std::string(), + net::HTTP_INTERNAL_SERVER_ERROR); + mock_time_task_runner_->RunUntilIdle(); + test_url_loader_factory_.ClearResponses(); } // Expects a non-empty and valid Geoposition, including the specified @@ -123,15 +120,15 @@ EXPECT_THAT(position->error_code, mojom::Geoposition::ErrorCode::POSITION_UNAVAILABLE); } + // Use a TaskRunner on which we can fast-forward time. const scoped_refptr<base::TestMockTimeTaskRunner> mock_time_task_runner_; - const base::TestMockTimeTaskRunner::ScopedContext mock_time_scoped_context_; // notifier_ requires a NetworkChangeNotifier to exist. std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_; - // Intercept URL fetchers. - net::TestURLFetcherFactory url_fetcher_factory_; + // Test URLLoaderFactory for handling requests to the geolocation API. + network::TestURLLoaderFactory test_url_loader_factory_; // The object under test. PublicIpAddressLocationNotifier notifier_; @@ -144,10 +141,10 @@ notifier_.QueryNextPosition(base::Time::Now(), PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS, query.MakeCallback()); + // Expect a URL fetch & send a valid response. - net::TestURLFetcher* const fetcher = GetTestUrlFetcher(); - EXPECT_THAT(fetcher, testing::NotNull()); - RespondToFetchWithLatitude(fetcher, 1.0f); + RespondToFetchWithLatitude(1.0f); + // Expect the query to return. ExpectValidPosition(query.position(), 1.0f); } @@ -160,9 +157,7 @@ TestPositionQuery query_1; notifier_.QueryNextPosition(time, PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS, query_1.MakeCallback()); - net::TestURLFetcher* const fetcher = GetTestUrlFetcher(); - EXPECT_THAT(fetcher, testing::NotNull()); - RespondToFetchWithLatitude(fetcher, 1.0f); + RespondToFetchWithLatitude(1.0f); ExpectValidPosition(query_1.position(), 1.0f); // Second query for an earlier time. @@ -171,7 +166,7 @@ PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS, query_2.MakeCallback()); // Expect a cached result, so no new network request. - EXPECT_THAT(GetTestUrlFetcher(), testing::IsNull()); + EXPECT_EQ(0, test_url_loader_factory_.NumPending()); // Expect the same result as query_1. ExpectValidPosition(query_2.position(), 1.0f); } @@ -185,9 +180,7 @@ notifier_.QueryNextPosition(base::Time::Now(), PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS, query_1.MakeCallback()); - net::TestURLFetcher* const fetcher = GetTestUrlFetcher(); - EXPECT_THAT(fetcher, testing::NotNull()); - RespondToFetchWithLatitude(fetcher, 1.0f); + RespondToFetchWithLatitude(1.0f); ExpectValidPosition(query_1.position(), 1.0f); // Second query seeking a position newer than the result of query_1. @@ -196,7 +189,7 @@ PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS, query_2.MakeCallback()); // Expect no network request or callback. - EXPECT_THAT(GetTestUrlFetcher(), testing::IsNull()); + EXPECT_EQ(0, test_url_loader_factory_.NumPending()); EXPECT_FALSE(query_2.position().has_value()); // Fake a network change notification. @@ -206,9 +199,7 @@ mock_time_task_runner_->FastForwardUntilNoTasksRemain(); // Now expect a network request and query_2 to return. - net::TestURLFetcher* const fetcher_2 = GetTestUrlFetcher(); - EXPECT_THAT(fetcher_2, testing::NotNull()); - RespondToFetchWithLatitude(fetcher_2, 2.0f); + RespondToFetchWithLatitude(2.0f); ExpectValidPosition(query_2.position(), 2.0f); } @@ -221,9 +212,7 @@ notifier_.QueryNextPosition(base::Time::Now(), PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS, query_1.MakeCallback()); - net::TestURLFetcher* const fetcher = GetTestUrlFetcher(); - EXPECT_THAT(fetcher, testing::NotNull()); - RespondToFetchWithLatitude(fetcher, 1.0f); + RespondToFetchWithLatitude(1.0f); ExpectValidPosition(query_1.position(), 1.0f); // Second query seeking a position newer than the result of query_1. @@ -232,7 +221,7 @@ PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS, query_2.MakeCallback()); // Expect no network request or callback since network has not changed. - EXPECT_THAT(GetTestUrlFetcher(), testing::IsNull()); + EXPECT_EQ(0, test_url_loader_factory_.NumPending()); EXPECT_FALSE(query_2.position().has_value()); // Fake several consecutive network changes notification. @@ -242,16 +231,14 @@ mock_time_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(5)); } // Expect still no network request or callback. - EXPECT_THAT(GetTestUrlFetcher(), testing::IsNull()); + EXPECT_EQ(0, test_url_loader_factory_.NumPending()); EXPECT_FALSE(query_2.position().has_value()); // Wait longer. mock_time_task_runner_->FastForwardUntilNoTasksRemain(); // Now expect a network request & query_2 to return. - net::TestURLFetcher* const fetcher_2 = GetTestUrlFetcher(); - EXPECT_THAT(fetcher_2, testing::NotNull()); - RespondToFetchWithLatitude(fetcher_2, 2.0f); + RespondToFetchWithLatitude(2.0f); ExpectValidPosition(query_2.position(), 2.0f); } @@ -262,9 +249,7 @@ notifier_.QueryNextPosition(base::Time::Now(), PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS, query_1.MakeCallback()); - net::TestURLFetcher* const fetcher = GetTestUrlFetcher(); - EXPECT_THAT(fetcher, testing::NotNull()); - RespondToFetchWithLatitude(fetcher, 1.0f); + RespondToFetchWithLatitude(1.0f); ExpectValidPosition(query_1.position(), 1.0f); // Multiple queries seeking positions newer than the result of query_1. @@ -278,7 +263,7 @@ query_3.MakeCallback()); // Expect no network requests or callback since network has not changed. - EXPECT_THAT(GetTestUrlFetcher(), testing::IsNull()); + EXPECT_EQ(0, test_url_loader_factory_.NumPending()); EXPECT_FALSE(query_2.position().has_value()); EXPECT_FALSE(query_3.position().has_value()); @@ -289,9 +274,7 @@ mock_time_task_runner_->FastForwardUntilNoTasksRemain(); // Now expect a network request & fake a valid response. - net::TestURLFetcher* const fetcher_2 = GetTestUrlFetcher(); - EXPECT_THAT(fetcher_2, testing::NotNull()); - RespondToFetchWithLatitude(fetcher_2, 2.0f); + RespondToFetchWithLatitude(2.0f); // Expect all queries to now return. ExpectValidPosition(query_2.position(), 2.0f); ExpectValidPosition(query_3.position(), 2.0f); @@ -305,9 +288,7 @@ PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS, query.MakeCallback()); // Expect a URL fetch & send a valid response. - net::TestURLFetcher* const fetcher = GetTestUrlFetcher(); - EXPECT_THAT(fetcher, testing::NotNull()); - RespondToFetchWithServerError(fetcher); + RespondToFetchWithServerError(); // Expect the query to return. ExpectError(query.position()); }
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc index 72fa406..3aaaab47 100644 --- a/services/network/network_context_unittest.cc +++ b/services/network/network_context_unittest.cc
@@ -1784,6 +1784,7 @@ GURL domain("https://google.com"); logging_service->OnHeader(url::Origin::Create(domain), + net::IPAddress(192, 168, 0, 1), "{\"report_to\":\"group\",\"max_age\":86400}"); ASSERT_EQ(1u, logging_service->GetPolicyOriginsForTesting().size()); @@ -1808,9 +1809,11 @@ GURL domain1("https://google.com"); logging_service->OnHeader(url::Origin::Create(domain1), + net::IPAddress(192, 168, 0, 1), "{\"report_to\":\"group\",\"max_age\":86400}"); GURL domain2("https://chromium.org"); logging_service->OnHeader(url::Origin::Create(domain2), + net::IPAddress(192, 168, 0, 1), "{\"report_to\":\"group\",\"max_age\":86400}"); ASSERT_EQ(2u, logging_service->GetPolicyOriginsForTesting().size());
diff --git a/services/ui/gpu_host/gpu_host_unittest.cc b/services/ui/gpu_host/gpu_host_unittest.cc index 87be309..9bc7d7a 100644 --- a/services/ui/gpu_host/gpu_host_unittest.cc +++ b/services/ui/gpu_host/gpu_host_unittest.cc
@@ -56,6 +56,7 @@ gpu::GpuPreferences(), base::nullopt, base::nullopt, + nullptr /* vulkan_implementation */, /*exit_callback=*/base::DoNothing()) {} } // namespace
diff --git a/storage/browser/database/database_tracker.h b/storage/browser/database/database_tracker.h index 2daecebb..e8863de2 100644 --- a/storage/browser/database/database_tracker.h +++ b/storage/browser/database/database_tracker.h
@@ -93,7 +93,7 @@ const base::string16& database_name) = 0; protected: - virtual ~Observer() {} + virtual ~Observer() = default; }; DatabaseTracker(const base::FilePath& profile_path, @@ -121,7 +121,9 @@ void CloseTrackerDatabaseAndClearCaches(); - const base::FilePath& DatabaseDirectory() const { return db_dir_; } + // Thread-safe getter. + const base::FilePath& database_directory() const { return db_dir_; } + base::FilePath GetFullDBFilePath(const std::string& origin_identifier, const base::string16& database_name); @@ -130,7 +132,7 @@ virtual bool GetAllOriginIdentifiers(std::vector<std::string>* origin_ids); virtual bool GetAllOriginsInfo(std::vector<OriginInfo>* origins_info); - // Safe to call on any thread. + // Thread-safe getter. storage::QuotaManagerProxy* quota_manager_proxy() const { return quota_manager_proxy_.get(); } @@ -281,7 +283,12 @@ bool force_keep_session_state_ = false; bool shutting_down_ = false; const base::FilePath profile_path_; + + // Can be accessed from any thread via database_directory(). + // + // Thread-safety argument: The member is immutable. const base::FilePath db_dir_; + std::unique_ptr<sql::Connection> db_; std::unique_ptr<DatabasesTable> databases_table_; std::unique_ptr<sql::MetaTable> meta_table_; @@ -294,9 +301,12 @@ PendingDeletionCallbacks deletion_callbacks_; // Apps and Extensions can have special rights. - scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_; + const scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_; - scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_; + // Can be accessed from any thread via quota_manager_proxy(). + // + // Thread-safety argument: The reference is immutable. + const scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_; // The database tracker thread we're supposed to run file IO on. scoped_refptr<base::SequencedTaskRunner> task_runner_;
diff --git a/storage/browser/database/database_tracker_unittest.cc b/storage/browser/database/database_tracker_unittest.cc index daed560..f213778c 100644 --- a/storage/browser/database/database_tracker_unittest.cc +++ b/storage/browser/database/database_tracker_unittest.cc
@@ -218,10 +218,10 @@ tracker->DatabaseOpened(kOrigin2, kDB3, kDescription, 0, &database_size); EXPECT_TRUE(base::CreateDirectory( - tracker->DatabaseDirectory().Append(base::FilePath::FromUTF16Unsafe( + tracker->database_directory().Append(base::FilePath::FromUTF16Unsafe( tracker->GetOriginDirectory(kOrigin1))))); EXPECT_TRUE(base::CreateDirectory( - tracker->DatabaseDirectory().Append(base::FilePath::FromUTF16Unsafe( + tracker->database_directory().Append(base::FilePath::FromUTF16Unsafe( tracker->GetOriginDirectory(kOrigin2))))); EXPECT_EQ( 1, base::WriteFile(tracker->GetFullDBFilePath(kOrigin1, kDB1), "a", 1)); @@ -247,12 +247,12 @@ result = callback.GetResult(result); EXPECT_EQ(net::OK, result); EXPECT_FALSE( - base::PathExists(tracker->DatabaseDirectory().AppendASCII(kOrigin1))); + base::PathExists(tracker->database_directory().AppendASCII(kOrigin1))); // Recreate db1. tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0, &database_size); EXPECT_TRUE(base::CreateDirectory( - tracker->DatabaseDirectory().Append(base::FilePath::FromUTF16Unsafe( + tracker->database_directory().Append(base::FilePath::FromUTF16Unsafe( tracker->GetOriginDirectory(kOrigin1))))); EXPECT_EQ( 1, base::WriteFile(tracker->GetFullDBFilePath(kOrigin1, kDB1), "a", 1)); @@ -281,7 +281,7 @@ result = callback.GetResult(result); EXPECT_EQ(net::OK, result); EXPECT_FALSE( - base::PathExists(tracker->DatabaseDirectory().AppendASCII(kOrigin1))); + base::PathExists(tracker->database_directory().AppendASCII(kOrigin1))); EXPECT_TRUE(base::PathExists(tracker->GetFullDBFilePath(kOrigin2, kDB2))); EXPECT_TRUE(base::PathExists(tracker->GetFullDBFilePath(kOrigin2, kDB3))); @@ -339,10 +339,10 @@ // Write some data to each file and check that the listeners are // called with the appropriate values. EXPECT_TRUE(base::CreateDirectory( - tracker->DatabaseDirectory().Append(base::FilePath::FromUTF16Unsafe( + tracker->database_directory().Append(base::FilePath::FromUTF16Unsafe( tracker->GetOriginDirectory(kOrigin1))))); EXPECT_TRUE(base::CreateDirectory( - tracker->DatabaseDirectory().Append(base::FilePath::FromUTF16Unsafe( + tracker->database_directory().Append(base::FilePath::FromUTF16Unsafe( tracker->GetOriginDirectory(kOrigin2))))); EXPECT_EQ( 1, base::WriteFile(tracker->GetFullDBFilePath(kOrigin1, kDB1), "a", 1));
diff --git a/storage/common/database/database_connections.cc b/storage/common/database/database_connections.cc index ace4dc4..479b45b 100644 --- a/storage/common/database/database_connections.cc +++ b/storage/common/database/database_connections.cc
@@ -71,8 +71,12 @@ int64_t DatabaseConnections::GetOpenDatabaseSize( const std::string& origin_identifier, const base::string16& database_name) const { - DCHECK(IsDatabaseOpened(origin_identifier, database_name)); - return connections_[origin_identifier][database_name].second; + OriginConnections::const_iterator origin_it = + connections_.find(origin_identifier); + DCHECK(origin_it != connections_.end()) << "Database not opened"; + DBConnections::const_iterator it = origin_it->second.find(database_name); + DCHECK(it != origin_it->second.end()) << "Database not opened"; + return it->second.second; } void DatabaseConnections::SetOpenDatabaseSize(
diff --git a/storage/common/database/database_connections.h b/storage/common/database/database_connections.h index ff46934..79d6b94 100644 --- a/storage/common/database/database_connections.h +++ b/storage/common/database/database_connections.h
@@ -38,7 +38,7 @@ std::vector<std::pair<std::string, base::string16>> RemoveConnections( const DatabaseConnections& connections); - // Database sizes can be kept only if IsDatabaseOpened returns true. + // Can be called only if IsDatabaseOpened would have returned true. int64_t GetOpenDatabaseSize(const std::string& origin_identifier, const base::string16& database_name) const; void SetOpenDatabaseSize(const std::string& origin_identifier, @@ -49,10 +49,12 @@ std::vector<std::pair<std::string, base::string16>> ListConnections() const; private: - // Mapping from name to <openCount, size> - typedef std::map<base::string16, std::pair<int, int64_t>> DBConnections; - typedef std::map<std::string, DBConnections> OriginConnections; - mutable OriginConnections connections_; // mutable for GetOpenDatabaseSize + // Maps database names to (open count, database size). + using DBConnections = std::map<base::string16, std::pair<int, int64_t>>; + // Maps origin identifiers to DBConnections. + using OriginConnections = std::map<std::string, DBConnections>; + + OriginConnections connections_; // Returns true if the last connection was removed. bool RemoveConnectionsHelper(const std::string& origin_identifier,
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter index e4a75204..6c2e0d08 100644 --- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter +++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -209,7 +209,6 @@ -ExtensionWebRequestApiTest.WebRequestDeclarative2 -ExtensionWebRequestApiTest.WebRequestDiceHeaderProtection -ExtensionWebRequestApiTest.WebRequestTypes --ExtensionWebRequestApiTest.WebRequestTestOSDD # Note WebRequestUnloadImmediately is disabled on Linux -ExtensionWebRequestApiTest.WebRequestUnloadImmediately
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 2f1389597..89c5f2a 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -1326,6 +1326,21 @@ ] } ], + "DetectingHeavyPages": [ + { + "platforms": [ + "android" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "DetectingHeavyPages" + ] + } + ] + } + ], "DownloadHomeMoreButton": [ { "platforms": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG index 979f0cea..9b5217e 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -490,7 +490,6 @@ crbug.com/591099 fast/block/float/nopaint-after-layer-destruction.html [ Failure ] crbug.com/591099 fast/block/float/nopaint-after-layer-destruction2.html [ Failure ] crbug.com/591099 fast/block/float/overlapping-floats-paint-hittest-order-1.html [ Failure ] -crbug.com/591099 fast/block/line-layout/floats-do-not-fit-on-line.html [ Failure ] crbug.com/591099 fast/block/positioning/positioned-child-inside-relative-positioned-anonymous-block.html [ Failure ] crbug.com/591099 fast/borders/bidi-002.html [ Failure ] crbug.com/859497 fast/borders/bidi-009a.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 3db4991..c3e6976 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -343,7 +343,6 @@ crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/basic/truncation-rtl.html [ Failure ] ### virtual/layout_ng/fast/block/float -crbug.com/810335 virtual/layout_ng/fast/block/float/003.html [ Failure ] crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/float/020.html [ Failure ] crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/float/026.html [ Failure ] crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/float/028.html [ Failure ] @@ -819,7 +818,7 @@ crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/mixed-opacity-test.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/mixed-positioning-stacking-order.html [ Failure ] crbug.com/714962 virtual/layout_ng_experimental/fast/multicol/multicol-becomes-abspos-crash.html [ Failure ] -crbug.com/626703 virtual/layout_ng_experimental/fast/multicol/multicol-becomes-paged-auto-height.html [ Crash ] +crbug.com/626703 virtual/layout_ng_experimental/fast/multicol/multicol-becomes-paged-auto-height.html [ Crash Pass ] crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/multicol-with-child-renderLayer-for-input.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/nested-3-multicols-fixed-height.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/nested-auto-height-extra-block-inbetween.html [ Failure ] @@ -1025,7 +1024,7 @@ crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/widows-and-orphans.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/fast/multicol/widows.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/fast/pagination/auto-height-with-break.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/fast/pagination/auto-height.html [ Crash ] +crbug.com/591099 virtual/layout_ng_experimental/fast/pagination/auto-height.html [ Crash Pass ] crbug.com/591099 virtual/layout_ng_experimental/fast/pagination/break-in-paged-overflow.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/fast/pagination/caret-range-outside-paged-x-rtl-vertical-rl.html [ Failure Crash ] crbug.com/591099 virtual/layout_ng_experimental/fast/pagination/caret-range-outside-paged-x-rtl.html [ Failure ] @@ -1045,8 +1044,8 @@ crbug.com/591099 virtual/layout_ng_experimental/fast/pagination/div-y-vertical-lr-rtl.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/fast/pagination/div-y-vertical-rl-ltr.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/fast/pagination/div-y-vertical-rl-rtl.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/fast/pagination/first-letter-inherit-all-crash.html [ Crash ] -crbug.com/591099 virtual/layout_ng_experimental/fast/pagination/modal-dialog-crash.html [ Crash ] +crbug.com/591099 virtual/layout_ng_experimental/fast/pagination/first-letter-inherit-all-crash.html [ Crash Pass ] +crbug.com/591099 virtual/layout_ng_experimental/fast/pagination/modal-dialog-crash.html [ Crash Pass ] crbug.com/591099 virtual/layout_ng_experimental/fast/pagination/multicol.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/fast/pagination/paged-x-column-gap.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/fast/pagination/repeating-thead-tfoot-paged-x.html [ Failure ] @@ -1154,8 +1153,8 @@ crbug.com/591099 virtual/layout_ng_experimental/printing/css2.1/page-break-after-004.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/printing/css2.1/page-break-before-000.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/printing/fixed-positioned-but-static-headers-and-footers.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/printing/fixed-positioned-child-repeats-even-when-html-and-body-are-zero-height.html [ Crash ] -crbug.com/591099 virtual/layout_ng_experimental/printing/fixed-positioned-child-shouldnt-print.html [ Crash ] +crbug.com/591099 virtual/layout_ng_experimental/printing/fixed-positioned-child-repeats-even-when-html-and-body-are-zero-height.html [ Crash Pass ] +crbug.com/591099 virtual/layout_ng_experimental/printing/fixed-positioned-child-shouldnt-print.html [ Crash Pass ] crbug.com/591099 virtual/layout_ng_experimental/printing/fixed-positioned-headers-and-footers-clipped.html [ Failure ] crbug.com/824918 virtual/layout_ng_experimental/printing/fixed-positioned-headers-and-footers-inside-transform.html [ Crash Failure ] crbug.com/591099 virtual/layout_ng_experimental/printing/fixed-positioned-headers-and-footers-larger-than-page.html [ Failure ] @@ -4630,3 +4629,5 @@ crbug.com/860706 [ Mac ] virtual/gpu/fast/canvas/canvas-blending-image-over-image.html [ Timeout Pass ] crbug.com/860706 [ Mac ] virtual/gpu/fast/canvas/color-space/canvas-createImageBitmap-rec2020.html [ Timeout Pass ] crbug.com/860706 [ Mac ] virtual/gpu/fast/canvas/canvas-blending-color-over-pattern.html [ Timeout Pass ] +crbug.com/860706 [ Mac ] virtual/gpu/fast/canvas/canvas-blending-pattern-over-pattern.html [ Timeout Pass ] +crbug.com/860706 [ Mac ] virtual/gpu/fast/canvas/canvas-shadow-source-in.html [ Timeout Pass ] \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json index b960978..58a2271 100644 --- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json +++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -9735,6 +9735,18 @@ {} ] ], + "css/CSS2/floats/floats-line-wrap-shifted-001.html": [ + [ + "/css/CSS2/floats/floats-line-wrap-shifted-001.html", + [ + [ + "/css/CSS2/floats/floats-line-wrap-shifted-001-ref.html", + "==" + ] + ], + {} + ] + ], "css/CSS2/floats/floats-placement-vertical-001a.xht": [ [ "/css/CSS2/floats/floats-placement-vertical-001a.xht", @@ -107420,6 +107432,11 @@ {} ] ], + "css/CSS2/floats/floats-line-wrap-shifted-001-ref.html": [ + [ + {} + ] + ], "css/CSS2/floats/floats-placement-vertical-001-ref.xht": [ [ {} @@ -158305,6 +158322,11 @@ {} ] ], + "interfaces/csp-embedded-enforcement.idl": [ + [ + {} + ] + ], "interfaces/css-animations.idl": [ [ {} @@ -185636,6 +185658,12 @@ {} ] ], + "content-security-policy/embedded-enforcement/idlharness.window.js": [ + [ + "/content-security-policy/embedded-enforcement/idlharness.window.html", + {} + ] + ], "content-security-policy/embedded-enforcement/iframe-csp-attribute.html": [ [ "/content-security-policy/embedded-enforcement/iframe-csp-attribute.html", @@ -276667,6 +276695,10 @@ "70aeb617f5d580917b385346ba629e035f062c32", "testharness" ], + "content-security-policy/embedded-enforcement/idlharness.window.js": [ + "e009d639fbb4ede1085c365038fb79d1e0625143", + "testharness" + ], "content-security-policy/embedded-enforcement/iframe-csp-attribute.html": [ "d5a253732352f46d33c1a58d1a3183a88daa3a75", "testharness" @@ -282647,6 +282679,14 @@ "f9b30873ba1da1309d17f2ae6f0777656521e5b2", "reftest" ], + "css/CSS2/floats/floats-line-wrap-shifted-001-ref.html": [ + "97d01b457c2032e59de20eb768aa025607e9b046", + "support" + ], + "css/CSS2/floats/floats-line-wrap-shifted-001.html": [ + "1e5c1373145ea0f217fa4cf354eeae5883b629af", + "reftest" + ], "css/CSS2/floats/floats-placement-vertical-001-ref.xht": [ "219c3d13a6859b58907f35df0a5602ba215a0335", "support" @@ -377491,6 +377531,10 @@ "29a0bcde9ddd6629c7bf05757cea45c831fe9a6b", "support" ], + "interfaces/csp-embedded-enforcement.idl": [ + "57d276da4bf41e5f47dd903411a748c3c6ebfd79", + "support" + ], "interfaces/css-animations.idl": [ "804917872e1fd13cb9edaee693d4e011fcd7b79e", "support" @@ -377680,7 +377724,7 @@ "support" ], "interfaces/performance-timeline.idl": [ - "57f26fe863d12c7672905d185e9a2c7ab9cb98a0", + "d9e73d5bb30f757c743f6bcff4aad6de4efc633c", "support" ], "interfaces/permissions.idl": [ @@ -377836,7 +377880,7 @@ "support" ], "interfaces/webxr.idl": [ - "f12a5bab0506e9e45cd06e29bf3acc15f7c2e8df", + "cc9199634844a31a06e4d25c4095a7193d308c90", "support" ], "interfaces/worklets.idl": [ @@ -388332,7 +388376,7 @@ "testharness" ], "performance-timeline/idlharness.any.js": [ - "0a3ea0b532a1634008b776489b7409b348952d6f", + "842da267dbe611c9f1505ca93e6ff799f25d7ee5", "testharness" ], "performance-timeline/performanceentry-tojson.any.js": [ @@ -413560,7 +413604,7 @@ "support" ], "webxr/interfaces.https-expected.txt": [ - "61c3134ea7352340f3eaa5ccc78701a64bd1d201", + "d7d20b425b896e27e9dd6991937e4f452341a279", "support" ], "webxr/interfaces.https.html": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/embedded-enforcement/idlharness.window.js b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/embedded-enforcement/idlharness.window.js new file mode 100644 index 0000000..38fa663 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/embedded-enforcement/idlharness.window.js
@@ -0,0 +1,21 @@ +// META: script=/resources/WebIDLParser.js +// META: script=/resources/idlharness.js + +// https://w3c.github.io/webappsec-csp/embedded/ + +'use strict'; + +promise_test(async () => { + const idl = await fetch('/interfaces/csp-embedded-enforcement.idl').then(r => r.text()); + const html = await fetch('/interfaces/html.idl').then(r => r.text()); + const dom = await fetch('/interfaces/dom.idl').then(r => r.text()); + + const idl_array = new IdlArray(); + idl_array.add_idls(idl); + idl_array.add_dependency_idls(html); + idl_array.add_dependency_idls(dom); + idl_array.add_objects({ + HTMLIFrameElement: ['document.createElement("iframe")'], + }); + idl_array.test(); +}, 'csp-embedded-enforcement IDL');
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/csp-embedded-enforcement.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/csp-embedded-enforcement.idl new file mode 100644 index 0000000..7d752eb --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/csp-embedded-enforcement.idl
@@ -0,0 +1,8 @@ +// GENERATED CONTENT - DO NOT EDIT +// Content of this file was automatically extracted from the +// "Content Security Policy: Embedded Enforcement" spec. +// See: https://w3c.github.io/webappsec-csp/embedded/ + +partial interface HTMLIFrameElement { + [CEReactions] attribute DOMString csp; +};
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/performance-timeline.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/performance-timeline.idl index 857be8c..a8b78fb 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/performance-timeline.idl +++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/performance-timeline.idl
@@ -4,37 +4,33 @@ // See: https://w3c.github.io/performance-timeline/ partial interface Performance { - PerformanceEntryList getEntries(); - PerformanceEntryList getEntriesByType(DOMString type); - PerformanceEntryList getEntriesByName(DOMString name, - optional DOMString type); -}; -typedef sequence<PerformanceEntry> PerformanceEntryList; + PerformanceEntryList getEntries(); + PerformanceEntryList getEntriesByType(DOMString type); + PerformanceEntryList getEntriesByName(DOMString name, optional DOMString type); +};typedef sequence<PerformanceEntry> PerformanceEntryList; [Exposed=(Window,Worker)] interface PerformanceEntry { - readonly attribute DOMString name; - readonly attribute DOMString entryType; - readonly attribute DOMHighResTimeStamp startTime; - readonly attribute DOMHighResTimeStamp duration; - [Default] object toJSON(); + readonly attribute DOMString name; + readonly attribute DOMString entryType; + readonly attribute DOMHighResTimeStamp startTime; + readonly attribute DOMHighResTimeStamp duration; + [Default] object toJSON(); }; callback PerformanceObserverCallback = void (PerformanceObserverEntryList entries, PerformanceObserver observer); -[Constructor(PerformanceObserverCallback callback), - Exposed=(Window,Worker)] +[Constructor(PerformanceObserverCallback callback), Exposed=(Window,Worker)] interface PerformanceObserver { - void observe(PerformanceObserverInit options); - void disconnect(); - PerformanceEntryList takeRecords(); + void observe(PerformanceObserverInit options); + void disconnect(); + PerformanceEntryList takeRecords(); }; dictionary PerformanceObserverInit { - required sequence<DOMString> entryTypes; - boolean buffered = false; + required sequence<DOMString> entryTypes; + boolean buffered = false; }; [Exposed=(Window,Worker)] interface PerformanceObserverEntryList { - PerformanceEntryList getEntries(); - PerformanceEntryList getEntriesByType(DOMString type); - PerformanceEntryList getEntriesByName(DOMString name, - optional DOMString type); + PerformanceEntryList getEntries(); + PerformanceEntryList getEntriesByType(DOMString type); + PerformanceEntryList getEntriesByName(DOMString name, optional DOMString type); };
diff --git a/third_party/WebKit/LayoutTests/external/wpt/performance-timeline/idlharness.any.js b/third_party/WebKit/LayoutTests/external/wpt/performance-timeline/idlharness.any.js index b15a667..66e75cc 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/performance-timeline/idlharness.any.js +++ b/third_party/WebKit/LayoutTests/external/wpt/performance-timeline/idlharness.any.js
@@ -6,21 +6,22 @@ 'use strict'; -promise_test(async () => { - const idl_array = new IdlArray(); - const idl = await fetch("/interfaces/performance-timeline.idl").then(r => r.text()); - const dom = await fetch("/interfaces/dom.idl").then(r => r.text()); - const hrtime = await fetch("/interfaces/hr-time.idl").then(r => r.text()); +idl_test( + ['performance-timeline'], + ['hr-time', 'dom'], + idl_array => { + try { + const callback = (e, o) => {}; + self.observerEntry = new ResizeObserverEntry(callback); + } catch (e) { + // Will be surfaced when entry is undefined below. + } - // create first mark - self.performance.mark("mark"); - - idl_array.add_idls(idl); - idl_array.add_dependency_idls(hrtime); - idl_array.add_dependency_idls(dom); - idl_array.add_objects({ - Performance: ["performance"], - PerformanceMark: [self.performance.getEntriesByName("mark")[0]], - }); - idl_array.test(); -}, "Test IDL implementation of performance-timeline API"); + idl_array.add_objects({ + Performance: ['performance'], + // PerformanceEntry implicitly tested in user-timing. + ResizeObserverEntry: ['observerEntry'], + }); + }, + 'Test IDL implementation of performance-timeline API' +);
diff --git a/third_party/WebKit/LayoutTests/fast/canvas-api/canvas-textMetrics-advances.html b/third_party/WebKit/LayoutTests/fast/canvas-api/canvas-textMetrics-advances.html new file mode 100644 index 0000000..5739540 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas-api/canvas-textMetrics-advances.html
@@ -0,0 +1,102 @@ +<!DOCTYPE HTML> +<head> +<meta charset="UTF-8"> +<style> +@font-face { + font-family: Libertine; + src: url('../../third_party/Libertine/LinLibertine_R.woff'); +} +</style> +</head> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script> + +const kAligns = [ "left", "right", "center", "start", "end" ]; + +const kTexts = [ + { text: "Hello", rtl: false }, + { text: "傳統是假的", rtl: false }, + { text: "フェミニズム", rtl: false }, + { text: "ليس", rtl: true }, + { text: "\u202EHello", rtl: true }, + // TODO(davidqu): Fix the following edge cases: + //{ text: "الله", rtl: true }, // Special ligatures. + //{ text: "ليس في اسمنا", rtl: true }, // RTL only works for single "words". + //{ text: "\u202EHello World", rtl: true }, + //{ text: "🏁", rtl: false }, // One glyph with two "characters". + //{ text: "एक आम भाषा", rtl: false }, // Special post-modifying characters. + //{ text: "a\u0301", rtl: true }, // Combining diacritical marks +] + +function forEachExample(fn) { + for (const ex of kTexts) { + for (const align of kAligns) { + fn(ex, align); + } + } +} + +function isNonDecreasing(array) { + for (var i = 1; i < array.length; i++) { + if (array[i] < array[i-1]) { + return false; + } + } + return true; +} + +function getTextMetrics(ctx, text, align="left", direction="ltr") { + ctx.font = '25px Libertine'; + ctx.textAlign = align; + ctx.direction = direction; + return ctx.measureText(text); +} + +function testEmptyStringReturnsEmptyAdvances(ctx) { + const tm = getTextMetrics(ctx, ""); + assert_array_equals(tm.advances, [], "Empty string must return empty advances"); +} + +function testAllPositive(ctx) { + forEachExample((ex, align) => { + const tm = getTextMetrics(ctx, ex.text, align, ex.rtl ? "rtl" : "ltr", ); + assert_true(tm.advances.every(function isPositive(i) {return i >= 0; }), + "Advances must be all positive (" + ex.text + ")"); + }); +} + +function testNonDecreasing(ctx) { + forEachExample((ex, align) => { + const tm = getTextMetrics(ctx, ex.text, align, ex.rtl ? "rtl" : "ltr"); + assert_true(isNonDecreasing(tm.advances), + "Advances must be non-decreasing (" + ex.text + ")"); + }); +} + +function testLastAdvanceLessThanWith(ctx) { + forEachExample((ex, align) => { + const tm = getTextMetrics(ctx, ex.text, align, ex.rtl ? "rtl" : "ltr"); + assert_less_than(tm.advances.slice(-1)[0], tm.width, + "Last advance must be strictly less than total width (" + ex.text + ")"); + }); +} + +function testAdvances(ctx) { + testEmptyStringReturnsEmptyAdvances(ctx); + testAllPositive(ctx); + testNonDecreasing(ctx); + testLastAdvanceLessThanWith(ctx); +} + +async_test(t => { + var canvas = document.createElement('canvas'); + canvas.width = 100; + canvas.height = 100; + var ctx = canvas.getContext('2d'); + // Kick off loading of the font + ctx.font = '50px Libertine'; + ctx.fillText(" ", 0, 0); + document.fonts.ready.then(t.step_func_done(testAdvances(ctx))); +}, "Test TextMetrics advances."); +</script>
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/selection/selection-within-composited-scroller-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/selection/selection-within-composited-scroller-expected.txt similarity index 100% rename from third_party/WebKit/LayoutTests/platform/win/paint/invalidation/selection/selection-within-composited-scroller-expected.txt rename to third_party/WebKit/LayoutTests/paint/invalidation/selection/selection-within-composited-scroller-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/overflow/image-selection-highlight-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/overflow/image-selection-highlight-expected.txt deleted file mode 100644 index f2c5242..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/overflow/image-selection-highlight-expected.txt +++ /dev/null
@@ -1,49 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x600 - LayoutBlockFlow {HTML} at (0,0) size 800x600 - LayoutBlockFlow {BODY} at (8,8) size 784x584 - LayoutBlockFlow {P} at (0,0) size 784x40 - LayoutText {#text} at (0,0) size 212x19 - text run at (0,0) width 212: "This tests for a regression against " - LayoutInline {I} at (0,0) size 767x39 - LayoutInline {A} at (0,0) size 348x19 [color=#0000EE] - LayoutText {#text} at (212,0) size 348x19 - text run at (212,0) width 348: "http://bugzilla.opendarwin.org/show_bug.cgi?id=6673" - LayoutText {#text} at (559,0) size 767x39 - text run at (559,0) width 5: " " - text run at (563,0) width 204: "Selection highlight doesn't scroll" - text run at (0,20) width 369: "along with an image contained in an overflow:scroll block" - LayoutText {#text} at (368,20) size 5x19 - text run at (368,20) width 5: "." - LayoutBlockFlow {P} at (0,56) size 784x40 - LayoutText {#text} at (0,0) size 748x39 - text run at (0,0) width 412: "There should be one contiguous highlight from \x{201C}elit\x{201D} to \x{201C}Etiam\x{201D}, " - text run at (412,0) width 336: "including the orange square, and no other highlighted" - text run at (0,20) width 36: "areas." - LayoutBlockFlow {HR} at (0,112) size 784x2 [border: (1px inset #EEEEEE)] -layer at (8,130) size 100x200 clip at (8,130) size 85x200 scrollY 40.00 scrollHeight 320 - LayoutBlockFlow {DIV} at (0,122) size 100x200 - LayoutText {#text} at (0,0) size 84x119 - text run at (0,0) width 84: "Lorem ipsum" - text run at (0,20) width 51: "dolor sit" - text run at (0,40) width 34: "amet," - text run at (0,60) width 78: "consectetuer" - text run at (0,80) width 64: "adipiscing" - text run at (0,100) width 27: "elit. " - LayoutImage {IMG} at (27,105) size 10x10 - LayoutText {#text} at (37,100) size 83x219 - text run at (37,100) width 4: " " - text run at (41,100) width 37: "Etiam" - text run at (0,120) width 57: "et ipsum." - text run at (0,140) width 31: "Nam" - text run at (0,160) width 78: "consectetuer" - text run at (0,180) width 81: "mi eget velit." - text run at (0,200) width 83: "Sed nec risus" - text run at (0,220) width 60: "vitae felis" - text run at (0,240) width 39: "auctor" - text run at (0,260) width 53: "ultricies." - text run at (0,280) width 79: "Pellentesque" - text run at (0,300) width 54: "aliquet..." -selection start: position 58 of child 0 {#text} of child 7 {DIV} of body -selection end: position 11 of child 2 {#text} of child 7 {DIV} of body
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/selection/atsui-partial-selection-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/text/selection/atsui-partial-selection-expected.txt deleted file mode 100644 index 49b33e9..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/text/selection/atsui-partial-selection-expected.txt +++ /dev/null
@@ -1,32 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x600 - LayoutBlockFlow {HTML} at (0,0) size 800x600 - LayoutBlockFlow {BODY} at (8,8) size 784x576 - LayoutBlockFlow {P} at (0,0) size 784x40 - LayoutText {#text} at (0,0) size 52x19 - text run at (0,0) width 52: "Test for " - LayoutInline {I} at (0,0) size 749x39 - LayoutInline {A} at (0,0) size 299x19 [color=#0000EE] - LayoutText {#text} at (51,0) size 299x19 - text run at (51,0) width 299: "http://bugs.webkit.org/show_bug.cgi?id=11124" - LayoutText {#text} at (349,0) size 749x39 - text run at (349,0) width 5: " " - text run at (353,0) width 396: "REGRESSION (r14297): No drag image for partially-selected" - text run at (0,20) width 79: "complex text" - LayoutText {#text} at (79,20) size 4x19 - text run at (79,20) width 4: "." - LayoutBlockFlow {P} at (0,56) size 784x20 - LayoutText {#text} at (0,0) size 144x19 - text run at (0,0) width 144: "This should look like \x{201C}" - LayoutInline {SPAN} at (0,0) size 84x19 [color=#008000] - LayoutText {#text} at (144,0) size 84x19 - text run at (144,0) width 84: "Lore\x{300}m ipsum" - LayoutText {#text} at (228,0) size 15x19 - text run at (228,0) width 15: "\x{201D}: " - LayoutInline {SPAN} at (0,0) size 88x19 - LayoutText {#text} at (243,0) size 88x19 - text run at (243,0) width 88: " Lore\x{300}m ipsum" - LayoutText {#text} at (0,0) size 0x0 -selection start: position 1 of child 0 {#text} of child 3 {SPAN} of child 2 {P} of body -selection end: position 13 of child 0 {#text} of child 3 {SPAN} of child 2 {P} of body
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/selection/emphasis-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/text/selection/emphasis-expected.txt deleted file mode 100644 index f6f6e42..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/text/selection/emphasis-expected.txt +++ /dev/null
@@ -1,198 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x554 - LayoutBlockFlow {HTML} at (0,0) size 800x554 - LayoutBlockFlow {BODY} at (8,8) size 784x538 - LayoutBlockFlow {DIV} at (4,4) size 366x146 [border: (3px solid #000000)] - LayoutText {#text} at (3,3) size 270x27 - text run at (3,3) width 270: "Lorem ipsum dolor sit amet," - LayoutInline {SPAN} at (0,0) size 213x27 - LayoutText {#text} at (3,45) size 213x27 - text run at (3,45) width 213: "consectetur adipiscing" - LayoutText {#text} at (216,45) size 130x27 - text run at (216,45) width 6: " " - text run at (222,45) width 124: "elit. Aliquam" - LayoutInline {SPAN} at (0,0) size 109x27 - LayoutText {#text} at (3,73) size 109x27 - text run at (3,73) width 109: "odio sapien" - LayoutText {#text} at (112,73) size 330x69 - text run at (112,73) width 12: ", " - text run at (124,73) width 209: "lobortis eu iaculis vel," - text run at (3,115) width 207: "scelerisque nec dolor." - LayoutText {#text} at (374,119) size 6x27 - text run at (374,119) width 6: " " - LayoutBlockFlow {DIV} at (384,4) size 366x146 [border: (3px solid #000000)] - LayoutText {#text} at (3,3) size 270x27 - text run at (3,3) width 270: "Lorem ipsum dolor sit amet," - LayoutInline {SPAN} at (0,0) size 213x27 - LayoutText {#text} at (3,45) size 213x27 - text run at (3,45) width 213: "consectetur adipiscing" - LayoutText {#text} at (216,45) size 130x27 - text run at (216,45) width 6: " " - text run at (222,45) width 124: "elit. Aliquam" - LayoutInline {SPAN} at (0,0) size 109x27 - LayoutText {#text} at (3,73) size 109x27 - text run at (3,73) width 109: "odio sa\x{300}pien" - LayoutText {#text} at (112,73) size 330x69 - text run at (112,73) width 12: ", " - text run at (124,73) width 209: "lobortis eu iaculis vel," - text run at (3,115) width 207: "scelerisque nec dolor." - LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {DIV} at (4,167) size 366x161 [border: (3px solid #000000)] - LayoutText {#text} at (3,18) size 70x27 - text run at (3,18) width 70: "Lorem " - LayoutInline {SPAN} at (0,0) size 57x27 - LayoutText {#text} at (73,18) size 57x27 - text run at (73,18) width 57: "ipsum" - LayoutText {#text} at (130,18) size 6x27 - text run at (130,18) width 6: " " - LayoutInline {SPAN} at (0,0) size 50x27 - LayoutText {#text} at (136,18) size 50x27 - text run at (136,18) width 50: "dolor" - LayoutText {#text} at (186,18) size 6x27 - text run at (186,18) width 6: " " - LayoutInline {SPAN} at (0,0) size 22x27 - LayoutText {#text} at (192,18) size 22x27 - text run at (192,18) width 22: "sit" - LayoutText {#text} at (214,18) size 6x27 - text run at (214,18) width 6: " " - LayoutInline {SPAN} at (0,0) size 47x27 - LayoutText {#text} at (220,18) size 47x27 - text run at (220,18) width 47: "amet" - LayoutText {#text} at (267,18) size 6x27 - text run at (267,18) width 6: "," - LayoutInline {SPAN} at (0,0) size 111x27 - LayoutText {#text} at (3,60) size 111x27 - text run at (3,60) width 111: "consectetur" - LayoutText {#text} at (114,60) size 6x27 - text run at (114,60) width 6: " " - LayoutInline {SPAN} at (0,0) size 96x27 - LayoutText {#text} at (120,60) size 96x27 - text run at (120,60) width 96: "adipiscing" - LayoutText {#text} at (216,60) size 6x27 - text run at (216,60) width 6: " " - LayoutInline {SPAN} at (0,0) size 30x27 - LayoutText {#text} at (222,60) size 30x27 - text run at (222,60) width 30: "elit" - LayoutText {#text} at (252,60) size 12x27 - text run at (252,60) width 12: ". " - LayoutInline {SPAN} at (0,0) size 82x27 - LayoutText {#text} at (264,60) size 82x27 - text run at (264,60) width 82: "Aliquam" - LayoutText {#text} at (346,60) size 6x27 - text run at (346,60) width 6: "," - LayoutInline {SPAN} at (0,0) size 42x27 - LayoutText {#text} at (3,102) size 42x27 - text run at (3,102) width 42: "odio" - LayoutText {#text} at (45,102) size 6x27 - text run at (45,102) width 6: " " - LayoutInline {SPAN} at (0,0) size 61x27 - LayoutText {#text} at (51,102) size 61x27 - text run at (51,102) width 61: "sapien" - LayoutText {#text} at (112,102) size 12x27 - text run at (112,102) width 12: ", " - LayoutInline {SPAN} at (0,0) size 72x27 - LayoutText {#text} at (124,102) size 72x27 - text run at (124,102) width 72: "lobortis" - LayoutText {#text} at (196,102) size 330x55 - text run at (196,102) width 6: " " - text run at (202,102) width 131: "eu iaculis vel," - text run at (3,130) width 207: "scelerisque nec dolor." - LayoutText {#text} at (374,297) size 6x27 - text run at (374,297) width 6: " " - LayoutBlockFlow {DIV} at (384,158) size 366x156 [border: (3px solid #000000)] - LayoutText {#text} at (18,3) size 27x70 - text run at (18,3) width 70: "Lorem " - LayoutInline {SPAN} at (0,0) size 27x57 - LayoutText {#text} at (18,73) size 27x57 - text run at (18,73) width 57: "ipsum" - LayoutText {#text} at (0,0) size 0x0 - LayoutInline {SPAN} at (0,0) size 27x50 - LayoutText {#text} at (60,3) size 27x50 - text run at (60,3) width 50: "dolor" - LayoutText {#text} at (60,53) size 27x6 - text run at (60,53) width 6: " " - LayoutInline {SPAN} at (0,0) size 27x22 - LayoutText {#text} at (60,59) size 27x22 - text run at (60,59) width 22: "sit" - LayoutText {#text} at (60,81) size 27x6 - text run at (60,81) width 6: " " - LayoutInline {SPAN} at (0,0) size 27x47 - LayoutText {#text} at (60,87) size 27x47 - text run at (60,87) width 47: "amet" - LayoutText {#text} at (60,134) size 27x6 - text run at (60,134) width 6: "," - LayoutInline {SPAN} at (0,0) size 27x111 - LayoutText {#text} at (99,3) size 27x111 - text run at (99,3) width 111: "consectetur" - LayoutText {#text} at (0,0) size 0x0 - LayoutInline {SPAN} at (0,0) size 27x96 - LayoutText {#text} at (141,3) size 27x96 - text run at (141,3) width 96: "adipiscing" - LayoutText {#text} at (141,99) size 27x6 - text run at (141,99) width 6: " " - LayoutInline {SPAN} at (0,0) size 27x30 - LayoutText {#text} at (141,105) size 27x30 - text run at (141,105) width 30: "elit" - LayoutText {#text} at (141,135) size 27x6 - text run at (141,135) width 6: "." - LayoutInline {SPAN} at (0,0) size 27x82 - LayoutText {#text} at (183,3) size 27x82 - text run at (183,3) width 82: "Aliquam" - LayoutText {#text} at (183,85) size 27x12 - text run at (183,85) width 12: ", " - LayoutInline {SPAN} at (0,0) size 27x42 - LayoutText {#text} at (183,97) size 27x42 - text run at (183,97) width 42: "odio" - LayoutText {#text} at (0,0) size 0x0 - LayoutInline {SPAN} at (0,0) size 27x61 - LayoutText {#text} at (225,3) size 27x61 - text run at (225,3) width 61: "sapien" - LayoutText {#text} at (225,64) size 27x12 - text run at (225,64) width 12: ", " - LayoutInline {SPAN} at (0,0) size 27x72 - LayoutText {#text} at (225,76) size 27x72 - text run at (225,76) width 72: "lobortis" - LayoutText {#text} at (253,3) size 83x146 - text run at (253,3) width 131: "eu iaculis vel," - text run at (281,3) width 146: "scelerisque nec" - text run at (309,3) width 55: "dolor." - LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {DIV} at (4,336) size 366x198 [border: (3px solid #000000)] - LayoutText {#text} at (3,13) size 270x27 - text run at (3,13) width 270: "Lorem ipsum dolor sit amet," - LayoutInline {SPAN} at (0,0) size 213x27 - LayoutText {#text} at (3,61) size 213x27 - text run at (3,61) width 213: "consectetur adipiscing" - LayoutText {#text} at (216,61) size 130x27 - text run at (216,61) width 6: " " - text run at (222,61) width 124: "elit. Aliquam" - LayoutInline {SPAN} at (0,0) size 109x27 - LayoutText {#text} at (3,109) size 109x27 - text run at (3,109) width 109: "odio sapien" - LayoutText {#text} at (112,109) size 330x75 - text run at (112,109) width 12: ", " - text run at (124,109) width 209: "lobortis eu iaculis vel," - text run at (3,157) width 207: "scelerisque nec dolor." - LayoutText {#text} at (374,493) size 6x27 - text run at (374,493) width 6: " " - LayoutBlockFlow {DIV} at (384,378) size 366x146 [border: (3px solid #000000)] - LayoutText {#text} at (3,3) size 270x27 - text run at (3,3) width 270: "Lorem ipsum dolor sit amet," - LayoutInline {SPAN} at (0,0) size 213x27 - LayoutText {#text} at (3,45) size 213x27 - text run at (3,45) width 213: "consectetur adipiscing" - LayoutText {#text} at (216,45) size 130x27 - text run at (216,45) width 6: " " - text run at (222,45) width 124: "elit. Aliquam" - LayoutInline {SPAN} at (0,0) size 109x27 - LayoutText {#text} at (3,73) size 109x27 - text run at (3,73) width 109: "odio sapien" - LayoutText {#text} at (112,73) size 330x69 - text run at (112,73) width 12: ", " - text run at (124,73) width 209: "lobortis eu iaculis vel," - text run at (3,115) width 207: "scelerisque nec dolor." - LayoutText {#text} at (0,0) size 0x0 - LayoutText {#text} at (0,0) size 0x0 -selection start: position 10 of child 0 {#text} of child 1 {SPAN} of child 10 {DIV} of body -selection end: position 7 of child 0 {#text} of child 3 {SPAN} of child 10 {DIV} of body
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/selection/justified-selection-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/text/selection/justified-selection-expected.txt deleted file mode 100644 index d7f8b8e8..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/text/selection/justified-selection-expected.txt +++ /dev/null
@@ -1,33 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x600 - LayoutBlockFlow {HTML} at (0,0) size 800x600 - LayoutBlockFlow {BODY} at (8,8) size 784x584 - LayoutBlockFlow {P} at (0,0) size 784x20 - LayoutText {#text} at (0,0) size 106x19 - text run at (0,0) width 106: "Test for revision " - LayoutInline {A} at (0,0) size 49x19 [color=#0000EE] - LayoutText {#text} at (105,0) size 49x19 - text run at (105,0) width 49: "#20574" - LayoutText {#text} at (153,0) size 5x19 - text run at (153,0) width 5: "." - LayoutBlockFlow {P} at (0,36) size 784x20 - LayoutText {#text} at (0,0) size 251x19 - text run at (0,0) width 251: "The two blue boxes should be identical." - LayoutBlockFlow {DIV} at (0,72) size 106x46 [border: (3px solid #0000FF)] - LayoutText {#text} at (3,3) size 10x19 - text run at (3,3) width 10: "L" - LayoutInline {SPAN} at (0,0) size 40x19 [color=#008000] [bgcolor=#FFFF00] - LayoutText {#text} at (13,3) size 40x19 - text run at (13,3) width 40: "o r" - LayoutText {#text} at (53,3) size 100x39 - text run at (53,3) width 50: "e mi" - text run at (3,23) width 67: "psumdolor" - LayoutBlockFlow (anonymous) at (0,118) size 784x20 - LayoutBR {BR} at (0,0) size 0x19 - LayoutBlockFlow {DIV} at (0,138) size 106x46 [border: (3px solid #0000FF)] - LayoutText {#text} at (3,3) size 100x39 - text run at (3,3) width 100: "Lo re mi" - text run at (3,23) width 67: "psumdolor" -selection start: position 1 of child 0 {#text} of child 8 {DIV} of body -selection end: position 4 of child 0 {#text} of child 8 {DIV} of body
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/selection/selection-multiple-runs-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/text/selection/selection-multiple-runs-expected.txt deleted file mode 100644 index 2cc01c4e..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/text/selection/selection-multiple-runs-expected.txt +++ /dev/null
@@ -1,21 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x244 - LayoutBlockFlow {HTML} at (0,0) size 800x244 - LayoutBlockFlow {BODY} at (8,30) size 784x206 - LayoutBlockFlow {P} at (0,0) size 784x70 - LayoutText {#text} at (0,0) size 766x69 - text run at (0,0) width 766: "The selection should be painted correctly from and including \x{732B}" - text run at (0,35) width 579: "until and including C, then from right to left for " - text run at (579,35) width 39 RTL: "\x{627}\x{644}\x{639}\x{631}" - text run at (618,35) width 8: "." - LayoutBlockFlow {DIV} at (0,100) size 784x53 - LayoutText {#text} at (0,7) size 415x34 - text run at (0,7) width 351: "\x{543E}\x{8F29}\x{306F}\x{732B}\x{3067} \x{92E}\x{93E}\x{928}\x{915} \x{939}\x{93F}\x{928}\x{94D}\x{926}\x{940}ABC" - text run at (351,7) width 64 RTL: "\x{627}\x{644}\x{639}\x{631}\x{628}\x{64A}\x{629}" - LayoutBlockFlow {DIV} at (0,153) size 784x53 - LayoutText {#text} at (0,7) size 415x34 - text run at (0,7) width 351: "\x{543E}\x{8F29}\x{306F}\x{732B}\x{3067} \x{92E}\x{93E}\x{928}\x{915} \x{939}\x{93F}\x{928}\x{94D}\x{926}\x{940}ABC" - text run at (351,7) width 64 RTL: "\x{627}\x{644}\x{639}\x{631}\x{628}\x{64A}\x{629}" -selection start: position 3 of child 0 {#text} of child 5 {DIV} of body -selection end: position 24 of child 0 {#text} of child 5 {DIV} of body
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/selection/should-use-atsui-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/text/selection/should-use-atsui-expected.txt deleted file mode 100644 index f199fc6..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/text/selection/should-use-atsui-expected.txt +++ /dev/null
@@ -1,25 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x600 - LayoutBlockFlow {HTML} at (0,0) size 800x600 - LayoutBlockFlow {BODY} at (8,8) size 784x584 - LayoutBlockFlow {P} at (0,0) size 784x40 - LayoutText {#text} at (0,0) size 52x19 - text run at (0,0) width 52: "Test for " - LayoutInline {I} at (0,0) size 734x39 - LayoutText {#text} at (51,0) size 734x39 - text run at (51,0) width 683: "http://bugzilla.opendarwin.org/show_bug.cgi?id=6132 Incorrect selection highlighting for ATSUI text when" - text run at (0,20) width 176: "selected range is \"CG-safe\"" - LayoutText {#text} at (176,20) size 4x19 - text run at (176,20) width 4: "." - LayoutBlockFlow {P} at (0,56) size 784x20 - LayoutText {#text} at (0,0) size 708x19 - text run at (0,0) width 708: "The word \x{201C}dolor\x{201D} below should be highlighted in its entirety. The highlight should not extend beyond that word." - LayoutBlockFlow {HR} at (0,92) size 784x2 [border: (1px inset #EEEEEE)] - LayoutBlockFlow (anonymous) at (0,102) size 784x20 - LayoutInline {SPAN} at (0,0) size 173x19 - LayoutText {#text} at (0,0) size 173x19 - text run at (0,0) width 173: "Lo\x{308}re\x{300}m ipsum dolor sit amet" - LayoutText {#text} at (0,0) size 0x0 -selection start: position 14 of child 0 {#text} of child 7 {SPAN} of body -selection end: position 19 of child 0 {#text} of child 7 {SPAN} of body
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/writing-mode/japanese-rl-selection-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/writing-mode/japanese-rl-selection-expected.txt deleted file mode 100644 index 7cc5f34e61..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/writing-mode/japanese-rl-selection-expected.txt +++ /dev/null
@@ -1,23 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (418,0) size 382x600 - LayoutBlockFlow {HTML} at (0,0) size 382x600 [border: (10px solid #800000)] - LayoutBlockFlow {BODY} at (18,18) size 346x564 [border: (5px solid #000000)] - LayoutBlockFlow {DIV} at (5,105) size 336x400 - LayoutText {#text} at (0,0) size 335x399 - text run at (0,0) width 399: "\x{305B}\x{3063}\x{304B}\x{304F}\x{898B}\x{3064}\x{3051}\x{305F}\x{3059}\x{3070}\x{3089}\x{3057}\x{3044}\x{8A18}\x{4E8B}\x{304C}\x{3069}\x{3053}\x{306B}" - text run at (24,0) width 399: "\x{3042}\x{3063}\x{305F}\x{304B}\x{5FD8}\x{308C}\x{3066}\x{3057}\x{307E}\x{3063}\x{305F}\x{7D4C}\x{9A13}\x{306F}\x{3042}\x{308A}\x{307E}\x{3059}\x{304B}" - text run at (48,0) width 399: "\x{306A}\x{3089}\x{30BF}\x{30A4}\x{30C8}\x{30EB}\x{3068}\x{30A2}\x{30C9}\x{30EC}\x{30B9}\x{3060}\x{3051}\x{3067}\x{306A}\x{304F}\x{3001}\x{8A2A}\x{554F}" - text run at (72,0) width 399: "\x{3057}\x{305F}\x{30A6}\x{30A7}\x{30D6}\x{30DA}\x{30FC}\x{30B8}\x{306E}\x{30B3}\x{30F3}\x{30C6}\x{30F3}\x{30C4}\x{304B}\x{3089}\x{3082}\x{691C}\x{7D22}" - text run at (96,0) width 399: "\x{3059}\x{308B}\x{3053}\x{3068}\x{304C}\x{3067}\x{304D}\x{307E}\x{3059}\x{3002}\x{305B}\x{3063}\x{304B}\x{304F}\x{898B}\x{3064}\x{3051}\x{305F}\x{3059}" - text run at (120,0) width 399: "\x{3070}\x{3089}\x{3057}\x{3044}\x{8A18}\x{4E8B}\x{304C}\x{3069}\x{3053}\x{306B}\x{3042}\x{3063}\x{305F}\x{304B}\x{5FD8}\x{308C}\x{3066}\x{3057}\x{307E}" - text run at (144,0) width 383: "\x{3063}\x{305F}\x{7D4C}\x{9A13}\x{306F}\x{3042}\x{308A}\x{307E}\x{3059}\x{304B} \x{306A}\x{3089}\x{30BF}\x{30A4}\x{30C8}\x{30EB}\x{3068}\x{30A2}" - text run at (168,0) width 399: "\x{30C9}\x{30EC}\x{30B9}\x{3060}\x{3051}\x{3067}\x{306A}\x{304F}\x{3001}\x{8A2A}\x{554F}\x{3057}\x{305F}\x{30A6}\x{30A7}\x{30D6}\x{30DA}\x{30FC}\x{30B8}" - text run at (192,0) width 399: "\x{306E}\x{30B3}\x{30F3}\x{30C6}\x{30F3}\x{30C4}\x{304B}\x{3089}\x{3082}\x{691C}\x{7D22}\x{3059}\x{308B}\x{3053}\x{3068}\x{304C}\x{3067}\x{304D}\x{307E}" - text run at (216,0) width 399: "\x{3059}\x{3002}\x{8A2A}\x{554F}\x{3057}\x{305F}\x{30A6}\x{30A7}\x{30D6}\x{30DA}\x{30FC}\x{30B8}\x{306E}\x{30B3}\x{30F3}\x{30C6}\x{30F3}\x{30C4}\x{304B}" - text run at (240,0) width 399: "\x{3089}\x{3082}\x{691C}\x{7D22}\x{3059}\x{308B}\x{3053}\x{3068}\x{304C}\x{3067}\x{304D}\x{307E}\x{3059}\x{3002}\x{305B}\x{3063}\x{304B}\x{304F}\x{898B}" - text run at (264,0) width 399: "\x{3064}\x{3051}\x{305F}\x{3059}\x{3070}\x{3089}\x{3057}\x{3044}\x{8A18}\x{4E8B}\x{304C}\x{3069}\x{3053}\x{306B}\x{3042}\x{3063}\x{305F}\x{304B}\x{5FD8}" - text run at (288,0) width 383: "\x{308C}\x{3066}\x{3057}\x{307E}\x{3063}\x{305F}\x{7D4C}\x{9A13}\x{306F}\x{3042}\x{308A}\x{307E}\x{3059}\x{304B} \x{306A}\x{3089}\x{30BF}\x{30A4}" - text run at (312,0) width 315: "\x{30C8}\x{30EB}\x{3068}\x{30A2}\x{30C9}\x{30EC}\x{30B9}\x{3060}\x{3051}\x{3067}\x{306A}\x{304F}\x{3001}\x{8A2A}\x{554F}" -selection start: position 5 of child 0 {#text} of child 1 {DIV} of body -selection end: position 252 of child 0 {#text} of child 1 {DIV} of body
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/editing/selection/modify-up-on-rtl-wrapping-text-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/editing/selection/modify-up-on-rtl-wrapping-text-expected.txt new file mode 100644 index 0000000..3caa47b --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/editing/selection/modify-up-on-rtl-wrapping-text-expected.txt
@@ -0,0 +1,13 @@ +This tests clicking on the left of RTL text puts the caret at the end of the line. + +PASS: on ך לכ, caret is at 4 initially +PASS: on ך לכ, caret is at 2 after moving upwards once +PASS: on כ ככ כככ, caret is at 8 initially +PASS: on כ ככ כככ, caret is at 5 after moving upwards once +PASS: on כ ככ כככ, caret is at 2 after moving upwards twice +PASS: on גכ יגכ יגכ יגכ יגכ, caret is at 18 initially +PASS: on גכ יגכ יגכ יגכ יגכ, caret is at 14 after moving upwards once +PASS: on גכ יגכ יגכ יגכ יגכ, caret is at 10 after moving upwards twice +PASS: on גכ יגכ יגכ יגכ יגכ, caret is at 6 after moving upwards 3 times +PASS: on גכ יגכ יגכ יגכ יגכ, caret is at 3 after moving upwards 4 times +
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/editing/selection/offset-from-point-complex-scripts-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/editing/selection/offset-from-point-complex-scripts-expected.txt new file mode 100644 index 0000000..e4ad1bd --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/editing/selection/offset-from-point-complex-scripts-expected.txt
@@ -0,0 +1 @@ +0 4 3 2 6
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/selection/selection-painted-separately-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/selection/selection-painted-separately-expected.png new file mode 100644 index 0000000..ab30ea5 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/selection/selection-painted-separately-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/editing/selection/modify-up-on-rtl-wrapping-text-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/editing/selection/modify-up-on-rtl-wrapping-text-expected.txt new file mode 100644 index 0000000..a16d129 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/editing/selection/modify-up-on-rtl-wrapping-text-expected.txt
@@ -0,0 +1,10 @@ +This tests clicking on the left of RTL text puts the caret at the end of the line. + +PASS: on ך לכ, caret is at 4 initially +PASS: on ך לכ, caret is at 2 after moving upwards once +PASS: on כ ככ כככ, caret is at 8 initially +PASS: on כ ככ כככ, caret is at 5 after moving upwards once +PASS: on כ ככ כככ, caret is at 2 after moving upwards twice +PASS: on גכ יגכ יגכ יגכ יגכ, caret is at 18 initially +FAIL: on גכ יגכ יגכ יגכ יגכ, caret is at 15 after moving upwards once but expected at 14 +
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/editing/selection/offset-from-point-complex-scripts-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/editing/selection/offset-from-point-complex-scripts-expected.txt new file mode 100644 index 0000000..50a789e --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/editing/selection/offset-from-point-complex-scripts-expected.txt
@@ -0,0 +1 @@ +0 5 4 3 2 6
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/fast/text/selection/selection-painted-separately-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/fast/text/selection/selection-painted-separately-expected.png new file mode 100644 index 0000000..e64b0af --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/fast/text/selection/selection-painted-separately-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/editing/selection/modify-up-on-rtl-wrapping-text-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/editing/selection/modify-up-on-rtl-wrapping-text-expected.txt new file mode 100644 index 0000000..3caa47b --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-retina/editing/selection/modify-up-on-rtl-wrapping-text-expected.txt
@@ -0,0 +1,13 @@ +This tests clicking on the left of RTL text puts the caret at the end of the line. + +PASS: on ך לכ, caret is at 4 initially +PASS: on ך לכ, caret is at 2 after moving upwards once +PASS: on כ ככ כככ, caret is at 8 initially +PASS: on כ ככ כככ, caret is at 5 after moving upwards once +PASS: on כ ככ כככ, caret is at 2 after moving upwards twice +PASS: on גכ יגכ יגכ יגכ יגכ, caret is at 18 initially +PASS: on גכ יגכ יגכ יגכ יגכ, caret is at 14 after moving upwards once +PASS: on גכ יגכ יגכ יגכ יגכ, caret is at 10 after moving upwards twice +PASS: on גכ יגכ יגכ יגכ יגכ, caret is at 6 after moving upwards 3 times +PASS: on גכ יגכ יגכ יגכ יגכ, caret is at 3 after moving upwards 4 times +
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/editing/selection/offset-from-point-complex-scripts-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/editing/selection/offset-from-point-complex-scripts-expected.txt new file mode 100644 index 0000000..e4ad1bd --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-retina/editing/selection/offset-from-point-complex-scripts-expected.txt
@@ -0,0 +1 @@ +0 4 3 2 6
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/atsui-partial-selection-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/atsui-partial-selection-expected.png new file mode 100644 index 0000000..6e90dbd --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/atsui-partial-selection-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/emphasis-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/emphasis-expected.png new file mode 100644 index 0000000..af48c0db --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/emphasis-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/justified-selection-at-edge-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/justified-selection-at-edge-expected.png new file mode 100644 index 0000000..0254daf --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/justified-selection-at-edge-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/justified-selection-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/justified-selection-expected.png new file mode 100644 index 0000000..ead45108 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/justified-selection-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/selection-multiple-runs-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/selection-multiple-runs-expected.png new file mode 100644 index 0000000..831359be --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/selection-multiple-runs-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/selection-painted-separately-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/selection-painted-separately-expected.png new file mode 100644 index 0000000..ab30ea5 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/text/selection/selection-painted-separately-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/editing/selection/replaced-boundaries-1-expected.png b/third_party/WebKit/LayoutTests/platform/win7/editing/selection/replaced-boundaries-1-expected.png new file mode 100644 index 0000000..1b850154 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win7/editing/selection/replaced-boundaries-1-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/color-emoji-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/color-emoji-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/color-emoji-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/color-emoji-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/complex-preferred-logical-widths-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/complex-preferred-logical-widths-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/complex-preferred-logical-widths-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/complex-preferred-logical-widths-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/drawBidiText-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/drawBidiText-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/drawBidiText-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/drawBidiText-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/drawBidiText-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/paint/drawBidiText-expected.txt similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/drawBidiText-expected.txt rename to third_party/WebKit/LayoutTests/platform/win7/paint/drawBidiText-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/emoticons-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/emoticons-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/emoticons-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/emoticons-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/emphasis-complex-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/emphasis-complex-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/emphasis-complex-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/emphasis-complex-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/fallback-traits-fixup-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/fallback-traits-fixup-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/fallback-traits-fixup-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/fallback-traits-fixup-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/font-fallback-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/font-fallback-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/font-fallback-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/font-fallback-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/font-fallback-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/paint/font-fallback-expected.txt similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/font-fallback-expected.txt rename to third_party/WebKit/LayoutTests/platform/win7/paint/font-fallback-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/international/bidi-listbox-atsui-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/international/bidi-listbox-atsui-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/international/bidi-listbox-atsui-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/international/bidi-listbox-atsui-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/international/bidi-listbox-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/international/bidi-listbox-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/international/bidi-listbox-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/international/bidi-listbox-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/international/hindi-spacing-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/international/hindi-spacing-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/international/hindi-spacing-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/international/hindi-spacing-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/international/lang-glyph-cache-separation-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/international/lang-glyph-cache-separation-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/international/lang-glyph-cache-separation-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/international/lang-glyph-cache-separation-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/international/unicode-bidi-plaintext-in-textarea-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/international/unicode-bidi-plaintext-in-textarea-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/international/unicode-bidi-plaintext-in-textarea-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/international/unicode-bidi-plaintext-in-textarea-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/justify-ideograph-complex-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/justify-ideograph-complex-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/justify-ideograph-complex-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/justify-ideograph-complex-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/justify-ideograph-simple-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/justify-ideograph-simple-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/justify-ideograph-simple-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/justify-ideograph-simple-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/justify-ideograph-vertical-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/justify-ideograph-vertical-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/justify-ideograph-vertical-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/justify-ideograph-vertical-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/mac-system-ui-trak-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/paint/mac-system-ui-trak-expected.txt similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/mac-system-ui-trak-expected.txt rename to third_party/WebKit/LayoutTests/platform/win7/paint/mac-system-ui-trak-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/midword-break-before-surrogate-pair-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/midword-break-before-surrogate-pair-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/midword-break-before-surrogate-pair-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/midword-break-before-surrogate-pair-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/paint/selection/atsui-partial-selection-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/selection/atsui-partial-selection-expected.png new file mode 100644 index 0000000..6e90dbd --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win7/paint/selection/atsui-partial-selection-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/paint/selection/emphasis-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/selection/emphasis-expected.png new file mode 100644 index 0000000..af48c0db --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win7/paint/selection/emphasis-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/selection/flexbox-selection-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/selection/flexbox-selection-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/selection/flexbox-selection-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/selection/flexbox-selection-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/selection/flexbox-selection-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/paint/selection/flexbox-selection-expected.txt similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/selection/flexbox-selection-expected.txt rename to third_party/WebKit/LayoutTests/platform/win7/paint/selection/flexbox-selection-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/selection/flexbox-selection-nested-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/selection/flexbox-selection-nested-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/selection/flexbox-selection-nested-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/selection/flexbox-selection-nested-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/selection/flexbox-selection-nested-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/paint/selection/flexbox-selection-nested-expected.txt similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/selection/flexbox-selection-nested-expected.txt rename to third_party/WebKit/LayoutTests/platform/win7/paint/selection/flexbox-selection-nested-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/win7/paint/selection/justified-selection-at-edge-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/selection/justified-selection-at-edge-expected.png new file mode 100644 index 0000000..0254daf --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win7/paint/selection/justified-selection-at-edge-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/paint/selection/justified-selection-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/selection/justified-selection-expected.png new file mode 100644 index 0000000..ead45108 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win7/paint/selection/justified-selection-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/selection/khmer-selection-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/selection/khmer-selection-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/selection/khmer-selection-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/selection/khmer-selection-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/selection/mixed-directionality-selection-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/selection/mixed-directionality-selection-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/selection/mixed-directionality-selection-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/selection/mixed-directionality-selection-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/paint/selection/selection-multiple-runs-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/selection/selection-multiple-runs-expected.png new file mode 100644 index 0000000..831359be --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win7/paint/selection/selection-multiple-runs-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/paint/selection/text-selection-inline-block-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/selection/text-selection-inline-block-expected.png new file mode 100644 index 0000000..9bb2c7a --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win7/paint/selection/text-selection-inline-block-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/paint/selection/text-selection-inline-block-rtl-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/selection/text-selection-inline-block-rtl-expected.png new file mode 100644 index 0000000..656183c --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win7/paint/selection/text-selection-inline-block-rtl-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/textIteratorNilRenderer-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/textIteratorNilRenderer-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/textIteratorNilRenderer-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/textIteratorNilRenderer-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/textIteratorNilRenderer-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/paint/textIteratorNilRenderer-expected.txt similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/textIteratorNilRenderer-expected.txt rename to third_party/WebKit/LayoutTests/platform/win7/paint/textIteratorNilRenderer-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/unicode-fallback-font-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/unicode-fallback-font-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/unicode-fallback-font-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/unicode-fallback-font-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/unicode-fallback-font-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/paint/unicode-fallback-font-expected.txt similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/unicode-fallback-font-expected.txt rename to third_party/WebKit/LayoutTests/platform/win7/paint/unicode-fallback-font-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/updateNewFont-expected.png b/third_party/WebKit/LayoutTests/platform/win7/paint/updateNewFont-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/updateNewFont-expected.png rename to third_party/WebKit/LayoutTests/platform/win7/paint/updateNewFont-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/updateNewFont-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/paint/updateNewFont-expected.txt similarity index 100% rename from third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/text/updateNewFont-expected.txt rename to third_party/WebKit/LayoutTests/platform/win7/paint/updateNewFont-expected.txt
diff --git a/third_party/WebKit/LayoutTests/vr/resources/mock-vr-service.js b/third_party/WebKit/LayoutTests/vr/resources/mock-vr-service.js index d3c0460..c9abd5b 100644 --- a/third_party/WebKit/LayoutTests/vr/resources/mock-vr-service.js +++ b/third_party/WebKit/LayoutTests/vr/resources/mock-vr-service.js
@@ -21,11 +21,20 @@ device.mojom.VRDisplayFrameTransportMethod.SUBMIT_AS_MAILBOX_HOLDER; options.waitForTransferNotification = true; options.waitForRenderNotification = true; + + let magicWindowPtr = new device.mojom.VRMagicWindowProviderPtr(); + let magicWindowRequest = mojo.makeRequest(magicWindowPtr); + let magicWindowBinding = new mojo.Binding( + device.mojom.VRMagicWindowProvider, this, magicWindowRequest); + return Promise.resolve({ - connection: { - clientRequest: request, - provider: provider, - transportOptions: options + session: { + connection: { + clientRequest: request, + provider: provider, + transportOptions: options + }, + magicWindowProvider: magicWindowPtr } }); } @@ -80,14 +89,9 @@ let displayBinding = new mojo.Binding(device.mojom.VRDisplayHost, this, displayRequest); - let magicWindowPtr = new device.mojom.VRMagicWindowProviderPtr(); - let magicWindowRequest = mojo.makeRequest(magicWindowPtr); - let magicWindowBinding = new mojo.Binding( - device.mojom.VRMagicWindowProvider, this, magicWindowRequest); - let clientRequest = mojo.makeRequest(this.displayClient_); - this.service_.client_.onDisplayConnected(magicWindowPtr, displayPtr, - clientRequest, this.displayInfo_); + this.service_.client_.onDisplayConnected( + displayPtr, clientRequest, this.displayInfo_); } }
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 4a3113cc..541998aad 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -7097,6 +7097,7 @@ getter actualBoundingBoxDescent getter actualBoundingBoxLeft getter actualBoundingBoxRight + getter advances getter alphabeticBaseline getter emHeightAscent getter emHeightDescent
diff --git a/third_party/WebKit/LayoutTests/xr/resources/xr-device-mocking.js b/third_party/WebKit/LayoutTests/xr/resources/xr-device-mocking.js index 2be7b2c..997141c 100644 --- a/third_party/WebKit/LayoutTests/xr/resources/xr-device-mocking.js +++ b/third_party/WebKit/LayoutTests/xr/resources/xr-device-mocking.js
@@ -313,14 +313,25 @@ options.waitForRenderNotification = true; let connection; - if (result.supportsSession) + if (result.supportsSession) { connection = { clientRequest: this.presentation_provider_.getClientRequest(), provider: this.presentation_provider_.bindProvider(sessionOptions), transportOptions: options }; - return Promise.resolve({connection: connection}); + let magicWindowPtr = new device.mojom.VRMagicWindowProviderPtr(); + let magicWindowRequest = mojo.makeRequest(magicWindowPtr); + let magicWindowBinding = new mojo.Binding( + device.mojom.VRMagicWindowProvider, this, magicWindowRequest); + + return Promise.resolve({ + session: + {connection: connection, magicWindowProvider: magicWindowPtr} + }); + } else { + return Promise.resolve({session: null}); + } }); } @@ -409,14 +420,9 @@ let displayBinding = new mojo.Binding(device.mojom.VRDisplayHost, this, displayRequest); - let magicWindowPtr = new device.mojom.VRMagicWindowProviderPtr(); - let magicWindowRequest = mojo.makeRequest(magicWindowPtr); - let magicWindowBinding = new mojo.Binding( - device.mojom.VRMagicWindowProvider, this, magicWindowRequest); - let clientRequest = mojo.makeRequest(this.displayClient_); this.service_.client_.onDisplayConnected( - magicWindowPtr, displayPtr, clientRequest, this.displayInfo_); + displayPtr, clientRequest, this.displayInfo_); } addInputSource(input_source) {
diff --git a/third_party/blink/public/platform/web_surface_layer_bridge.h b/third_party/blink/public/platform/web_surface_layer_bridge.h index ed484b0..2b3d981 100644 --- a/third_party/blink/public/platform/web_surface_layer_bridge.h +++ b/third_party/blink/public/platform/web_surface_layer_bridge.h
@@ -5,6 +5,9 @@ #ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_SURFACE_LAYER_BRIDGE_H_ #define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_SURFACE_LAYER_BRIDGE_H_ +#include <memory> + +#include "cc/layers/surface_layer.h" #include "components/viz/common/surfaces/surface_id.h" #include "third_party/blink/public/platform/web_common.h" #include "third_party/blink/public/platform/web_layer_tree_view.h" @@ -22,7 +25,7 @@ virtual void UnregisterContentsLayer(cc::Layer*) = 0; // Called when a SurfaceLayer is activated. - virtual void OnSurfaceIdUpdated(viz::SurfaceId surface_id){}; + virtual void OnSurfaceIdUpdated(viz::SurfaceId surface_id) {} }; // Maintains and exposes the SurfaceLayer. @@ -30,14 +33,15 @@ public: static std::unique_ptr<WebSurfaceLayerBridge> Create( WebLayerTreeView*, - WebSurfaceLayerBridgeObserver*); + WebSurfaceLayerBridgeObserver*, + cc::UpdateSubmissionStateCB); virtual ~WebSurfaceLayerBridge(); virtual cc::Layer* GetCcLayer() const = 0; virtual const viz::FrameSinkId& GetFrameSinkId() const = 0; + virtual const viz::SurfaceId& GetSurfaceId() const = 0; virtual void ClearSurfaceId() = 0; virtual void SetContentsOpaque(bool) = 0; virtual void CreateSurfaceLayer() = 0; - virtual const viz::SurfaceId& GetSurfaceId() const = 0; }; } // namespace blink
diff --git a/third_party/blink/public/platform/web_video_frame_submitter.h b/third_party/blink/public/platform/web_video_frame_submitter.h index 6b69062..b3eb085 100644 --- a/third_party/blink/public/platform/web_video_frame_submitter.h +++ b/third_party/blink/public/platform/web_video_frame_submitter.h
@@ -6,7 +6,7 @@ #define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_VIDEO_FRAME_SUBMITTER_H_ #include "cc/layers/video_frame_provider.h" -#include "components/viz/common/surfaces/frame_sink_id.h" +#include "components/viz/common/surfaces/surface_id.h" #include "media/base/video_rotation.h" #include "third_party/blink/public/platform/web_common.h" @@ -46,10 +46,14 @@ virtual void SetRotation(media::VideoRotation) = 0; // Prepares the compositor frame sink to accept frames by providing - // a FrameSinkId. The callback is to be used when on context loss to prevent + // a SurfaceId. The callback is to be used when on context loss to prevent // the submitter from continuing to submit frames with invalid resources. - virtual void EnableSubmission(viz::FrameSinkId, + virtual void EnableSubmission(viz::SurfaceId, WebFrameSinkDestroyedCallback) = 0; + + // Updates whether we should submit frames or not based on whether the video + // is visible on screen. + virtual void UpdateSubmissionState(bool) = 0; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc index 355d039..5f8f288 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.cc +++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -39,7 +39,6 @@ #include "build/build_config.h" #include "cc/layers/picture_layer.h" #include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h" -#include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/web_float_point.h" #include "third_party/blink/public/platform/web_image.h" #include "third_party/blink/public/platform/web_input_event.h" @@ -94,6 +93,7 @@ #include "third_party/blink/renderer/core/frame/browser_controls.h" #include "third_party/blink/renderer/core/frame/event_handler_registry.h" #include "third_party/blink/renderer/core/frame/fullscreen_controller.h" +#include "third_party/blink/renderer/core/frame/link_highlights.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame_client.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" @@ -139,7 +139,6 @@ #include "third_party/blink/renderer/core/page/validation_message_client_impl.h" #include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h" #include "third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h" -#include "third_party/blink/renderer/core/paint/link_highlight_impl.h" #include "third_party/blink/renderer/core/paint/paint_layer.h" #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h" #include "third_party/blink/renderer/core/timing/dom_window_performance.h" @@ -148,7 +147,6 @@ #include "third_party/blink/renderer/platform/cursor.h" #include "third_party/blink/renderer/platform/fonts/font_cache.h" #include "third_party/blink/renderer/platform/geometry/float_rect.h" -#include "third_party/blink/renderer/platform/graphics/color.h" #include "third_party/blink/renderer/platform/graphics/compositor_mutator_client.h" #include "third_party/blink/renderer/platform/graphics/compositor_mutator_impl.h" #include "third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h" @@ -379,11 +377,6 @@ WebViewImpl::~WebViewImpl() { DCHECK(!page_); - - // Each highlight uses m_owningWebViewImpl->m_linkHighlightsTimeline - // in destructor. m_linkHighlightsTimeline might be destroyed earlier - // than m_linkHighlights. - DCHECK(link_highlights_.IsEmpty()); } ValidationMessageClient* WebViewImpl::GetValidationMessageClient() const { @@ -602,8 +595,7 @@ case WebInputEvent::kGestureTapCancel: case WebInputEvent::kGestureTap: case WebInputEvent::kGestureLongPress: - for (size_t i = 0; i < link_highlights_.size(); ++i) - link_highlights_[i]->StartHighlightAnimationIfNeeded(); + GetPage()->GetLinkHighlights().StartHighlightAnimationIfNeeded(); break; default: break; @@ -651,8 +643,7 @@ RoundedIntSize(targeted_event.GetHitTestResult().LocalPoint()); EnableTapHighlights(highlight_nodes); - for (size_t i = 0; i < link_highlights_.size(); ++i) - link_highlights_[i]->StartHighlightAnimationIfNeeded(); + GetPage()->GetLinkHighlights().StartHighlightAnimationIfNeeded(); event_result = WebInputEventResult::kHandledSystem; event_cancelled = true; break; @@ -1245,30 +1236,7 @@ void WebViewImpl::EnableTapHighlights( HeapVector<Member<Node>>& highlight_nodes) { - if (highlight_nodes.IsEmpty()) - return; - - // Always clear any existing highlight when this is invoked, even if we - // don't get a new target to highlight. - link_highlights_.clear(); - - for (size_t i = 0; i < highlight_nodes.size(); ++i) { - Node* node = highlight_nodes[i]; - - if (!node || !node->GetLayoutObject()) - continue; - - Color highlight_color = - node->GetLayoutObject()->Style()->TapHighlightColor(); - // Safari documentation for -webkit-tap-highlight-color says if the - // specified color has 0 alpha, then tap highlighting is disabled. - // http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safaricssref/articles/standardcssproperties.html - if (!highlight_color.Alpha()) - continue; - - link_highlights_.push_back(LinkHighlightImpl::Create(node, this)); - } - + GetPage()->GetLinkHighlights().SetTapHighlights(highlight_nodes); UpdateAllLifecyclePhases(); } @@ -1766,8 +1734,8 @@ // TODO(chrishtr): link highlights don't currently paint themselves, it's // still driven by cc. Fix this. - for (size_t i = 0; i < link_highlights_.size(); ++i) - link_highlights_[i]->UpdateGeometry(); + // TODO(pdr): Move this to LocalFrameView::UpdateLifecyclePhasesInternal. + GetPage()->GetLinkHighlights().UpdateGeometry(); if (LocalFrameView* view = MainFrameImpl()->GetFrameView()) { LocalFrame* frame = MainFrameImpl()->GetFrame(); @@ -2118,12 +2086,6 @@ } void WebViewImpl::WillCloseLayerTreeView() { - if (link_highlights_timeline_) { - link_highlights_.clear(); - DetachCompositorAnimationTimeline(link_highlights_timeline_.get()); - link_highlights_timeline_.reset(); - } - if (layer_tree_view_) GetPage()->WillCloseLayerTreeView(*layer_tree_view_, nullptr); @@ -3157,7 +3119,8 @@ GetPage()->GetVisualViewport().MainFrameDidChangeSize(); // Make sure link highlight from previous page is cleared. - link_highlights_.clear(); + // TODO(pdr): Move this to Page::DidCommitLoad. + GetPage()->GetLinkHighlights().ResetForPageNavigation(); if (!MainFrameImpl()) return; } @@ -3448,18 +3411,6 @@ client_->WidgetClient()->ScheduleAnimation(); } -void WebViewImpl::AttachCompositorAnimationTimeline( - CompositorAnimationTimeline* timeline) { - if (animation_host_) - animation_host_->AddTimeline(*timeline); -} - -void WebViewImpl::DetachCompositorAnimationTimeline( - CompositorAnimationTimeline* timeline) { - if (animation_host_) - animation_host_->RemoveTimeline(*timeline); -} - void WebViewImpl::InitializeLayerTreeView() { if (client_) { layer_tree_view_ = client_->InitializeLayerTreeView(); @@ -3485,11 +3436,6 @@ // hit this code and then delete allowsBrokenNullLayerTreeView. DCHECK(layer_tree_view_ || !client_ || client_->WidgetClient()->AllowsBrokenNullLayerTreeView()); - - if (Platform::Current()->IsThreadedAnimationEnabled() && layer_tree_view_) { - link_highlights_timeline_ = CompositorAnimationTimeline::Create(); - AttachCompositorAnimationTimeline(link_highlights_timeline_.get()); - } } void WebViewImpl::ApplyViewportDeltas(
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.h b/third_party/blink/renderer/core/exported/web_view_impl.h index f35cbf2..1126c8c 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.h +++ b/third_party/blink/renderer/core/exported/web_view_impl.h
@@ -56,7 +56,6 @@ #include "third_party/blink/renderer/core/page/event_with_hit_test_results.h" #include "third_party/blink/renderer/core/page/page_widget_delegate.h" #include "third_party/blink/renderer/core/page/scoped_page_pauser.h" -#include "third_party/blink/renderer/platform/animation/compositor_animation_timeline.h" #include "third_party/blink/renderer/platform/geometry/int_point.h" #include "third_party/blink/renderer/platform/geometry/int_rect.h" #include "third_party/blink/renderer/platform/graphics/graphics_layer.h" @@ -78,7 +77,6 @@ class DevToolsEmulator; class Frame; class FullscreenController; -class LinkHighlightImpl; class PageOverlay; class PageScaleConstraintsSet; class PaintLayerCompositor; @@ -340,9 +338,6 @@ GraphicsLayer* RootGraphicsLayer(); void RegisterViewportLayersWithCompositor(); PaintLayerCompositor* Compositor() const; - CompositorAnimationTimeline* LinkHighlightsTimeline() const { - return link_highlights_timeline_.get(); - } PageScheduler* Scheduler() const override; void SetVisibilityState(mojom::PageVisibilityState, bool) override; @@ -397,12 +392,6 @@ bool HasHorizontalScrollbar(); bool HasVerticalScrollbar(); - // Exposed for tests. - unsigned NumLinkHighlights() { return link_highlights_.size(); } - LinkHighlightImpl* GetLinkHighlight(int i) { - return link_highlights_[i].get(); - } - WebSettingsImpl* SettingsImpl(); // Returns the bounding box of the block type node touched by the WebPoint. @@ -540,8 +529,6 @@ void SetRootGraphicsLayer(GraphicsLayer*); void SetRootLayer(scoped_refptr<cc::Layer>); - void AttachCompositorAnimationTimeline(CompositorAnimationTimeline*); - void DetachCompositorAnimationTimeline(CompositorAnimationTimeline*); LocalFrame* FocusedLocalFrameInWidget() const; LocalFrame* FocusedLocalFrameAvailableForIme() const; @@ -652,8 +639,6 @@ GraphicsLayer* visual_viewport_container_layer_; bool matches_heuristics_for_gpu_rasterization_; - Vector<std::unique_ptr<LinkHighlightImpl>> link_highlights_; - std::unique_ptr<CompositorAnimationTimeline> link_highlights_timeline_; std::unique_ptr<FullscreenController> fullscreen_controller_; WebPoint last_tap_disambiguation_best_candidate_position_;
diff --git a/third_party/blink/renderer/core/frame/BUILD.gn b/third_party/blink/renderer/core/frame/BUILD.gn index 9343b9ac..faf80c78 100644 --- a/third_party/blink/renderer/core/frame/BUILD.gn +++ b/third_party/blink/renderer/core/frame/BUILD.gn
@@ -78,6 +78,8 @@ "intervention_report_body.h", "layout_subtree_root_list.cc", "layout_subtree_root_list.h", + "link_highlights.cc", + "link_highlights.h", "local_dom_window.cc", "local_dom_window.h", "local_frame.cc",
diff --git a/third_party/blink/renderer/core/frame/frame_view.h b/third_party/blink/renderer/core/frame/frame_view.h index 429a2e0..3ea14499 100644 --- a/third_party/blink/renderer/core/frame/frame_view.h +++ b/third_party/blink/renderer/core/frame/frame_view.h
@@ -5,6 +5,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FRAME_VIEW_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FRAME_VIEW_H_ +#include "third_party/blink/renderer/core/dom/document_lifecycle.h" #include "third_party/blink/renderer/core/frame/embedded_content_view.h" namespace blink { @@ -14,7 +15,8 @@ class CORE_EXPORT FrameView : public EmbeddedContentView { public: ~FrameView() override = default; - virtual void UpdateViewportIntersectionsForSubtree() = 0; + virtual void UpdateViewportIntersectionsForSubtree( + DocumentLifecycle::LifecycleState) = 0; virtual bool GetIntrinsicSizingInfo(IntrinsicSizingInfo&) const = 0; virtual bool HasIntrinsicSizingInfo() const = 0;
diff --git a/third_party/blink/renderer/core/frame/link_highlights.cc b/third_party/blink/renderer/core/frame/link_highlights.cc new file mode 100644 index 0000000..34f1ffce --- /dev/null +++ b/third_party/blink/renderer/core/frame/link_highlights.cc
@@ -0,0 +1,108 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/core/frame/link_highlights.h" + +#include <memory> + +#include "cc/layers/picture_layer.h" +#include "third_party/blink/public/platform/platform.h" +#include "third_party/blink/public/platform/web_layer_tree_view.h" +#include "third_party/blink/renderer/core/dom/node.h" +#include "third_party/blink/renderer/core/layout/layout_object.h" +#include "third_party/blink/renderer/core/page/chrome_client.h" +#include "third_party/blink/renderer/core/page/page.h" +#include "third_party/blink/renderer/core/paint/link_highlight_impl.h" +#include "third_party/blink/renderer/platform/animation/compositor_animation_host.h" +#include "third_party/blink/renderer/platform/animation/compositor_animation_timeline.h" + +namespace blink { + +LinkHighlights::LinkHighlights(Page& owner) : page_(&owner) {} + +LinkHighlights::~LinkHighlights() { + RemoveAllHighlights(); +} + +void LinkHighlights::Trace(blink::Visitor* visitor) { + visitor->Trace(page_); +} + +void LinkHighlights::RemoveAllHighlights() { + if (timeline_) { + for (auto& highlight : link_highlights_) + timeline_->AnimationDestroyed(*highlight); + } + link_highlights_.clear(); +} + +void LinkHighlights::ResetForPageNavigation() { + RemoveAllHighlights(); +} + +void LinkHighlights::SetTapHighlights( + HeapVector<Member<Node>>& highlight_nodes) { + // Always clear any existing highlight when this is invoked, even if we + // don't get a new target to highlight. + RemoveAllHighlights(); + + for (size_t i = 0; i < highlight_nodes.size(); ++i) { + Node* node = highlight_nodes[i]; + + if (!node || !node->GetLayoutObject()) + continue; + + Color highlight_color = + node->GetLayoutObject()->Style()->TapHighlightColor(); + // Safari documentation for -webkit-tap-highlight-color says if the + // specified color has 0 alpha, then tap highlighting is disabled. + // http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safaricssref/articles/standardcssproperties.html + if (!highlight_color.Alpha()) + continue; + + link_highlights_.push_back(LinkHighlightImpl::Create(node)); + if (timeline_) + timeline_->AnimationAttached(*link_highlights_.back()); + } +} + +void LinkHighlights::UpdateGeometry() { + for (auto& highlight : link_highlights_) + highlight->UpdateGeometry(); +} + +LocalFrame* LinkHighlights::MainFrame() const { + return GetPage().MainFrame() && GetPage().MainFrame()->IsLocalFrame() + ? GetPage().DeprecatedLocalMainFrame() + : nullptr; +} + +void LinkHighlights::StartHighlightAnimationIfNeeded() { + for (auto& highlight : link_highlights_) + highlight->StartHighlightAnimationIfNeeded(); + + if (auto* local_frame = MainFrame()) + GetPage().GetChromeClient().ScheduleAnimation(local_frame->View()); +} + +void LinkHighlights::LayerTreeViewInitialized( + WebLayerTreeView& layer_tree_view) { + if (Platform::Current()->IsThreadedAnimationEnabled()) { + timeline_ = CompositorAnimationTimeline::Create(); + animation_host_ = std::make_unique<CompositorAnimationHost>( + layer_tree_view.CompositorAnimationHost()); + animation_host_->AddTimeline(*timeline_); + } +} + +void LinkHighlights::WillCloseLayerTreeView(WebLayerTreeView& layer_tree_view) { + RemoveAllHighlights(); + if (timeline_) { + animation_host_->RemoveTimeline(*timeline_); + timeline_.reset(); + } + animation_host_ = nullptr; +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/frame/link_highlights.h b/third_party/blink/renderer/core/frame/link_highlights.h new file mode 100644 index 0000000..2eb1e31 --- /dev/null +++ b/third_party/blink/renderer/core/frame/link_highlights.h
@@ -0,0 +1,66 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_LINK_HIGHLIGHTS_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_LINK_HIGHLIGHTS_H_ + +#include <memory> + +#include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/platform/heap/handle.h" + +namespace blink { + +class Page; +class LinkHighlightImpl; +class CompositorAnimationHost; +class CompositorAnimationTimeline; +class WebLayerTreeView; +class LocalFrame; + +class CORE_EXPORT LinkHighlights final + : public GarbageCollectedFinalized<LinkHighlights> { + public: + static LinkHighlights* Create(Page& page) { return new LinkHighlights(page); } + virtual ~LinkHighlights(); + + virtual void Trace(blink::Visitor*); + + void ResetForPageNavigation(); + + void SetTapHighlights(HeapVector<Member<Node>>&); + + void UpdateGeometry(); + + void StartHighlightAnimationIfNeeded(); + + void LayerTreeViewInitialized(WebLayerTreeView&); + void WillCloseLayerTreeView(WebLayerTreeView&); + + private: + FRIEND_TEST_ALL_PREFIXES(LinkHighlightImplTest, verifyWebViewImplIntegration); + FRIEND_TEST_ALL_PREFIXES(LinkHighlightImplTest, resetDuringNodeRemoval); + FRIEND_TEST_ALL_PREFIXES(LinkHighlightImplTest, resetLayerTreeView); + FRIEND_TEST_ALL_PREFIXES(LinkHighlightImplTest, multipleHighlights); + + explicit LinkHighlights(Page&); + + void RemoveAllHighlights(); + + LocalFrame* MainFrame() const; + + Page& GetPage() const { + DCHECK(page_); + return *page_; + } + + Member<Page> page_; + Vector<std::unique_ptr<LinkHighlightImpl>> link_highlights_; + std::unique_ptr<CompositorAnimationHost> animation_host_; + std::unique_ptr<CompositorAnimationTimeline> timeline_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_LINK_HIGHLIGHTS_H_
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc index d53247c..9844b6b 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.cc +++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -2379,7 +2379,8 @@ ¤t_update_lifecycle_phases_target_state_, target_state); if (ShouldThrottleRendering()) { - UpdateThrottlingStatusForSubtree(); + UpdateViewportIntersectionsForSubtree( + std::min(target_state, DocumentLifecycle::kCompositingClean)); return Lifecycle().GetState() == target_state; } @@ -2409,7 +2410,7 @@ } if (target_state == DocumentLifecycle::kLayoutClean) { - UpdateThrottlingStatusForSubtree(); + UpdateViewportIntersectionsForSubtree(target_state); return Lifecycle().GetState() == target_state; } @@ -2419,9 +2420,7 @@ // OOPIF local frame roots that are throttled can return now that layout // is clean and intersection observations can be calculated. if (ShouldThrottleRendering()) { - if (target_state == DocumentLifecycle::kPaintClean) - UpdateViewportIntersectionsForSubtree(); - UpdateThrottlingStatusForSubtree(); + UpdateViewportIntersectionsForSubtree(target_state); return Lifecycle().GetState() == target_state; } @@ -2442,8 +2441,6 @@ frame_view.allows_layout_invalidation_after_layout_clean_ = false; }); - bool should_update_intersection_observations = false; - { TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "SetLayerTreeId", TRACE_EVENT_SCOPE_THREAD, "data", @@ -2467,13 +2464,6 @@ *this); } - // Save off this value now, since PrePaintTreeWalk will clear out - // the NeedsPaintPropertyUpdate bits. - should_update_intersection_observations = - layout_view->NeedsPaintPropertyUpdate() || - layout_view->DescendantNeedsPaintPropertyUpdate() || - needs_intersection_observation_; - if (target_state >= DocumentLifecycle::kPrePaintClean) { UpdateCompositedSelectionIfNeeded(); @@ -2523,14 +2513,6 @@ } } - if (should_update_intersection_observations) { - TRACE_EVENT0("blink,benchmark", - "LocalFrameView::UpdateViewportIntersectionsForSubtree"); - SCOPED_UMA_AND_UKM_TIMER("Blink.IntersectionObservation.UpdateTime", - UkmMetricNames::kIntersectionObservation); - UpdateViewportIntersectionsForSubtree(); - } - DCHECK(!frame_->Selection().NeedsLayoutSelectionUpdate()); DCHECK(ShouldThrottleRendering() || (frame_->GetDocument()->Printing() && @@ -2544,7 +2526,13 @@ }); } - UpdateThrottlingStatusForSubtree(); + { + TRACE_EVENT0("blink,benchmark", + "LocalFrameView::UpdateViewportIntersectionsForSubtree"); + SCOPED_UMA_AND_UKM_TIMER("Blink.IntersectionObservation.UpdateTime", + UkmMetricNames::kIntersectionObservation); + UpdateViewportIntersectionsForSubtree(target_state); + } return Lifecycle().GetState() == target_state; } @@ -2593,7 +2581,6 @@ { SCOPED_UMA_AND_UKM_TIMER("Blink.PrePaint.UpdateTime", UkmMetricNames::kPrePaint); - PrePaintTreeWalk().WalkTree(*this); } @@ -3880,7 +3867,8 @@ CollectAnnotatedRegions(*curr, regions); } -void LocalFrameView::UpdateViewportIntersectionsForSubtree() { +void LocalFrameView::UpdateViewportIntersectionsForSubtree( + DocumentLifecycle::LifecycleState target_state) { // TODO(dcheng): Since LocalFrameView tree updates are deferred, FrameViews // might still be in the LocalFrameView hierarchy even though the associated // Document is already detached. Investigate if this check and a similar check @@ -3889,29 +3877,19 @@ if (!GetFrame().GetDocument()->IsActive()) return; - RecordDeferredLoadingStats(); - if (!NeedsLayout()) { - // Notify javascript IntersectionObservers - if (GetFrame().GetDocument()->GetIntersectionObserverController()) { - GetFrame() - .GetDocument() - ->GetIntersectionObserverController() - ->ComputeTrackedIntersectionObservations(); + if (target_state == DocumentLifecycle::kPaintClean) { + RecordDeferredLoadingStats(); + if (!NeedsLayout()) { + // Notify javascript IntersectionObservers + if (GetFrame().GetDocument()->GetIntersectionObserverController()) { + GetFrame() + .GetDocument() + ->GetIntersectionObserverController() + ->ComputeTrackedIntersectionObservations(); + } } } - for (Frame* child = frame_->Tree().FirstChild(); child; - child = child->Tree().NextSibling()) { - child->View()->UpdateViewportIntersectionsForSubtree(); - } - - needs_intersection_observation_ = false; -} - -void LocalFrameView::UpdateThrottlingStatusForSubtree() { - if (!GetFrame().GetDocument()->IsActive()) - return; - // Don't throttle display:none frames (see updateRenderThrottlingStatus). HTMLFrameOwnerElement* owner_element = frame_->DeprecatedLocalOwner(); if (hidden_for_throttling_ && owner_element && @@ -3923,9 +3901,11 @@ kDontNotifyChildren); } - ForAllChildLocalFrameViews([](LocalFrameView& child_view) { - child_view.UpdateThrottlingStatusForSubtree(); - }); + for (Frame* child = frame_->Tree().FirstChild(); child; + child = child->Tree().NextSibling()) { + child->View()->UpdateViewportIntersectionsForSubtree(target_state); + } + needs_intersection_observation_ = false; } void LocalFrameView::UpdateRenderThrottlingStatusForTesting() {
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.h b/third_party/blink/renderer/core/frame/local_frame_view.h index 30519b5..5c4d983 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.h +++ b/third_party/blink/renderer/core/frame/local_frame_view.h
@@ -734,8 +734,8 @@ template <typename Function> void ForAllNonThrottledLocalFrameViews(const Function&); - void UpdateViewportIntersectionsForSubtree() override; - void UpdateThrottlingStatusForSubtree(); + void UpdateViewportIntersectionsForSubtree( + DocumentLifecycle::LifecycleState) override; void NotifyResizeObservers();
diff --git a/third_party/blink/renderer/core/frame/remote_frame_view.cc b/third_party/blink/renderer/core/frame/remote_frame_view.cc index 47f1be0..f3f61fa1 100644 --- a/third_party/blink/renderer/core/frame/remote_frame_view.cc +++ b/third_party/blink/renderer/core/frame/remote_frame_view.cc
@@ -63,9 +63,12 @@ return view; } -void RemoteFrameView::UpdateViewportIntersectionsForSubtree() { +void RemoteFrameView::UpdateViewportIntersectionsForSubtree( + DocumentLifecycle::LifecycleState target_state) { if (!remote_frame_->OwnerLayoutObject()) return; + if (target_state < DocumentLifecycle::kPaintClean) + return; LocalFrameView* local_root_view = ToLocalFrame(remote_frame_->Tree().Parent())->LocalFrameRoot().View();
diff --git a/third_party/blink/renderer/core/frame/remote_frame_view.h b/third_party/blink/renderer/core/frame/remote_frame_view.h index 25b94e7..1f6fba0e 100644 --- a/third_party/blink/renderer/core/frame/remote_frame_view.h +++ b/third_party/blink/renderer/core/frame/remote_frame_view.h
@@ -56,7 +56,8 @@ void Show() override; void SetParentVisible(bool) override; - void UpdateViewportIntersectionsForSubtree() override; + void UpdateViewportIntersectionsForSubtree( + DocumentLifecycle::LifecycleState) override; bool GetIntrinsicSizingInfo(IntrinsicSizingInfo&) const override;
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc index 2478cce..d22074bd 100644 --- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc +++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -29,7 +29,9 @@ #include <math.h> +#include <limits> #include <memory> +#include <utility> #include "base/location.h" #include "base/numerics/checked_math.h" @@ -1427,8 +1429,8 @@ if (frame) { layer_tree_view = frame->GetPage()->GetChromeClient().GetWebLayerTreeView(frame); - surface_layer_bridge_ = - std::make_unique<::blink::SurfaceLayerBridge>(layer_tree_view, this); + surface_layer_bridge_ = std::make_unique<::blink::SurfaceLayerBridge>( + layer_tree_view, this, base::DoNothing()); // Creates a placeholder layer first before Surface is created. surface_layer_bridge_->CreateSolidColorLayer(); }
diff --git a/third_party/blink/renderer/core/html/canvas/text_metrics.cc b/third_party/blink/renderer/core/html/canvas/text_metrics.cc index 1639dce..864bfe6 100644 --- a/third_party/blink/renderer/core/html/canvas/text_metrics.cc +++ b/third_party/blink/renderer/core/html/canvas/text_metrics.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "third_party/blink/renderer/core/html/canvas/text_metrics.h" +#include "third_party/blink/renderer/platform/fonts/character_range.h" namespace blink { @@ -64,6 +65,12 @@ FloatRect bbox = font.BoundingBox(text_run); const FontMetrics& font_metrics = font_data->GetFontMetrics(); + Vector<CharacterRange> ranges = font.IndividualCharacterRanges(text_run); + advances_.resize(ranges.size()); + for (unsigned i = 0; i < ranges.size(); i++) { + advances_[i] = ranges[i].start; + } + // x direction width_ = bbox.Width();
diff --git a/third_party/blink/renderer/core/html/canvas/text_metrics.h b/third_party/blink/renderer/core/html/canvas/text_metrics.h index c132aa2..51fc4e388 100644 --- a/third_party/blink/renderer/core/html/canvas/text_metrics.h +++ b/third_party/blink/renderer/core/html/canvas/text_metrics.h
@@ -51,6 +51,7 @@ } double width() const { return width_; } + const Vector<double>& advances() const { return advances_; } double actualBoundingBoxLeft() const { return actual_bounding_box_left_; } double actualBoundingBoxRight() const { return actual_bounding_box_right_; } double fontBoundingBoxAscent() const { return font_bounding_box_ascent_; } @@ -77,6 +78,7 @@ // x-direction double width_ = 0.0; + Vector<double> advances_; double actual_bounding_box_left_ = 0.0; double actual_bounding_box_right_ = 0.0;
diff --git a/third_party/blink/renderer/core/html/canvas/text_metrics.idl b/third_party/blink/renderer/core/html/canvas/text_metrics.idl index e84a831..bcaa5e2 100644 --- a/third_party/blink/renderer/core/html/canvas/text_metrics.idl +++ b/third_party/blink/renderer/core/html/canvas/text_metrics.idl
@@ -29,6 +29,7 @@ interface TextMetrics { // x-direction readonly attribute float width; // advance width + [RuntimeEnabled=ExtendedTextMetrics] readonly attribute FrozenArray<double> advances; [RuntimeEnabled=ExtendedTextMetrics] readonly attribute double actualBoundingBoxLeft; [RuntimeEnabled=ExtendedTextMetrics] readonly attribute double actualBoundingBoxRight;
diff --git a/third_party/blink/renderer/core/layout/layout_text.cc b/third_party/blink/renderer/core/layout/layout_text.cc index 6389fbd..bb8a4d45 100644 --- a/third_party/blink/renderer/core/layout/layout_text.cc +++ b/third_party/blink/renderer/core/layout/layout_text.cc
@@ -683,7 +683,9 @@ if (LineDirectionPointFitsInBox(point_line_direction.ToInt(), box, should_affinity_be_downstream)) { return CreatePositionWithAffinityForBoxAfterAdjustingOffsetForBiDi( - box, box->OffsetForPosition(point_line_direction), + box, + box->OffsetForPosition(point_line_direction, IncludePartialGlyphs, + BreakGlyphs), should_affinity_be_downstream); } } @@ -697,7 +699,9 @@ should_affinity_be_downstream); return CreatePositionWithAffinityForBoxAfterAdjustingOffsetForBiDi( last_box, - last_box->OffsetForPosition(point_line_direction) + last_box->Start(), + last_box->OffsetForPosition(point_line_direction, IncludePartialGlyphs, + BreakGlyphs) + + last_box->Start(), should_affinity_be_downstream); } return CreatePositionWithAffinity(0);
diff --git a/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h b/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h index a1ccf5b4..9a3994b 100644 --- a/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h +++ b/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h
@@ -866,7 +866,8 @@ x_pos_to_break += LayoutUnit::Epsilon(); if (run.Rtl()) x_pos_to_break = word_measurement.width - x_pos_to_break; - len = font.OffsetForPosition(run, x_pos_to_break, false); + len = font.OffsetForPosition(run, x_pos_to_break, OnlyFullGlyphs, + DontBreakGlyphs); int end = start + len; if (len) { end = break_iterator.PreviousBreakOpportunity(end, start); @@ -908,8 +909,9 @@ TextRun run = ConstructTextRun(font, text, start, len, style); run.SetTabSize(!collapse_white_space_, style.GetTabSize()); run.SetXPos(width_.CurrentWidth()); - unsigned max_prefix_length = - font.OffsetForPosition(run, max_prefix_width, false); + // TODO(fserb): Check if this need to be BreakGlyphs. + unsigned max_prefix_length = font.OffsetForPosition( + run, max_prefix_width, OnlyFullGlyphs, DontBreakGlyphs); if (max_prefix_length < Hyphenation::kMinimumPrefixLength) return false;
diff --git a/third_party/blink/renderer/core/layout/line/inline_text_box.cc b/third_party/blink/renderer/core/layout/line/inline_text_box.cc index 17d3cca7..80dca35b5 100644 --- a/third_party/blink/renderer/core/layout/line/inline_text_box.cc +++ b/third_party/blink/renderer/core/layout/line/inline_text_box.cc
@@ -424,7 +424,10 @@ // more accurate position in rtl text. // TODO(crbug.com/722043: This doesn't always give the best results. bool ltr = IsLeftToRightDirection(); - int offset = OffsetForPosition(ellipsis_x, !ltr); + int offset = OffsetForPosition(ellipsis_x, + ltr ? OnlyFullGlyphs : IncludePartialGlyphs, + DontBreakGlyphs); + // Full truncation is only necessary when we're flowing left-to-right. if (flow_is_ltr && offset == 0 && ltr == flow_is_ltr) { // No characters should be laid out. Set ourselves to full truncation and @@ -625,7 +628,8 @@ } int InlineTextBox::OffsetForPosition(LayoutUnit line_offset, - bool include_partial_glyphs) const { + IncludePartialGlyphsOption partial_glyphs, + BreakGlyphsOption break_glyphs) const { if (IsLineBreak()) return 0; @@ -639,7 +643,7 @@ const Font& font = style.GetFont(); return font.OffsetForPosition(ConstructTextRun(style), (line_offset - LogicalLeft()).ToFloat(), - include_partial_glyphs); + partial_glyphs, break_glyphs); } LayoutUnit InlineTextBox::PositionForOffset(int offset) const {
diff --git a/third_party/blink/renderer/core/layout/line/inline_text_box.h b/third_party/blink/renderer/core/layout/line/inline_text_box.h index cace2c5..fb34617 100644 --- a/third_party/blink/renderer/core/layout/line/inline_text_box.h +++ b/third_party/blink/renderer/core/layout/line/inline_text_box.h
@@ -206,7 +206,8 @@ public: virtual int OffsetForPosition(LayoutUnit x, - bool include_partial_glyphs = true) const; + IncludePartialGlyphsOption, + BreakGlyphsOption) const; virtual LayoutUnit PositionForOffset(int offset) const; // Returns false for offset after line break.
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc index 6025b3e0d..5b21a32 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -251,9 +251,10 @@ IsLtr(line_info->BaseDirection()) ? 0 : 1, box); } - if (line_box_.IsEmpty() && !container_builder_.UnpositionedListMarker()) { - return; // The line was empty. - } + // We can return early if we don't have any children (and don't need to + // create a line-box for a list marker, etc). + if (line_box_.IsEmpty() && line_info->IsEmptyLine()) + return; box_states_->OnEndPlaceItems(&line_box_, baseline_type_); @@ -284,12 +285,7 @@ // Handle out-of-flow positioned objects. They need inline offsets for their // static positions. - if (!PlaceOutOfFlowObjects(*line_info, line_box_metrics) && - !container_builder_.UnpositionedListMarker()) { - // If we have out-of-flow objects but nothing else, we don't have line box - // metrics nor BFC offset. Exit early. - return; - } + PlaceOutOfFlowObjects(*line_info, line_box_metrics); // Even if we have something in-flow, it may just be empty items that // shouldn't trigger creation of a line. Exit now if that's the case. @@ -438,10 +434,9 @@ // Place all out-of-flow objects in |line_box_| and clear them. // @return whether |line_box_| has any in-flow fragments. -bool NGInlineLayoutAlgorithm::PlaceOutOfFlowObjects( +void NGInlineLayoutAlgorithm::PlaceOutOfFlowObjects( const NGLineInfo& line_info, const NGLineHeightMetrics& line_box_metrics) { - bool has_fragments = false; for (NGLineBoxFragmentBuilder::Child& child : line_box_) { if (LayoutObject* box = child.out_of_flow_positioned_box) { // The static position is at the line-top. Ignore the block_offset. @@ -471,11 +466,8 @@ child.out_of_flow_positioned_box = child.out_of_flow_containing_box = nullptr; - } else if (!has_fragments) { - has_fragments = child.HasFragment(); } } - return has_fragments; } // Place a list marker.
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h index 017544f..4fcf7b1 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h
@@ -72,7 +72,7 @@ void PlaceLayoutResult(NGInlineItemResult*, NGInlineBoxState*, LayoutUnit inline_offset = LayoutUnit()); - bool PlaceOutOfFlowObjects(const NGLineInfo&, const NGLineHeightMetrics&); + void PlaceOutOfFlowObjects(const NGLineInfo&, const NGLineHeightMetrics&); void PlaceListMarker(const NGInlineItem&, NGInlineItemResult*, const NGLineInfo&);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc index 05934ae6..2593375 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
@@ -202,9 +202,16 @@ result.CheckConsistency(); #endif + // We should create a line-box when: + // - We have an item which needs a line box (text, etc). + // - A list-marker is present, and it would be the last line or last line + // before a forced new-line. + // - During min/max content sizing (to correctly determine the line width). + // // TODO(kojii): There are cases where we need to PlaceItems() without creating // line boxes. These cases need to be reviewed. if (ShouldCreateLineBox(line_info->Results()) || + (has_list_marker_ && line_info->IsLastLine()) || mode_ != NGLineBreakerMode::kContent) ComputeLineLocation(line_info); else @@ -284,7 +291,7 @@ MoveToNextOf(item); } else if (item.Type() == NGInlineItem::kListMarker) { NGInlineItemResult* item_result = AddItem(item, item_results); - item_result->should_create_line_box = true; + has_list_marker_ = true; DCHECK(!item_result->can_break_after); MoveToNextOf(item); } else {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h index 103ad53..d223f4d 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
@@ -221,6 +221,9 @@ // https://quirks.spec.whatwg.org/#the-line-height-calculation-quirk bool in_line_height_quirks_mode_ = false; + // True when the line we are breaking has a list marker. + bool has_list_marker_ = false; + bool ignore_floats_ = false; };
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.cc index 3ded252..7c70596 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.cc
@@ -192,9 +192,9 @@ DCHECK(TextShapeResult()); const LayoutUnit& point_in_line_direction = Style().IsHorizontalWritingMode() ? point.left : point.top; - const bool include_partial_glyphs = true; return TextShapeResult()->OffsetForPosition(point_in_line_direction.ToFloat(), - include_partial_glyphs) + + IncludePartialGlyphs, + BreakGlyphs) + StartOffset(); }
diff --git a/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.cc b/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.cc index c579125..876df62 100644 --- a/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.cc +++ b/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.cc
@@ -64,7 +64,16 @@ // Compute the baseline of the child content. NGLineHeightMetrics content_metrics; if (content.IsLineBox()) { - content_metrics = ToNGPhysicalLineBoxFragment(content).Metrics(); + const NGPhysicalLineBoxFragment& line_box = + ToNGPhysicalLineBoxFragment(content); + + // If this child is an empty line-box, the list marker should be aligned + // with the next non-empty line box produced. (This can occur with floats + // producing empty line-boxes). + if (line_box.Children().IsEmpty() && !line_box.BreakToken()->IsFinished()) + return false; + + content_metrics = line_box.Metrics(); } else { NGBoxFragment content_fragment(space.GetWritingMode(), ToNGPhysicalBoxFragment(content));
diff --git a/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc b/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc index dfaacf6..6965c06 100644 --- a/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc +++ b/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.cc
@@ -57,7 +57,9 @@ next_box->DirtyLineBoxes(); } -int SVGInlineTextBox::OffsetForPosition(LayoutUnit, bool) const { +int SVGInlineTextBox::OffsetForPosition(LayoutUnit, + IncludePartialGlyphsOption, + BreakGlyphsOption) const { // SVG doesn't use the standard offset <-> position selection system, as it's // not suitable for SVGs complex needs. Vertical text selection, inline boxes // spanning multiple lines (contrary to HTML, etc.) @@ -80,11 +82,10 @@ if (fragment.AffectedByTextLength()) position /= fragment.length_adjust_scale; - const bool include_partial_glyphs = true; TextRun text_run = ConstructTextRun(line_layout_item.StyleRef(), fragment); return fragment.character_offset - Start() + line_layout_item.ScaledFont().OffsetForPosition( - text_run, position, include_partial_glyphs); + text_run, position, IncludePartialGlyphs, BreakGlyphs); } LayoutUnit SVGInlineTextBox::PositionForOffset(int) const {
diff --git a/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.h b/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.h index ced60f1..00cbed81 100644 --- a/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.h +++ b/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.h
@@ -39,7 +39,8 @@ void SetLogicalHeight(LayoutUnit height) { logical_height_ = height; } int OffsetForPosition(LayoutUnit x, - bool include_partial_glyphs = true) const override; + IncludePartialGlyphsOption, + BreakGlyphsOption) const override; LayoutUnit PositionForOffset(int offset) const override; void Paint(const PaintInfo&,
diff --git a/third_party/blink/renderer/core/page/page.cc b/third_party/blink/renderer/core/page/page.cc index c22147f..5f98429 100644 --- a/third_party/blink/renderer/core/page/page.cc +++ b/third_party/blink/renderer/core/page/page.cc
@@ -38,6 +38,7 @@ #include "third_party/blink/renderer/core/frame/dom_timer.h" #include "third_party/blink/renderer/core/frame/event_handler_registry.h" #include "third_party/blink/renderer/core/frame/frame_console.h" +#include "third_party/blink/renderer/core/frame/link_highlights.h" #include "third_party/blink/renderer/core/frame/local_frame_client.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/frame/page_scale_constraints.h" @@ -162,6 +163,7 @@ visual_viewport_(VisualViewport::Create(*this)), overscroll_controller_( OverscrollController::Create(GetVisualViewport(), GetChromeClient())), + link_highlights_(LinkHighlights::Create(*this)), plugin_data_(nullptr), opened_by_dom_(false), tab_key_cycles_through_elements_(true), @@ -262,6 +264,10 @@ return *overscroll_controller_; } +LinkHighlights& Page::GetLinkHighlights() { + return *link_highlights_; +} + DOMRectList* Page::NonFastScrollableRectsForTesting(const LocalFrame* frame) { // Update lifecycle to kPrePaintClean. This includes the compositing update // and ScrollingCoordinator::UpdateAfterPaint, which computes the non-fast @@ -725,6 +731,7 @@ visitor->Trace(global_root_scroller_controller_); visitor->Trace(visual_viewport_); visitor->Trace(overscroll_controller_); + visitor->Trace(link_highlights_); visitor->Trace(main_frame_); visitor->Trace(plugin_data_); visitor->Trace(validation_message_client_); @@ -739,12 +746,14 @@ LocalFrameView* view) { if (GetScrollingCoordinator()) GetScrollingCoordinator()->LayerTreeViewInitialized(layer_tree_view, view); + GetLinkHighlights().LayerTreeViewInitialized(layer_tree_view); } void Page::WillCloseLayerTreeView(WebLayerTreeView& layer_tree_view, LocalFrameView* view) { if (scrolling_coordinator_) scrolling_coordinator_->WillCloseLayerTreeView(layer_tree_view, view); + GetLinkHighlights().WillCloseLayerTreeView(layer_tree_view); } void Page::WillBeDestroyed() {
diff --git a/third_party/blink/renderer/core/page/page.h b/third_party/blink/renderer/core/page/page.h index c2cc3cc..3245d4c2 100644 --- a/third_party/blink/renderer/core/page/page.h +++ b/third_party/blink/renderer/core/page/page.h
@@ -59,6 +59,7 @@ class DragController; class FocusController; class Frame; +class LinkHighlights; class OverscrollController; struct PageScaleConstraints; class PageScaleConstraintsSet; @@ -216,6 +217,8 @@ VisualViewport& GetVisualViewport(); const VisualViewport& GetVisualViewport() const; + LinkHighlights& GetLinkHighlights(); + OverscrollController& GetOverscrollController(); const OverscrollController& GetOverscrollController() const; @@ -363,6 +366,7 @@ global_root_scroller_controller_; const Member<VisualViewport> visual_viewport_; const Member<OverscrollController> overscroll_controller_; + const Member<LinkHighlights> link_highlights_; Member<PluginData> plugin_data_;
diff --git a/third_party/blink/renderer/core/paint/link_highlight_impl.cc b/third_party/blink/renderer/core/paint/link_highlight_impl.cc index 45511ba..683971b 100644 --- a/third_party/blink/renderer/core/paint/link_highlight_impl.cc +++ b/third_party/blink/renderer/core/paint/link_highlight_impl.cc
@@ -38,10 +38,10 @@ #include "third_party/blink/public/web/blink.h" #include "third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h" #include "third_party/blink/renderer/core/dom/node.h" -#include "third_party/blink/renderer/core/exported/web_settings_impl.h" #include "third_party/blink/renderer/core/exported/web_view_impl.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" +#include "third_party/blink/renderer/core/frame/settings.h" #include "third_party/blink/renderer/core/frame/web_frame_widget_base.h" #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" #include "third_party/blink/renderer/core/layout/layout_box_model_object.h" @@ -68,15 +68,12 @@ namespace blink { -std::unique_ptr<LinkHighlightImpl> LinkHighlightImpl::Create( - Node* node, - WebViewImpl* owning_web_view) { - return base::WrapUnique(new LinkHighlightImpl(node, owning_web_view)); +std::unique_ptr<LinkHighlightImpl> LinkHighlightImpl::Create(Node* node) { + return base::WrapUnique(new LinkHighlightImpl(node)); } -LinkHighlightImpl::LinkHighlightImpl(Node* node, WebViewImpl* owning_web_view) +LinkHighlightImpl::LinkHighlightImpl(Node* node) : node_(node), - owning_web_view_(owning_web_view), current_graphics_layer_(nullptr), is_scrolling_graphics_layer_(false), geometry_needs_update_(false), @@ -84,15 +81,12 @@ start_time_(CurrentTimeTicks()), unique_id_(NewUniqueObjectId()) { DCHECK(node_); - DCHECK(owning_web_view); content_layer_ = cc::PictureLayer::Create(this); content_layer_->SetTransformOrigin(FloatPoint3D()); compositor_animation_ = CompositorAnimation::Create(); DCHECK(compositor_animation_); compositor_animation_->SetAnimationDelegate(this); - if (owning_web_view_->LinkHighlightsTimeline()) - owning_web_view_->LinkHighlightsTimeline()->AnimationAttached(*this); CompositorElementId element_id = CompositorElementIdFromUniqueObjectId(unique_id_); @@ -106,8 +100,6 @@ LinkHighlightImpl::~LinkHighlightImpl() { if (compositor_animation_->IsElementAttached()) compositor_animation_->DetachElement(); - if (owning_web_view_->LinkHighlightsTimeline()) - owning_web_view_->LinkHighlightsTimeline()->AnimationDestroyed(*this); compositor_animation_->SetAnimationDelegate(nullptr); compositor_animation_.reset(); @@ -228,7 +220,9 @@ // links: these should ideally be merged into a single rect before creating // the path, but that's another CL. if (quads.size() == 1 && transformed_quad.IsRectilinear() && - !owning_web_view_->SettingsImpl()->MockGestureTapHighlightsEnabled()) { + !node_->GetDocument() + .GetSettings() + ->GetMockGestureTapHighlightsEnabled()) { FloatSize rect_rounding_radii(3, 3); new_path.AddRoundedRect(transformed_quad.BoundingBox(), rect_rounding_radii); @@ -326,7 +320,6 @@ compositor_animation_->AddKeyframeModel(std::move(keyframe_model)); Invalidate(); - owning_web_view_->MainFrameImpl()->FrameWidgetImpl()->ScheduleAnimation(); } void LinkHighlightImpl::ClearGraphicsLayerLinkHighlightPointer() {
diff --git a/third_party/blink/renderer/core/paint/link_highlight_impl.h b/third_party/blink/renderer/core/paint/link_highlight_impl.h index 9c4a76d8f..2158cf7 100644 --- a/third_party/blink/renderer/core/paint/link_highlight_impl.h +++ b/third_party/blink/renderer/core/paint/link_highlight_impl.h
@@ -50,14 +50,13 @@ class GraphicsLayer; class LayoutBoxModelObject; class Node; -class WebViewImpl; class CORE_EXPORT LinkHighlightImpl final : public LinkHighlight, public cc::ContentLayerClient, public CompositorAnimationDelegate, public CompositorAnimationClient { public: - static std::unique_ptr<LinkHighlightImpl> Create(Node*, WebViewImpl*); + static std::unique_ptr<LinkHighlightImpl> Create(Node*); ~LinkHighlightImpl() override; void StartHighlightAnimationIfNeeded(); @@ -88,7 +87,7 @@ } private: - LinkHighlightImpl(Node*, WebViewImpl*); + LinkHighlightImpl(Node*); void ReleaseResources(); void ComputeQuads(const Node&, Vector<FloatQuad>&) const; @@ -104,7 +103,6 @@ Path path_; Persistent<Node> node_; - WebViewImpl* owning_web_view_; GraphicsLayer* current_graphics_layer_; bool is_scrolling_graphics_layer_; std::unique_ptr<CompositorAnimation> compositor_animation_;
diff --git a/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc b/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc index b24337a..1739a05 100644 --- a/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc +++ b/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc
@@ -40,11 +40,13 @@ #include "third_party/blink/renderer/core/events/web_input_event_conversion.h" #include "third_party/blink/renderer/core/exported/web_view_impl.h" #include "third_party/blink/renderer/core/frame/frame_test_helpers.h" +#include "third_party/blink/renderer/core/frame/link_highlights.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" #include "third_party/blink/renderer/core/input/event_handler.h" #include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/core/page/touch_disambiguation.h" +#include "third_party/blink/renderer/platform/animation/compositor_animation_timeline.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/geometry/int_rect.h" #include "third_party/blink/renderer/platform/graphics/graphics_layer.h" @@ -104,26 +106,34 @@ web_view_impl->EnableTapHighlightAtPoint( GetTargetedEvent(web_view_impl, touch_event)); - EXPECT_TRUE(web_view_impl->GetLinkHighlight(0)); - EXPECT_TRUE(web_view_impl->GetLinkHighlight(0)->Layer()); + const auto& highlights = + web_view_impl->GetPage()->GetLinkHighlights().link_highlights_; + EXPECT_TRUE(highlights.at(0)); + EXPECT_TRUE(highlights.at(0)->Layer()); // Find a target inside a scrollable div touch_event.SetPositionInWidget(WebFloatPoint(20, 100)); web_view_impl->EnableTapHighlightAtPoint( GetTargetedEvent(web_view_impl, touch_event)); - ASSERT_TRUE(web_view_impl->GetLinkHighlight(0)); + ASSERT_TRUE(highlights.at(0)); + + // Enesure the timeline was added to a host. + EXPECT_TRUE(!!web_view_impl->GetPage() + ->GetLinkHighlights() + .timeline_->GetAnimationTimeline() + ->animation_host()); // Don't highlight if no "hand cursor" touch_event.SetPositionInWidget( WebFloatPoint(20, 220)); // An A-link with cross-hair cursor. web_view_impl->EnableTapHighlightAtPoint( GetTargetedEvent(web_view_impl, touch_event)); - ASSERT_EQ(0U, web_view_impl->NumLinkHighlights()); + ASSERT_EQ(0U, highlights.size()); touch_event.SetPositionInWidget(WebFloatPoint(20, 260)); // A text input box. web_view_impl->EnableTapHighlightAtPoint( GetTargetedEvent(web_view_impl, touch_event)); - ASSERT_EQ(0U, web_view_impl->NumLinkHighlights()); + ASSERT_EQ(0U, highlights.size()); Platform::Current() ->GetURLLoaderMockFactory() @@ -152,16 +162,17 @@ ASSERT_TRUE(touch_node); web_view_impl->EnableTapHighlightAtPoint(targeted_event); - ASSERT_TRUE(web_view_impl->GetLinkHighlight(0)); + const auto& highlights = web_view_impl->GetPage()->GetLinkHighlights(); + ASSERT_TRUE(highlights.link_highlights_.at(0)); GraphicsLayer* highlight_layer = - web_view_impl->GetLinkHighlight(0)->CurrentGraphicsLayerForTesting(); + highlights.link_highlights_.at(0)->CurrentGraphicsLayerForTesting(); ASSERT_TRUE(highlight_layer); EXPECT_TRUE(highlight_layer->GetLinkHighlight(0)); touch_node->remove(IGNORE_EXCEPTION_FOR_TESTING); web_view_impl->UpdateAllLifecyclePhases(); - ASSERT_EQ(0U, highlight_layer->NumLinkHighlights()); + EXPECT_EQ(0U, highlight_layer->NumLinkHighlights()); Platform::Current() ->GetURLLoaderMockFactory() @@ -191,10 +202,12 @@ ASSERT_TRUE(touch_node); web_view_impl->EnableTapHighlightAtPoint(targeted_event); - ASSERT_TRUE(web_view_impl->GetLinkHighlight(0)); + const auto& highlights = + web_view_impl->GetPage()->GetLinkHighlights().link_highlights_; + ASSERT_TRUE(highlights.at(0)); GraphicsLayer* highlight_layer = - web_view_impl->GetLinkHighlight(0)->CurrentGraphicsLayerForTesting(); + highlights.at(0)->CurrentGraphicsLayerForTesting(); ASSERT_TRUE(highlight_layer); EXPECT_TRUE(highlight_layer->GetLinkHighlight(0)); @@ -228,7 +241,9 @@ good_targets, highlight_nodes); web_view_impl->EnableTapHighlights(highlight_nodes); - EXPECT_EQ(2U, web_view_impl->NumLinkHighlights()); + const auto& highlights = + web_view_impl->GetPage()->GetLinkHighlights().link_highlights_; + EXPECT_EQ(2U, highlights.size()); Platform::Current() ->GetURLLoaderMockFactory()
diff --git a/third_party/blink/renderer/core/scheduler/frame_throttling_test.cc b/third_party/blink/renderer/core/scheduler/frame_throttling_test.cc index d4c09dc..63f4af4 100644 --- a/third_party/blink/renderer/core/scheduler/frame_throttling_test.cc +++ b/third_party/blink/renderer/core/scheduler/frame_throttling_test.cc
@@ -710,9 +710,6 @@ // layout, but should still unthrottle the frame. frame_element->setAttribute(styleAttr, "transform: translateY(0px)"); CompositeFrame(); // Unthrottle the frame. - - EXPECT_FALSE( - frame_element->contentDocument()->View()->ShouldThrottleRendering()); CompositeFrame(); // Handle the pending visual update of the unthrottled // frame. EXPECT_EQ(DocumentLifecycle::kPaintClean,
diff --git a/third_party/blink/renderer/modules/vr/vr_controller.cc b/third_party/blink/renderer/modules/vr/vr_controller.cc index da0e2fb..6805adad 100644 --- a/third_party/blink/renderer/modules/vr/vr_controller.cc +++ b/third_party/blink/renderer/modules/vr/vr_controller.cc
@@ -60,13 +60,11 @@ // here. Upon calling SetClient in the constructor we should receive one call // for each VRDisplay that was already connected at the time. void VRController::OnDisplayConnected( - device::mojom::blink::VRMagicWindowProviderPtr magic_window_provider, device::mojom::blink::VRDisplayHostPtr display, device::mojom::blink::VRDisplayClientRequest request, device::mojom::blink::VRDisplayInfoPtr display_info) { VRDisplay* vr_display = - new VRDisplay(navigator_vr_, std::move(magic_window_provider), - std::move(display), std::move(request)); + new VRDisplay(navigator_vr_, std::move(display), std::move(request)); vr_display->Update(display_info); vr_display->OnConnected(); vr_display->FocusChanged();
diff --git a/third_party/blink/renderer/modules/vr/vr_controller.h b/third_party/blink/renderer/modules/vr/vr_controller.h index 5d5fae9..b91a0e5 100644 --- a/third_party/blink/renderer/modules/vr/vr_controller.h +++ b/third_party/blink/renderer/modules/vr/vr_controller.h
@@ -34,8 +34,7 @@ void GetDisplays(ScriptPromiseResolver*); void SetListeningForActivate(bool); - void OnDisplayConnected(device::mojom::blink::VRMagicWindowProviderPtr, - device::mojom::blink::VRDisplayHostPtr, + void OnDisplayConnected(device::mojom::blink::VRDisplayHostPtr, device::mojom::blink::VRDisplayClientRequest, device::mojom::blink::VRDisplayInfoPtr) override;
diff --git a/third_party/blink/renderer/modules/vr/vr_display.cc b/third_party/blink/renderer/modules/vr/vr_display.cc index 73ea3f76..a221211 100644 --- a/third_party/blink/renderer/modules/vr/vr_display.cc +++ b/third_party/blink/renderer/modules/vr/vr_display.cc
@@ -95,16 +95,25 @@ VRDisplay::VRDisplay( NavigatorVR* navigator_vr, - device::mojom::blink::VRMagicWindowProviderPtr magic_window_provider, device::mojom::blink::VRDisplayHostPtr display, device::mojom::blink::VRDisplayClientRequest request) : PausableObject(navigator_vr->GetDocument()), navigator_vr_(navigator_vr), capabilities_(new VRDisplayCapabilities()), - magic_window_provider_(std::move(magic_window_provider)), display_(std::move(display)), display_client_binding_(this, std::move(request)) { PauseIfNeeded(); // Initialize SuspendabaleObject. + + // Request a non-exclusive session to provide magic window. + device::mojom::blink::XRSessionOptionsPtr options = + device::mojom::blink::XRSessionOptions::New(); + options->immersive = false; + // Set in_on_display_activate to true, this will prevent the request present + // from being logged. + // TODO(offenwanger): clean up the logging when refactors are complete. + display_->RequestSession(std::move(options), true, + WTF::Bind(&VRDisplay::OnMagicWindowRequestReturned, + WrapPersistent(this))); } VRDisplay::~VRDisplay() = default; @@ -227,7 +236,26 @@ if (display_blurred_) return; - if (!is_presenting_) { + if (is_presenting_) { + DCHECK(vr_presentation_provider_.is_bound()); + + if (pending_presenting_vsync_) + return; + + pending_magic_window_vsync_ = false; + pending_presenting_vsync_ = true; + vr_presentation_provider_->GetFrameData( + WTF::Bind(&VRDisplay::OnPresentingVSync, WrapWeakPersistent(this))); + + DVLOG(2) << __FUNCTION__ << " done: pending_presenting_vsync_=" + << pending_presenting_vsync_; + } else { + // Check if magic_window_provider_, if not then we are not fully + // initialized, or we do not support magic window, so don't request the + // vsync. If and when magic_window_provider_ is set it will run this code + // again. + if (!magic_window_provider_) + return; if (pending_magic_window_vsync_) return; magic_window_vsync_waiting_for_pose_.Reset(); @@ -239,20 +267,7 @@ doc->RequestAnimationFrame(new VRDisplayFrameRequestCallback(this)); DVLOG(2) << __FUNCTION__ << " done: pending_magic_window_vsync_=" << pending_magic_window_vsync_; - return; } - DCHECK(vr_presentation_provider_.is_bound()); - - if (pending_presenting_vsync_) - return; - - pending_magic_window_vsync_ = false; - pending_presenting_vsync_ = true; - vr_presentation_provider_->GetFrameData( - WTF::Bind(&VRDisplay::OnPresentingVSync, WrapWeakPersistent(this))); - - DVLOG(2) << __FUNCTION__ - << " done: pending_presenting_vsync_=" << pending_presenting_vsync_; } int VRDisplay::requestAnimationFrame(V8FrameRequestCallback* callback) { @@ -485,19 +500,19 @@ } void VRDisplay::OnRequestSessionReturned( - device::mojom::blink::XRPresentationConnectionPtr connection) { + device::mojom::blink::XRSessionPtr session) { pending_present_request_ = false; - if (connection) { - vr_presentation_provider_.Bind(std::move(connection->provider)); + if (session && session->connection) { + vr_presentation_provider_.Bind(std::move(session->connection->provider)); vr_presentation_provider_.set_connection_error_handler( WTF::Bind(&VRDisplay::OnPresentationProviderConnectionError, WrapWeakPersistent(this))); frame_transport_ = new XRFrameTransport(); frame_transport_->BindSubmitFrameClient( - std::move(connection->client_request)); + std::move(session->connection->client_request)); frame_transport_->SetTransportOptions( - std::move(connection->transport_options)); + std::move(session->connection->transport_options)); this->BeginPresent(); } else { @@ -512,6 +527,16 @@ } } +void VRDisplay::OnMagicWindowRequestReturned( + device::mojom::blink::XRSessionPtr session) { + if (!session || !session->magic_window_provider) { + // System does not support any kind of magic window. + return; + } + magic_window_provider_.Bind(std::move(session->magic_window_provider)); + RequestVSync(); +} + ScriptPromise VRDisplay::exitPresent(ScriptState* script_state) { DVLOG(1) << __FUNCTION__; ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
diff --git a/third_party/blink/renderer/modules/vr/vr_display.h b/third_party/blink/renderer/modules/vr/vr_display.h index 17d6d01..bfd14698 100644 --- a/third_party/blink/renderer/modules/vr/vr_display.h +++ b/third_party/blink/renderer/modules/vr/vr_display.h
@@ -108,7 +108,6 @@ friend class VRController; VRDisplay(NavigatorVR*, - device::mojom::blink::VRMagicWindowProviderPtr, device::mojom::blink::VRDisplayHostPtr, device::mojom::blink::VRDisplayClientRequest); @@ -124,8 +123,8 @@ VRController* Controller(); private: - void OnRequestSessionReturned( - device::mojom::blink::XRPresentationConnectionPtr connection); + void OnRequestSessionReturned(device::mojom::blink::XRSessionPtr session); + void OnMagicWindowRequestReturned(device::mojom::blink::XRSessionPtr session); void OnConnected(); void OnDisconnected(); @@ -219,6 +218,7 @@ bool did_log_requestPresent_ = false; device::mojom::blink::VRMagicWindowProviderPtr magic_window_provider_; + device::mojom::blink::VRDisplayHostPtr display_; bool present_image_needs_copy_ = false;
diff --git a/third_party/blink/renderer/modules/webaudio/audio_destination_node.h b/third_party/blink/renderer/modules/webaudio/audio_destination_node.h index 6267e9f..c143f86 100644 --- a/third_party/blink/renderer/modules/webaudio/audio_destination_node.h +++ b/third_party/blink/renderer/modules/webaudio/audio_destination_node.h
@@ -64,9 +64,20 @@ virtual double SampleRate() const = 0; virtual unsigned long MaxChannelCount() const = 0; + void ContextDestroyed() { is_execution_context_destroyed_ = true; } + bool IsExecutionContextDestroyed() const { + return is_execution_context_destroyed_; + } + protected: // The number of sample frames processed by the destination so far. size_t current_sample_frame_; + + private: + // True if the execution context is being destroyed. If this is true, the + // destination ndoe must avoid checking for or accessing the execution + // context. + bool is_execution_context_destroyed_ = false; }; // -----------------------------------------------------------------------------
diff --git a/third_party/blink/renderer/modules/webaudio/base_audio_context.cc b/third_party/blink/renderer/modules/webaudio/base_audio_context.cc index 1b6fa474..f30bd88 100644 --- a/third_party/blink/renderer/modules/webaudio/base_audio_context.cc +++ b/third_party/blink/renderer/modules/webaudio/base_audio_context.cc
@@ -120,6 +120,14 @@ if (destination_node_) { destination_node_->Handler().Initialize(); + // TODO(crbug.com/863951). The audio thread needs some things from the + // destination handler like the currentTime. But the audio thread + // shouldn't access the |destination_node_| since it's an Oilpan object. + // Thus, get the destination handler, a non-oilpan object, so we can get + // the items directly from the handler instead of through the destination + // node. + destination_handler_ = &destination_node_->GetAudioDestinationHandler(); + // The AudioParams in the listener need access to the destination node, so // only create the listener if the destination node exists. listener_ = AudioListener::Create(*this); @@ -160,6 +168,7 @@ } void BaseAudioContext::ContextDestroyed(ExecutionContext*) { + destination()->GetAudioDestinationHandler().ContextDestroyed(); Uninitialize(); }
diff --git a/third_party/blink/renderer/modules/webaudio/base_audio_context.h b/third_party/blink/renderer/modules/webaudio/base_audio_context.h index 9da78b3..f55e32c4 100644 --- a/third_party/blink/renderer/modules/webaudio/base_audio_context.h +++ b/third_party/blink/renderer/modules/webaudio/base_audio_context.h
@@ -127,16 +127,12 @@ AudioDestinationNode* destination() const; size_t CurrentSampleFrame() const { - return destination_node_->GetAudioDestinationHandler().CurrentSampleFrame(); + return destination_handler_->CurrentSampleFrame(); } - double currentTime() const { - return destination_node_->GetAudioDestinationHandler().CurrentTime(); - } + double currentTime() const { return destination_handler_->CurrentTime(); } - float sampleRate() const { - return destination_node_->GetAudioDestinationHandler().SampleRate(); - } + float sampleRate() const { return destination_handler_->SampleRate(); } String state() const; AudioContextState ContextState() const { return context_state_; } @@ -445,6 +441,9 @@ AudioIOPosition output_position_; + // The handler associated with the above |destination_node_|. + scoped_refptr<AudioDestinationHandler> destination_handler_; + Member<AudioWorklet> audio_worklet_; // In order to update some information (e.g. current frame) in
diff --git a/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc b/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc index 3e8126d..673121b 100644 --- a/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc +++ b/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc
@@ -265,6 +265,12 @@ render_thread_.reset(); + // If the execution context has been destroyed, there's no where to + // send the notification, so just return. + if (IsExecutionContextDestroyed()) { + return; + } + // The OfflineAudioContext might be gone. if (Context() && Context()->GetExecutionContext()) Context()->FireCompletionEvent();
diff --git a/third_party/blink/renderer/modules/xr/xr.cc b/third_party/blink/renderer/modules/xr/xr.cc index 1b4aace..58c4a8a 100644 --- a/third_party/blink/renderer/modules/xr/xr.cc +++ b/third_party/blink/renderer/modules/xr/xr.cc
@@ -127,13 +127,12 @@ // here. Upon calling SetClient in the constructor we should receive one call // for each XRDevice that was already connected at the time. void XR::OnDisplayConnected( - device::mojom::blink::VRMagicWindowProviderPtr magic_window_provider, device::mojom::blink::VRDisplayHostPtr display, device::mojom::blink::VRDisplayClientRequest client_request, device::mojom::blink::VRDisplayInfoPtr display_info) { XRDevice* xr_device = - new XRDevice(this, std::move(magic_window_provider), std::move(display), - std::move(client_request), std::move(display_info)); + new XRDevice(this, std::move(display), std::move(client_request), + std::move(display_info)); devices_.push_back(xr_device);
diff --git a/third_party/blink/renderer/modules/xr/xr.h b/third_party/blink/renderer/modules/xr/xr.h index 19c80ba..4c6efa8c 100644 --- a/third_party/blink/renderer/modules/xr/xr.h +++ b/third_party/blink/renderer/modules/xr/xr.h
@@ -37,8 +37,7 @@ ScriptPromise requestDevice(ScriptState*); // XRServiceClient overrides. - void OnDisplayConnected(device::mojom::blink::VRMagicWindowProviderPtr, - device::mojom::blink::VRDisplayHostPtr, + void OnDisplayConnected(device::mojom::blink::VRDisplayHostPtr, device::mojom::blink::VRDisplayClientRequest, device::mojom::blink::VRDisplayInfoPtr) override;
diff --git a/third_party/blink/renderer/modules/xr/xr_device.cc b/third_party/blink/renderer/modules/xr/xr_device.cc index 1a883f2..42656d7 100644 --- a/third_party/blink/renderer/modules/xr/xr_device.cc +++ b/third_party/blink/renderer/modules/xr/xr_device.cc
@@ -40,12 +40,10 @@ XRDevice::XRDevice( XR* xr, - device::mojom::blink::VRMagicWindowProviderPtr magic_window_provider, device::mojom::blink::VRDisplayHostPtr display, device::mojom::blink::VRDisplayClientRequest client_request, device::mojom::blink::VRDisplayInfoPtr display_info) : xr_(xr), - magic_window_provider_(std::move(magic_window_provider)), display_(std::move(display)), display_client_binding_(this, std::move(client_request)) { SetXRDisplayInfo(std::move(display_info)); @@ -208,14 +206,17 @@ void XRDevice::OnRequestSessionReturned( ScriptPromiseResolver* resolver, const XRSessionCreationOptions& options, - device::mojom::blink::XRPresentationConnectionPtr connection) { - if (!connection) { + device::mojom::blink::XRSessionPtr session_ptr) { + if (!session_ptr) { DOMException* exception = DOMException::Create( DOMExceptionCode::kNotAllowedError, kRequestFailed); resolver->Reject(exception); return; } + if (session_ptr->magic_window_provider) + magic_window_provider_.Bind(std::move(session_ptr->magic_window_provider)); + XRPresentationContext* output_context = nullptr; if (options.hasOutputContext()) { output_context = options.outputContext(); @@ -232,7 +233,8 @@ sessions_.insert(session); if (options.immersive()) { - frameProvider()->BeginImmersiveSession(session, std::move(connection)); + frameProvider()->BeginImmersiveSession(session, + std::move(session_ptr->connection)); } resolver->Resolve(session);
diff --git a/third_party/blink/renderer/modules/xr/xr_device.h b/third_party/blink/renderer/modules/xr/xr_device.h index ac7df4f..f4db8e21 100644 --- a/third_party/blink/renderer/modules/xr/xr_device.h +++ b/third_party/blink/renderer/modules/xr/xr_device.h
@@ -28,7 +28,6 @@ public: XRDevice(XR*, - device::mojom::blink::VRMagicWindowProviderPtr, device::mojom::blink::VRDisplayHostPtr, device::mojom::blink::VRDisplayClientRequest, device::mojom::blink::VRDisplayInfoPtr); @@ -84,10 +83,9 @@ const char* checkSessionSupport(const XRSessionCreationOptions&) const; - void OnRequestSessionReturned( - ScriptPromiseResolver* resolver, - const XRSessionCreationOptions& options, - device::mojom::blink::XRPresentationConnectionPtr connection); + void OnRequestSessionReturned(ScriptPromiseResolver* resolver, + const XRSessionCreationOptions& options, + device::mojom::blink::XRSessionPtr session); void OnSupportsSessionReturned(ScriptPromiseResolver* resolver, bool supports_session);
diff --git a/third_party/blink/renderer/modules/xr/xr_frame_provider.cc b/third_party/blink/renderer/modules/xr/xr_frame_provider.cc index ce5e8c46..3fefb14 100644 --- a/third_party/blink/renderer/modules/xr/xr_frame_provider.cc +++ b/third_party/blink/renderer/modules/xr/xr_frame_provider.cc
@@ -200,8 +200,10 @@ void XRFrameProvider::ScheduleNonImmersiveFrame() { TRACE_EVENT0("gpu", __FUNCTION__); DCHECK(!immersive_session_) - << "Scheduling should be done via the immersive session if present."; - DCHECK(device_->xrMagicWindowProviderPtr()); + << "Scheduling should be done via the exclusive session if present."; + DCHECK(device_->xrMagicWindowProviderPtr()) + << "If there is no exclusive session, it should be impossible to " + "schedule a frame without a MagicWindowProvider."; if (pending_non_immersive_vsync_) return;
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn index 45fc93c..ee19530 100644 --- a/third_party/blink/renderer/platform/BUILD.gn +++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1732,6 +1732,7 @@ "feature_policy/feature_policy_test.cc", "fonts/android/font_cache_android_test.cc", "fonts/bitmap_glyphs_blacklist_test.cc", + "fonts/cursor_position_test.cc", "fonts/font_cache_test.cc", "fonts/font_description_test.cc", "fonts/font_family_test.cc", @@ -1972,6 +1973,7 @@ "testing/blink_perf_test_suite.cc", "testing/blink_perf_test_suite.h", "testing/run_all_perf_tests.cc", + "testing/shape_result_perf_test.cc", "testing/shaping_line_breaker_perf_test.cc", ]
diff --git a/third_party/blink/renderer/platform/exported/web_font.cc b/third_party/blink/renderer/platform/exported/web_font.cc index 1d1c3d7..4e1dd3c 100644 --- a/third_party/blink/renderer/platform/exported/web_font.cc +++ b/third_party/blink/renderer/platform/exported/web_font.cc
@@ -108,7 +108,8 @@ } int WebFont::OffsetForPosition(const WebTextRun& run, float position) const { - return private_->GetFont().OffsetForPosition(run, position, true); + return private_->GetFont().OffsetForPosition( + run, position, IncludePartialGlyphs, DontBreakGlyphs); } WebFloatRect WebFont::SelectionRectForText(const WebTextRun& run,
diff --git a/third_party/blink/renderer/platform/exported/web_surface_layer_bridge.cc b/third_party/blink/renderer/platform/exported/web_surface_layer_bridge.cc index e434b44..8910562d 100644 --- a/third_party/blink/renderer/platform/exported/web_surface_layer_bridge.cc +++ b/third_party/blink/renderer/platform/exported/web_surface_layer_bridge.cc
@@ -11,8 +11,10 @@ std::unique_ptr<WebSurfaceLayerBridge> WebSurfaceLayerBridge::Create( WebLayerTreeView* layer_tree_view, - WebSurfaceLayerBridgeObserver* observer) { - return std::make_unique<SurfaceLayerBridge>(layer_tree_view, observer); + WebSurfaceLayerBridgeObserver* observer, + cc::UpdateSubmissionStateCB update_submission_state_callback) { + return std::make_unique<SurfaceLayerBridge>( + layer_tree_view, observer, std::move(update_submission_state_callback)); } WebSurfaceLayerBridge::~WebSurfaceLayerBridge() = default;
diff --git a/third_party/blink/renderer/platform/fonts/cursor_position_test.cc b/third_party/blink/renderer/platform/fonts/cursor_position_test.cc new file mode 100644 index 0000000..2ffd9a8 --- /dev/null +++ b/third_party/blink/renderer/platform/fonts/cursor_position_test.cc
@@ -0,0 +1,457 @@ +// 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 "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/platform/file_path_conversion.h" +#include "third_party/blink/public/platform/web_string.h" +#include "third_party/blink/renderer/platform/fonts/font.h" +#include "third_party/blink/renderer/platform/fonts/font_description.h" +#include "third_party/blink/renderer/platform/testing/font_test_helpers.h" +#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" + +using blink::test::CreateTestFont; + +namespace blink { + +class CursorPositionTest : public ::testing::Test { + public: + enum FontName { + ahem, + amiri, + megalopolis, + roboto, + }; + + float GetWidth(FontName font_name, + const String& text, + bool ltr, + int start = 0, + int end = -1) { + FontDescription::VariantLigatures ligatures( + FontDescription::kEnabledLigaturesState); + Font font = CreateTestFont("TestFont", + test::PlatformTestDataPath(font_path[font_name]), + 100, &ligatures); + TextRun text_run( + text, /* xpos */ 0, /* expansion */ 0, + TextRun::kAllowTrailingExpansion | TextRun::kForbidLeadingExpansion, + ltr ? TextDirection::kLtr : TextDirection::kRtl, false); + + if (end == -1) + end = text_run.length(); + DCHECK_GE(start, 0); + DCHECK_LE(start, static_cast<int>(text_run.length())); + DCHECK_GE(end, -1); + DCHECK_LE(end, static_cast<int>(text_run.length())); + FloatRect rect = + font.SelectionRectForText(text_run, FloatPoint(), 12, start, end); + return rect.Width(); + } + + int GetCharacter(FontName font_name, + const String& text, + bool ltr, + float position, + bool partial) { + FontDescription::VariantLigatures ligatures( + FontDescription::kEnabledLigaturesState); + Font font = CreateTestFont("TestFont", + test::PlatformTestDataPath(font_path[font_name]), + 100, &ligatures); + TextRun text_run( + text, /* xpos */ 0, /* expansion */ 0, + TextRun::kAllowTrailingExpansion | TextRun::kForbidLeadingExpansion, + ltr ? TextDirection::kLtr : TextDirection::kRtl, false); + + return font.OffsetForPosition( + text_run, position, partial ? IncludePartialGlyphs : OnlyFullGlyphs, + BreakGlyphs); + } + + private: + std::map<FontName, String> font_path = { + {ahem, "Ahem.woff"}, + {amiri, "third_party/Amiri/amiri_arabic.woff2"}, + {megalopolis, "third_party/MEgalopolis/MEgalopolisExtra.woff"}, + {roboto, "third_party/Roboto/roboto-regular.woff2"}, + }; +}; + +TEST_F(CursorPositionTest, LTRMouse) { + EXPECT_EQ(GetCharacter(ahem, "X", true, 0, false), 0); + EXPECT_EQ(GetCharacter(ahem, "X", true, 0, true), 0); + EXPECT_EQ(GetCharacter(ahem, "X", true, 10, false), 0); + EXPECT_EQ(GetCharacter(ahem, "X", true, 10, true), 0); + EXPECT_EQ(GetCharacter(ahem, "X", true, 60, false), 0); + EXPECT_EQ(GetCharacter(ahem, "X", true, 60, true), 1); + EXPECT_EQ(GetCharacter(ahem, "X", true, 100, false), 1); + EXPECT_EQ(GetCharacter(ahem, "X", true, 100, true), 1); + + EXPECT_EQ(GetCharacter(ahem, "XXX", true, 10, false), 0); + EXPECT_EQ(GetCharacter(ahem, "XXX", true, 10, true), 0); + EXPECT_EQ(GetCharacter(ahem, "XXX", true, 60, false), 0); + EXPECT_EQ(GetCharacter(ahem, "XXX", true, 60, true), 1); + EXPECT_EQ(GetCharacter(ahem, "XXX", true, 100, true), 1); + EXPECT_EQ(GetCharacter(ahem, "XXX", true, 100, false), 1); + EXPECT_EQ(GetCharacter(ahem, "XXX", true, 125, true), 1); + EXPECT_EQ(GetCharacter(ahem, "XXX", true, 125, true), 1); + EXPECT_EQ(GetCharacter(ahem, "XXX", true, 151, false), 1); + EXPECT_EQ(GetCharacter(ahem, "XXX", true, 151, true), 2); + EXPECT_EQ(GetCharacter(ahem, "XXX", true, 175, false), 1); + EXPECT_EQ(GetCharacter(ahem, "XXX", true, 175, true), 2); +} + +TEST_F(CursorPositionTest, LTRLigatureMouse) { + const float kFUWidth = GetWidth(megalopolis, "FU", true); + const float kRAWidth = GetWidth(megalopolis, "RA", true); + + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, kFUWidth / 4 - 1, false), + 0); + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, kFUWidth / 4 - 1, true), 0); + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, kFUWidth / 4 + 1, false), + 0); + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, kFUWidth / 4 + 1, true), 1); + + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, kFUWidth / 2 - 1, false), + 0); + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, kFUWidth / 2 - 1, true), 1); + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, kFUWidth / 2 + 1, false), + 1); + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, kFUWidth / 2 + 1, true), 1); + + EXPECT_EQ( + GetCharacter(megalopolis, "FURA", true, kFUWidth * 3 / 4 - 1, false), 1); + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, kFUWidth * 3 / 4 - 1, true), + 1); + EXPECT_EQ( + GetCharacter(megalopolis, "FURA", true, kFUWidth * 3 / 4 + 1, false), 1); + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, kFUWidth * 3 / 4 + 1, true), + 2); + + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, kFUWidth - 1, false), 1); + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, kFUWidth - 1, true), 2); + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, kFUWidth + 1, false), 2); + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, kFUWidth + 1, true), 2); + + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, kFUWidth + kRAWidth / 4 - 1, + false), + 2); + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, kFUWidth + kRAWidth / 4 - 1, + true), + 2); + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, kFUWidth + kRAWidth / 4 + 1, + false), + 2); + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, kFUWidth + kRAWidth / 4 + 1, + true), + 3); + + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, kFUWidth + kRAWidth / 2 - 1, + false), + 2); + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, kFUWidth + kRAWidth / 2 - 1, + true), + 3); + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, kFUWidth + kRAWidth / 2 + 1, + false), + 3); + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, kFUWidth + kRAWidth / 2 + 1, + true), + 3); + + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, + kFUWidth + kRAWidth * 3 / 4 - 1, false), + 3); + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, + kFUWidth + kRAWidth * 3 / 4 - 1, true), + 3); + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, + kFUWidth + kRAWidth * 3 / 4 + 1, false), + 3); + EXPECT_EQ(GetCharacter(megalopolis, "FURA", true, + kFUWidth + kRAWidth * 3 / 4 + 1, true), + 4); + + EXPECT_EQ( + GetCharacter(megalopolis, "FURA", true, kFUWidth + kRAWidth - 1, false), + 3); + EXPECT_EQ( + GetCharacter(megalopolis, "FURA", true, kFUWidth + kRAWidth - 1, true), + 4); + EXPECT_EQ( + GetCharacter(megalopolis, "FURA", true, kFUWidth + kRAWidth + 1, false), + 4); + EXPECT_EQ( + GetCharacter(megalopolis, "FURA", true, kFUWidth + kRAWidth + 1, true), + 4); +} + +TEST_F(CursorPositionTest, RTLMouse) { + // The widths below are from the final shaped version, not from the single + // characters. They were extracted with "hb-shape --font-size=100" + + EXPECT_EQ(GetCharacter(ahem, "X", false, 0, false), 1); + EXPECT_EQ(GetCharacter(ahem, "X", false, 0, true), 1); + EXPECT_EQ(GetCharacter(ahem, "X", false, 10, false), 0); + EXPECT_EQ(GetCharacter(ahem, "X", false, 10, true), 1); + EXPECT_EQ(GetCharacter(ahem, "X", false, 49, false), 0); + EXPECT_EQ(GetCharacter(ahem, "X", false, 49, true), 1); + EXPECT_EQ(GetCharacter(ahem, "X", false, 51, false), 0); + EXPECT_EQ(GetCharacter(ahem, "X", false, 51, true), 0); + EXPECT_EQ(GetCharacter(ahem, "X", false, 60, false), 0); + EXPECT_EQ(GetCharacter(ahem, "X", false, 60, true), 0); + EXPECT_EQ(GetCharacter(ahem, "X", false, 100, false), 0); + EXPECT_EQ(GetCharacter(ahem, "X", false, 100, true), 0); + + const float kAloneTaWidth = GetWidth(amiri, u"ت", false); + EXPECT_EQ(GetCharacter(amiri, u"ت", false, 0, false), 1); + EXPECT_EQ(GetCharacter(amiri, u"ت", false, 0, true), 1); + EXPECT_EQ(GetCharacter(amiri, u"ت", false, kAloneTaWidth / 4, false), 0); + EXPECT_EQ(GetCharacter(amiri, u"ت", false, kAloneTaWidth / 4, true), 1); + EXPECT_EQ(GetCharacter(amiri, u"ت", false, kAloneTaWidth * 2 / 3, false), 0); + EXPECT_EQ(GetCharacter(amiri, u"ت", false, kAloneTaWidth * 2 / 3, true), 0); + EXPECT_EQ(GetCharacter(amiri, u"ت", false, 2 * kAloneTaWidth, false), 0); + EXPECT_EQ(GetCharacter(amiri, u"ت", false, 2 * kAloneTaWidth, true), 0); + + const float kAboveTaWidth = 10; + const float kAboveKhaWidth = 55; + EXPECT_EQ(GetCharacter(amiri, u"تخ", false, 0, false), 2); + EXPECT_EQ(GetCharacter(amiri, u"تخ", false, 0, true), 2); + EXPECT_EQ(GetCharacter(amiri, u"تخ", false, kAboveTaWidth / 4, false), 1); + EXPECT_EQ(GetCharacter(amiri, u"تخ", false, kAboveTaWidth / 4, true), 2); + EXPECT_EQ(GetCharacter(amiri, u"تخ", false, kAboveTaWidth * 2 / 3, false), 1); + EXPECT_EQ(GetCharacter(amiri, u"تخ", false, kAboveTaWidth * 2 / 3, true), 1); + EXPECT_EQ(GetCharacter(amiri, u"تخ", false, kAboveTaWidth + 1, false), 0); + EXPECT_EQ(GetCharacter(amiri, u"تخ", false, kAboveTaWidth + 1, true), 1); + EXPECT_EQ(GetCharacter(amiri, u"تخ", false, + kAboveTaWidth + kAboveKhaWidth / 4, false), + 0); + EXPECT_EQ(GetCharacter(amiri, u"تخ", false, + kAboveTaWidth + kAboveKhaWidth / 4, true), + 1); + EXPECT_EQ(GetCharacter(amiri, u"تخ", false, + kAboveTaWidth + kAboveKhaWidth * 2 / 3, false), + 0); + EXPECT_EQ(GetCharacter(amiri, u"تخ", false, + kAboveTaWidth + kAboveKhaWidth * 2 / 3, true), + 0); + EXPECT_EQ(GetCharacter(amiri, u"تخ", false, + kAboveTaWidth + kAboveKhaWidth + 1, false), + 0); + EXPECT_EQ(GetCharacter(amiri, u"تخ", false, + kAboveTaWidth + kAboveKhaWidth + 1, true), + 0); + EXPECT_EQ(GetCharacter(amiri, u"تخ", false, + 2 * (kAboveTaWidth + kAboveKhaWidth), false), + 0); + EXPECT_EQ(GetCharacter(amiri, u"تخ", false, + 2 * (kAboveTaWidth + kAboveKhaWidth), true), + 0); +} + +TEST_F(CursorPositionTest, RTLLigatureMouse) { + const float kFUWidth = GetWidth(megalopolis, "FU", true); + const float kRAWidth = GetWidth(megalopolis, "RA", true); + + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, kFUWidth / 4 - 1, false), + 3); + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, kFUWidth / 4 - 1, true), + 4); + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, kFUWidth / 4 + 1, false), + 3); + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, kFUWidth / 4 + 1, true), + 3); + + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, kFUWidth / 2 - 1, false), + 3); + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, kFUWidth / 2 - 1, true), + 3); + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, kFUWidth / 2 + 1, false), + 2); + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, kFUWidth / 2 + 1, true), + 3); + + EXPECT_EQ( + GetCharacter(megalopolis, "ARUF", false, kFUWidth * 3 / 4 - 1, false), 2); + EXPECT_EQ( + GetCharacter(megalopolis, "ARUF", false, kFUWidth * 3 / 4 - 1, true), 3); + EXPECT_EQ( + GetCharacter(megalopolis, "ARUF", false, kFUWidth * 3 / 4 + 1, false), 2); + EXPECT_EQ( + GetCharacter(megalopolis, "ARUF", false, kFUWidth * 3 / 4 + 1, true), 2); + + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, kFUWidth - 1, false), 2); + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, kFUWidth - 1, true), 2); + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, kFUWidth + 1, false), 1); + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, kFUWidth + 1, true), 2); + + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, + kFUWidth + kRAWidth / 4 - 1, false), + 1); + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, + kFUWidth + kRAWidth / 4 - 1, true), + 2); + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, + kFUWidth + kRAWidth / 4 + 1, false), + 1); + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, + kFUWidth + kRAWidth / 4 + 1, true), + 1); + + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, + kFUWidth + kRAWidth / 2 - 1, false), + 1); + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, + kFUWidth + kRAWidth / 2 - 1, true), + 1); + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, + kFUWidth + kRAWidth / 2 + 1, false), + 0); + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, + kFUWidth + kRAWidth / 2 + 1, true), + 1); + + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, + kFUWidth + kRAWidth * 3 / 4 - 1, false), + 0); + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, + kFUWidth + kRAWidth * 3 / 4 - 1, true), + 1); + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, + kFUWidth + kRAWidth * 3 / 4 + 1, false), + 0); + EXPECT_EQ(GetCharacter(megalopolis, "ARUF", false, + kFUWidth + kRAWidth * 3 / 4 + 1, true), + 0); + + EXPECT_EQ( + GetCharacter(megalopolis, "ARUF", false, kFUWidth + kRAWidth - 1, false), + 0); + EXPECT_EQ( + GetCharacter(megalopolis, "ARUF", false, kFUWidth + kRAWidth - 1, true), + 0); + EXPECT_EQ( + GetCharacter(megalopolis, "ARUF", false, kFUWidth + kRAWidth + 1, false), + 0); + EXPECT_EQ( + GetCharacter(megalopolis, "ARUF", false, kFUWidth + kRAWidth + 1, true), + 0); +} + +TEST_F(CursorPositionTest, LTRText) { + EXPECT_EQ(GetWidth(ahem, "X", true, 0, 1), 100); + + EXPECT_EQ(GetWidth(ahem, "XXX", true, 0, 1), 100); + EXPECT_EQ(GetWidth(ahem, "XXX", true, 0, 2), 200); + EXPECT_EQ(GetWidth(ahem, "XXX", true, 0, 3), 300); + EXPECT_EQ(GetWidth(ahem, "XXX", true, 1, 2), 100); + EXPECT_EQ(GetWidth(ahem, "XXX", true, 1, 3), 200); + EXPECT_EQ(GetWidth(ahem, "XXX", true, 2, 3), 100); +} + +TEST_F(CursorPositionTest, LTRLigature) { + const float kFUWidth = GetWidth(megalopolis, "FU", true); + const float kRAWidth = GetWidth(megalopolis, "RA", true); + + EXPECT_NEAR(GetWidth(megalopolis, "FURA", true, 0, 1), kFUWidth / 2, 1.0); + EXPECT_NEAR(GetWidth(megalopolis, "FURA", true, 0, 2), kFUWidth, 1.0); + EXPECT_NEAR(GetWidth(megalopolis, "FURA", true, 0, 3), + kFUWidth + kRAWidth / 2, 1.0); + EXPECT_NEAR(GetWidth(megalopolis, "FURA", true, 0, 4), kFUWidth + kRAWidth, + 1.0); + + EXPECT_NEAR(GetWidth(megalopolis, "FURA", true, 1, 2), kFUWidth / 2, 1.0); + EXPECT_NEAR(GetWidth(megalopolis, "FURA", true, 1, 3), + kFUWidth / 2 + kRAWidth / 2, 1.0); + EXPECT_NEAR(GetWidth(megalopolis, "FURA", true, 1, 4), + kFUWidth / 2 + kRAWidth, 1.0); + + EXPECT_NEAR(GetWidth(megalopolis, "FURA", true, 2, 3), kRAWidth / 2, 1.0); + EXPECT_NEAR(GetWidth(megalopolis, "FURA", true, 2, 4), kRAWidth, 1.0); + + EXPECT_NEAR(GetWidth(megalopolis, "FURA", true, 3, 4), kRAWidth / 2, 1.0); + + const float kFFIWidth = GetWidth(roboto, "ffi", true); + const float kFFWidth = GetWidth(roboto, "ff", true); + const float kIWidth = GetWidth(roboto, u"î", true); + + EXPECT_NEAR(GetWidth(roboto, "ffi", true, 0, 1), kFFIWidth / 3.0, 1.0); + EXPECT_NEAR(GetWidth(roboto, "ffi", true, 0, 2), kFFIWidth * 2.0 / 3.0, 1.0); + EXPECT_NEAR(GetWidth(roboto, "ffi", true, 0, 3), kFFIWidth, 1.0); + EXPECT_NEAR(GetWidth(roboto, "ffi", true, 1, 2), kFFIWidth / 3.0, 1.0); + EXPECT_NEAR(GetWidth(roboto, "ffi", true, 1, 3), kFFIWidth * 2.0 / 3.0, 1.0); + EXPECT_NEAR(GetWidth(roboto, "ffi", true, 2, 3), kFFIWidth / 3.0, 1.0); + + EXPECT_NEAR(GetWidth(roboto, u"ffî", true, 0, 1), kFFWidth / 2.0, 1.0); + EXPECT_NEAR(GetWidth(roboto, u"ffî", true, 0, 2), kFFWidth, 1.0); + EXPECT_NEAR(GetWidth(roboto, u"ffî", true, 0, 3), kFFWidth + kIWidth, 1.0); + EXPECT_NEAR(GetWidth(roboto, u"ffî", true, 1, 2), kFFWidth / 2.0, 1.0); + EXPECT_NEAR(GetWidth(roboto, u"ffî", true, 1, 3), kFFWidth / 2.0 + kIWidth, + 1.0); + EXPECT_NEAR(GetWidth(roboto, u"ffî", true, 2, 3), kIWidth, 1.0); +} + +TEST_F(CursorPositionTest, RTLText) { + // The widths below are from the final shaped version, not from the single + // characters. They were extracted with "hb-shape --font-size=100" + + EXPECT_EQ(GetWidth(amiri, u"ت", false, 0, 1), 93); + + const float kAboveKhaWidth = 55; + const float kAboveTaWidth = 10; + EXPECT_NEAR(GetWidth(amiri, u"تخ", false, 0, 1), kAboveKhaWidth, 1.0); + EXPECT_NEAR(GetWidth(amiri, u"تخ", false, 0, 2), + kAboveKhaWidth + kAboveTaWidth, 1.0); + EXPECT_NEAR(GetWidth(amiri, u"تخ", false, 1, 2), kAboveTaWidth, 1.0); + + const float kTaWidth = 75; + const float kKhaWidth = 7; + const float kLamWidth = 56; + const float kAlifWidth = 22; + EXPECT_NEAR(GetWidth(amiri, u"الخط", false, 0, 1), kAlifWidth, 1.0); + EXPECT_NEAR(GetWidth(amiri, u"الخط", false, 0, 2), kAlifWidth + kLamWidth, + 1.0); + EXPECT_NEAR(GetWidth(amiri, u"الخط", false, 0, 3), + kAlifWidth + kLamWidth + kKhaWidth, 1.0); + EXPECT_NEAR(GetWidth(amiri, u"الخط", false, 0, 4), + kAlifWidth + kLamWidth + kKhaWidth + kTaWidth, 1.0); + EXPECT_NEAR(GetWidth(amiri, u"الخط", false, 1, 2), kLamWidth, 1.0); + EXPECT_NEAR(GetWidth(amiri, u"الخط", false, 1, 3), kLamWidth + kKhaWidth, + 1.0); + EXPECT_NEAR(GetWidth(amiri, u"الخط", false, 1, 4), + kLamWidth + kKhaWidth + kTaWidth, 1.0); + EXPECT_NEAR(GetWidth(amiri, u"الخط", false, 2, 3), kKhaWidth, 1.0); + EXPECT_NEAR(GetWidth(amiri, u"الخط", false, 2, 4), kKhaWidth + kTaWidth, 1.0); + EXPECT_NEAR(GetWidth(amiri, u"الخط", false, 3, 4), kTaWidth, 1.0); + + const float kMeemWidth = GetWidth(amiri, u"م", false); + EXPECT_EQ(GetWidth(amiri, u"مَ", false, 0, 1), kMeemWidth); + EXPECT_EQ(GetWidth(amiri, u"مَ", false, 0, 2), kMeemWidth); + EXPECT_EQ(GetWidth(amiri, u"مَ", false, 1, 2), kMeemWidth); +} + +TEST_F(CursorPositionTest, RTLLigature) { + const float kFUWidth = GetWidth(megalopolis, "FU", true); + const float kRAWidth = GetWidth(megalopolis, "RA", true); + + EXPECT_NEAR(GetWidth(megalopolis, "ARUF", false, 0, 1), kRAWidth / 2, 1.0); + EXPECT_NEAR(GetWidth(megalopolis, "ARUF", false, 0, 2), kRAWidth, 1.0); + EXPECT_NEAR(GetWidth(megalopolis, "ARUF", false, 0, 3), + kRAWidth + kFUWidth / 2, 1.0); + EXPECT_NEAR(GetWidth(megalopolis, "ARUF", false, 0, 4), kRAWidth + kFUWidth, + 1.0); + + EXPECT_NEAR(GetWidth(megalopolis, "ARUF", false, 1, 2), kRAWidth / 2, 1.0); + EXPECT_NEAR(GetWidth(megalopolis, "ARUF", false, 1, 3), + kRAWidth / 2 + kFUWidth / 2, 1.0); + EXPECT_NEAR(GetWidth(megalopolis, "ARUF", false, 1, 4), + kRAWidth / 2 + kFUWidth, 1.0); + + EXPECT_NEAR(GetWidth(megalopolis, "ARUF", false, 2, 3), kFUWidth / 2, 1.0); + EXPECT_NEAR(GetWidth(megalopolis, "ARUF", false, 2, 4), kFUWidth, 1.0); + + EXPECT_NEAR(GetWidth(megalopolis, "ARUF", false, 3, 4), kFUWidth / 2, 1.0); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/font.cc b/third_party/blink/renderer/platform/fonts/font.cc index 6c1378c..140c9e34 100644 --- a/third_party/blink/renderer/platform/fonts/font.cc +++ b/third_party/blink/renderer/platform/fonts/font.cc
@@ -390,10 +390,11 @@ int Font::OffsetForPosition(const TextRun& run, float x_float, - bool include_partial_glyphs) const { + IncludePartialGlyphsOption partial_glyphs, + BreakGlyphsOption break_glyphs) const { FontCachePurgePreventer purge_preventer; CachingWordShaper shaper(*this); - return shaper.OffsetForPosition(run, x_float, include_partial_glyphs); + return shaper.OffsetForPosition(run, x_float, partial_glyphs, break_glyphs); } ShapeCache* Font::GetShapeCache() const {
diff --git a/third_party/blink/renderer/platform/fonts/font.h b/third_party/blink/renderer/platform/fonts/font.h index d2fad11..de3a27c 100644 --- a/third_party/blink/renderer/platform/fonts/font.h +++ b/third_party/blink/renderer/platform/fonts/font.h
@@ -143,7 +143,8 @@ int OffsetForPosition(const TextRun&, float position, - bool include_partial_glyphs) const; + IncludePartialGlyphsOption, + BreakGlyphsOption) const; FloatRect SelectionRectForText(const TextRun&, const FloatPoint&, int h,
diff --git a/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.cc b/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.cc index 0006c16d..41f5fa9c 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.cc
@@ -80,13 +80,15 @@ return total_width; } -int CachingWordShaper::OffsetForPosition(const TextRun& run, - float target_x, - bool include_partial_glyphs) { +int CachingWordShaper::OffsetForPosition( + const TextRun& run, + float target_x, + IncludePartialGlyphsOption partial_glyphs, + BreakGlyphsOption break_glyphs) { ShapeResultBuffer buffer; ShapeResultsForRun(GetShapeCache(), &font_, run, &buffer); - return buffer.OffsetForPosition(run, target_x, include_partial_glyphs); + return buffer.OffsetForPosition(run, target_x, partial_glyphs, break_glyphs); } void CachingWordShaper::FillResultBuffer(const TextRunPaintInfo& run_info, @@ -101,7 +103,7 @@ ShapeResultBuffer buffer; float total_width = ShapeResultsForRun(GetShapeCache(), &font_, run, &buffer); - return buffer.GetCharacterRange(run.Direction(), total_width, from, to); + return buffer.GetCharacterRange(total_width, run.Direction(), from, to); } Vector<CharacterRange> CachingWordShaper::IndividualCharacterRanges(
diff --git a/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.h b/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.h index ab719be..1adfe22 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.h +++ b/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.h
@@ -55,7 +55,8 @@ FloatRect* glyph_bounds); int OffsetForPosition(const TextRun&, float target_x, - bool include_partial_glyphs); + IncludePartialGlyphsOption, + BreakGlyphsOption); void FillResultBuffer(const TextRunPaintInfo&, ShapeResultBuffer*); CharacterRange GetCharacterRange(const TextRun&, unsigned from, unsigned to);
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harf_buzz_shaper.cc b/third_party/blink/renderer/platform/fonts/shaping/harf_buzz_shaper.cc index 0a23914..f9e4c5c 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/harf_buzz_shaper.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/harf_buzz_shaper.cc
@@ -48,6 +48,7 @@ #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h" #include "third_party/blink/renderer/platform/fonts/small_caps_iterator.h" #include "third_party/blink/renderer/platform/fonts/utf16_text_iterator.h" +#include "third_party/blink/renderer/platform/text/text_break_iterator.h" #include "third_party/blink/renderer/platform/wtf/compiler.h" #include "third_party/blink/renderer/platform/wtf/deque.h" #include "third_party/blink/renderer/platform/wtf/math_extras.h" @@ -337,10 +338,13 @@ // Here we need to specify glyph positions. BufferSlice next_slice; for (const BufferSlice* current_slice = &slice;;) { + Vector<unsigned> graphemes; + GraphemesClusterList(text_, current_slice->start_character_index, + current_slice->num_characters, &graphemes); ShapeResult::RunInfo* run = new ShapeResult::RunInfo( current_font, direction, canvas_rotation, script, current_slice->start_character_index, current_slice->num_glyphs, - current_slice->num_characters); + current_slice->num_characters, graphemes); shape_result->InsertRun(base::WrapUnique(run), current_slice->start_glyph_index, current_slice->num_glyphs, range_data->buffer);
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harf_buzz_shaper_test.cc b/third_party/blink/renderer/platform/fonts/shaping/harf_buzz_shaper_test.cc index bd338bf0..33f63fd 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/harf_buzz_shaper_test.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/harf_buzz_shaper_test.cc
@@ -673,16 +673,24 @@ Font ahem = CreateAhem(10); scoped_refptr<ShapeResult> result = SplitRun(shaper.Shape(&ahem, TextDirection::kLtr), 2); - EXPECT_EQ(data.offset_ltr, result->OffsetForPosition(data.position, false)); - EXPECT_EQ(data.hit_test_ltr, result->OffsetForPosition(data.position, true)); + EXPECT_EQ(data.offset_ltr, + result->OffsetForPosition(data.position, OnlyFullGlyphs, + DontBreakGlyphs)); + EXPECT_EQ(data.hit_test_ltr, + result->OffsetForPosition(data.position, IncludePartialGlyphs, + DontBreakGlyphs)); EXPECT_EQ(data.fit_ltr_ltr, result->OffsetToFit(data.position, TextDirection::kLtr)); EXPECT_EQ(data.fit_ltr_rtl, result->OffsetToFit(data.position, TextDirection::kRtl)); result = SplitRun(shaper.Shape(&ahem, TextDirection::kRtl), 3); - EXPECT_EQ(data.offset_rtl, result->OffsetForPosition(data.position, false)); - EXPECT_EQ(data.hit_test_rtl, result->OffsetForPosition(data.position, true)); + EXPECT_EQ(data.offset_rtl, + result->OffsetForPosition(data.position, OnlyFullGlyphs, + DontBreakGlyphs)); + EXPECT_EQ(data.hit_test_rtl, + result->OffsetForPosition(data.position, IncludePartialGlyphs, + DontBreakGlyphs)); EXPECT_EQ(data.fit_rtl_ltr, result->OffsetToFit(data.position, TextDirection::kLtr)); EXPECT_EQ(data.fit_rtl_rtl, @@ -728,14 +736,15 @@ // A Value-Parameterized Test class to test OffsetForPosition() with // |include_partial_glyphs| parameter. -class IncludePartialGlyphs : public HarfBuzzShaperTest, - public testing::WithParamInterface<bool> {}; +class IncludePartialGlyphsTest : public HarfBuzzShaperTest, + public ::testing::WithParamInterface<bool> {}; INSTANTIATE_TEST_CASE_P(OffsetForPositionTest, - IncludePartialGlyphs, - testing::Bool()); + IncludePartialGlyphsTest, + ::testing::Bool()); -TEST_P(IncludePartialGlyphs, OffsetForPositionMatchesPositionForOffsetLatin) { +TEST_P(IncludePartialGlyphsTest, + OffsetForPositionMatchesPositionForOffsetLatin) { String string = To16Bit("Hello World!", 12); TextDirection direction = TextDirection::kLtr; @@ -743,35 +752,39 @@ scoped_refptr<ShapeResult> result = shaper.Shape(&font, direction); bool include_partial_glyphs = GetParam(); - EXPECT_EQ(0u, result->OffsetForPosition(result->PositionForOffset(0), - include_partial_glyphs)); - EXPECT_EQ(1u, result->OffsetForPosition(result->PositionForOffset(1), - include_partial_glyphs)); - EXPECT_EQ(2u, result->OffsetForPosition(result->PositionForOffset(2), - include_partial_glyphs)); - EXPECT_EQ(3u, result->OffsetForPosition(result->PositionForOffset(3), - include_partial_glyphs)); - EXPECT_EQ(4u, result->OffsetForPosition(result->PositionForOffset(4), - include_partial_glyphs)); - EXPECT_EQ(5u, result->OffsetForPosition(result->PositionForOffset(5), - include_partial_glyphs)); - EXPECT_EQ(6u, result->OffsetForPosition(result->PositionForOffset(6), - include_partial_glyphs)); - EXPECT_EQ(7u, result->OffsetForPosition(result->PositionForOffset(7), - include_partial_glyphs)); - EXPECT_EQ(8u, result->OffsetForPosition(result->PositionForOffset(8), - include_partial_glyphs)); - EXPECT_EQ(9u, result->OffsetForPosition(result->PositionForOffset(9), - include_partial_glyphs)); + IncludePartialGlyphsOption partial = + include_partial_glyphs ? IncludePartialGlyphs : OnlyFullGlyphs; + + EXPECT_EQ(0u, result->OffsetForPosition(result->PositionForOffset(0), partial, + DontBreakGlyphs)); + EXPECT_EQ(1u, result->OffsetForPosition(result->PositionForOffset(1), partial, + DontBreakGlyphs)); + EXPECT_EQ(2u, result->OffsetForPosition(result->PositionForOffset(2), partial, + DontBreakGlyphs)); + EXPECT_EQ(3u, result->OffsetForPosition(result->PositionForOffset(3), partial, + DontBreakGlyphs)); + EXPECT_EQ(4u, result->OffsetForPosition(result->PositionForOffset(4), partial, + DontBreakGlyphs)); + EXPECT_EQ(5u, result->OffsetForPosition(result->PositionForOffset(5), partial, + DontBreakGlyphs)); + EXPECT_EQ(6u, result->OffsetForPosition(result->PositionForOffset(6), partial, + DontBreakGlyphs)); + EXPECT_EQ(7u, result->OffsetForPosition(result->PositionForOffset(7), partial, + DontBreakGlyphs)); + EXPECT_EQ(8u, result->OffsetForPosition(result->PositionForOffset(8), partial, + DontBreakGlyphs)); + EXPECT_EQ(9u, result->OffsetForPosition(result->PositionForOffset(9), partial, + DontBreakGlyphs)); EXPECT_EQ(10u, result->OffsetForPosition(result->PositionForOffset(10), - include_partial_glyphs)); + partial, DontBreakGlyphs)); EXPECT_EQ(11u, result->OffsetForPosition(result->PositionForOffset(11), - include_partial_glyphs)); + partial, DontBreakGlyphs)); EXPECT_EQ(12u, result->OffsetForPosition(result->PositionForOffset(12), - include_partial_glyphs)); + partial, DontBreakGlyphs)); } -TEST_P(IncludePartialGlyphs, OffsetForPositionMatchesPositionForOffsetArabic) { +TEST_P(IncludePartialGlyphsTest, + OffsetForPositionMatchesPositionForOffsetArabic) { UChar arabic_string[] = {0x628, 0x64A, 0x629}; TextDirection direction = TextDirection::kRtl; @@ -779,36 +792,43 @@ scoped_refptr<ShapeResult> result = shaper.Shape(&font, direction); bool include_partial_glyphs = GetParam(); - EXPECT_EQ(0u, result->OffsetForPosition(result->PositionForOffset(0), - include_partial_glyphs)); - EXPECT_EQ(1u, result->OffsetForPosition(result->PositionForOffset(1), - include_partial_glyphs)); - EXPECT_EQ(2u, result->OffsetForPosition(result->PositionForOffset(2), - include_partial_glyphs)); - EXPECT_EQ(3u, result->OffsetForPosition(result->PositionForOffset(3), - include_partial_glyphs)); + IncludePartialGlyphsOption partial = + include_partial_glyphs ? IncludePartialGlyphs : OnlyFullGlyphs; + + EXPECT_EQ(0u, result->OffsetForPosition(result->PositionForOffset(0), partial, + DontBreakGlyphs)); + EXPECT_EQ(1u, result->OffsetForPosition(result->PositionForOffset(1), partial, + DontBreakGlyphs)); + EXPECT_EQ(2u, result->OffsetForPosition(result->PositionForOffset(2), partial, + DontBreakGlyphs)); + EXPECT_EQ(3u, result->OffsetForPosition(result->PositionForOffset(3), partial, + DontBreakGlyphs)); } -TEST_P(IncludePartialGlyphs, OffsetForPositionMatchesPositionForOffsetMixed) { +TEST_P(IncludePartialGlyphsTest, + OffsetForPositionMatchesPositionForOffsetMixed) { UChar mixed_string[] = {0x628, 0x64A, 0x629, 0xE20, 0x65E5, 0x62}; HarfBuzzShaper shaper(String(mixed_string, 6)); scoped_refptr<ShapeResult> result = shaper.Shape(&font, TextDirection::kLtr); bool include_partial_glyphs = GetParam(); - EXPECT_EQ(0u, result->OffsetForPosition(result->PositionForOffset(0), - include_partial_glyphs)); - EXPECT_EQ(1u, result->OffsetForPosition(result->PositionForOffset(1), - include_partial_glyphs)); - EXPECT_EQ(2u, result->OffsetForPosition(result->PositionForOffset(2), - include_partial_glyphs)); - EXPECT_EQ(3u, result->OffsetForPosition(result->PositionForOffset(3), - include_partial_glyphs)); - EXPECT_EQ(4u, result->OffsetForPosition(result->PositionForOffset(4), - include_partial_glyphs)); - EXPECT_EQ(5u, result->OffsetForPosition(result->PositionForOffset(5), - include_partial_glyphs)); - EXPECT_EQ(6u, result->OffsetForPosition(result->PositionForOffset(6), - include_partial_glyphs)); + IncludePartialGlyphsOption partial = + include_partial_glyphs ? IncludePartialGlyphs : OnlyFullGlyphs; + + EXPECT_EQ(0u, result->OffsetForPosition(result->PositionForOffset(0), partial, + DontBreakGlyphs)); + EXPECT_EQ(1u, result->OffsetForPosition(result->PositionForOffset(1), partial, + DontBreakGlyphs)); + EXPECT_EQ(2u, result->OffsetForPosition(result->PositionForOffset(2), partial, + DontBreakGlyphs)); + EXPECT_EQ(3u, result->OffsetForPosition(result->PositionForOffset(3), partial, + DontBreakGlyphs)); + EXPECT_EQ(4u, result->OffsetForPosition(result->PositionForOffset(4), partial, + DontBreakGlyphs)); + EXPECT_EQ(5u, result->OffsetForPosition(result->PositionForOffset(5), partial, + DontBreakGlyphs)); + EXPECT_EQ(6u, result->OffsetForPosition(result->PositionForOffset(6), partial, + DontBreakGlyphs)); } TEST_F(HarfBuzzShaperTest, CachedOffsetPositionMappingForOffsetLatin) {
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc index d3316a8..88e9c01 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
@@ -101,90 +101,221 @@ return XPositionForOffset(offset, adjust_mid_cluster); } +unsigned ShapeResult::RunInfo::NumGraphemes(unsigned start, + unsigned end) const { + if (graphemes_.size() == 0 || start >= num_characters_) + return 0; + DCHECK_LT(start, end); + DCHECK_LE(end, num_characters_); + return graphemes_[end - 1] - graphemes_[start] + 1; +} + +// XPositionForOffset returns the X position (in layout space) from the +// beginning of the run to the beginning of the cluster of glyphs for X +// character. +// For RTL, beginning means the right most side of the cluster. +// Characters may spawn multiple glyphs. +// In the case that multiple characters form a Unicode grapheme cluster, we +// distribute the width of the grapheme cluster among the number of cursor +// positions returned by cursor-based TextBreakIterator. float ShapeResult::RunInfo::XPositionForOffset( unsigned offset, AdjustMidCluster adjust_mid_cluster) const { DCHECK_LE(offset, num_characters_); const unsigned num_glyphs = glyph_data_.size(); - unsigned glyph_index = 0; - float position = 0; - if (Rtl()) { - while (glyph_index < num_glyphs && - glyph_data_[glyph_index].character_index > offset) { - position += glyph_data_[glyph_index].advance; - ++glyph_index; - } - // If |glyph_index| is at the end, the glyph for |offset| is missing, along - // with all glyphs before it. We can't adjust position to the start - // direction. - if (glyph_index == num_glyphs) - return position; - // Adjust offset if it's not on the cluster boundary. In RTL, this means - // that the adjusted position is the left side of the character. - if (adjust_mid_cluster == AdjustMidCluster::kToEnd && - glyph_data_[glyph_index].character_index < offset) { - return position; - } - // For RTL, we need to return the right side boundary of the character. - // Add advance of glyphs which are part of the character. - while (glyph_index < num_glyphs - 1 && - glyph_data_[glyph_index].character_index == - glyph_data_[glyph_index + 1].character_index) { - position += glyph_data_[glyph_index].advance; - ++glyph_index; - } - position += glyph_data_[glyph_index].advance; - } else { - while (glyph_index < num_glyphs && - glyph_data_[glyph_index].character_index < offset) { - position += glyph_data_[glyph_index].advance; - ++glyph_index; - } - // Adjust offset if it's not on the cluster boundary. - if (adjust_mid_cluster == AdjustMidCluster::kToStart && glyph_index && - (glyph_index < num_glyphs ? glyph_data_[glyph_index].character_index - : num_characters_) > offset) { - offset = glyph_data_[--glyph_index].character_index; - for (; glyph_data_[glyph_index].character_index == offset; - --glyph_index) { - position -= glyph_data_[glyph_index].advance; - if (!glyph_index) - break; + + // In this context, a glyph sequence is a sequence of glyphs that shares the + // same character_index and therefore represent the same interval of source + // characters. glyph_sequence_start marks the character index at the beginning + // of the interval of characters for which this glyph sequence was formed as + // the result of shaping; glyph_sequence_end marks the end of the interval of + // characters for which this glyph sequence was formed. [glyph_sequence_start, + // glyph_sequence_end) is inclusive on the start for the range of characters + // of the current sequence we are visiting. + unsigned glyph_sequence_start = 0; + unsigned glyph_sequence_end = num_characters_; + // the advance of the current glyph sequence. + float glyph_sequence_advance = 0.0; + // the accumulated advance up to the current glyph sequence. + float accumulated_position = 0; + + if (!Rtl()) { + for (unsigned i = 0; i < num_glyphs; ++i) { + unsigned current_glyph_char_index = glyph_data_[i].character_index; + // If this glyph is still part of the same glyph sequence for the grapheme + // cluster at character index glyph_sequence_start, add its advance to the + // glyph_sequence's advance. + if (glyph_sequence_start == current_glyph_char_index) { + glyph_sequence_advance += glyph_data_[i].advance; + continue; } + + // We are about to move out of a glyph sequence that contains offset, so + // the current glyph sequence is the one we are looking for. + if (glyph_sequence_start <= offset && offset < current_glyph_char_index) { + glyph_sequence_end = current_glyph_char_index; + break; + } + + glyph_sequence_start = current_glyph_char_index; + // Since we always update glyph_sequence_end when we break, set this to + // last_character in case this is the final iteration of the loop. + glyph_sequence_end = num_characters_; + accumulated_position += glyph_sequence_advance; + glyph_sequence_advance = glyph_data_[i].advance; + } + + } else { + glyph_sequence_start = glyph_sequence_end = num_characters_; + + for (unsigned i = 0; i < num_glyphs; ++i) { + unsigned current_glyph_char_index = glyph_data_[i].character_index; + // If this glyph is still part of the same glyph sequence for the grapheme + // cluster at character index glyph_sequence_start, add its advance to the + // glyph_sequence's advance. + if (glyph_sequence_start == current_glyph_char_index) { + glyph_sequence_advance += glyph_data_[i].advance; + continue; + } + + // We are about to move out of a glyph sequence that contains offset, so + // the current glyph sequence is the one we are looking for. + if (glyph_sequence_start <= offset && offset < glyph_sequence_end) { + break; + } + + glyph_sequence_end = glyph_sequence_start; + glyph_sequence_start = current_glyph_char_index; + accumulated_position += glyph_sequence_advance; + glyph_sequence_advance = glyph_data_[i].advance; } } - return position; + + // This is the character position inside the glyph sequence. + unsigned pos = offset - glyph_sequence_start; + + // We calculate the number of Unicode grapheme clusters (actually cursor + // position stops) on the subset of characters. We use this to divide + // glyph_sequence_advance by the number of unicode grapheme clusters this + // glyph sequence was shaped for, and thus linearly interpolate the cursor + // position based on accumulated position and a fraction of + // glyph_sequence_advance. + unsigned graphemes = NumGraphemes(glyph_sequence_start, glyph_sequence_end); + if (graphemes > 1) { + DCHECK_GE(glyph_sequence_end, glyph_sequence_start); + unsigned size = glyph_sequence_end - glyph_sequence_start; + unsigned place = graphemes * pos / size; + pos -= place; + glyph_sequence_advance = glyph_sequence_advance / graphemes; + if (Rtl()) { + accumulated_position += glyph_sequence_advance * (graphemes - place - 1); + } else { + accumulated_position += glyph_sequence_advance * place; + } + } + + // Re-adapt based on adjust_mid_cluster. On LTR, if we want AdjustToEnd and + // offset is not at the beginning, we need to jump to the right side of the + // grapheme. On RTL, if we want AdjustToStart and offset is not at the end, we + // need to jump to the left side of the grapheme. + if (!Rtl() && adjust_mid_cluster == AdjustMidCluster::kToEnd && pos != 0) { + accumulated_position += glyph_sequence_advance; + } else if (Rtl() && adjust_mid_cluster == AdjustMidCluster::kToEnd && + pos != 0) { + accumulated_position -= glyph_sequence_advance; + } + + if (Rtl()) { + // For RTL, we return the right side. + accumulated_position += glyph_sequence_advance; + } + + return accumulated_position; } +// In some ways, CharacterIndexForXPosition is the reverse of +// XPositionForOffset. Given a target pixel distance on screen space, returns a +// character index for the end of the interval that would be included within +// that space. @break_glyphs_option controls wether we use grapheme information +// to break glyphs into grapheme clusters and return character that are a part +// of a glyph. void ShapeResult::RunInfo::CharacterIndexForXPosition( float target_x, + BreakGlyphsOption break_glyphs_option, GlyphIndexResult* result) const { DCHECK(target_x >= 0 && target_x <= width_); const unsigned num_glyphs = glyph_data_.size(); - float current_x = 0; - unsigned glyph_index = 0; - while (true) { - unsigned current_character_index = glyph_data_[glyph_index].character_index; - float current_advance = glyph_data_[glyph_index].advance; - unsigned next_glyph_index = glyph_index + 1; - while (next_glyph_index < num_glyphs && - current_character_index == - glyph_data_[next_glyph_index].character_index) - current_advance += glyph_data_[next_glyph_index++].advance; - float next_x = current_x + current_advance; - if (target_x < next_x || next_glyph_index == num_glyphs) { - result->glyph_index = glyph_index; - result->next_glyph_index = next_glyph_index; - result->character_index = current_character_index; - result->origin_x = current_x; - result->advance = current_advance; - return; - } - current_x = next_x; - glyph_index = next_glyph_index; + result->origin_x = 0; + unsigned glyph_sequence_start = 0; + unsigned glyph_sequence_end = num_characters_; + result->advance = 0.0; + + // on RTL, we start on the last index. + if (Rtl()) { + glyph_sequence_start = glyph_sequence_end = num_characters_; } - NOTREACHED(); + + for (unsigned i = 0; i < num_glyphs; ++i) { + unsigned current_glyph_char_index = glyph_data_[i].character_index; + // If the glyph is part of the same sequence, we just accumulate the + // advance. + if (glyph_sequence_start == current_glyph_char_index) { + result->advance += glyph_data_[i].advance; + continue; + } + + // Since we are about to move to the next sequence of glyphs, check if + // the target falls inside it, if it does, we found our sequence. + if (result->origin_x + result->advance > target_x) { + if (!Rtl()) { + glyph_sequence_end = current_glyph_char_index; + } + break; + } + + // Move to the next sequence, update accumulated_x. + if (Rtl()) { + // Notice that on RTL, as we move to our next sequence, we already know + // both bounds. Nonetheless, we still need to move forward so we can + // capture all glyphs of this sequence. + glyph_sequence_end = glyph_sequence_start; + } + glyph_sequence_start = current_glyph_char_index; + result->origin_x += result->advance; + result->advance = glyph_data_[i].advance; + } + + // At this point, we have [glyph_sequence_start, glyph_sequence_end) + // representing a sequence of glyphs, of size glyph_sequence_advance. We + // linearly interpolate how much space each character takes, and reduce the + // sequence to only match the character size. + if (break_glyphs_option == BreakGlyphs) { + int graphemes = NumGraphemes(glyph_sequence_start, glyph_sequence_end); + if (graphemes > 1) { + float unit_size = result->advance / graphemes; + unsigned step = floor((target_x - result->origin_x) / unit_size); + unsigned glyph_length = glyph_sequence_end - glyph_sequence_start; + unsigned final_size = floor(glyph_length / graphemes); + result->origin_x += unit_size * step; + if (!Rtl()) { + glyph_sequence_start += step; + glyph_sequence_end = glyph_sequence_start + final_size; + } else { + glyph_sequence_end -= step; + glyph_sequence_start = glyph_sequence_end - final_size; + } + result->advance = unit_size; + } + } + + if (!Rtl()) { + result->left_character_index = glyph_sequence_start; + result->right_character_index = glyph_sequence_end; + } else { + result->left_character_index = glyph_sequence_end; + result->right_character_index = glyph_sequence_start; + } } void HarfBuzzRunGlyphData::SetGlyphAndPositions(uint16_t glyph_id, @@ -322,107 +453,111 @@ return StartIndexForResult(); } -// Returns the offset of the character of |result| for LTR. -unsigned ShapeResult::OffsetLtr(const GlyphIndexResult& result) const { - DCHECK(IsLtr(Direction())); - return result.characters_on_left_runs + result.character_index; -} - -// Returns the offset of the character of |result| for RTL. -unsigned ShapeResult::OffsetRtl(const GlyphIndexResult& result, float x) const { - DCHECK(IsRtl(Direction())); - if (!result.IsInRun()) - return NumCharacters() - result.characters_on_left_runs; - // In RTL, the boundary belongs to the left character. This subtle difference - // allows round trips between OffsetForPoint and PointForOffset. - if (UNLIKELY(x == result.origin_x)) - return OffsetLeftRtl(result); - return NumCharacters() - result.characters_on_left_runs - - runs_[result.run_index]->num_characters_ + result.character_index; -} - -// Returns the offset of the character on the right of |result| for LTR. -unsigned ShapeResult::OffsetRightLtr(const GlyphIndexResult& result) const { - DCHECK(IsLtr(Direction())); - if (result.run_index >= runs_.size()) - return NumCharacters(); - const RunInfo& run = *runs_[result.run_index]; - return result.characters_on_left_runs + - (result.next_glyph_index < run.glyph_data_.size() - ? run.glyph_data_[result.next_glyph_index].character_index - : run.num_characters_); -} - -// Returns the offset of the character on the left of |result| for RTL. -unsigned ShapeResult::OffsetLeftRtl(const GlyphIndexResult& result) const { - DCHECK(IsRtl(Direction())); - if (!result.glyph_index) - return NumCharacters() - result.characters_on_left_runs; - const RunInfo& run = *runs_[result.run_index]; - return NumCharacters() - result.characters_on_left_runs - - run.num_characters_ + - run.glyph_data_[result.glyph_index - 1].character_index; -} - // If the position is outside of the result, returns the start or the end offset // depends on the position. void ShapeResult::OffsetForPosition(float target_x, + BreakGlyphsOption break_glyphs_option, GlyphIndexResult* result) const { - if (target_x <= 0) + if (target_x <= 0) { + if (Rtl()) { + result->left_character_index = result->right_character_index = + NumCharacters(); + } return; + } - unsigned characters_so_far = 0; + unsigned characters_so_far = Rtl() ? NumCharacters() : 0; float current_x = 0; + for (unsigned i = 0; i < runs_.size(); ++i) { const RunInfo* run = runs_[i].get(); if (!run) continue; + if (Rtl()) + characters_so_far -= runs_[i]->num_characters_; float next_x = current_x + run->width_; float offset_for_run = target_x - current_x; if (offset_for_run >= 0 && offset_for_run < run->width_) { // The x value in question is within this script run. - run->CharacterIndexForXPosition(offset_for_run, result); + run->CharacterIndexForXPosition(offset_for_run, break_glyphs_option, + result); result->run_index = i; result->characters_on_left_runs = characters_so_far; + if (Rtl()) { + result->left_character_index = + characters_so_far + result->left_character_index; + result->right_character_index = + characters_so_far + result->right_character_index; + DCHECK_LE(result->left_character_index, NumCharacters() + 1); + DCHECK_LE(result->right_character_index, NumCharacters()); + } else { + result->left_character_index += characters_so_far; + result->right_character_index += characters_so_far; + DCHECK_LE(result->left_character_index, NumCharacters()); + DCHECK_LE(result->right_character_index, NumCharacters() + 1); + } result->origin_x += current_x; - DCHECK_LE(result->characters_on_left_runs + result->character_index, - NumCharacters()); return; } - characters_so_far += run->num_characters_; + if (!Rtl()) + characters_so_far += run->num_characters_; current_x = next_x; } - result->run_index = runs_.size(); - result->characters_on_left_runs = characters_so_far; -} - -unsigned ShapeResult::OffsetForPosition(float x) const { - GlyphIndexResult result; - OffsetForPosition(x, &result); - return IsLtr(Direction()) ? OffsetLtr(result) : OffsetRtl(result, x); -} - -unsigned ShapeResult::OffsetForHitTest(float x) const { - GlyphIndexResult result; - OffsetForPosition(x, &result); - if (IsLtr(Direction())) { - if (result.IsInRun() && x > result.origin_x + result.advance / 2) - return OffsetRightLtr(result); - return OffsetLtr(result); + if (Rtl()) { + result->left_character_index = 0; + result->right_character_index = 0; + } else { + result->left_character_index += characters_so_far; + result->right_character_index += characters_so_far; } - if (result.IsInRun() && x <= result.origin_x + result.advance / 2) - return OffsetLeftRtl(result); - return OffsetRtl(result, x); + + result->run_index = runs_.size() - 1; + result->characters_on_left_runs = characters_so_far; + + DCHECK_LE(result->left_character_index, NumCharacters()); + DCHECK_LE(result->right_character_index, NumCharacters() + 1); +} + +unsigned ShapeResult::OffsetForPosition( + float x, + BreakGlyphsOption break_glyphs_option) const { + GlyphIndexResult result; + OffsetForPosition(x, break_glyphs_option, &result); + + // For LTR, the offset is always the left one. + if (!Rtl()) + return result.left_character_index; + + // For RTL the offset is the right one, except that the interval is open + // on other side. So in case we are exactly at the boundary, we return the + // left index. + if (x == result.origin_x) + return result.left_character_index; + return result.right_character_index; +} + +unsigned ShapeResult::OffsetForHitTest( + float x, + BreakGlyphsOption break_glyphs_option) const { + GlyphIndexResult result; + OffsetForPosition(x, break_glyphs_option, &result); + + if (x - result.origin_x <= result.advance / 2) + return result.left_character_index; + return result.right_character_index; } unsigned ShapeResult::OffsetToFit(float x, TextDirection line_direction) const { GlyphIndexResult result; - OffsetForPosition(x, &result); - if (IsLtr(line_direction)) { - return IsLtr(Direction()) ? OffsetLtr(result) : OffsetLeftRtl(result); - } - return IsRtl(Direction()) ? OffsetRtl(result, x) : OffsetRightLtr(result); + OffsetForPosition(x, DontBreakGlyphs, &result); + + if (IsLtr(line_direction)) + return result.left_character_index; + + if (x == result.origin_x && IsRtl(Direction())) + return result.left_character_index; + return result.right_character_index; } float ShapeResult::PositionForOffset( @@ -799,21 +934,24 @@ // synthesize a run without glyphs. void ShapeResult::InsertRunForIndex(unsigned start_character_index) { DCHECK(runs_.IsEmpty()); + // TODO(fserb): do we need the proper graphemes? + Vector<unsigned> graphemes; runs_.push_back(std::make_unique<RunInfo>( primary_font_.get(), !Rtl() ? HB_DIRECTION_LTR : HB_DIRECTION_RTL, CanvasRotationInVertical::kRegular, HB_SCRIPT_UNKNOWN, - start_character_index, 0, num_characters_)); + start_character_index, 0, num_characters_, graphemes)); } ShapeResult::RunInfo* ShapeResult::InsertRunForTesting( unsigned start_index, unsigned num_characters, TextDirection direction, - Vector<uint16_t> safe_break_offsets) { + Vector<uint16_t> safe_break_offsets, + Vector<unsigned> graphemes) { std::unique_ptr<RunInfo> run = std::make_unique<ShapeResult::RunInfo>( nullptr, IsLtr(direction) ? HB_DIRECTION_LTR : HB_DIRECTION_RTL, CanvasRotationInVertical::kRegular, HB_SCRIPT_COMMON, start_index, - num_characters, num_characters); + num_characters, num_characters, std::move(graphemes)); unsigned i = 0; for (auto& glyph_data : run->glyph_data_) glyph_data.SetGlyphAndPositions(0, i++, 0, FloatSize(), false); @@ -1049,9 +1187,12 @@ const SimpleFontData* font_data = font->PrimaryFont(); // Tab characters are always LTR or RTL, not TTB, even when // isVerticalAnyUpright(). + // We don't pass proper graphemes for tabulation. + Vector<unsigned> graphemes; std::unique_ptr<ShapeResult::RunInfo> run = std::make_unique<RunInfo>( font_data, text_run.Rtl() ? HB_DIRECTION_RTL : HB_DIRECTION_LTR, - CanvasRotationInVertical::kRegular, HB_SCRIPT_COMMON, 0, count, count); + CanvasRotationInVertical::kRegular, HB_SCRIPT_COMMON, 0, count, count, + graphemes); float position = text_run.XPos() + position_offset; float start_position = position; for (unsigned i = 0; i < count; i++) { @@ -1213,7 +1354,7 @@ // TODO(layout-dev): Remove once CharacterPositionData::OffsetForPosition // properly supports RTL. if (Rtl()) - return OffsetForPosition(x); + return OffsetForPosition(x, DontBreakGlyphs); DCHECK(character_position_); return character_position_->OffsetForPosition(x);
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result.h index 0342539..926faed 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.h +++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
@@ -67,6 +67,22 @@ unsigned safe_to_break_before : 1; }; +// There are two options for how OffsetForPosition behaves: +// IncludePartialGlyphs - decides what to do when the position hits more than +// 50% of the glyph. If enabled, we count that glyph, if disable we don't. +enum IncludePartialGlyphsOption { + OnlyFullGlyphs, + IncludePartialGlyphs, +}; + +// BreakGlyphs - allows OffsetForPosition to consider graphemes separations +// inside a glyph. It allows the function to return a point inside a glyph when +// multiple graphemes share a glyph (for example, in a ligature) +enum BreakGlyphsOption { + DontBreakGlyphs, + BreakGlyphs, +}; + class PLATFORM_EXPORT ShapeResult : public RefCounted<ShapeResult> { public: static scoped_refptr<ShapeResult> Create(const Font* font, @@ -124,18 +140,21 @@ // Returns the offset, relative to StartIndexForResult, whose (origin, // origin+advance) contains |x|. - unsigned OffsetForPosition(float x) const; - + unsigned OffsetForPosition(float x, BreakGlyphsOption) const; // Returns the offset whose glyph boundary is nearest to |x|. Depends on // whether |x| is on the left-half or the right-half of the glyph, it // determines the left-boundary or the right-boundary, then computes the // offset from the bidi direction. - unsigned OffsetForHitTest(float x) const; + unsigned OffsetForHitTest(float x, BreakGlyphsOption) const; // Returns the offset that can fit to between |x| and the left or the right // edge. The side of the edge is determined by |line_direction|. unsigned OffsetToFit(float x, TextDirection line_direction) const; - unsigned OffsetForPosition(float x, bool include_partial_glyphs) const { - return !include_partial_glyphs ? OffsetForPosition(x) : OffsetForHitTest(x); + unsigned OffsetForPosition(float x, + IncludePartialGlyphsOption include_partial_glyphs, + BreakGlyphsOption break_glyphs_option) const { + return include_partial_glyphs == OnlyFullGlyphs + ? OffsetForPosition(x, break_glyphs_option) + : OffsetForHitTest(x, break_glyphs_option); } // Returns the position for a given offset, relative to StartIndexForResult. @@ -198,7 +217,8 @@ RunInfo* InsertRunForTesting(unsigned start_index, unsigned num_characters, TextDirection, - Vector<uint16_t> safe_break_offsets = {}); + Vector<uint16_t> safe_break_offsets = {}, + Vector<unsigned> graphemes = {}); #if DCHECK_IS_ON() void CheckConsistency() const; #endif @@ -221,26 +241,21 @@ unsigned run_index = 0; // The total number of characters of runs_[0..run_index - 1]. unsigned characters_on_left_runs = 0; - unsigned character_index = 0; - unsigned glyph_index = 0; - // |next_glyph_index| may not be |glyph_index| + 1 when a cluster is of - // multiple glyphs; i.e., ligatures or combining glyphs. - unsigned next_glyph_index = 0; + + // Those are the left and right character indexes of the group of glyphs + // that were selected by OffsetForPosition. + unsigned left_character_index = 0; + unsigned right_character_index = 0; + // The glyph origin of the glyph. float origin_x = 0; // The advance of the glyph. float advance = 0; - - // True if the position was found on a run. False otherwise. - bool IsInRun() const { return next_glyph_index; } }; - unsigned OffsetLtr(const GlyphIndexResult&) const; - unsigned OffsetRtl(const GlyphIndexResult&, float x) const; - unsigned OffsetRightLtr(const GlyphIndexResult&) const; - unsigned OffsetLeftRtl(const GlyphIndexResult&) const; - - void OffsetForPosition(float target_x, GlyphIndexResult*) const; + void OffsetForPosition(float target_x, + BreakGlyphsOption, + GlyphIndexResult*) const; // Helper class storing a map between offsets and x-positions. // Unlike the RunInfo and GlyphData structures in ShapeResult, which operates
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.cc index 4aaab9f3..1800d807 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.cc
@@ -5,6 +5,7 @@ #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.h" #include "third_party/blink/renderer/platform/fonts/character_range.h" +#include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h" #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h" #include "third_party/blink/renderer/platform/fonts/simple_font_data.h" #include "third_party/blink/renderer/platform/geometry/float_point.h" @@ -27,6 +28,13 @@ return GetCharacterRangeInternal(results, direction, total_width, from, to); } +CharacterRange ShapeResultBuffer::GetCharacterRange(float total_width, + TextDirection direction, + unsigned from, + unsigned to) const { + return GetCharacterRangeInternal(results_, direction, total_width, from, to); +} + CharacterRange ShapeResultBuffer::GetCharacterRangeInternal( const Vector<scoped_refptr<const ShapeResult>, 64>& results, TextDirection direction, @@ -123,13 +131,6 @@ return CharacterRange(to_x, from_x, -min_y, max_y); } -CharacterRange ShapeResultBuffer::GetCharacterRange(TextDirection direction, - float total_width, - unsigned from, - unsigned to) const { - return GetCharacterRangeInternal(results_, direction, total_width, from, to); -} - void ShapeResultBuffer::AddRunInfoRanges(const ShapeResult::RunInfo& run_info, float offset, Vector<CharacterRange>& ranges) { @@ -172,9 +173,11 @@ return ranges; } -int ShapeResultBuffer::OffsetForPosition(const TextRun& run, - float target_x, - bool include_partial_glyphs) const { +int ShapeResultBuffer::OffsetForPosition( + const TextRun& run, + float target_x, + IncludePartialGlyphsOption partial_glyphs, + BreakGlyphsOption break_glyphs) const { unsigned total_offset; if (run.Rtl()) { total_offset = run.length(); @@ -184,8 +187,8 @@ continue; total_offset -= word_result->NumCharacters(); if (target_x >= 0 && target_x <= word_result->Width()) { - int offset_for_word = - word_result->OffsetForPosition(target_x, include_partial_glyphs); + int offset_for_word = word_result->OffsetForPosition( + target_x, partial_glyphs, break_glyphs); return total_offset + offset_for_word; } target_x -= word_result->Width(); @@ -195,8 +198,8 @@ for (const auto& word_result : results_) { if (!word_result) continue; - int offset_for_word = - word_result->OffsetForPosition(target_x, include_partial_glyphs); + int offset_for_word = word_result->OffsetForPosition( + target_x, partial_glyphs, break_glyphs); DCHECK_GE(offset_for_word, 0); total_offset += offset_for_word; if (target_x >= 0 && target_x <= word_result->Width())
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.h index f1092b5..ace7dcd 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.h +++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.h
@@ -33,11 +33,12 @@ bool HasVerticalOffsets() const { return has_vertical_offsets_; } - int OffsetForPosition(const TextRun&, + int OffsetForPosition(const TextRun& run, float target_x, - bool include_partial_glyphs) const; - CharacterRange GetCharacterRange(TextDirection, - float total_width, + IncludePartialGlyphsOption, + BreakGlyphsOption) const; + CharacterRange GetCharacterRange(float total_width, + TextDirection, unsigned from, unsigned to) const; Vector<CharacterRange> IndividualCharacterRanges(TextDirection,
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h index 5d479ea0..3609c766 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h +++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h
@@ -37,6 +37,7 @@ #include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h" #include "third_party/blink/renderer/platform/wtf/allocator.h" #include "third_party/blink/renderer/platform/wtf/noncopyable.h" +#include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink { @@ -72,12 +73,14 @@ hb_script_t script, unsigned start_index, unsigned num_glyphs, - unsigned num_characters) + unsigned num_characters, + Vector<unsigned> graphemes) : font_data_(const_cast<SimpleFontData*>(font)), direction_(dir), canvas_rotation_(canvas_rotation), script_(script), glyph_data_(num_glyphs), + graphemes_(graphemes), start_index_(start_index), num_characters_(num_characters), width_(0.0f) {} @@ -88,6 +91,7 @@ canvas_rotation_(other.canvas_rotation_), script_(other.script_), glyph_data_(other.glyph_data_), + graphemes_(other.graphemes_), start_index_(other.start_index_), num_characters_(other.num_characters_), width_(other.width_) {} @@ -100,12 +104,21 @@ unsigned PreviousSafeToBreakOffset(unsigned) const; float XPositionForVisualOffset(unsigned, AdjustMidCluster) const; float XPositionForOffset(unsigned, AdjustMidCluster) const; - void CharacterIndexForXPosition(float, GlyphIndexResult*) const; + void CharacterIndexForXPosition(float, + BreakGlyphsOption, + GlyphIndexResult*) const; + void SetGlyphAndPositions(unsigned index, + uint16_t glyph_id, + float advance, + float offset_x, + float offset_y); size_t GlyphToCharacterIndex(size_t i) const { return start_index_ + glyph_data_[i].character_index; } + unsigned NumGraphemes(unsigned start, unsigned end) const; + // For memory reporting. size_t ByteSize() const { return sizeof(this) + glyph_data_.size() * sizeof(HarfBuzzRunGlyphData); @@ -159,9 +172,18 @@ auto glyphs = FindGlyphDataRange(start, end); unsigned number_of_glyphs = std::distance(glyphs.begin, glyphs.end); + Vector<unsigned> sub_graphemes; + if (graphemes_.size()) { + sub_graphemes.resize(number_of_characters); + for (unsigned i = 0; i < number_of_characters; ++i) { + sub_graphemes[i] = graphemes_[start + i]; + } + } + auto run = std::make_unique<RunInfo>( font_data_.get(), direction_, canvas_rotation_, script_, - start_index_ + start, number_of_glyphs, number_of_characters); + start_index_ + start, number_of_glyphs, number_of_characters, + std::move(sub_graphemes)); static_assert(base::is_trivially_copyable<HarfBuzzRunGlyphData>::value, "HarfBuzzRunGlyphData should be trivially copyable"); @@ -270,6 +292,11 @@ CanvasRotationInVertical canvas_rotation_; hb_script_t script_; Vector<HarfBuzzRunGlyphData> glyph_data_; + + // graphemes_[i] is the number of graphemes up to (and including) the ith + // character in the run. + Vector<unsigned> graphemes_; + unsigned start_index_; unsigned num_characters_; float width_;
diff --git a/third_party/blink/renderer/platform/graphics/surface_layer_bridge.cc b/third_party/blink/renderer/platform/graphics/surface_layer_bridge.cc index 949bcd8..3aa75b4d 100644 --- a/third_party/blink/renderer/platform/graphics/surface_layer_bridge.cc +++ b/third_party/blink/renderer/platform/graphics/surface_layer_bridge.cc
@@ -4,6 +4,8 @@ #include "third_party/blink/renderer/platform/graphics/surface_layer_bridge.h" +#include <utility> + #include "base/feature_list.h" #include "cc/layers/layer.h" #include "cc/layers/solid_color_layer.h" @@ -21,9 +23,13 @@ namespace blink { -SurfaceLayerBridge::SurfaceLayerBridge(WebLayerTreeView* layer_tree_view, - WebSurfaceLayerBridgeObserver* observer) +SurfaceLayerBridge::SurfaceLayerBridge( + WebLayerTreeView* layer_tree_view, + WebSurfaceLayerBridgeObserver* observer, + cc::UpdateSubmissionStateCB update_submission_state_callback) : observer_(observer), + update_submission_state_callback_( + std::move(update_submission_state_callback)), binding_(this), frame_sink_id_(Platform::Current()->GenerateFrameSinkId()), parent_frame_sink_id_(layer_tree_view ? layer_tree_view->GetFrameSinkId() @@ -118,7 +124,7 @@ } void SurfaceLayerBridge::CreateSurfaceLayer() { - surface_layer_ = cc::SurfaceLayer::Create(); + surface_layer_ = cc::SurfaceLayer::Create(update_submission_state_callback_); // This surface_id is essentially just a placeholder for the real one we will // get in OnFirstSurfaceActivation. We need it so that we properly get a @@ -127,8 +133,12 @@ frame_sink_id_, parent_local_surface_id_allocator_.GetCurrentLocalSurfaceId()); + surface_layer_->SetPrimarySurfaceId(current_surface_id_, + cc::DeadlinePolicy::UseDefaultDeadline()); + surface_layer_->SetStretchContentToFillBounds(true); surface_layer_->SetIsDrawable(true); + surface_layer_->SetMayContainVideo(true); if (observer_) { observer_->RegisterContentsLayer(surface_layer_.get()); @@ -138,8 +148,4 @@ surface_layer_->SetContentsOpaque(false); } -const viz::SurfaceId& SurfaceLayerBridge::GetSurfaceId() const { - return current_surface_id_; -} - } // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/surface_layer_bridge.h b/third_party/blink/renderer/platform/graphics/surface_layer_bridge.h index afb53d3..120b32a6 100644 --- a/third_party/blink/renderer/platform/graphics/surface_layer_bridge.h +++ b/third_party/blink/renderer/platform/graphics/surface_layer_bridge.h
@@ -34,7 +34,10 @@ : public blink::mojom::blink::EmbeddedFrameSinkClient, public WebSurfaceLayerBridge { public: - SurfaceLayerBridge(WebLayerTreeView*, WebSurfaceLayerBridgeObserver*); + SurfaceLayerBridge( + WebLayerTreeView*, + WebSurfaceLayerBridgeObserver*, + cc::UpdateSubmissionStateCB update_submission_state_callback); ~SurfaceLayerBridge() override; void CreateSolidColorLayer(); @@ -48,7 +51,10 @@ void ClearSurfaceId() override; void SetContentsOpaque(bool) override; void CreateSurfaceLayer() override; - const viz::SurfaceId& GetSurfaceId() const override; + + const viz::SurfaceId& GetSurfaceId() const override { + return current_surface_id_; + } private: scoped_refptr<cc::SurfaceLayer> surface_layer_; @@ -56,6 +62,7 @@ // The |observer_| handles unregistering the contents layer on its own. WebSurfaceLayerBridgeObserver* observer_; + cc::UpdateSubmissionStateCB update_submission_state_callback_; viz::ParentLocalSurfaceIdAllocator parent_local_surface_id_allocator_; mojo::Binding<blink::mojom::blink::EmbeddedFrameSinkClient> binding_;
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc index d1a112314..906e20e 100644 --- a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc +++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
@@ -4,6 +4,8 @@ #include "third_party/blink/renderer/platform/graphics/video_frame_submitter.h" +#include <vector> + #include "base/task_runner.h" #include "base/threading/sequenced_task_runner_handle.h" #include "base/trace_event/trace_event.h" @@ -11,7 +13,6 @@ #include "cc/scheduler/video_frame_controller.h" #include "components/viz/common/resources/resource_id.h" #include "components/viz/common/resources/returned_resource.h" -#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" #include "media/base/video_frame.h" #include "services/ui/public/cpp/gpu/context_provider_command_buffer.h" #include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom-blink.h" @@ -50,16 +51,29 @@ } void VideoFrameSubmitter::EnableSubmission( - viz::FrameSinkId id, + viz::SurfaceId id, WebFrameSinkDestroyedCallback frame_sink_destroyed_callback) { // TODO(lethalantidote): Set these fields earlier in the constructor. Will // need to construct VideoFrameSubmitter later in order to do this. - frame_sink_id_ = id; + surface_id_ = id; frame_sink_destroyed_callback_ = frame_sink_destroyed_callback; if (resource_provider_->IsInitialized()) StartSubmitting(); } +void VideoFrameSubmitter::UpdateSubmissionState(bool should_submit) { + should_submit_ = should_submit; + UpdateSubmissionStateInternal(); +} + +void VideoFrameSubmitter::UpdateSubmissionStateInternal() { + if (compositor_frame_sink_) { + compositor_frame_sink_->SetNeedsBeginFrame(is_rendering_ && should_submit_); + if (should_submit_) + SubmitSingleFrame(); + } +} + void VideoFrameSubmitter::StopUsingProvider() { DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_); if (is_rendering_) @@ -72,12 +86,8 @@ DCHECK(is_rendering_); DCHECK(provider_); - if (compositor_frame_sink_) { - // Push out final frame. - SubmitSingleFrame(); - compositor_frame_sink_->SetNeedsBeginFrame(false); - } is_rendering_ = false; + UpdateSubmissionStateInternal(); } void VideoFrameSubmitter::SubmitSingleFrame() { @@ -89,11 +99,13 @@ viz::BeginFrameAck current_begin_frame_ack = viz::BeginFrameAck::CreateManualAckWithDamage(); scoped_refptr<media::VideoFrame> video_frame = provider_->GetCurrentFrame(); - base::SequencedTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&VideoFrameSubmitter::SubmitFrame, - weak_ptr_factory_.GetWeakPtr(), - current_begin_frame_ack, video_frame)); - provider_->PutCurrentFrame(); + if (video_frame) { + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(&VideoFrameSubmitter::SubmitFrame, + weak_ptr_factory_.GetWeakPtr(), + current_begin_frame_ack, video_frame)); + provider_->PutCurrentFrame(); + } } void VideoFrameSubmitter::DidReceiveFrame() { @@ -110,9 +122,10 @@ void VideoFrameSubmitter::StartRendering() { DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_); DCHECK(!is_rendering_); - if (compositor_frame_sink_) - compositor_frame_sink_->SetNeedsBeginFrame(true); is_rendering_ = true; + + if (compositor_frame_sink_) + compositor_frame_sink_->SetNeedsBeginFrame(is_rendering_ && should_submit_); } void VideoFrameSubmitter::Initialize(cc::VideoFrameProvider* provider) { @@ -149,13 +162,13 @@ resource_provider_->Initialize(nullptr, this); } - if (frame_sink_id_.is_valid()) + if (surface_id_.is_valid()) StartSubmitting(); } void VideoFrameSubmitter::StartSubmitting() { DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_); - DCHECK(frame_sink_id_.is_valid()); + DCHECK(surface_id_.is_valid()); mojom::blink::EmbeddedFrameSinkProviderPtr provider; Platform::Current()->GetInterfaceProvider()->GetInterface( @@ -164,25 +177,13 @@ viz::mojom::blink::CompositorFrameSinkClientPtr client; binding_.Bind(mojo::MakeRequest(&client)); provider->CreateCompositorFrameSink( - frame_sink_id_, std::move(client), + surface_id_.frame_sink_id(), std::move(client), mojo::MakeRequest(&compositor_frame_sink_)); compositor_frame_sink_.set_connection_error_handler(base::BindOnce( &VideoFrameSubmitter::OnContextLost, base::Unretained(this))); - if (is_rendering_) - compositor_frame_sink_->SetNeedsBeginFrame(true); - - scoped_refptr<media::VideoFrame> video_frame = provider_->GetCurrentFrame(); - if (video_frame) { - viz::BeginFrameAck current_begin_frame_ack = - viz::BeginFrameAck::CreateManualAckWithDamage(); - base::SequencedTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&VideoFrameSubmitter::SubmitFrame, - weak_ptr_factory_.GetWeakPtr(), - current_begin_frame_ack, video_frame)); - provider_->PutCurrentFrame(); - } + UpdateSubmissionStateInternal(); } void VideoFrameSubmitter::SubmitFrame( @@ -190,10 +191,7 @@ scoped_refptr<media::VideoFrame> video_frame) { TRACE_EVENT0("media", "VideoFrameSubmitter::SubmitFrame"); DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_); - - // The context may have been destroyed between the call being scheduled and it - // running. The lack of compositor_frame_sink_ is used as a sign. - if (!compositor_frame_sink_) + if (!compositor_frame_sink_ || !should_submit_) return; viz::CompositorFrame compositor_frame; @@ -219,15 +217,9 @@ &compositor_frame.resource_list); compositor_frame.render_pass_list.push_back(std::move(render_pass)); - if (compositor_frame.size_in_pixels() != current_size_in_pixels_) { - parent_local_surface_id_allocator_.GenerateId(); - current_size_in_pixels_ = compositor_frame.size_in_pixels(); - } - // TODO(lethalantidote): Address third/fourth arg in SubmitCompositorFrame. compositor_frame_sink_->SubmitCompositorFrame( - parent_local_surface_id_allocator_.GetCurrentLocalSurfaceId(), - std::move(compositor_frame), nullptr, 0); + surface_id_.local_surface_id(), std::move(compositor_frame), nullptr, 0); resource_provider_->ReleaseFrameResources(); waiting_for_compositor_ack_ = true; @@ -236,7 +228,8 @@ void VideoFrameSubmitter::OnBeginFrame(const viz::BeginFrameArgs& args) { TRACE_EVENT0("media", "VideoFrameSubmitter::OnBeginFrame"); DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_); - viz::BeginFrameAck current_begin_frame_ack(args, false); + viz::BeginFrameAck current_begin_frame_ack = + viz::BeginFrameAck(args.source_id, args.sequence_number, false); if (args.type == viz::BeginFrameArgs::MISSED) { compositor_frame_sink_->DidNotProduceFrame(current_begin_frame_ack); return; @@ -280,14 +273,18 @@ } waiting_for_compositor_ack_ = false; - resource_provider_->OnContextLost(); - // |compositor_frame_sink_| should be reset last. compositor_frame_sink_.reset(); + resource_provider_->OnContextLost(); context_provider_callback_.Run( base::BindOnce(&VideoFrameSubmitter::OnReceivedContextProvider, weak_ptr_factory_.GetWeakPtr())); + + // We need to trigger another submit so that surface_id's get propagated + // correctly. If we don't, we don't get any more signals to update the + // submission state. + should_submit_ = true; } void VideoFrameSubmitter::DidReceiveCompositorFrameAck(
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter.h b/third_party/blink/renderer/platform/graphics/video_frame_submitter.h index 0f8d3934..aa95cf0 100644 --- a/third_party/blink/renderer/platform/graphics/video_frame_submitter.h +++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter.h
@@ -5,12 +5,14 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_VIDEO_FRAME_SUBMITTER_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_VIDEO_FRAME_SUBMITTER_H_ +#include <memory> +#include <utility> + #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" #include "components/viz/client/shared_bitmap_reporter.h" #include "components/viz/common/gpu/context_provider.h" #include "components/viz/common/resources/shared_bitmap.h" -#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/system/buffer.h" #include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom-blink.h" @@ -37,7 +39,7 @@ ~VideoFrameSubmitter() override; - bool Rendering() { return is_rendering_; }; + bool Rendering() { return is_rendering_; } cc::VideoFrameProvider* Provider() { return provider_; } mojo::Binding<viz::mojom::blink::CompositorFrameSinkClient>* Binding() { return &binding_; @@ -45,6 +47,7 @@ void SetSink(viz::mojom::blink::CompositorFrameSinkPtr* sink) { compositor_frame_sink_ = std::move(*sink); } + void SetSurfaceId(viz::SurfaceId id) { surface_id_ = id; } void OnReceivedContextProvider( bool, @@ -59,8 +62,8 @@ // WebVideoFrameSubmitter implementation. void Initialize(cc::VideoFrameProvider*) override; void SetRotation(media::VideoRotation) override; - void EnableSubmission(viz::FrameSinkId, - WebFrameSinkDestroyedCallback) override; + void EnableSubmission(viz::SurfaceId, WebFrameSinkDestroyedCallback) override; + void UpdateSubmissionState(bool) override; // viz::ContextLostObserver implementation. void OnContextLost() override; @@ -83,8 +86,11 @@ private: FRIEND_TEST_ALL_PREFIXES(VideoFrameSubmitterTest, ContextLostDuringSubmit); + FRIEND_TEST_ALL_PREFIXES(VideoFrameSubmitterTest, + ShouldSubmitPreventsSubmission); void StartSubmitting(); + void UpdateSubmissionStateInternal(); void SubmitFrame(const viz::BeginFrameAck&, scoped_refptr<media::VideoFrame>); // Pulls frame and submits it to compositor. @@ -97,16 +103,16 @@ scoped_refptr<ui::ContextProviderCommandBuffer> context_provider_; viz::mojom::blink::CompositorFrameSinkPtr compositor_frame_sink_; mojo::Binding<viz::mojom::blink::CompositorFrameSinkClient> binding_; - viz::ParentLocalSurfaceIdAllocator parent_local_surface_id_allocator_; WebContextProviderCallback context_provider_callback_; std::unique_ptr<VideoFrameResourceProvider> resource_provider_; WebFrameSinkDestroyedCallback frame_sink_destroyed_callback_; - viz::FrameSinkId frame_sink_id_; + viz::SurfaceId surface_id_; bool waiting_for_compositor_ack_ = false; bool is_rendering_; + // If we are not on screen, we should not submit. + bool should_submit_ = false; media::VideoRotation rotation_; - gfx::Size current_size_in_pixels_; THREAD_CHECKER(media_thread_checker_);
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc b/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc index addcc897..4512c5f 100644 --- a/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc +++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc
@@ -157,7 +157,15 @@ viz::mojom::blink::CompositorFrameSinkRequest request = mojo::MakeRequest(&submitter_sink); sink_ = std::make_unique<StrictMock<MockCompositorFrameSink>>(&request); + + // By setting the submission state before we set the sink, we can make + // testing easier without having to worry about the first sent frame. + submitter_->UpdateSubmissionState(true); submitter_->SetSink(&submitter_sink); + submitter_->SetSurfaceId(viz::SurfaceId( + viz::FrameSinkId(1, 1), + viz::LocalSurfaceId(11, + base::UnguessableToken::Deserialize(0x111111, 0)))); } protected: @@ -262,6 +270,44 @@ scoped_task_environment_.RunUntilIdle(); } +TEST_F(VideoFrameSubmitterTest, ShouldSubmitPreventsSubmission) { + MakeSubmitter(); + scoped_task_environment_.RunUntilIdle(); + + EXPECT_CALL(*sink_, SetNeedsBeginFrame(false)); + submitter_->UpdateSubmissionState(false); + scoped_task_environment_.RunUntilIdle(); + + EXPECT_CALL(*sink_, SetNeedsBeginFrame(false)); + submitter_->StartRendering(); + scoped_task_environment_.RunUntilIdle(); + + EXPECT_CALL(*sink_, SetNeedsBeginFrame(true)); + EXPECT_CALL(*provider_, GetCurrentFrame()) + .WillOnce(Return(media::VideoFrame::CreateFrame( + media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)), + gfx::Size(8, 8), base::TimeDelta()))); + EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _)); + EXPECT_CALL(*provider_, PutCurrentFrame()); + EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _)); + EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _)); + EXPECT_CALL(*resource_provider_, ReleaseFrameResources()); + submitter_->UpdateSubmissionState(true); + scoped_task_environment_.RunUntilIdle(); + + EXPECT_CALL(*sink_, SetNeedsBeginFrame(false)); + submitter_->UpdateSubmissionState(false); + scoped_task_environment_.RunUntilIdle(); + + EXPECT_CALL(*provider_, GetCurrentFrame()) + .WillOnce(Return(media::VideoFrame::CreateFrame( + media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)), + gfx::Size(8, 8), base::TimeDelta()))); + EXPECT_CALL(*provider_, PutCurrentFrame()); + + submitter_->SubmitSingleFrame(); +} + TEST_F(VideoFrameSubmitterTest, RotationInformationPassedToResourceProvider) { // Check to see if rotation is communicated pre-rendering. MakeSubmitter();
diff --git a/third_party/blink/renderer/platform/testing/shape_result_perf_test.cc b/third_party/blink/renderer/platform/testing/shape_result_perf_test.cc new file mode 100644 index 0000000..008e697d --- /dev/null +++ b/third_party/blink/renderer/platform/testing/shape_result_perf_test.cc
@@ -0,0 +1,170 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/time/time.h" +#include "cc/base/lap_timer.h" + +#include "build/build_config.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/perf/perf_test.h" +#include "third_party/blink/renderer/platform/fonts/font.h" +#include "third_party/blink/renderer/platform/fonts/font_description.h" +#include "third_party/blink/renderer/platform/testing/font_test_helpers.h" +#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" + +using blink::test::CreateTestFont; + +namespace blink { + +static const int kTimeLimitMillis = 3000; +static const int kWarmupRuns = 10000; +static const int kTimeCheckInterval = 1000000; + +class ShapeResultPerfTest { + public: + enum FontName { + ahem, + amiri, + megalopolis, + roboto, + }; + + ShapeResultPerfTest() + : timer(kWarmupRuns, + base::TimeDelta::FromMilliseconds(kTimeLimitMillis), + kTimeCheckInterval) {} + + protected: + TextRun SetupFont(FontName font_name, const String& text, bool ltr) { + FontDescription::VariantLigatures ligatures( + FontDescription::kEnabledLigaturesState); + font = CreateTestFont("TestFont", + test::PlatformTestDataPath(font_path[font_name]), 100, + &ligatures); + + return TextRun( + text, /* xpos */ 0, /* expansion */ 0, + TextRun::kAllowTrailingExpansion | TextRun::kForbidLeadingExpansion, + ltr ? TextDirection::kLtr : TextDirection::kRtl, false); + } + + Font font; + + std::map<FontName, String> font_path = { + {ahem, "Ahem.woff"}, + {amiri, "third_party/Amiri/amiri_arabic.woff2"}, + {megalopolis, "third_party/MEgalopolis/MEgalopolisExtra.woff"}, + {roboto, "third_party/Roboto/roboto-regular.woff2"}, + }; + + cc::LapTimer timer; +}; + +class OffsetForPositionPerfTest : public ShapeResultPerfTest, + public testing::TestWithParam<float> { + public: + void OffsetForPosition(TextRun& run, + IncludePartialGlyphsOption partial, + BreakGlyphsOption breakopt) { + timer.Reset(); + float position = GetParam(); + do { + font.OffsetForPosition(run, position, partial, breakopt); + timer.NextLap(); + } while (!timer.HasTimeLimitExpired()); + } +}; + +class CharacterRangePerfTest : public ShapeResultPerfTest, + public testing::TestWithParam<int> { + public: + void GetCharacter(TextRun& run) { + timer.Reset(); + int endpos = GetParam(); + do { + font.SelectionRectForText(run, FloatPoint(), 100, 0, endpos); + timer.NextLap(); + } while (!timer.HasTimeLimitExpired()); + } +}; + +TEST_P(OffsetForPositionPerfTest, LTROffsetForPositionFullBreak) { + TextRun run = SetupFont(ahem, "FURACOLO", true); + OffsetForPosition(run, OnlyFullGlyphs, BreakGlyphs); + perf_test::PrintResult("OffsetForPositionPerfTest", " LTR full break", "", + timer.LapsPerSecond(), "runs/s", true); +} + +TEST_P(OffsetForPositionPerfTest, LTROffsetForPositionFullDontBreak) { + TextRun run = SetupFont(ahem, "FURACOLO", true); + OffsetForPosition(run, OnlyFullGlyphs, DontBreakGlyphs); + perf_test::PrintResult("OffsetForPositionPerfTest", " LTR full", "", + timer.LapsPerSecond(), "runs/s", true); +} + +TEST_P(OffsetForPositionPerfTest, LTROffsetForPositionIncludePartialBreak) { + TextRun run = SetupFont(ahem, "FURACOLO", true); + OffsetForPosition(run, IncludePartialGlyphs, BreakGlyphs); + perf_test::PrintResult("OffsetForPositionPerfTest", " LTR partial break", "", + timer.LapsPerSecond(), "runs/s", true); +} + +TEST_P(OffsetForPositionPerfTest, LTROffsetForPositionIncludePartialDontBreak) { + TextRun run = SetupFont(ahem, "FURACOLO", true); + OffsetForPosition(run, IncludePartialGlyphs, DontBreakGlyphs); + perf_test::PrintResult("OffsetForPositionPerfTest", " LTR partial", "", + timer.LapsPerSecond(), "runs/s", true); +} + +TEST_P(OffsetForPositionPerfTest, RTLOffsetForPositionFullBreak) { + TextRun run = SetupFont(ahem, "OLOCARUF", false); + OffsetForPosition(run, OnlyFullGlyphs, BreakGlyphs); + perf_test::PrintResult("OffsetForPositionPerfTest", " RTL full break", "", + timer.LapsPerSecond(), "runs/s", true); +} + +TEST_P(OffsetForPositionPerfTest, RTLOffsetForPositionFullDontBreak) { + TextRun run = SetupFont(ahem, "OLOCARUF", false); + OffsetForPosition(run, OnlyFullGlyphs, DontBreakGlyphs); + perf_test::PrintResult("OffsetForPositionPerfTest", " RTL full", "", + timer.LapsPerSecond(), "runs/s", true); +} + +TEST_P(OffsetForPositionPerfTest, RTLOffsetForPositionIncludePartialBreak) { + TextRun run = SetupFont(ahem, "OLOCARUF", false); + OffsetForPosition(run, IncludePartialGlyphs, BreakGlyphs); + perf_test::PrintResult("OffsetForPositionPerfTest", " RTL partial break", "", + timer.LapsPerSecond(), "runs/s", true); +} + +TEST_P(OffsetForPositionPerfTest, RTLOffsetForPositionIncludePartialDontBreak) { + TextRun run = SetupFont(ahem, "OLOCARUF", false); + OffsetForPosition(run, IncludePartialGlyphs, DontBreakGlyphs); + perf_test::PrintResult("OffsetForPositionPerfTest", " RTL partial", "", + timer.LapsPerSecond(), "runs/s", true); +} + +INSTANTIATE_TEST_CASE_P(OffsetForPosition, + OffsetForPositionPerfTest, + testing::Values(0, 10, 60, 100, 200, 350)); + +TEST_P(CharacterRangePerfTest, LTRCharacterForPosition) { + TextRun run = SetupFont(ahem, "FURACOLO", true); + GetCharacter(run); + perf_test::PrintResult("CharacterRangePerfTest", " LTR", "", + timer.LapsPerSecond(), "runs/s", true); +} + +TEST_P(CharacterRangePerfTest, RTLCharacterForPosition) { + TextRun run = SetupFont(ahem, "OLOCARUF", false); + GetCharacter(run); + perf_test::PrintResult("CharacterRangePerfTest", " RTL", "", + timer.LapsPerSecond(), "runs/s", true); +} + +INSTANTIATE_TEST_CASE_P(CharacterRange, + CharacterRangePerfTest, + testing::Values(0, 1, 2, 4, 8)); + +} // namespace blink
diff --git a/third_party/blink/renderer/platform/text/text_break_iterator.cc b/third_party/blink/renderer/platform/text/text_break_iterator.cc index 2373b2f..bc6d101 100644 --- a/third_party/blink/renderer/platform/text/text_break_iterator.cc +++ b/third_party/blink/renderer/platform/text/text_break_iterator.cc
@@ -53,8 +53,7 @@ return num; } -void GraphemesClusterList(const UChar* text, - unsigned text_length, +void GraphemesClusterList(String text, unsigned start, unsigned length, Vector<unsigned>* graphemes) { @@ -62,8 +61,8 @@ if (!length) return; - DCHECK_LE(static_cast<unsigned>(start + length), text_length); - NonSharedCharacterBreakIterator it(&text[start], length); + String substring = text.Substring(start, length); + NonSharedCharacterBreakIterator it(substring); int cursor_pos = it.Next(); unsigned count = 0;
diff --git a/third_party/blink/renderer/platform/text/text_break_iterator.h b/third_party/blink/renderer/platform/text/text_break_iterator.h index a578d46..958e3f8 100644 --- a/third_party/blink/renderer/platform/text/text_break_iterator.h +++ b/third_party/blink/renderer/platform/text/text_break_iterator.h
@@ -365,8 +365,7 @@ // Returns a list of graphemes cluster at each character using character break // rules. -PLATFORM_EXPORT void GraphemesClusterList(const UChar* text, - unsigned text_length, +PLATFORM_EXPORT void GraphemesClusterList(String text, unsigned start, unsigned length, Vector<unsigned>* graphemes);
diff --git a/third_party/blink/renderer/platform/text/text_break_iterator_test.cc b/third_party/blink/renderer/platform/text/text_break_iterator_test.cc index 1c70153..fd23955 100644 --- a/third_party/blink/renderer/platform/text/text_break_iterator_test.cc +++ b/third_party/blink/renderer/platform/text/text_break_iterator_test.cc
@@ -75,8 +75,7 @@ unsigned start, unsigned length) { Vector<unsigned> result; - ::blink::GraphemesClusterList(input.Characters16(), input.length(), start, - length, &result); + ::blink::GraphemesClusterList(input, start, length, &result); return result; }
diff --git a/tools/clang/scripts/run_tool.py b/tools/clang/scripts/run_tool.py index ad85dd3..82ae64d 100755 --- a/tools/clang/scripts/run_tool.py +++ b/tools/clang/scripts/run_tool.py
@@ -299,9 +299,12 @@ sys.stderr.write('\n') done_count = self.__success_count + self.__failed_count percentage = (float(done_count) / len(self.__compdb_entries)) * 100 - sys.stderr.write( - 'Processed %d files with %s tool (%d failures) [%.2f%%]\r' % - (done_count, self.__toolname, self.__failed_count, percentage)) + # Only output progress for every 100th entry, to make log files easier to + # inspect. + if done_count % 100 == 0 or done_count == len(self.__compdb_entries): + sys.stderr.write( + 'Processed %d files with %s tool (%d failures) [%.2f%%]\r' % + (done_count, self.__toolname, self.__failed_count, percentage)) def main():
diff --git a/tools/code_coverage/test_suite.txt b/tools/code_coverage/test_suite.txt index 900f1b5..abe7e57 100644 --- a/tools/code_coverage/test_suite.txt +++ b/tools/code_coverage/test_suite.txt
@@ -45,7 +45,6 @@ interactive_ui_tests ipc_tests jingle_unittests -keyboard_unittests latency_unittests leveldb_service_unittests libjingle_xmpp_unittests
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 35c98ad0f..a5d378e 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -28183,6 +28183,7 @@ <int value="-474806100" label="DataReductionProxyMainMenu:enabled"/> <int value="-474322576" label="disable-quick-unlock-pin"/> <int value="-473087416" label="DragTabsInTabletMode:enabled"/> + <int value="-472014137" label="HomepageTile:disabled"/> <int value="-472013317" label="WebRTC-H264WithOpenH264FFmpeg:disabled"/> <int value="-471405972" label="ViewsProfileChooser:disabled"/> <int value="-471085510" label="MultiDeviceApi:enabled"/> @@ -28199,6 +28200,7 @@ <int value="-435914745" label="ClipboardContentSetting:disabled"/> <int value="-430360431" label="disable-password-generation"/> <int value="-428599163" label="NTPDownloadSuggestions:enabled"/> + <int value="-426815606" label="HomepageTile:enabled"/> <int value="-424701311" label="SignedHTTPExchange:disabled"/> <int value="-418868128" label="enable-experimental-web-platform-features"/> <int value="-410852857" label="ImprovedA2HS:disabled"/> @@ -32503,6 +32505,7 @@ <int value="11" label="Discarded: report-to not a string"/> <int value="12" label="Removed (max-age = 0)"/> <int value="13" label="Set (max-age > 0)"/> + <int value="14" label="Discarded: missing remote endpoint"/> </enum> <enum name="NetNetworkErrorLoggingRequestOutcome">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index f6ec479..4d1f563 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -40218,7 +40218,7 @@ </histogram> <histogram name="Media.EME.EncryptionScheme.Initial.Audio" - units="MediaEncryptionScheme"> + enum="MediaEncryptionScheme"> <owner>jrummell@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -40228,7 +40228,7 @@ </histogram> <histogram name="Media.EME.EncryptionScheme.Initial.Video" - units="MediaEncryptionScheme"> + enum="MediaEncryptionScheme"> <owner>jrummell@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> @@ -63923,6 +63923,16 @@ </summary> </histogram> +<histogram name="OfflinePages.PublishPageResult" + enum="OfflinePagesSavePageResult"> + <owner>petewil@chromium.org</owner> + <summary> + Result of publishing downloaded page. CANCELLED means the page to publish + isn't found. ALREADY_EXISTS means the page have already been published + before. + </summary> +</histogram> + <histogram name="OfflinePages.RedirectResult" enum="OfflinePagesRedirectResult"> <obsolete> Deprecated 8/2016. Use OfflinePages.RequestResult instead. @@ -93802,6 +93812,9 @@ <histogram base="true" name="SimpleCache.ReadIsParallelizable" enum="SimpleCacheReadParallelizable"> + <obsolete> + Removed 2018-07-02. See https://crrev.com/c/1122706 + </obsolete> <owner>morlovich@chromium.org</owner> <summary> For each Read operation, whether it could have been issued in parallel of a @@ -93951,6 +93964,9 @@ <histogram base="true" name="SimpleCache.WriteDependencyType" enum="SimpleCacheWriteDependencyType"> + <obsolete> + Removed 2018-07-02. See https://crrev.com/c/1122706 + </obsolete> <owner>morlovich@chromium.org</owner> <summary> Shows whether a write operation depends on the previous operation in queue
diff --git a/tools/perf/core/upload_results_to_perf_dashboard.py b/tools/perf/core/upload_results_to_perf_dashboard.py index ad82a6ce..2bff331 100755 --- a/tools/perf/core/upload_results_to_perf_dashboard.py +++ b/tools/perf/core/upload_results_to_perf_dashboard.py
@@ -12,6 +12,7 @@ import optparse import re import sys +import time import urllib from core import results_dashboard @@ -71,12 +72,16 @@ is_reference_build = 'reference' in options.name stripped_test_name = options.name.replace('.reference', '') - return results_dashboard.MakeHistogramSetWithDiagnostics( + begin_time = time.time() + hs = results_dashboard.MakeHistogramSetWithDiagnostics( options.results_file, stripped_test_name, options.configuration_name, options.buildername, options.buildnumber, revisions, is_reference_build, perf_dashboard_machine_group=options.perf_dashboard_machine_group) - + end_time = time.time() + print 'Duration of adding diagnostics for %s: %d seconds' % ( + stripped_test_name, end_time - begin_time) + return hs def _CreateParser(): # Parse options
diff --git a/tools/perf/page_sets/data/rendering_desktop.json b/tools/perf/page_sets/data/rendering_desktop.json index f7abf07..4782916 100644 --- a/tools/perf/page_sets/data/rendering_desktop.json +++ b/tools/perf/page_sets/data/rendering_desktop.json
@@ -78,6 +78,81 @@ "google_image_search": { "DEFAULT": "top_25_007.wprgo" }, + "accu_weather_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "amazon_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "blogspot_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "booking.com_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "cnn_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "ebay_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "espn_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "facebook_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "gmail_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "google_calendar_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "google_docs_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "google_image_search_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "google_plus_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "google_web_search_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "linkedin_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "pinterest_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "techcrunch_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "twitch_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "twitter_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "wikipedia_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "wordpress_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "yahoo_answers_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "yahoo_news_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "yahoo_sports_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "youtube_2018": { + "DEFAULT": "top_25_012.wprgo" + }, "maps_move": { "DEFAULT": "key_desktop_move_cases_000.wprgo" },
diff --git a/tools/perf/page_sets/data/rendering_mobile.json b/tools/perf/page_sets/data/rendering_mobile.json index 2007270..0c6bf453 100644 --- a/tools/perf/page_sets/data/rendering_mobile.json +++ b/tools/perf/page_sets/data/rendering_mobile.json
@@ -276,7 +276,7 @@ "linkedin_mobile_sync_scroll": { "DEFAULT": "key_mobile_sites_002.wprgo" }, - "google_docs": { + "google_docs": { "DEFAULT": "top_25_009.wprgo" }, "google_docs_desktop_gpu_raster": { @@ -432,6 +432,156 @@ "google_image_search_desktop_gpu_raster": { "DEFAULT": "top_25_007.wprgo" }, + "accu_weather_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "accu_weather_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "twitch_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "twitch_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "google_docs_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "google_docs_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "facebook_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "facebook_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "wikipedia_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "wikipedia_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "yahoo_answers_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "yahoo_answers_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "booking.com_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "booking.com_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "wordpress_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "wordpress_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "espn_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "espn_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "blogspot_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "blogspot_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "yahoo_news_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "yahoo_news_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "pinterest_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "pinterest_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "yahoo_sports_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "yahoo_sports_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "techcrunch_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "techcrunch_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "amazon_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "amazon_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "cnn_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "cnn_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "ebay_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "ebay_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "linkedin_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "linkedin_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "youtube_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "youtube_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "gmail_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "gmail_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "google_plus_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "google_plus_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "twitter_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "twitter_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "google_web_search_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "google_web_search_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "google_calendar_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "google_calendar_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, + "google_image_search_2018": { + "DEFAULT": "top_25_012.wprgo" + }, + "google_image_search_2018_desktop_gpu_raster": { + "DEFAULT": "top_25_012.wprgo" + }, "filter_terrain_svg": { "DEFAULT": "tough_filters_cases_002.wprgo" },
diff --git a/tools/perf/page_sets/data/top_25_012.wprgo.sha1 b/tools/perf/page_sets/data/top_25_012.wprgo.sha1 index 217f848..92eb6273 100644 --- a/tools/perf/page_sets/data/top_25_012.wprgo.sha1 +++ b/tools/perf/page_sets/data/top_25_012.wprgo.sha1
@@ -1 +1 @@ -bd503b282964e34176b6c617d84d38aee20aa07c \ No newline at end of file +371b648115b68061656913d0f01a8cd651bc755b \ No newline at end of file
diff --git a/tools/perf/page_sets/login_helpers/google_login.py b/tools/perf/page_sets/login_helpers/google_login.py index 84bd47e..9540886 100644 --- a/tools/perf/page_sets/login_helpers/google_login.py +++ b/tools/perf/page_sets/login_helpers/google_login.py
@@ -29,9 +29,9 @@ 'document.querySelector("%s") !== null' % (_PASSWORD_SELECTOR)) -def LoginGoogleAccount(action_runner, - credential='googletest', # Recommended credential. - credentials_path=login_utils.DEFAULT_CREDENTIAL_PATH): +def BaseLoginGoogle(action_runner, + credential='googletest', # Recommended credential. + credentials_path=login_utils.DEFAULT_CREDENTIAL_PATH): """Logs in into Google account. This function navigates the tab into Google's login page and logs in a user @@ -73,4 +73,19 @@ login_utils.InputWithSelector(action_runner, password, _PASSWORD_SELECTOR) action_runner.ClickElement(selector=_SIGNIN_SELECTOR) + + +def LoginGoogleAccount(action_runner, + credential='googletest', # Recommended credential. + credentials_path=login_utils.DEFAULT_CREDENTIAL_PATH): + """ Login for old UI """ + BaseLoginGoogle(action_runner, credential, credentials_path) action_runner.WaitForElement(text='My Account') + + +def NewLoginGoogleAccount(action_runner, + credential='googletest', # Recommended credential. + credentials_path=login_utils.DEFAULT_CREDENTIAL_PATH): + """ Login for new UI """ + BaseLoginGoogle(action_runner, credential, credentials_path) + action_runner.WaitForElement(text='Google Account')
diff --git a/tools/perf/page_sets/rendering/top_real_world_desktop.py b/tools/perf/page_sets/rendering/top_real_world_desktop.py index f9bdb10..bd6429e2 100644 --- a/tools/perf/page_sets/rendering/top_real_world_desktop.py +++ b/tools/perf/page_sets/rendering/top_real_world_desktop.py
@@ -4,6 +4,7 @@ from telemetry.page import shared_page_state from page_sets.login_helpers import google_login +from page_sets.login_helpers import linkedin_login from page_sets.rendering import rendering_story from page_sets.rendering import story_tags @@ -54,6 +55,27 @@ action_runner.WaitForElement(text='Next') +class GoogleWebSearch2018Page(TopRealWorldDesktopPage): + """ Why: top google property; a google tab is often open """ + BASE_NAME = 'google_web_search_2018' + URL = 'https://www.google.com/#hl=en&q=barack+obama' + + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name_suffix='', + extra_browser_args=None): + super(GoogleWebSearch2018Page, self).__init__( + page_set=page_set, + shared_page_state_class=shared_page_state_class, + name_suffix=name_suffix, + extra_browser_args=extra_browser_args) + + def RunNavigateSteps(self, action_runner): + super(GoogleWebSearch2018Page, self).RunNavigateSteps(action_runner) + action_runner.WaitForElement(text='Next') + + class GoogleImageSearchPage(TopRealWorldDesktopPage): """ Why: tough image case; top google properties """ BASE_NAME = 'google_image_search' @@ -75,6 +97,26 @@ super(GoogleImageSearchPage, self).RunNavigateSteps(action_runner) +class GoogleImageSearch2018Page(TopRealWorldDesktopPage): + """ Why: tough image case; top google properties """ + BASE_NAME = 'google_image_search_2018' + URL = 'https://www.google.com/search?q=cats&tbm=isch' + + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name_suffix='', + extra_browser_args=None): + super(GoogleImageSearch2018Page, self).__init__( + page_set=page_set, + shared_page_state_class=shared_page_state_class, + name_suffix=name_suffix, + extra_browser_args=extra_browser_args) + + def RunNavigateSteps(self, action_runner): + super(GoogleImageSearch2018Page, self).RunNavigateSteps(action_runner) + + class GmailPage(TopRealWorldDesktopPage): """ Why: productivity, top google properties """ ABSTRACT_STORY = True @@ -177,6 +219,27 @@ action_runner.WaitForElement(text='Home') +class GooglePlus2018Page(TopRealWorldDesktopPage): + """ Why: social; top google property; Public profile; infinite scrolls """ + BASE_NAME = 'google_plus_2018' + URL = 'https://plus.google.com/110031535020051778989/posts' + + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name_suffix='', + extra_browser_args=None): + super(GooglePlus2018Page, self).__init__( + page_set=page_set, + shared_page_state_class=shared_page_state_class, + name_suffix=name_suffix, + extra_browser_args=extra_browser_args) + + def RunNavigateSteps(self, action_runner): + super(GooglePlus2018Page, self).RunNavigateSteps(action_runner) + action_runner.WaitForElement(text='Posts') + + class YoutubePage(TopRealWorldDesktopPage): """ Why: #3 (Alexa global) """ BASE_NAME = 'youtube' @@ -199,6 +262,27 @@ action_runner.Wait(2) +class Youtube2018Page(TopRealWorldDesktopPage): + """ Why: #3 (Alexa global) """ + BASE_NAME = 'youtube_2018' + URL = 'http://www.youtube.com' + + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name_suffix='', + extra_browser_args=None): + super(Youtube2018Page, self).__init__( + page_set=page_set, + shared_page_state_class=shared_page_state_class, + name_suffix=name_suffix, + extra_browser_args=extra_browser_args) + + def RunNavigateSteps(self, action_runner): + super(Youtube2018Page, self).RunNavigateSteps(action_runner) + action_runner.WaitForElement(selector='#buttons') + + class BlogspotPage(TopRealWorldDesktopPage): """ Why: #11 (Alexa global), google property; some blogger layouts have infinite scroll but more interesting """ @@ -221,6 +305,28 @@ action_runner.WaitForElement(text='accessibility') +class Blogspot2018Page(TopRealWorldDesktopPage): + """ Why: #11 (Alexa global), google property; some blogger layouts have + infinite scroll but more interesting """ + BASE_NAME = 'blogspot_2018' + URL = 'http://googlewebmastercentral.blogspot.com/' + + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name_suffix='', + extra_browser_args=None): + super(Blogspot2018Page, self).__init__( + page_set=page_set, + shared_page_state_class=shared_page_state_class, + name_suffix=name_suffix, + extra_browser_args=extra_browser_args) + + def RunNavigateSteps(self, action_runner): + super(Blogspot2018Page, self).RunNavigateSteps(action_runner) + action_runner.WaitForElement('div[class="searchBox"]') + + class WordpressPage(TopRealWorldDesktopPage): """ Why: #18 (Alexa global), Picked an interesting post """ BASE_NAME = 'wordpress' @@ -246,6 +352,31 @@ ) +class Wordpress2018Page(TopRealWorldDesktopPage): + """ Why: #18 (Alexa global), Picked an interesting post """ + BASE_NAME = 'wordpress_2018' + # pylint: disable=line-too-long + URL = 'http://en.blog.wordpress.com/2012/09/04/freshly-pressed-editors-picks-for-august-2012/' + + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name_suffix='', + extra_browser_args=None): + super(Wordpress2018Page, self).__init__( + page_set=page_set, + shared_page_state_class=shared_page_state_class, + name_suffix=name_suffix, + extra_browser_args=extra_browser_args) + + def RunNavigateSteps(self, action_runner): + super(Wordpress2018Page, self).RunNavigateSteps(action_runner) + action_runner.WaitForElement( + # pylint: disable=line-too-long + 'a[href="https://en.blog.wordpress.com/2012/08/30/new-themes-able-and-sight/"]' + ) + + class FacebookPage(TopRealWorldDesktopPage): """ Why: top social,Public profile """ BASE_NAME = 'facebook' @@ -267,6 +398,27 @@ action_runner.WaitForElement(text='Videos') +class Facebook2018Page(TopRealWorldDesktopPage): + """ Why: top social,Public profile """ + BASE_NAME = 'facebook_2018' + URL = 'https://www.facebook.com/barackobama' + + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name_suffix='', + extra_browser_args=None): + super(Facebook2018Page, self).__init__( + page_set=page_set, + shared_page_state_class=shared_page_state_class, + name_suffix=name_suffix, + extra_browser_args=extra_browser_args) + + def RunNavigateSteps(self, action_runner): + super(Facebook2018Page, self).RunNavigateSteps(action_runner) + action_runner.WaitForElement(text='Videos') + + class LinkedinPage(TopRealWorldDesktopPage): """ Why: #12 (Alexa global), Public profile. """ BASE_NAME = 'linkedin' @@ -284,6 +436,27 @@ extra_browser_args=extra_browser_args) +class Linkedin2018Page(TopRealWorldDesktopPage): + """ Why: #12 (Alexa global), Public profile. """ + BASE_NAME = 'linkedin_2018' + URL = 'http://www.linkedin.com/in/linustorvalds' + + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name_suffix='', + extra_browser_args=None): + super(Linkedin2018Page, self).__init__( + page_set=page_set, + shared_page_state_class=shared_page_state_class, + name_suffix=name_suffix, + extra_browser_args=extra_browser_args) + + def RunNavigateSteps(self, action_runner): + linkedin_login.LoginDesktopAccount(action_runner, 'linkedin') + super(Linkedin2018Page, self).RunNavigateSteps(action_runner) + + class WikipediaPage(TopRealWorldDesktopPage): """ Why: #6 (Alexa) most visited worldwide,Picked an interesting page. """ BASE_NAME = 'wikipedia' @@ -301,6 +474,23 @@ extra_browser_args=extra_browser_args) +class Wikipedia2018Page(TopRealWorldDesktopPage): + """ Why: #6 (Alexa) most visited worldwide,Picked an interesting page. """ + BASE_NAME = 'wikipedia_2018' + URL = 'http://en.wikipedia.org/wiki/Wikipedia' + + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name_suffix='', + extra_browser_args=None): + super(Wikipedia2018Page, self).__init__( + page_set=page_set, + shared_page_state_class=shared_page_state_class, + name_suffix=name_suffix, + extra_browser_args=extra_browser_args) + + class TwitterPage(TopRealWorldDesktopPage): """ Why: #8 (Alexa global),Picked an interesting page """ BASE_NAME = 'twitter' @@ -322,6 +512,27 @@ action_runner.Wait(2) +class Twitter2018Page(TopRealWorldDesktopPage): + """ Why: #8 (Alexa global),Picked an interesting page """ + BASE_NAME = 'twitter_2018' + URL = 'https://twitter.com/katyperry' + + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name_suffix='', + extra_browser_args=None): + super(Twitter2018Page, self).__init__( + page_set=page_set, + shared_page_state_class=shared_page_state_class, + name_suffix=name_suffix, + extra_browser_args=extra_browser_args) + + def RunNavigateSteps(self, action_runner): + super(Twitter2018Page, self).RunNavigateSteps(action_runner) + action_runner.WaitForElement(selector='.ProfileNav') + + class PinterestPage(TopRealWorldDesktopPage): """ Why: #37 (Alexa global) """ BASE_NAME = 'pinterest' @@ -339,6 +550,23 @@ extra_browser_args=extra_browser_args) +class Pinterest2018Page(TopRealWorldDesktopPage): + """ Why: #37 (Alexa global) """ + BASE_NAME = 'pinterest_2018' + URL = 'https://www.pinterest.com/search/pins/?q=flowers&rs=typed' + + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name_suffix='', + extra_browser_args=None): + super(Pinterest2018Page, self).__init__( + page_set=page_set, + shared_page_state_class=shared_page_state_class, + name_suffix=name_suffix, + extra_browser_args=extra_browser_args) + + class ESPNPage(TopRealWorldDesktopPage): """ Why: #1 sports """ ABSTRACT_STORY = True @@ -373,6 +601,23 @@ extra_browser_args=extra_browser_args) +class AccuWeather2018Page(TopRealWorldDesktopPage): + """ Why: #2 weather according to Alexa """ + BASE_NAME = 'accu_weather_2018' + URL = 'https://www.accuweather.com/en/us/new-york-ny/10017/weather-forecast/349727' + + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name_suffix='', + extra_browser_args=None): + super(AccuWeather2018Page, self).__init__( + page_set=page_set, + shared_page_state_class=shared_page_state_class, + name_suffix=name_suffix, + extra_browser_args=extra_browser_args) + + class YahooGamesPage(TopRealWorldDesktopPage): """ Why: #1 games according to Alexa (with actual games in it) """ BASE_NAME = 'yahoo_games' @@ -394,6 +639,32 @@ action_runner.Wait(2) +class Twitch2018Page(TopRealWorldDesktopPage): + """ Why: #1 games according to Alexa """ + BASE_NAME = 'twitch_2018' + URL = 'https://www.twitch.tv' + + def __init__(self, + page_set, + shared_page_state_class=shared_page_state.SharedPageState, + name_suffix='', + extra_browser_args=None): + super(Twitch2018Page, self).__init__( + page_set=page_set, + shared_page_state_class=shared_page_state_class, + name_suffix=name_suffix, + extra_browser_args=extra_browser_args) + + def RunPageInteractions(self, action_runner): + action_runner.WaitForElement(selector='#mantle_skin') + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPageToElement(selector='.footer') + if self.story_set.scroll_forever: + while True: + action_runner.ScrollPage(direction='up') + action_runner.ScrollPage(direction='down') + + class GmailSmoothPage(GmailPage): """ Why: productivity, top google properties """ BASE_NAME = 'gmail' @@ -419,6 +690,30 @@ element_function='window.__scrollableElementForTelemetry') +class Gmail2018SmoothPage(TopRealWorldDesktopPage): + """ Why: productivity, top google properties """ + BASE_NAME = 'gmail_2018' + URL = 'https://mail.google.com/mail/' + + def RunNavigateSteps(self, action_runner): + google_login.NewLoginGoogleAccount(action_runner, 'googletest') + super(Gmail2018SmoothPage, self).RunNavigateSteps(action_runner) + action_runner.WaitForJavaScriptCondition( + 'window.gmonkey !== undefined &&' + 'document.getElementById("gb") !== null') + + def RunPageInteractions(self, action_runner): + action_runner.WaitForElement(selector='.Tm.aeJ') + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollElement(selector='.Tm.aeJ') + if self.story_set.scroll_forever: + while True: + action_runner.ScrollElement( + direction='up', selector='.Tm.aeJ') + action_runner.ScrollElement( + direction='down', selector='.Tm.aeJ') + + class GoogleCalendarSmoothPage(GoogleCalendarPage): """ Why: productivity, top google properties """ BASE_NAME='google_calendar' @@ -435,6 +730,37 @@ direction='down', selector='#scrolltimedeventswk') +class GoogleCalendar2018SmoothPage(TopRealWorldDesktopPage): + """ Why: productivity, top google properties """ + BASE_NAME='google_calendar_2018' + URL='https://www.google.com/calendar/' + + def RunNavigateSteps(self, action_runner): + google_login.NewLoginGoogleAccount(action_runner, 'googletest') + super(GoogleCalendar2018SmoothPage, self).RunNavigateSteps(action_runner) + action_runner.WaitForElement('span[class~="sm8sCf"]') + action_runner.ExecuteJavaScript(""" + (function() { + var elem = document.createElement('meta'); + elem.name='viewport'; + elem.content='initial-scale=1'; + document.body.appendChild(elem); + })();""") + action_runner.Wait(1) + + + def RunPageInteractions(self, action_runner): + action_runner.WaitForElement('span[class~="sm8sCf"]') + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollElement(selector='#YPCqFe') + if self.story_set.scroll_forever: + while True: + action_runner.ScrollElement( + direction='up', selector='#YPCqFe') + action_runner.ScrollElement( + direction='down', selector='#YPCqFe') + + class GoogleDocSmoothPage(GoogleDocPage): """ Why: productivity, top google properties; Sample doc in the link """ BASE_NAME='google_docs' @@ -451,6 +777,29 @@ direction='down', selector='.kix-appview-editor') +class GoogleDoc2018SmoothPage(TopRealWorldDesktopPage): + """ Why: productivity, top google properties; Sample doc in the link """ + # pylint: disable=line-too-long + URL = 'https://docs.google.com/document/d/1X-IKNjtEnx-WW5JIKRLsyhz5sbsat3mfTpAPUSX3_s4/view' + BASE_NAME='google_docs_2018' + + def RunNavigateSteps(self, action_runner): + super(GoogleDoc2018SmoothPage, self).RunNavigateSteps(action_runner) + action_runner.WaitForJavaScriptCondition( + 'document.getElementsByClassName("kix-appview-editor").length') + + def RunPageInteractions(self, action_runner): + action_runner.WaitForElement(selector='#printButton') + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollElement(selector='.kix-appview-editor') + if self.story_set.scroll_forever: + while True: + action_runner.ScrollElement( + direction='up', selector='.kix-appview-editor') + action_runner.ScrollElement( + direction='down', selector='.kix-appview-editor') + + class ESPNSmoothPage(ESPNPage): """ Why: #1 sports """ BASE_NAME='espn' @@ -465,18 +814,45 @@ action_runner.ScrollPage(direction='down', left_start_ratio=0.1) +class ESPN2018SmoothPage(TopRealWorldDesktopPage): + """ Why: #1 sports """ + BASE_NAME='espn_2018' + URL = 'http://espn.go.com' + + def RunPageInteractions(self, action_runner): + action_runner.WaitForElement(selector='#global-scoreboard') + with action_runner.CreateGestureInteraction('ScrollAction'): + action_runner.ScrollPage(left_start_ratio=0.1) + if self.story_set.scroll_forever: + while True: + action_runner.ScrollPage(direction='up', left_start_ratio=0.1) + action_runner.ScrollPage(direction='down', left_start_ratio=0.1) + + class YahooNewsPage(TopRealWorldDesktopPage): """Why: #1 news worldwide (Alexa global)""" BASE_NAME = 'yahoo_news' URL = 'http://news.yahoo.com' +class YahooNews2018Page(TopRealWorldDesktopPage): + """Why: #1 news worldwide (Alexa global)""" + BASE_NAME = 'yahoo_news_2018' + URL = 'http://news.yahoo.com' + + class CNNNewsPage(TopRealWorldDesktopPage): """Why: #2 news worldwide""" BASE_NAME = 'cnn' URL = 'http://www.cnn.com' +class CNNNews2018Page(TopRealWorldDesktopPage): + """Why: #2 news worldwide""" + BASE_NAME = 'cnn_2018' + URL = 'http://www.cnn.com' + + class AmazonPage(TopRealWorldDesktopPage): # Why: #1 world commerce website by visits; #3 commerce in the US by # time spent @@ -484,31 +860,68 @@ URL = 'http://www.amazon.com' +class Amazon2018Page(TopRealWorldDesktopPage): + # Why: #1 world commerce website by visits; #3 commerce in the US by + # time spent + BASE_NAME = 'amazon_2018' + URL = 'http://www.amazon.com' + + class EbayPage(TopRealWorldDesktopPage): # Why: #1 commerce website by time spent by users in US BASE_NAME = 'ebay' URL = 'http://www.ebay.com' +class Ebay2018Page(TopRealWorldDesktopPage): + # Why: #1 commerce website by time spent by users in US + BASE_NAME = 'ebay_2018' + URL = 'http://www.ebay.com' + + class BookingPage(TopRealWorldDesktopPage): # Why: #1 Alexa recreation BASE_NAME = 'booking.com' URL = 'http://booking.com' +class Booking2018Page(TopRealWorldDesktopPage): + # Why: #1 Alexa recreation + BASE_NAME = 'booking.com_2018' + URL = 'http://booking.com' + + class YahooAnswersPage(TopRealWorldDesktopPage): # Why: #1 Alexa reference BASE_NAME = 'yahoo_answers' URL = 'http://answers.yahoo.com' +class YahooAnswers2018Page(TopRealWorldDesktopPage): + # Why: #1 Alexa reference + BASE_NAME = 'yahoo_answers_2018' + URL = 'http://answers.yahoo.com' + + class YahooSportsPage(TopRealWorldDesktopPage): # Why: #1 Alexa sports BASE_NAME = 'yahoo_sports' URL = 'http://sports.yahoo.com/' +class YahooSports2018Page(TopRealWorldDesktopPage): + # Why: #1 Alexa sports + BASE_NAME = 'yahoo_sports_2018' + URL = 'http://sports.yahoo.com/' + + class TechCrunchPage(TopRealWorldDesktopPage): # Why: top tech blog BASE_NAME = 'techcrunch' URL = 'http://techcrunch.com' + + +class TechCrunch2018Page(TopRealWorldDesktopPage): + # Why: top tech blog + BASE_NAME = 'techcrunch_2018' + URL = 'http://techcrunch.com'
diff --git a/ui/android/delegated_frame_host_android.cc b/ui/android/delegated_frame_host_android.cc index e72f359..e305ae3 100644 --- a/ui/android/delegated_frame_host_android.cc +++ b/ui/android/delegated_frame_host_android.cc
@@ -26,16 +26,6 @@ namespace { -// Wait up to 5 seconds for the first frame to be produced. Having Android -// display a placeholder for a longer period of time is preferable to drawing -// nothing, and the first frame can take a while on low-end systems. -static const int64_t kFirstFrameTimeoutSeconds = 5; - -// Wait up to 1 second for a frame of the correct size to be produced. Android -// OS will only wait 4 seconds, so we limit this to 1 second to make sure we -// have always produced a frame before the OS stops waiting. -static const int64_t kResizeTimeoutSeconds = 1; - scoped_refptr<cc::SurfaceLayer> CreateSurfaceLayer( const viz::SurfaceId& primary_surface_id, const viz::SurfaceId& fallback_surface_id, @@ -225,8 +215,8 @@ // a renderer frame is available instead. if (!enable_surface_synchronization_ && compositor->IsDrawingFirstVisibleFrame() && !HasDelegatedContent()) { - compositor_attach_until_frame_lock_ = compositor->GetCompositorLock( - this, base::TimeDelta::FromSeconds(kFirstFrameTimeoutSeconds)); + compositor_attach_until_frame_lock_ = + compositor->GetCompositorLock(this, FirstFrameTimeout()); } compositor->AddChildFrameSink(frame_sink_id_); if (!enable_viz_) @@ -267,12 +257,9 @@ if (!enable_surface_synchronization_) return; - // Use the default deadline to synchronize web content with browser UI. - // TODO(fsamuel): We probably want to use the deadlines - // kFirstFrameTimeoutSeconds and kResizeTimeoutSeconds for equivalent - // cases with surface synchronization too. - EmbedSurface(new_pending_local_surface_id, new_pending_size_in_pixels, - cc::DeadlinePolicy::UseDefaultDeadline()); + EmbedSurface( + new_pending_local_surface_id, new_pending_size_in_pixels, + cc::DeadlinePolicy::UseSpecifiedDeadline(FirstFrameTimeoutFrames())); } void DelegatedFrameHostAndroid::EmbedSurface( @@ -284,6 +271,8 @@ pending_local_surface_id_ = new_pending_local_surface_id; pending_surface_size_in_pixels_ = new_pending_size_in_pixels; + viz::SurfaceId current_primary_surface_id = + content_layer_->primary_surface_id(); if (!frame_evictor_->visible()) { // If the tab is resized while hidden, reset the fallback so that the next @@ -299,10 +288,28 @@ // is visible, EmbedSurface will be called again. See WasShown. return; } - - viz::SurfaceId primary_surface_id(frame_sink_id_, pending_local_surface_id_); - content_layer_->SetPrimarySurfaceId(primary_surface_id, deadline_policy); - content_layer_->SetBounds(new_pending_size_in_pixels); + if (!current_primary_surface_id.is_valid() || + current_primary_surface_id.local_surface_id() != + pending_local_surface_id_) { + if (base::android::BuildInfo::GetInstance()->sdk_int() < + base::android::SDK_VERSION_OREO) { + // On version of Android earlier than Oreo, we would like to produce new + // content as soon as possible or the OS will create an additional black + // gutter. We only reset the deadline on the first frame (no bounds yet + // specified) or on resize, and only if the deadline policy is not + // infinite. + if (deadline_policy.policy_type() != + cc::DeadlinePolicy::kUseInfiniteDeadline && + (content_layer_->bounds().IsEmpty() || + content_layer_->bounds() != pending_surface_size_in_pixels_)) { + deadline_policy = cc::DeadlinePolicy::UseSpecifiedDeadline(0u); + } + } + viz::SurfaceId primary_surface_id(frame_sink_id_, + pending_local_surface_id_); + content_layer_->SetPrimarySurfaceId(primary_surface_id, deadline_policy); + content_layer_->SetBounds(new_pending_size_in_pixels); + } } void DelegatedFrameHostAndroid::PixelSizeWillChange( @@ -322,8 +329,8 @@ if (registered_parent_compositor_) { if (HasSavedFrame() && content_layer_->bounds() != expected_pixel_size_) { compositor_pending_resize_lock_ = - registered_parent_compositor_->GetCompositorLock( - this, base::TimeDelta::FromSeconds(kResizeTimeoutSeconds)); + registered_parent_compositor_->GetCompositorLock(this, + ResizeTimeout()); } } }
diff --git a/ui/android/delegated_frame_host_android.h b/ui/android/delegated_frame_host_android.h index 94371aa..2c6ba56b 100644 --- a/ui/android/delegated_frame_host_android.h +++ b/ui/android/delegated_frame_host_android.h
@@ -62,6 +62,26 @@ ~DelegatedFrameHostAndroid() override; + // Wait up to 5 seconds for the first frame to be produced. Having Android + // display a placeholder for a longer period of time is preferable to drawing + // nothing, and the first frame can take a while on low-end systems. + static constexpr base::TimeDelta FirstFrameTimeout() { + return base::TimeDelta::FromSeconds(5); + } + static constexpr int64_t FirstFrameTimeoutFrames() { + return FirstFrameTimeout() / viz::BeginFrameArgs::DefaultInterval(); + } + + // Wait up to 1 second for a frame of the correct size to be produced. Android + // OS will only wait 4 seconds, so we limit this to 1 second to make sure we + // have always produced a frame before the OS stops waiting. + static constexpr base::TimeDelta ResizeTimeout() { + return base::TimeDelta::FromSeconds(1); + } + static constexpr int64_t ResizeTimeoutFrames() { + return ResizeTimeout() / viz::BeginFrameArgs::DefaultInterval(); + } + void SubmitCompositorFrame( const viz::LocalSurfaceId& local_surface_id, viz::CompositorFrame frame,
diff --git a/ui/compositor/recyclable_compositor_mac.cc b/ui/compositor/recyclable_compositor_mac.cc index c35c5e6..187aebad 100644 --- a/ui/compositor/recyclable_compositor_mac.cc +++ b/ui/compositor/recyclable_compositor_mac.cc
@@ -16,6 +16,9 @@ namespace { +// The number of RecyclableCompositorMacs in existence. +size_t g_recyclable_compositor_count = 0; + // Returns a task runner for creating a ui::Compositor. This allows compositor // tasks to be funneled through ui::WindowResizeHelper's task runner to allow // resize operations to coordinate with frames provided by the GPU process. @@ -43,6 +46,7 @@ GetCompositorTaskRunner(), features::IsSurfaceSynchronizationEnabled(), ui::IsPixelCanvasRecordingEnabled()) { + g_recyclable_compositor_count += 1; compositor_.SetAcceleratedWidget( accelerated_widget_mac_->accelerated_widget()); Suspend(); @@ -51,6 +55,7 @@ RecyclableCompositorMac::~RecyclableCompositorMac() { compositor_.RemoveObserver(this); + g_recyclable_compositor_count -= 1; } void RecyclableCompositorMac::Suspend() { @@ -100,9 +105,9 @@ std::unique_ptr<RecyclableCompositorMac> RecyclableCompositorMacFactory::CreateCompositor( ui::ContextFactory* context_factory, - ui::ContextFactoryPrivate* context_factory_private) { - active_compositor_count_ += 1; - if (!compositors_.empty()) { + ui::ContextFactoryPrivate* context_factory_private, + bool force_new_compositor) { + if (!compositors_.empty() && !force_new_compositor) { std::unique_ptr<RecyclableCompositorMac> result; result = std::move(compositors_.back()); compositors_.pop_back(); @@ -114,16 +119,6 @@ void RecyclableCompositorMacFactory::RecycleCompositor( std::unique_ptr<RecyclableCompositorMac> compositor) { - // When we get to zero compositors in use, destroy all spare compositors. - // This is done to appease tests that rely on compositors being destroyed - // immediately (if the compositor is recycled and continues to exist, its - // subsequent initialization will crash). - active_compositor_count_ -= 1; - if (!active_compositor_count_) { - compositors_.clear(); - return; - } - if (recycling_disabled_) return; @@ -132,6 +127,15 @@ // Make this RecyclableCompositorMac recyclable for future instances. compositors_.push_back(std::move(compositor)); + // When we get to zero active compositors in use, destroy all spare + // compositors. This is done to appease tests that rely on compositors being + // destroyed immediately (if the compositor is recycled and continues to + // exist, its subsequent initialization will crash). + if (g_recyclable_compositor_count == compositors_.size()) { + compositors_.clear(); + return; + } + // Post a task to free up the spare ui::Compositors when needed. Post this // to the browser main thread so that we won't free any compositors while // in a nested loop waiting to put up a new frame.
diff --git a/ui/compositor/recyclable_compositor_mac.h b/ui/compositor/recyclable_compositor_mac.h index 850fbb6..84dfbd9 100644 --- a/ui/compositor/recyclable_compositor_mac.h +++ b/ui/compositor/recyclable_compositor_mac.h
@@ -82,7 +82,8 @@ // Create a compositor, or recycle a preexisting one. std::unique_ptr<RecyclableCompositorMac> CreateCompositor( ui::ContextFactory* context_factory, - ui::ContextFactoryPrivate* context_factory_private); + ui::ContextFactoryPrivate* context_factory_private, + bool force_new_compositor = false); // Delete a compositor, or allow it to be recycled. void RecycleCompositor(std::unique_ptr<RecyclableCompositorMac> compositor); @@ -92,13 +93,11 @@ private: friend class base::NoDestructor<ui::RecyclableCompositorMacFactory>; + friend class RecyclableCompositorMac; RecyclableCompositorMacFactory(); ~RecyclableCompositorMacFactory(); void ReduceSpareCompositors(); - // The number of RecyclableCompositors that have been vended out and have - // not yet been recycled. - size_t active_compositor_count_ = 0; bool recycling_disabled_ = false; std::list<std::unique_ptr<RecyclableCompositorMac>> compositors_; base::WeakPtrFactory<RecyclableCompositorMacFactory> weak_factory_;
diff --git a/ui/ozone/platform/drm/gpu/mock_drm_device.cc b/ui/ozone/platform/drm/gpu/mock_drm_device.cc index ad4f3e4d0..fb66fdf 100644 --- a/ui/ozone/platform/drm/gpu/mock_drm_device.cc +++ b/ui/ozone/platform/drm/gpu/mock_drm_device.cc
@@ -7,11 +7,28 @@ #include <xf86drm.h> #include "base/logging.h" +#include "base/stl_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkCanvas.h" #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h" #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h" +// Private types defined in libdrm. Define them here so we can peek at the +// commit and ensure the expected state has been set correctly. +struct drmModeAtomicReqItem { + uint32_t object_id; + uint32_t property_id; + uint64_t value; +}; + +typedef drmModeAtomicReqItem* drmModeAtomicReqItemPtr; + +struct _drmModeAtomicReq { + uint32_t cursor; + uint32_t size_items; + drmModeAtomicReqItemPtr items; +}; + namespace ui { namespace { @@ -38,6 +55,13 @@ return drm_properties; } +template <class Type> +Type* FindObjectById(uint32_t id, std::vector<Type>& properties) { + auto it = std::find_if(properties.begin(), properties.end(), + [id](const Type& p) { return p.id == id; }); + return it != properties.end() ? &(*it) : nullptr; +} + } // namespace MockDrmDevice::CrtcProperties::CrtcProperties() = default; @@ -150,21 +174,13 @@ uint32_t object_id, uint32_t object_type) { if (object_type == DRM_MODE_OBJECT_PLANE) { - auto it = std::find_if( - plane_properties_.begin(), plane_properties_.end(), - [object_id](const PlaneProperties& p) { return p.id == object_id; }); - if (it == plane_properties_.end()) - return nullptr; - - return CreatePropertyObject(it->properties); + PlaneProperties* properties = FindObjectById(object_id, plane_properties_); + if (properties) + return CreatePropertyObject(properties->properties); } else if (object_type == DRM_MODE_OBJECT_CRTC) { - auto it = std::find_if( - crtc_properties_.begin(), crtc_properties_.end(), - [object_id](const CrtcProperties& p) { return p.id == object_id; }); - if (it == crtc_properties_.end()) - return nullptr; - - return CreatePropertyObject(it->properties); + CrtcProperties* properties = FindObjectById(object_id, crtc_properties_); + if (properties) + return CreatePropertyObject(properties->properties); } return nullptr; @@ -245,15 +261,12 @@ } ScopedDrmPlanePtr MockDrmDevice::GetPlane(uint32_t plane_id) { - auto it = std::find_if(plane_properties_.begin(), plane_properties_.end(), - [plane_id](const PlaneProperties& plane) { - return plane.id == plane_id; - }); - if (it == plane_properties_.end()) + PlaneProperties* properties = FindObjectById(plane_id, plane_properties_); + if (!properties) return nullptr; ScopedDrmPlanePtr plane(DrmAllocator<drmModePlane>()); - plane->possible_crtcs = it->crtc_mask; + plane->possible_crtcs = properties->crtc_mask; return plane; } @@ -281,10 +294,14 @@ ScopedDrmPropertyBlob MockDrmDevice::CreatePropertyBlob(void* blob, size_t size) { - return ScopedDrmPropertyBlob(new DrmPropertyBlobMetadata(this, 0xffffffff)); + uint32_t id = ++property_id_generator_; + allocated_property_blobs_.insert(id); + return ScopedDrmPropertyBlob(new DrmPropertyBlobMetadata(this, id)); } -void MockDrmDevice::DestroyPropertyBlob(uint32_t id) {} +void MockDrmDevice::DestroyPropertyBlob(uint32_t id) { + EXPECT_TRUE(allocated_property_blobs_.erase(id)); +} bool MockDrmDevice::GetCapability(uint64_t capability, uint64_t* value) { return true; @@ -374,10 +391,18 @@ } bool MockDrmDevice::CommitProperties( - drmModeAtomicReq* properties, + drmModeAtomicReq* request, uint32_t flags, uint32_t crtc_count, scoped_refptr<PageFlipRequest> page_flip_request) { + for (uint32_t i = 0; i < request->cursor; ++i) { + EXPECT_TRUE(ValidatePropertyValue(request->items[i].property_id, + request->items[i].value)); + EXPECT_TRUE(UpdateProperty(request->items[i].object_id, + request->items[i].property_id, + request->items[i].value)); + } + commit_count_++; if (page_flip_request) { callbacks_.push(page_flip_request->AddPageFlip()); @@ -407,4 +432,47 @@ blob_property_map_[blob->id] = std::move(blob); } +bool MockDrmDevice::UpdateProperty( + uint32_t id, + uint64_t value, + std::vector<DrmDevice::Property>* properties) { + DrmDevice::Property* property = FindObjectById(id, *properties); + if (!property) + return false; + + property->value = value; + return true; +} + +bool MockDrmDevice::UpdateProperty(uint32_t object_id, + uint32_t property_id, + uint64_t value) { + PlaneProperties* plane_properties = + FindObjectById(object_id, plane_properties_); + if (plane_properties) + return UpdateProperty(property_id, value, &plane_properties->properties); + + CrtcProperties* crtc_properties = FindObjectById(object_id, crtc_properties_); + if (crtc_properties) + return UpdateProperty(property_id, value, &crtc_properties->properties); + + return false; +} + +bool MockDrmDevice::ValidatePropertyValue(uint32_t id, uint64_t value) { + auto it = property_names_.find(id); + if (it == property_names_.end()) + return false; + + if (value == 0) + return true; + + std::vector<std::string> blob_properties = {"CTM", "DEGAMMA_LUT", "GAMMA_LUT", + "PLANE_CTM"}; + if (base::ContainsValue(blob_properties, it->second)) + return base::ContainsKey(allocated_property_blobs_, value); + + return true; +} + } // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/mock_drm_device.h b/ui/ozone/platform/drm/gpu/mock_drm_device.h index 1658cff..6da2226 100644 --- a/ui/ozone/platform/drm/gpu/mock_drm_device.h +++ b/ui/ozone/platform/drm/gpu/mock_drm_device.h
@@ -10,6 +10,7 @@ #include <stdint.h> #include <map> +#include <set> #include <vector> #include "base/containers/queue.h" @@ -161,7 +162,7 @@ bool MapDumbBuffer(uint32_t handle, size_t size, void** pixels) override; bool UnmapDumbBuffer(void* pixels, size_t size) override; bool CloseBufferHandle(uint32_t handle) override; - bool CommitProperties(drmModeAtomicReq* properties, + bool CommitProperties(drmModeAtomicReq* request, uint32_t flags, uint32_t crtc_count, scoped_refptr<PageFlipRequest> callback) override; @@ -173,6 +174,14 @@ private: ~MockDrmDevice() override; + bool UpdateProperty(uint32_t id, + uint64_t value, + std::vector<DrmDevice::Property>* properties); + + bool UpdateProperty(uint32_t object_id, uint32_t property_id, uint64_t value); + + bool ValidatePropertyValue(uint32_t id, uint64_t value); + int get_crtc_call_count_; int set_crtc_call_count_; int restore_crtc_call_count_; @@ -207,6 +216,12 @@ std::map<uint32_t, std::string> property_names_; + // TODO(dnicoara): Generate all IDs internal to MockDrmDevice. + // For now generate something with a high enough ID to be unique in tests. + uint32_t property_id_generator_ = 0xff000000; + + std::set<uint32_t> allocated_property_blobs_; + DISALLOW_COPY_AND_ASSIGN(MockDrmDevice); };
diff --git a/ui/views/cocoa/bridged_content_view.h b/ui/views/cocoa/bridged_content_view.h index 5bfbe297..a5a9b690 100644 --- a/ui/views/cocoa/bridged_content_view.h +++ b/ui/views/cocoa/bridged_content_view.h
@@ -33,6 +33,11 @@ // hierarchy rooted at |hostedView_|. Owned by the focused View. ui::TextInputClient* textInputClient_; + // The TextInputClient about to be set. Requests for a new -inputContext will + // use this, but while the input is changing, |self| still needs to service + // IME requests using the old |textInputClient_|. + ui::TextInputClient* pendingTextInputClient_; + // A tracking area installed to enable mouseMoved events. ui::ScopedCrTrackingArea cursorTrackingArea_;
diff --git a/ui/views/cocoa/bridged_content_view.mm b/ui/views/cocoa/bridged_content_view.mm index 9cf02c7..445d42c 100644 --- a/ui/views/cocoa/bridged_content_view.mm +++ b/ui/views/cocoa/bridged_content_view.mm
@@ -80,6 +80,13 @@ return client && client->GetTextDirection() == base::i18n::RIGHT_TO_LEFT; } +// Returns true if |event| may have triggered dismissal of an IME and would +// otherwise be ignored by a ui::TextInputClient when inserted. +bool IsImeTriggerEvent(NSEvent* event) { + ui::KeyboardCode key = ui::KeyboardCodeFromNSEvent(event); + return key == ui::VKEY_RETURN || key == ui::VKEY_TAB; +} + // Returns the boundary rectangle for composition characters in the // |requested_range|. Sets |actual_range| corresponding to the returned // rectangle. For cases, where there is no composition text or the @@ -325,11 +332,33 @@ [self removeTrackingArea:cursorTrackingArea_.get()]; } -- (void)setTextInputClient:(ui::TextInputClient*)textInputClient { - if (textInputClient_ == textInputClient) +- (void)setTextInputClient:(ui::TextInputClient*)newTextInputClient { + if (pendingTextInputClient_ == newTextInputClient) return; - textInputClient_ = textInputClient; + // This method may cause the IME window to dismiss, which may cause it to + // insert text (e.g. to replace marked text with "real" text). That should + // happen in the old -inputContext (which AppKit stores a reference to). + // Unfortunately, the only way to invalidate the the old -inputContext is to + // invoke -[NSApp updateWindows], which also wants a reference to the _new_ + // -inputContext. So put the new inputContext in |pendingTextInputClient_| and + // only use it for -inputContext. + ui::TextInputClient* oldInputClient = textInputClient_; + + // Since dismissing an IME may insert text, a misbehaving IME or a + // ui::TextInputClient that acts on InsertChar() to change focus a second time + // may invoke -setTextInputClient: recursively; with [NSApp updateWindows] + // still on the stack. Calling [NSApp updateWindows] recursively may upset + // an IME. Since the rest of this method is only to decide whether to call + // updateWindows, and we're already calling it, just bail out. + if (textInputClient_ != pendingTextInputClient_) { + pendingTextInputClient_ = newTextInputClient; + return; + } + + // Start by assuming no need to invoke -updateWindows. + textInputClient_ = newTextInputClient; + pendingTextInputClient_ = newTextInputClient; // If |self| was being used for the input context, and would now report a // different input context, manually invoke [NSApp updateWindows]. This is @@ -353,8 +382,12 @@ } if (current == [super inputContext]) { + DCHECK_NE(oldInputClient, textInputClient_); + textInputClient_ = oldInputClient; [NSApp updateWindows]; - DCHECK_EQ(nil, [NSTextInputContext currentInputContext]); + // Note: |pendingTextInputClient_| (and therefore +[NSTextInputContext + // currentInputContext] may have changed if called recursively. + textInputClient_ = pendingTextInputClient_; } } @@ -512,7 +545,7 @@ text = [text string]; bool isCharacterEvent = keyDownEvent_ && [text length] == 1; - // Pass the character event to the View hierarchy. Cases this handles (non- + // Pass "character" events to the View hierarchy. Cases this handles (non- // exhaustive)- // - Space key press on controls. Unlike Tab and newline which have // corresponding action messages, an insertText: message is generated for @@ -524,14 +557,26 @@ // key code to get the actual characters from the ui::KeyEvent. This for // example is necessary for menu mnemonic selection of non-latin text. - // Don't generate a key event when there is active composition text. These key + // Don't generate a key event when there is marked composition text. These key // down events should be consumed by the IME and not reach the Views layer. // For example, on pressing Return to commit composition text, if we passed a // synthetic key event to the View hierarchy, it will have the effect of - // performing the default action on the current dialog. We do not want this. + // performing the default action on the current dialog. We do not want this + // when there is marked text (Return should only confirm the IME). - // Also note that a single key down event can cause multiple - // insertText:replacementRange: action messages. Example, on pressing Alt+e, + // However, IME for phonetic languages such as Korean do not always _mark_ + // text when a composition is active. For these, correct behaviour is to + // handle the final -keyDown: that caused the composition to be committed, but + // only _after_ the sequence of insertText: messages coming from IME have been + // sent to the TextInputClient. Detect this by comparing to -[NSEvent + // characters]. Note we do not use -charactersIgnoringModifiers: so that, + // e.g., ß (Alt+s) will match mnemonics with ß rather than s. + bool isFinalInsertForKeyEvent = + isCharacterEvent && [text isEqualToString:[keyDownEvent_ characters]]; + + // Also note that a single, non-IME key down event can also cause multiple + // insertText:replacementRange: action messages being generated from within + // -keyDown:'s call to -interpretKeyEvents:. One example, on pressing Alt+e, // the accent (´) character is composed via setMarkedText:. Now on pressing // the character 'r', two insertText:replacementRange: action messages are // generated with the text value of accent (´) and 'r' respectively. The key @@ -541,7 +586,7 @@ // Currently there seems to be no use case to pass non-character events routed // from insertText: handlers to the View hierarchy. - if (isCharacterEvent && ![self hasMarkedText]) { + if (isFinalInsertForKeyEvent && ![self hasMarkedText]) { ui::KeyEvent charEvent([text characterAtIndex:0], ui::KeyboardCodeFromNSEvent(keyDownEvent_), ui::EF_NONE); @@ -561,18 +606,26 @@ // the key modifier since |text| already accounts for the pressed key // modifiers. - // Also, note we don't use |keyDownEvent_| to generate the synthetic - // ui::KeyEvent since for composed text, [keyDownEvent_ characters] might - // not be the same as |text|. This is because |keyDownEvent_| will - // correspond to the event that caused the composition text to be confirmed, - // say, Return key press. + // Also, note we don't check isFinalInsertForKeyEvent, nor use + // |keyDownEvent_| to generate the synthetic ui::KeyEvent since: For + // composed text, [keyDownEvent_ characters] might not be the same as + // |text|. This is because |keyDownEvent_| will correspond to the event that + // caused the composition text to be confirmed, say, Return key press. if (isCharacterEvent) { textInputClient_->InsertChar(ui::KeyEvent([text characterAtIndex:0], ui::VKEY_UNKNOWN, ui::EF_NONE)); + // Leave character events that may have triggered IME confirmation for + // inline IME (e.g. Korean) as "unhandled". There will be no more + // -insertText: messages, but we are unable to handle these via + // -handleKeyEvent: earlier in this method since toolkit-views client code + // assumes it can ignore characters associated with, e.g., VKEY_TAB. + DCHECK(keyDownEvent_); // Otherwise it is not a character event. + if ([self hasMarkedText] || !IsImeTriggerEvent(keyDownEvent_)) + hasUnhandledKeyDownEvent_ = NO; } else { textInputClient_->InsertText(base::SysNSStringToUTF16(text)); + hasUnhandledKeyDownEvent_ = NO; } - hasUnhandledKeyDownEvent_ = NO; } } @@ -746,7 +799,7 @@ - (NSTextInputContext*)inputContext { // If the textInputClient_ does not exist, return nil since this view does not // conform to NSTextInputClient protocol. - if (!textInputClient_) + if (!pendingTextInputClient_) return nil; // If a menu is active, and -[NSView interpretKeyEvents:] asks for the @@ -759,7 +812,7 @@ // (http://crbug.com/23219), we don't want to show IME candidate windows. // Returning nil prevents this view from getting messages defined as part of // the NSTextInputClient protocol. - switch (textInputClient_->GetTextInputType()) { + switch (pendingTextInputClient_->GetTextInputType()) { case ui::TEXT_INPUT_TYPE_NONE: case ui::TEXT_INPUT_TYPE_PASSWORD: return nil;
diff --git a/ui/views/cocoa/bridged_native_widget.mm b/ui/views/cocoa/bridged_native_widget.mm index 2c8faeab..1c631ed3 100644 --- a/ui/views/cocoa/bridged_native_widget.mm +++ b/ui/views/cocoa/bridged_native_widget.mm
@@ -1204,8 +1204,11 @@ AddCompositorSuperview(); + // TODO(ccameron): Re-enable compositor recycling here. + // https://crbug.com/863817 compositor_ = ui::RecyclableCompositorMacFactory::Get()->CreateCompositor( - context_factory, context_factory_private); + context_factory, context_factory_private, + true /* force_new_compositor */); compositor_->widget()->SetNSView(this); } @@ -1236,8 +1239,9 @@ return; compositor_->widget()->ResetNSView(); compositor_->compositor()->SetRootLayer(nullptr); - ui::RecyclableCompositorMacFactory::Get()->RecycleCompositor( - std::move(compositor_)); + // TODO(ccameron): Re-enable compositor recycling here. + // https://crbug.com/863817 + compositor_.reset(); } void BridgedNativeWidget::AddCompositorSuperview() {
diff --git a/ui/views/cocoa/bridged_native_widget_unittest.mm b/ui/views/cocoa/bridged_native_widget_unittest.mm index 282a17b..f25287d 100644 --- a/ui/views/cocoa/bridged_native_widget_unittest.mm +++ b/ui/views/cocoa/bridged_native_widget_unittest.mm
@@ -10,6 +10,7 @@ #import "base/mac/foundation_util.h" #import "base/mac/mac_util.h" +#import "base/mac/scoped_objc_class_swizzler.h" #import "base/mac/sdk_forward_declarations.h" #include "base/macros.h" #include "base/strings/stringprintf.h" @@ -28,6 +29,7 @@ #import "ui/views/cocoa/native_widget_mac_nswindow.h" #import "ui/views/cocoa/views_nswindow_delegate.h" #include "ui/views/controls/textfield/textfield.h" +#include "ui/views/controls/textfield/textfield_controller.h" #include "ui/views/controls/textfield/textfield_model.h" #include "ui/views/test/test_views_delegate.h" #include "ui/views/view.h" @@ -197,8 +199,54 @@ sel == @selector(moveLeftAndModifySelection:); } +// Used by InterpretKeyEventsDonorForNSView to simulate IME behavior. +using InterpretKeyEventsCallback = base::RepeatingCallback<void(id)>; +InterpretKeyEventsCallback* g_fake_interpret_key_events = nullptr; + +// Used by UpdateWindowsDonorForNSApp to hook -[NSApp updateWindows]. +base::RepeatingClosure* g_update_windows_closure = nullptr; + +// Used to provide a return value for +[NSTextInputContext currentInputContext]. +NSTextInputContext* g_fake_current_input_context = nullptr; + } // namespace +// Class to hook [NSView interpretKeyEvents:] to simulate it interacting with an +// IME window. +@interface InterpretKeyEventsDonorForNSView : NSView +@end + +@implementation InterpretKeyEventsDonorForNSView + +- (void)interpretKeyEvents:(NSArray<NSEvent*>*)eventArray { + ASSERT_TRUE(g_fake_interpret_key_events); + g_fake_interpret_key_events->Run(self); +} + +@end + +@interface UpdateWindowsDonorForNSApp : NSApplication +@end + +@implementation UpdateWindowsDonorForNSApp + +- (void)updateWindows { + ASSERT_TRUE(g_update_windows_closure); + g_update_windows_closure->Run(); +} + +@end +@interface CurrentInputContextDonorForNSTextInputContext : NSTextInputContext +@end + +@implementation CurrentInputContextDonorForNSTextInputContext + ++ (NSTextInputContext*)currentInputContext { + return g_fake_current_input_context; +} + +@end + // Class to override -[NSWindow toggleFullScreen:] to a no-op. This simulates // NSWindow's behavior when attempting to toggle fullscreen state again, when // the last attempt failed but Cocoa has not yet sent @@ -326,22 +374,21 @@ DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidgetTestBase); }; -class BridgedNativeWidgetTest : public BridgedNativeWidgetTestBase { +class BridgedNativeWidgetTest : public BridgedNativeWidgetTestBase, + public TextfieldController { public: + using HandleKeyEventCallback = + base::RepeatingCallback<bool(Textfield*, const ui::KeyEvent& key_event)>; + BridgedNativeWidgetTest(); ~BridgedNativeWidgetTest() override; // Install a textfield with input type |text_input_type| in the view hierarchy // and make it the text input client. Also initializes |dummy_text_view_|. - void InstallTextField(const base::string16& text, - ui::TextInputType text_input_type); - - // Install a textfield with input type ui::TEXT_INPUT_TYPE_TEXT in the view - // hierarchy and make it the text input client. Also initializes - // |dummy_text_view_|. - void InstallTextField(const base::string16& text); - - void InstallTextField(const std::string& text); + Textfield* InstallTextField( + const base::string16& text, + ui::TextInputType text_input_type = ui::TEXT_INPUT_TYPE_TEXT); + Textfield* InstallTextField(const std::string& text); // Returns the actual current text for |ns_view_|, or the selected substring. NSString* GetActualText(); @@ -372,10 +419,17 @@ // Helper method to set the private |keyDownEvent_| field on |ns_view_|. void SetKeyDownEvent(NSEvent* event); + // Sets a callback to run on the next HandleKeyEvent(). + void SetHandleKeyEventCallback(HandleKeyEventCallback callback); + // testing::Test: void SetUp() override; void TearDown() override; + // TextfieldController: + bool HandleKeyEvent(Textfield* sender, + const ui::KeyEvent& key_event) override; + protected: // Test delete to beginning of line or paragraph based on |sel|. |sel| can be // either deleteToBeginningOfLine: or deleteToBeginningOfParagraph:. @@ -402,6 +456,8 @@ // An NSTextView which helps set the expectations for our tests. base::scoped_nsobject<NSTextView> dummy_text_view_; + HandleKeyEventCallback handle_key_event_callback_; + base::test::ScopedTaskEnvironment scoped_task_environment_; private: @@ -415,12 +471,13 @@ BridgedNativeWidgetTest::~BridgedNativeWidgetTest() { } -void BridgedNativeWidgetTest::InstallTextField( +Textfield* BridgedNativeWidgetTest::InstallTextField( const base::string16& text, ui::TextInputType text_input_type) { Textfield* textfield = new Textfield(); textfield->SetText(text); textfield->SetTextInputType(text_input_type); + textfield->set_controller(this); view_->RemoveAllChildViews(true); view_->AddChildView(textfield); textfield->SetBoundsRect(init_params_.bounds); @@ -437,14 +494,11 @@ dummy_text_view_.reset( [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]); [dummy_text_view_ setString:SysUTF16ToNSString(text)]; + return textfield; } -void BridgedNativeWidgetTest::InstallTextField(const base::string16& text) { - InstallTextField(text, ui::TEXT_INPUT_TYPE_TEXT); -} - -void BridgedNativeWidgetTest::InstallTextField(const std::string& text) { - InstallTextField(base::ASCIIToUTF16(text), ui::TEXT_INPUT_TYPE_TEXT); +Textfield* BridgedNativeWidgetTest::InstallTextField(const std::string& text) { + return InstallTextField(base::ASCIIToUTF16(text)); } NSString* BridgedNativeWidgetTest::GetActualText() { @@ -502,6 +556,11 @@ [ns_view_ setValue:event forKey:@"keyDownEvent_"]; } +void BridgedNativeWidgetTest::SetHandleKeyEventCallback( + HandleKeyEventCallback callback) { + handle_key_event_callback_ = std::move(callback); +} + void BridgedNativeWidgetTest::SetUp() { BridgedNativeWidgetTestBase::SetUp(); @@ -534,6 +593,13 @@ BridgedNativeWidgetTestBase::TearDown(); } +bool BridgedNativeWidgetTest::HandleKeyEvent(Textfield* sender, + const ui::KeyEvent& key_event) { + if (handle_key_event_callback_) + return handle_key_event_callback_.Run(sender, key_event); + return false; +} + void BridgedNativeWidgetTest::TestDeleteBeginning(SEL sel) { InstallTextField("foo bar baz"); EXPECT_EQ_RANGE_3(NSMakeRange(11, 0), GetExpectedSelectionRange(), @@ -1325,6 +1391,187 @@ EXPECT_EQ_RANGE(query_range, actual_range); } +// Test simulated codepaths for IMEs that do not always "mark" text. E.g. +// phonetic languages such as Korean and Vietnamese. +TEST_F(BridgedNativeWidgetTest, TextInput_SimulatePhoneticIme) { + Textfield* textfield = InstallTextField(""); + EXPECT_TRUE([ns_view_ textInputClient]); + + base::mac::ScopedObjCClassSwizzler interpret_key_events_swizzler( + [NSView class], [InterpretKeyEventsDonorForNSView class], + @selector(interpretKeyEvents:)); + + // Sequence of calls (and corresponding keyDown events) obtained via tracing + // with 2-Set Korean IME and pressing q, o, then Enter on the keyboard. + NSEvent* q_in_ime = cocoa_test_event_utils::KeyEventWithKeyCode( + 12, [@"ㅂ" characterAtIndex:0], NSKeyDown, 0); + InterpretKeyEventsCallback handle_q_in_ime = base::BindRepeating([](id view) { + [view insertText:@"ㅂ" replacementRange:NSMakeRange(NSNotFound, 0)]; + }); + + NSEvent* o_in_ime = cocoa_test_event_utils::KeyEventWithKeyCode( + 31, [@"ㅐ" characterAtIndex:0], NSKeyDown, 0); + InterpretKeyEventsCallback handle_o_in_ime = base::BindRepeating([](id view) { + [view insertText:@"배" replacementRange:NSMakeRange(0, 1)]; + }); + + NSEvent* return_in_ime = cocoa_test_event_utils::SynthesizeKeyEvent( + widget_->GetNativeWindow(), true, ui::VKEY_RETURN, 0); + InterpretKeyEventsCallback handle_return_in_ime = + base::BindRepeating([](id view) { + // When confirming the composition, AppKit repeats itself. + [view insertText:@"배" replacementRange:NSMakeRange(0, 1)]; + [view insertText:@"배" replacementRange:NSMakeRange(0, 1)]; + // Note: there is no insertText:@"\r", which we would normally see when + // not in an IME context for VKEY_RETURN. + }); + + // Add a hook for the KeyEvent being received by the TextfieldController. E.g. + // this is where the Omnibox would start to search when Return is pressed. + bool saw_vkey_return = false; + SetHandleKeyEventCallback(base::BindRepeating( + [](bool* saw_return, Textfield* textfield, const ui::KeyEvent& event) { + if (event.key_code() == ui::VKEY_RETURN) { + EXPECT_FALSE(*saw_return); + *saw_return = true; + EXPECT_EQ(base::SysNSStringToUTF16(@"배"), textfield->text()); + } + return false; + }, + &saw_vkey_return)); + + EXPECT_EQ(base::UTF8ToUTF16(""), textfield->text()); + + g_fake_interpret_key_events = &handle_q_in_ime; + [ns_view_ keyDown:q_in_ime]; + EXPECT_EQ(base::SysNSStringToUTF16(@"ㅂ"), textfield->text()); + EXPECT_FALSE(saw_vkey_return); + + g_fake_interpret_key_events = &handle_o_in_ime; + [ns_view_ keyDown:o_in_ime]; + EXPECT_EQ(base::SysNSStringToUTF16(@"배"), textfield->text()); + EXPECT_FALSE(saw_vkey_return); + + // Note the "Enter" should not replace the replacement range, even though a + // replacement range was set. + g_fake_interpret_key_events = &handle_return_in_ime; + [ns_view_ keyDown:return_in_ime]; + EXPECT_EQ(base::SysNSStringToUTF16(@"배"), textfield->text()); + + // VKEY_RETURN should be seen by via the unhandled key event handler (but not + // via -insertText:. + EXPECT_TRUE(saw_vkey_return); + + g_fake_interpret_key_events = nullptr; +} + +// Test a codepath that could hypothetically cause [NSApp updateWindows] to be +// called recursively due to IME dismissal during teardown triggering a focus +// change. Twice. +TEST_F(BridgedNativeWidgetTest, TextInput_RecursiveUpdateWindows) { + Textfield* textfield = InstallTextField(""); + EXPECT_TRUE([ns_view_ textInputClient]); + + base::mac::ScopedObjCClassSwizzler interpret_key_events_swizzler( + [NSView class], [InterpretKeyEventsDonorForNSView class], + @selector(interpretKeyEvents:)); + base::mac::ScopedObjCClassSwizzler update_windows_swizzler( + [NSApplication class], [UpdateWindowsDonorForNSApp class], + @selector(updateWindows)); + base::mac::ScopedObjCClassSwizzler current_input_context_swizzler( + [NSTextInputContext class], + [CurrentInputContextDonorForNSTextInputContext class], + @selector(currentInputContext)); + + int vkey_return_count = 0; + + // Everything happens with this one event. + NSEvent* return_with_fake_ime = cocoa_test_event_utils::SynthesizeKeyEvent( + widget_->GetNativeWindow(), true, ui::VKEY_RETURN, 0); + + InterpretKeyEventsCallback generate_return_and_fake_ime = base::BindRepeating( + [](int* saw_return_count, id view) { + EXPECT_EQ(0, *saw_return_count); + // First generate the return to simulate an input context change. + [view insertText:@"\r" replacementRange:NSMakeRange(NSNotFound, 0)]; + + EXPECT_EQ(1, *saw_return_count); + }, + &vkey_return_count); + + bool saw_update_windows = false; + base::RepeatingClosure update_windows_closure = base::BindRepeating( + [](bool* saw_update_windows, BridgedContentView* view, + Textfield* textfield) { + // Ensure updateWindows is not invoked recursively. + EXPECT_FALSE(*saw_update_windows); + *saw_update_windows = true; + + // Inside updateWindows, assume the IME got dismissed and wants to + // insert its last bit of text for the old input context. + [view insertText:@"배" replacementRange:NSMakeRange(0, 1)]; + + // This is triggered by the setTextInputClient:nullptr in + // SetHandleKeyEventCallback(), so -inputContext should also be nil. + EXPECT_FALSE([view inputContext]); + + // Ensure we can't recursively call updateWindows. A TextInputClient + // reacting to InsertChar could theoretically do this, but toolkit-views + // DCHECKs if there is recursive event dispatch, so call + // setTextInputClient directly. + [view setTextInputClient:textfield]; + + // Finally simulate what -[NSApp updateWindows] should _actually_ do, + // which is to update the input context (from the first responder). + g_fake_current_input_context = [view inputContext]; + + // Now, the |textfield| set above should have been set again. + EXPECT_TRUE(g_fake_current_input_context); + }, + &saw_update_windows, ns_view_, textfield); + + SetHandleKeyEventCallback(base::BindRepeating( + [](int* saw_return_count, BridgedContentView* view, Textfield* textfield, + const ui::KeyEvent& event) { + if (event.key_code() == ui::VKEY_RETURN) { + *saw_return_count += 1; + // Simulate Textfield::OnBlur() by clearing the input method. + // Textfield needs to be in a Widget to do this normally. + [view setTextInputClient:nullptr]; + } + return false; + }, + &vkey_return_count, ns_view_)); + + // Starting text (just insert it). + [ns_view_ insertText:@"ㅂ" replacementRange:NSMakeRange(NSNotFound, 0)]; + + EXPECT_EQ(base::SysNSStringToUTF16(@"ㅂ"), textfield->text()); + + g_fake_interpret_key_events = &generate_return_and_fake_ime; + g_update_windows_closure = &update_windows_closure; + g_fake_current_input_context = [ns_view_ inputContext]; + EXPECT_TRUE(g_fake_current_input_context); + [ns_view_ keyDown:return_with_fake_ime]; + + // We should see one VKEY_RETURNs and one updateWindows. In particular, note + // that there is not a second VKEY_RETURN seen generated by keyDown: thinking + // the event has been unhandled. This is because it was handled when the fake + // IME sent \r. + EXPECT_TRUE(saw_update_windows); + EXPECT_EQ(1, vkey_return_count); + + // The text inserted during updateWindows should have been inserted, even + // though we were trying to change the input context. + EXPECT_EQ(base::SysNSStringToUTF16(@"배"), textfield->text()); + + EXPECT_TRUE(g_fake_current_input_context); + + g_fake_current_input_context = nullptr; + g_fake_interpret_key_events = nullptr; + g_update_windows_closure = nullptr; +} + typedef BridgedNativeWidgetTestBase BridgedNativeWidgetSimulateFullscreenTest; // Simulate the notifications that AppKit would send out if a fullscreen
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc index 19f7ed42..65ee52f 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc
@@ -1599,18 +1599,26 @@ if (LOWORD(w_param) != HIWORD(w_param)) NOTIMPLEMENTED() << "Received non-square scaling factors"; + int dpi; + float scaling_factor; + if (display::Display::HasForceDeviceScaleFactor()) { + scaling_factor = display::Display::GetForcedDeviceScaleFactor(); + dpi = display::win::GetDPIFromScalingFactor(scaling_factor); + } else { + dpi = LOWORD(w_param); + scaling_factor = display::win::GetScalingFactorFromDPI(dpi_); + } + // The first WM_DPICHANGED originates from EnableChildWindowDpiMessage during // initialization. We don't want to propagate this as the client is already // set at the current scale factor and may cause the window to display too // soon. See http://crbug.com/625076. - int dpi = LOWORD(w_param); if (dpi_ == dpi) return 0; dpi_ = dpi; SetBoundsInternal(gfx::Rect(*reinterpret_cast<RECT*>(l_param)), false); - delegate_->HandleWindowScaleFactorChanged( - display::win::GetScalingFactorFromDPI(dpi_)); + delegate_->HandleWindowScaleFactorChanged(scaling_factor); return 0; }
diff --git a/ui/web_dialogs/web_dialog_ui.cc b/ui/web_dialogs/web_dialog_ui.cc index 9b1d765..bb1b899 100644 --- a/ui/web_dialogs/web_dialog_ui.cc +++ b/ui/web_dialogs/web_dialog_ui.cc
@@ -120,4 +120,15 @@ HandleRenderFrameCreated(render_frame_host); } +MojoWebDialogUI::MojoWebDialogUI(content::WebUI* web_ui) + : WebDialogUIBase(web_ui), MojoWebUIController(web_ui) {} + +MojoWebDialogUI::~MojoWebDialogUI() = default; + +void MojoWebDialogUI::RenderFrameCreated( + content::RenderFrameHost* render_frame_host) { + content::WebUIController::RenderFrameCreated(render_frame_host); + HandleRenderFrameCreated(render_frame_host); +} + } // namespace ui
diff --git a/ui/web_dialogs/web_dialog_ui.h b/ui/web_dialogs/web_dialog_ui.h index 62d83ee3..3df3093c 100644 --- a/ui/web_dialogs/web_dialog_ui.h +++ b/ui/web_dialogs/web_dialog_ui.h
@@ -83,23 +83,17 @@ // Displays file URL contents inside a modal web dialog while also enabling // Mojo calls to be made from within the dialog. -template <typename Interface> class WEB_DIALOGS_EXPORT MojoWebDialogUI : public WebDialogUIBase, public MojoWebUIController { public: // When created, the delegate should already be set as user data on the // WebContents. - explicit MojoWebDialogUI(content::WebUI* web_ui) - : WebDialogUIBase(web_ui), MojoWebUIController(web_ui) {} - ~MojoWebDialogUI() override {} + explicit MojoWebDialogUI(content::WebUI* web_ui); + ~MojoWebDialogUI() override; private: // content::WebUIController: - void RenderFrameCreated( - content::RenderFrameHost* render_frame_host) override { - content::WebUIController::RenderFrameCreated(render_frame_host); - HandleRenderFrameCreated(render_frame_host); - } + void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override; DISALLOW_COPY_AND_ASSIGN(MojoWebDialogUI); };
diff --git a/ui/webui/resources/cr_elements/icons.html b/ui/webui/resources/cr_elements/icons.html index 186e3c61..4b842d6 100644 --- a/ui/webui/resources/cr_elements/icons.html +++ b/ui/webui/resources/cr_elements/icons.html
@@ -65,6 +65,7 @@ <g id="settings_icon"><path d="M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.3-.61-.22l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.23-.09-.49 0-.61.22l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98s.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.12.22.39.3.61.22l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.23.09.49 0 .61-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zM12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z"></path></g> <g id="star"><path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"></path></g> <g id="supervisor-account" viewBox="0 0 48 48"><path d="M0 0h48v48H0z" fill="none"></path><path d="M33 24c2.76 0 4.98-2.24 4.98-5s-2.22-5-4.98-5c-2.76 0-5 2.24-5 5s2.24 5 5 5zm-15-2c3.31 0 5.98-2.69 5.98-6s-2.67-6-5.98-6c-3.31 0-6 2.69-6 6s2.69 6 6 6zm15 6c-3.67 0-11 1.84-11 5.5V38h22v-4.5c0-3.66-7.33-5.5-11-5.5zm-15-2c-4.67 0-14 2.34-14 7v5h14v-4.5c0-1.7.67-4.67 4.74-6.94C21 26.19 19.31 26 18 26z"></path></g> + <g id="sync"><path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z"></path></g> <g id="warning"><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"></path></g> </defs> </svg>