diff --git a/DEPS b/DEPS index 865f2b3..be83482 100644 --- a/DEPS +++ b/DEPS
@@ -91,7 +91,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': 'f7df8568ae1f63ee17f08a73b49261afe9f7ea8c', + 'catapult_revision': '184187257422cb5901d928ae75b3caa6b9b1ae42', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other.
diff --git a/android_webview/browser/browser_view_renderer.cc b/android_webview/browser/browser_view_renderer.cc index 121512c..f9c9d19 100644 --- a/android_webview/browser/browser_view_renderer.cc +++ b/android_webview/browser/browser_view_renderer.cc
@@ -263,7 +263,7 @@ DCHECK(compositor_frame_consumer); if (compositor_frame_consumer != current_compositor_frame_consumer_) return; - PostInvalidate(); + PostInvalidate(compositor_); external_draw_constraints_ = current_compositor_frame_consumer_->GetParentDrawConstraintsOnUI(); UpdateMemoryPolicy(); @@ -359,7 +359,7 @@ clear_view_ = true; // Always invalidate ignoring the compositor to actually clear the webview. - PostInvalidate(); + PostInvalidate(compositor_); } void BrowserViewRenderer::SetOffscreenPreRaster(bool enable) { @@ -570,10 +570,14 @@ } } -void BrowserViewRenderer::DidUpdateContent() { +void BrowserViewRenderer::DidUpdateContent( + content::SynchronousCompositor* compositor) { TRACE_EVENT_INSTANT0("android_webview", "BrowserViewRenderer::DidUpdateContent", TRACE_EVENT_SCOPE_THREAD); + if (compositor != compositor_) + return; + clear_view_ = false; if (on_new_picture_enable_) client_->OnNewPicture(); @@ -608,12 +612,16 @@ } void BrowserViewRenderer::UpdateRootLayerState( + content::SynchronousCompositor* compositor, const gfx::Vector2dF& total_scroll_offset_dip, const gfx::Vector2dF& max_scroll_offset_dip, const gfx::SizeF& scrollable_size_dip, float page_scale_factor, float min_page_scale_factor, float max_page_scale_factor) { + if (compositor != compositor_) + return; + TRACE_EVENT_INSTANT1( "android_webview", "BrowserViewRenderer::UpdateRootLayerState", @@ -666,9 +674,13 @@ } void BrowserViewRenderer::DidOverscroll( + content::SynchronousCompositor* compositor, const gfx::Vector2dF& accumulated_overscroll, const gfx::Vector2dF& latest_overscroll_delta, const gfx::Vector2dF& current_fling_velocity) { + if (compositor != compositor_) + return; + const float physical_pixel_scale = dip_scale_ * page_scale_factor_; if (accumulated_overscroll == latest_overscroll_delta) overscroll_rounding_error_ = gfx::Vector2dF(); @@ -684,9 +696,13 @@ client_->DidOverscroll(rounded_overscroll_delta, fling_velocity_pixels); } -void BrowserViewRenderer::PostInvalidate() { +void BrowserViewRenderer::PostInvalidate( + content::SynchronousCompositor* compositor) { TRACE_EVENT_INSTANT0("android_webview", "BrowserViewRenderer::PostInvalidate", TRACE_EVENT_SCOPE_THREAD); + if (compositor != compositor_) + return; + client_->PostInvalidate(); }
diff --git a/android_webview/browser/browser_view_renderer.h b/android_webview/browser/browser_view_renderer.h index f7574e8e..37e21742 100644 --- a/android_webview/browser/browser_view_renderer.h +++ b/android_webview/browser/browser_view_renderer.h
@@ -116,15 +116,17 @@ void DidDestroyCompositor(content::SynchronousCompositor* compositor, int process_id, int routing_id) override; - void PostInvalidate() override; - void DidUpdateContent() override; - void UpdateRootLayerState(const gfx::Vector2dF& total_scroll_offset_dip, + void PostInvalidate(content::SynchronousCompositor* compositor) override; + void DidUpdateContent(content::SynchronousCompositor* compositor) override; + void UpdateRootLayerState(content::SynchronousCompositor* compositor, + const gfx::Vector2dF& total_scroll_offset_dip, const gfx::Vector2dF& max_scroll_offset_dip, const gfx::SizeF& scrollable_size_dip, float page_scale_factor, float min_page_scale_factor, float max_page_scale_factor) override; - void DidOverscroll(const gfx::Vector2dF& accumulated_overscroll, + void DidOverscroll(content::SynchronousCompositor* compositor, + const gfx::Vector2dF& accumulated_overscroll, const gfx::Vector2dF& latest_overscroll_delta, const gfx::Vector2dF& current_fling_velocity) override; @@ -153,7 +155,6 @@ void UpdateMemoryPolicy(); - uint32_t GetCompositorID(content::SynchronousCompositor* compositor); // For debug tracing or logging. Return the string representation of this // view renderer's state. std::string ToString() const;
diff --git a/android_webview/browser/browser_view_renderer_unittest.cc b/android_webview/browser/browser_view_renderer_unittest.cc index 1bcfd0f..b3640f27 100644 --- a/android_webview/browser/browser_view_renderer_unittest.cc +++ b/android_webview/browser/browser_view_renderer_unittest.cc
@@ -20,7 +20,9 @@ namespace android_webview { class SmokeTest : public RenderingTest { - void StartTest() override { browser_view_renderer_->PostInvalidate(); } + void StartTest() override { + browser_view_renderer_->PostInvalidate(compositor_.get()); + } void DidDrawOnRT() override { EndTest(); } }; @@ -32,7 +34,7 @@ ClearViewTest() : on_draw_count_(0) {} void StartTest() override { - browser_view_renderer_->PostInvalidate(); + browser_view_renderer_->PostInvalidate(compositor_.get()); browser_view_renderer_->ClearView(); } @@ -41,8 +43,9 @@ if (on_draw_count_ == 1) { // First OnDraw should be skipped due to ClearView. EXPECT_FALSE(success); - browser_view_renderer_->DidUpdateContent(); // Unset ClearView. - browser_view_renderer_->PostInvalidate(); + browser_view_renderer_->DidUpdateContent( + compositor_.get()); // Unset ClearView. + browser_view_renderer_->PostInvalidate(compositor_.get()); } else { // Following OnDraws should succeed. EXPECT_TRUE(success); @@ -65,7 +68,7 @@ new_constraints_ = ParentCompositorDrawConstraints( false, gfx::Transform(), window_->surface_size().IsEmpty()); new_constraints_.transform.Scale(2.0, 2.0); - browser_view_renderer_->PostInvalidate(); + browser_view_renderer_->PostInvalidate(compositor_.get()); } void WillOnDraw() override { @@ -157,7 +160,7 @@ CompositorNoFrameTest() : on_draw_count_(0) {} void StartTest() override { - browser_view_renderer_->PostInvalidate(); + browser_view_renderer_->PostInvalidate(compositor_.get()); } void WillOnDraw() override { @@ -175,11 +178,11 @@ if (0 == on_draw_count_) { // Should fail as there has been no frames from compositor. EXPECT_FALSE(success); - browser_view_renderer_->PostInvalidate(); + browser_view_renderer_->PostInvalidate(compositor_.get()); } else if (1 == on_draw_count_) { // Should succeed with frame from compositor. EXPECT_TRUE(success); - browser_view_renderer_->PostInvalidate(); + browser_view_renderer_->PostInvalidate(compositor_.get()); } else if (2 == on_draw_count_) { // Should still succeed with last frame, even if no frame from compositor. EXPECT_TRUE(success); @@ -242,7 +245,7 @@ bool AdvanceFrame() { next_frame_ = GetFrame(frame_number_++); if (next_frame_) { - browser_view_renderer_->PostInvalidate(); + browser_view_renderer_->PostInvalidate(compositor_.get()); return true; } return false;
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 7632d43d..89c6797 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -358,6 +358,7 @@ "//components/user_manager", "//content/public/browser", "//content/test:test_support", + "//mojo/edk/system", "//skia", "//testing/gtest", "//third_party/icu",
diff --git a/ash/test/DEPS b/ash/test/DEPS index 73c7fc62..c1cc0f73 100644 --- a/ash/test/DEPS +++ b/ash/test/DEPS
@@ -2,6 +2,7 @@ "+content/public/test/web_contents_tester.h", "+content/public/test/test_browser_thread_bundle.h", "+content/public/test/test_browser_context.h", + "+mojo/edk", "+win8/viewer", ]
diff --git a/ash/test/ash_unittests.cc b/ash/test/ash_unittests.cc index 9365587..91fcbfc 100644 --- a/ash/test/ash_unittests.cc +++ b/ash/test/ash_unittests.cc
@@ -5,10 +5,12 @@ #include "ash/test/test_suite.h" #include "base/bind.h" #include "base/test/launcher/unit_test_launcher.h" +#include "mojo/edk/embedder/embedder.h" int main(int argc, char** argv) { ash::test::AuraShellTestSuite test_suite(argc, argv); + mojo::edk::Init(); return base::LaunchUnitTests(argc, argv, base::Bind(&ash::test::AuraShellTestSuite::Run, base::Unretained(&test_suite)));
diff --git a/ash/wm/system_modal_container_layout_manager.cc b/ash/wm/system_modal_container_layout_manager.cc index 8a9e859..8446cfd 100644 --- a/ash/wm/system_modal_container_layout_manager.cc +++ b/ash/wm/system_modal_container_layout_manager.cc
@@ -11,6 +11,7 @@ #include "ash/shell.h" #include "ash/wm/dim_window.h" #include "ash/wm/window_util.h" +#include "base/stl_util.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/client/capture_client.h" #include "ui/aura/window.h" @@ -87,9 +88,13 @@ if (key != aura::client::kModalKey) return; - if (window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE) { + ui::ModalType new_modal = window->GetProperty(aura::client::kModalKey); + if (static_cast<ui::ModalType>(old) == new_modal) + return; + + if (new_modal != ui::MODAL_TYPE_NONE) { AddModalWindow(window); - } else if (static_cast<ui::ModalType>(old) != ui::MODAL_TYPE_NONE) { + } else { RemoveModalWindow(window); Shell::GetInstance()->OnModalWindowRemoved(window); } @@ -185,6 +190,8 @@ if (capture_window) capture_window->ReleaseCapture(); } + DCHECK(!ContainsValue(modal_windows_, window)); + modal_windows_.push_back(window); Shell::GetInstance()->CreateModalBackground(window); window->parent()->StackChildAtTop(window);
diff --git a/ash/wm/system_modal_container_layout_manager_unittest.cc b/ash/wm/system_modal_container_layout_manager_unittest.cc index c1579cf..f9b53e0 100644 --- a/ash/wm/system_modal_container_layout_manager_unittest.cc +++ b/ash/wm/system_modal_container_layout_manager_unittest.cc
@@ -6,6 +6,7 @@ #include "ash/common/session/session_state_delegate.h" #include "ash/common/shell_window_ids.h" +#include "ash/common/wm_shell.h" #include "ash/root_window_controller.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" @@ -13,6 +14,7 @@ #include "base/command_line.h" #include "base/compiler_specific.h" #include "base/run_loop.h" +#include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/compositor/layer.h" @@ -648,5 +650,31 @@ ShowKeyboard(false); } +TEST_F(SystemModalContainerLayoutManagerTest, UpdateModalType) { + aura::Window* modal_container = Shell::GetContainer( + Shell::GetPrimaryRootWindow(), kShellWindowId_SystemModalContainer); + views::Widget* widget = views::Widget::CreateWindowWithParent( + new TestWindow(false), modal_container); + widget->Show(); + aura::Window* window = widget->GetNativeWindow(); + EXPECT_FALSE(WmShell::Get()->IsSystemModalWindowOpen()); + + window->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_SYSTEM); + EXPECT_TRUE(WmShell::Get()->IsSystemModalWindowOpen()); + + // Setting twice should not cause error. + window->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_SYSTEM); + EXPECT_TRUE(WmShell::Get()->IsSystemModalWindowOpen()); + + window->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_NONE); + EXPECT_FALSE(WmShell::Get()->IsSystemModalWindowOpen()); + + window->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_SYSTEM); + EXPECT_TRUE(WmShell::Get()->IsSystemModalWindowOpen()); + + widget->Close(); + EXPECT_FALSE(WmShell::Get()->IsSystemModalWindowOpen()); +} + } // namespace test } // namespace ash
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn index 1445e4af..6376732 100644 --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn
@@ -537,6 +537,12 @@ configs = _executable_configs } +if (is_ios) { + set_defaults("ios_app_bundle") { + configs = _executable_configs + } +} + # Static library defaults. set_defaults("static_library") { configs = _native_compiler_configs
diff --git a/chrome/VERSION b/chrome/VERSION index 1b2f145..f2040b0 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=53 MINOR=0 -BUILD=2771 +BUILD=2772 PATCH=0
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index faa2d14..7b8f074 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -746,6 +746,15 @@ <message name="IDS_FILE_BROWSER_MANY_ENTRIES_SELECTED" desc="Many items (both files and directories) selected."> <ph name="SELCTED_FILES_COUNT">$1<ex>21</ex></ph> items selected </message> + <message name="IDS_FILE_BROWSER_METADATA_BOX_FILE_SIZE" desc="Label fo file size."> + Size + </message> + <message name="IDS_FILE_BROWSER_METADATA_BOX_GENERAL_INFO" desc="Category label for general file info."> + General Info + </message> + <message name="IDS_FILE_BROWSER_METADATA_BOX_MODIFICATION_TIME" desc="Label for file modification time."> + Modified Time + </message> <message name="IDS_FILE_BROWSER_CALCULATING_SIZE" desc="Message informing the user that total items size is being calculated."> Calculating size </message> @@ -2545,6 +2554,12 @@ <message name="IDS_OPTIONS_SETTINGS_STORAGE_MANAGER_TAB_TITLE" desc="Title for the storage manager tab."> Storage </message> + <message name="IDS_OPTIONS_SETTINGS_STORAGE_CLEAR_DRIVE_CACHE_TAB_TITLE" desc="Title for the storage manager confirmation dialog tab to remove Google Drive offline files."> + Offline files + </message> + <message name="IDS_OPTIONS_SETTINGS_STORAGE_CLEAR_DRIVE_CACHE_DESCRIPTION" desc="Description in the storage manager confirmation dialog to remove Google Drive offline files."> + You can free up space by deleting Google Drive offline files. Files marked as "Available offline" or in use will not be deleted. + </message> <message name="IDS_OPTIONS_SETTINGS_STORAGE_SIZE_CALCULATING" desc="In storage manager overlay, label for storage item's size indicating the size is being calculated."> Calculating... </message> @@ -2563,9 +2578,15 @@ <message name="IDS_OPTIONS_SETTINGS_STORAGE_SUBITEM_LABEL_DOWNLOADS" desc="In storage manager overlay, label for the size of Downloads directory."> Downloads </message> + <message name="IDS_OPTIONS_SETTINGS_STORAGE_SUBITEM_LABEL_DRIVE_CACHE" desc="In storage manager overlay, label for the size of Google Drive's offline files."> + Offline files + </message> <message name="IDS_OPTIONS_SETTINGS_STORAGE_SUBITEM_LABEL_ARC" desc="In storage manager overlay, label for the total size size of Android apps and cache."> Android apps and cache </message> + <message name="IDS_OPTIONS_SETTINGS_STORAGE_DELETE_ALL_BUTTON_TITLE" desc="In storage manager overlay, label for the total size size of Android apps and cache."> + Delete all + </message> <message name="IDS_OPTIONS_ACCOUNTS_ALLOW_BWSI_DESCRIPTION" desc="In the Accounts settings tab, the text on the checkbox to allow browse without signing in."> Enable Guest browsing </message> @@ -5772,6 +5793,29 @@ To check for updates, please use Ethernet or Wi-Fi. </message> + <!-- EOL Notification Strings --> + <message name="IDS_ABOUT_PAGE_EOL_SECURITY_ONLY" desc="The message in the about page to inform the user that this device is now receiving security updates only, containing the URLs."> + This device is receiving security updates only. <ph name="BEGIN_LINK_EOL"><a target="_blank" href="$1"></ph>More info<ph name="END_LINK_EOL"></a></ph> + </message> + <message name="IDS_ABOUT_PAGE_EOL_EOL" desc="The message in the about page to inform the user that this device will no longer receive regular security updates, containing the URLs."> + This device will no longer receive regular security updates. <ph name="BEGIN_LINK_EOL"><a target="_blank" href="$1"></ph>More info<ph name="END_LINK_EOL"></a></ph> + </message> + <message name="IDS_EOL_NOTIFICATION_SECURITY_ONLY" desc="Notification shown to inform the user that this device will no longer receive software updates."> + This device will no longer receive software updates. + </message> + <message name="IDS_EOL_NOTIFICATION_EOL" desc="Notification shown to inform the user that this device will no longer receive regular security updates."> + This device will no longer receive regular security updates. + </message> + <message name="IDS_EOL_MORE_INFO_BUTTON" desc="A button label shown in the notification for eol status change to get more information."> + More info + </message> + <message name="IDS_FLAGS_ENABLE_EOL_NOTIFICATION_NAME" desc="Name of the about:flag option to enable eol notification."> + Enable Device End of Life notification. + </message> + <message name="IDS_FLAGS_ENABLE_EOL_NOTIFICATION_DESCRIPTION" desc="Description of the about:flag option to enable eol notification."> + Enable Notifcation when Device is End of Life. + </message> + <!-- Genius App --> <message name="IDS_GENIUS_APP_NAME" desc="Name of the genius app in the app shelf"> Get Help
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 3b447f4..9a8f1ec 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -543,10 +543,7 @@ </message> <message name="IDS_CONTENT_CONTEXT_RELOADFRAME" desc="The name of the Reload Frame command in the content area context menu"> - Reload frame - </message> - <message name="IDS_CONTENT_CONTEXT_SAVEFRAMEAS" desc="The name of the Save Frame As command in the content area context menu"> - Save &frame as... + Reload &frame </message> <message name="IDS_CONTENT_CONTEXT_PRINTFRAME" desc="The name of the Print Frame command in the content area context menu"> &Print frame... @@ -756,10 +753,7 @@ </message> <message name="IDS_CONTENT_CONTEXT_RELOADFRAME" desc="In Title Case: The name of the Reload Frame command in the content area context menu"> - Reload Frame - </message> - <message name="IDS_CONTENT_CONTEXT_SAVEFRAMEAS" desc="In Title Case: The name of the Save Frame As command in the content area context menu"> - Save &Frame As... + Reload &Frame </message> <message name="IDS_CONTENT_CONTEXT_PRINTFRAME" desc="In Title Case: The name of the Print Frame command in the content area context menu"> &Print Frame...
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index f75d048..075118b 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -1890,8 +1890,7 @@ FEATURE_VALUE_TYPE(chrome::android::kImportantSitesInCBD)}, {"enable-autoplay-muted-videos", IDS_FLAGS_ENABLE_AUTOPLAY_MUTED_VIDEOS_NAME, - IDS_FLAGS_ENABLE_AUTOPLAY_MUTED_VIDEOS_DESCRIPTION, - kOsAndroid, + IDS_FLAGS_ENABLE_AUTOPLAY_MUTED_VIDEOS_DESCRIPTION, kOsAndroid, SINGLE_VALUE_TYPE(switches::kEnableAutoplayMutedVideos)}, #endif {"enable-pointer-events", // FLAGS:RECORD_UMA @@ -1910,8 +1909,7 @@ IDS_FLAGS_FONT_CACHE_SCALING_DESCRIPTION, kOsAll, FEATURE_VALUE_TYPE(features::kFontCacheScaling)}, #if defined(OS_ANDROID) - {"enable-vr-shell", - IDS_FLAGS_ENABLE_VR_SHELL_NAME, + {"enable-vr-shell", IDS_FLAGS_ENABLE_VR_SHELL_NAME, IDS_FLAGS_ENABLE_VR_SHELL_DESCRIPTION, kOsAndroid, ENABLE_DISABLE_VALUE_TYPE(switches::kEnableVrShell, switches::kDisableVrShell)}, @@ -1920,10 +1918,14 @@ IDS_FLAGS_ENABLE_ANDROID_PAY_INTEGRATION_V1_DESCRIPTION, kOsAndroid, FEATURE_VALUE_TYPE(chrome::android::kAndroidPayIntegrationV1)}, #endif - {"enable-weak-memorycache", - IDS_FLAGS_ENABLE_WEAK_MEMORYCACHE_NAME, + {"enable-weak-memorycache", IDS_FLAGS_ENABLE_WEAK_MEMORYCACHE_NAME, IDS_FLAGS_ENABLE_WEAK_MEMORYCACHE_DESCRIPTION, kOsAll, FEATURE_VALUE_TYPE(features::kWeakMemoryCache)}, +#if defined(OS_CHROMEOS) + {"enable-eol-notification", IDS_FLAGS_ENABLE_EOL_NOTIFICATION_NAME, + IDS_FLAGS_ENABLE_EOL_NOTIFICATION_DESCRIPTION, kOsCrOS, + SINGLE_VALUE_TYPE(chromeos::switches::kEnableEolNotification)}, +#endif // defined(OS_CHROMEOS) // NOTE: Adding new command-line switches requires adding corresponding // entries to enum "LoginCustomFlags" in histograms.xml. See note in
diff --git a/chrome/browser/chromeos/eol_notification.cc b/chrome/browser/chromeos/eol_notification.cc new file mode 100644 index 0000000..8b5f49eb --- /dev/null +++ b/chrome/browser/chromeos/eol_notification.cc
@@ -0,0 +1,152 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/eol_notification.h" + +#include "chrome/browser/browser_process.h" +#include "chrome/browser/notifications/notification.h" +#include "chrome/browser/notifications/notification_ui_manager.h" +#include "chrome/browser/ui/browser_navigator.h" +#include "chrome/browser/ui/browser_navigator_params.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/url_constants.h" +#include "chrome/grit/generated_resources.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/update_engine_client.h" +#include "components/prefs/pref_service.h" +#include "grit/ash_resources.h" +#include "third_party/cros_system_api/dbus/update_engine/dbus-constants.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" + +using message_center::MessageCenter; + +namespace chromeos { +namespace { + +const char kEolNotificationId[] = "eol"; +const char kDelegateId[] = "eol_delegate"; + +class EolNotificationDelegate : public NotificationDelegate { + public: + explicit EolNotificationDelegate(Profile* profile); + + private: + ~EolNotificationDelegate() override; + + // NotificationDelegate overrides: + void Close(bool by_user) override; + void ButtonClick(int button_index) override; + std::string id() const override; + + Profile* const profile_; + + void OpenMoreInfoPage(); + + DISALLOW_COPY_AND_ASSIGN(EolNotificationDelegate); +}; + +EolNotificationDelegate::EolNotificationDelegate(Profile* profile) + : profile_(profile) {} + +EolNotificationDelegate::~EolNotificationDelegate() {} + +void EolNotificationDelegate::Close(bool by_user) { + if (by_user) { + // set dismiss pref. + profile_->GetPrefs()->SetBoolean(prefs::kEolNotificationDismissed, true); + } +} + +void EolNotificationDelegate::ButtonClick(int button_index) { + // show eol link + OpenMoreInfoPage(); +} + +std::string EolNotificationDelegate::id() const { + return kDelegateId; +} + +void EolNotificationDelegate::OpenMoreInfoPage() { + chrome::NavigateParams params(profile_, GURL(chrome::kEolNotificationURL), + ui::PAGE_TRANSITION_LINK); + params.disposition = NEW_FOREGROUND_TAB; + params.window_action = chrome::NavigateParams::SHOW_WINDOW; + chrome::Navigate(¶ms); +} + +} // namespace + +EolNotification::EolNotification(Profile* profile) + : profile_(profile), + status_(update_engine::EndOfLifeStatus::kSupported), + weak_factory_(this) {} + +EolNotification::~EolNotification() {} + +void EolNotification::CheckEolStatus() { + UpdateEngineClient* update_engine_client = + DBusThreadManager::Get()->GetUpdateEngineClient(); + + // Request the Eol Status. + update_engine_client->GetEolStatus( + base::Bind(&EolNotification::OnEolStatus, weak_factory_.GetWeakPtr())); +} + +void EolNotification::OnEolStatus(int status) { + status_ = status; + + const int pre_eol_status = + profile_->GetPrefs()->GetInteger(prefs::kEolStatus); + profile_->GetPrefs()->SetInteger(prefs::kEolStatus, status_); + + if (status_ == update_engine::EndOfLifeStatus::kSupported) + return; + + if (pre_eol_status != status_) { + // If Eol status has changed, we should reset + // kEolNotificationDismissed and show notification. + profile_->GetPrefs()->SetBoolean(prefs::kEolNotificationDismissed, false); + } + + bool user_dismissed_eol_notification = + profile_->GetPrefs()->GetBoolean(prefs::kEolNotificationDismissed); + if (user_dismissed_eol_notification) + return; + + // When device is in Security-Only state, only show notification the first + // time. + if (status_ == update_engine::EndOfLifeStatus::kSecurityOnly) + profile_->GetPrefs()->SetBoolean(prefs::kEolNotificationDismissed, true); + + Update(); +} + +void EolNotification::Update() { + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + message_center::RichNotificationData data; + data.buttons.push_back(message_center::ButtonInfo( + l10n_util::GetStringUTF16(IDS_EOL_MORE_INFO_BUTTON))); + + Notification notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + base::string16(), // title + // TODO(xiaoyinh): Update the Eol icon once it's ready. + GetEolMessage(), bundle.GetImageNamed(IDR_AURA_NOTIFICATION_DISPLAY), + message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, + kEolNotificationId), + base::string16(), // display_source + GURL(), kEolNotificationId, data, new EolNotificationDelegate(profile_)); + g_browser_process->notification_ui_manager()->Add(notification, profile_); +} + +base::string16 EolNotification::GetEolMessage() { + if (status_ == update_engine::EndOfLifeStatus::kSecurityOnly) { + return l10n_util::GetStringUTF16(IDS_EOL_NOTIFICATION_SECURITY_ONLY); + } else { + return l10n_util::GetStringUTF16(IDS_EOL_NOTIFICATION_EOL); + } +} + +} // namespace chromeos
diff --git a/chrome/browser/chromeos/eol_notification.h b/chrome/browser/chromeos/eol_notification.h new file mode 100644 index 0000000..2ca80e8 --- /dev/null +++ b/chrome/browser/chromeos/eol_notification.h
@@ -0,0 +1,54 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_EOL_NOTIFICATION_H_ +#define CHROME_BROWSER_CHROMEOS_EOL_NOTIFICATION_H_ + +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/strings/string16.h" +#include "chrome/browser/profiles/profile.h" + +namespace message_center { +class MessageCenter; +} + +namespace chromeos { + +// EolNotification is created when user logs in. It is +// used to check current EndOfLife Status of the device, +// and show notification accordingly. +class EolNotification final { + public: + explicit EolNotification(Profile* profile); + ~EolNotification(); + + // Check Eol status from update engine. + void CheckEolStatus(); + + private: + // Callback invoked when |GetEolStatus()| has finished. + void OnEolStatus(int status); + + // Create or updates the notfication. + void Update(); + + // Returns messages that applys to this eol status. + base::string16 GetEolMessage(); + + // Profile which is associated with the EndOfLife notification. + Profile* const profile_; + + // Device Eol status. + int status_; + + // Factory of callbacks. + base::WeakPtrFactory<EolNotification> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(EolNotification); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_EOL_NOTIFICATION_H_
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc index 8db17b7..58ac1e62 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
@@ -474,6 +474,11 @@ IDS_FILE_BROWSER_MANY_DIRECTORIES_SELECTED); SET_STRING("MANY_ENTRIES_SELECTED", IDS_FILE_BROWSER_MANY_ENTRIES_SELECTED); SET_STRING("MANY_FILES_SELECTED", IDS_FILE_BROWSER_MANY_FILES_SELECTED); + SET_STRING("METADATA_BOX_FILE_SIZE", IDS_FILE_BROWSER_METADATA_BOX_FILE_SIZE); + SET_STRING("METADATA_BOX_GENERAL_INFO", + IDS_FILE_BROWSER_METADATA_BOX_GENERAL_INFO); + SET_STRING("METADATA_BOX_MODIFICATION_TIME", + IDS_FILE_BROWSER_METADATA_BOX_MODIFICATION_TIME); SET_STRING("MOUNT_ARCHIVE", IDS_FILE_BROWSER_MOUNT_ARCHIVE); SET_STRING("MOVE_FILESYSTEM_ERROR", IDS_FILE_BROWSER_MOVE_FILESYSTEM_ERROR); SET_STRING("MOVE_FILE_NAME", IDS_FILE_BROWSER_MOVE_FILE_NAME);
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc index 2ae53b8..59abe8a5 100644 --- a/chrome/browser/chromeos/login/session/user_session_manager.cc +++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -1210,6 +1210,12 @@ // resolved. if (delegate_) delegate_->OnProfilePrepared(profile, browser_launched); + + // Check to see if this profile should show EndOfLife Notification and show + // the message accordingly. + if (!ShouldShowEolNotification(profile)) + return; + CheckEolStatus(profile); } void UserSessionManager::ActivateWizard(const std::string& screen_name) { @@ -1669,6 +1675,18 @@ return state; } +void UserSessionManager::CheckEolStatus(Profile* profile) { + std::map<Profile*, std::unique_ptr<EolNotification>, ProfileCompare>::iterator + iter = eol_notification_handler_.find(profile); + if (iter == eol_notification_handler_.end()) { + auto eol_notification = base::WrapUnique(new EolNotification(profile)); + iter = eol_notification_handler_ + .insert(std::make_pair(profile, std::move(eol_notification))) + .first; + } + iter->second->CheckEolStatus(); +} + EasyUnlockKeyManager* UserSessionManager::GetEasyUnlockKeyManager() { if (!easy_unlock_key_manager_) easy_unlock_key_manager_.reset(new EasyUnlockKeyManager); @@ -1851,4 +1869,22 @@ token_handle_util_.reset(new TokenHandleUtil()); } +bool UserSessionManager::ShouldShowEolNotification(Profile* profile) { + if (!base::CommandLine::ForCurrentProcess()->HasSwitch( + chromeos::switches::kEnableEolNotification)) { + return false; + } + + // Do not show end of life notification if this device is managed by + // enterprise user. + if (g_browser_process->platform_part() + ->browser_policy_connector_chromeos() + ->IsEnterpriseManaged()) { + return false; + } + + // Do not show end of life notification if this is a guest session + return !profile->IsGuestSession(); +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.h b/chrome/browser/chromeos/login/session/user_session_manager.h index a97dd1f1..a0c7968 100644 --- a/chrome/browser/chromeos/login/session/user_session_manager.h +++ b/chrome/browser/chromeos/login/session/user_session_manager.h
@@ -14,6 +14,7 @@ #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "chrome/browser/chromeos/base/locale_util.h" +#include "chrome/browser/chromeos/eol_notification.h" #include "chrome/browser/chromeos/login/signin/oauth2_login_manager.h" #include "chrome/browser/chromeos/login/signin/token_handle_util.h" #include "chromeos/dbus/session_manager_client.h" @@ -229,6 +230,9 @@ scoped_refptr<input_method::InputMethodManager::State> GetDefaultIMEState( Profile* profile); + // Check given profile's EndofLife Status and show notification accordingly. + void CheckEolStatus(Profile* profile); + // Note this could return NULL if not enabled. EasyUnlockKeyManager* GetEasyUnlockKeyManager(); @@ -377,6 +381,10 @@ void CreateTokenUtilIfMissing(); + // Returns |true| if given profile show see EndofLife Notification when + // applicable. + bool ShouldShowEolNotification(Profile* profile); + // Test API methods. // Injects |user_context| that will be used to create StubAuthenticator @@ -462,6 +470,10 @@ std::map<Profile*, scoped_refptr<input_method::InputMethodManager::State>, ProfileCompare> default_ime_states_; + // Per-user-session EndofLife Notification + std::map<Profile*, std::unique_ptr<EolNotification>, ProfileCompare> + eol_notification_handler_; + // Manages Easy unlock cryptohome keys. std::unique_ptr<EasyUnlockKeyManager> easy_unlock_key_manager_; bool running_easy_unlock_key_ops_;
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc index 9e157c5..3f14ce9e 100644 --- a/chrome/browser/chromeos/preferences.cc +++ b/chrome/browser/chromeos/preferences.cc
@@ -45,6 +45,7 @@ #include "components/user_manager/user.h" #include "components/user_manager/user_manager.h" #include "content/public/browser/browser_thread.h" +#include "third_party/cros_system_api/dbus/update_engine/dbus-constants.h" #include "third_party/icu/source/i18n/unicode/timezone.h" #include "ui/base/ime/chromeos/extension_ime_util.h" #include "ui/base/ime/chromeos/ime_keyboard.h" @@ -316,6 +317,11 @@ registry->RegisterInt64Pref(prefs::kHatsLastInteractionTimestamp, base::Time().ToInternalValue()); + + // We don't sync EOL related prefs because they are device specific. + registry->RegisterBooleanPref(prefs::kEolNotificationDismissed, false); + registry->RegisterIntegerPref(prefs::kEolStatus, + update_engine::EndOfLifeStatus::kSupported); } void Preferences::InitUserPrefs(syncable_prefs::PrefServiceSyncable* prefs) {
diff --git a/chrome/browser/resources/help/help_content.html b/chrome/browser/resources/help/help_content.html index d1f8a12..3d1a967 100644 --- a/chrome/browser/resources/help/help_content.html +++ b/chrome/browser/resources/help/help_content.html
@@ -52,6 +52,7 @@ </if> <button id="relaunch" i18n-content="relaunch" hidden></button> <if expr="chromeos"> + <div id ="eol-message" hidden></div> <button id="relaunch-and-powerwash" i18n-content="relaunchAndPowerwash" hidden> </button>
diff --git a/chrome/browser/resources/help/help_page.js b/chrome/browser/resources/help/help_page.js index 2889d929..92d6465 100644 --- a/chrome/browser/resources/help/help_page.js +++ b/chrome/browser/resources/help/help_page.js
@@ -64,6 +64,18 @@ */ haveNeverCheckedForUpdates_: true, + /** + * Last EndofLife status received from the version updater. + * @private + */ + eolStatus_: null, + + /** + * Last EndofLife message received from the version updater. + * @private + */ + eolMessage_: null, + /** @override */ initializePage: function() { Page.prototype.initializePage.call(this); @@ -306,6 +318,18 @@ }, /** + * @param {string} eolStatus: The EndofLife status of the device. + * @param {string} eolMessage: The EndofLife message to display. + * @private + */ + updateEolMessage_: function(eolStatus, eolMessage) { + this.eolStatus_ = eolStatus; + this.eolMessage_ = eolMessage; + + this.updateUI_(); + }, + + /** * Updates UI elements on the page according to current state. * @private */ @@ -313,6 +337,8 @@ var status = this.status_; var message = this.message_; var channel = this.targetChannel_; + var eolStatus = this.eolStatus_; + var eolMessage = this.eolMessage_; if (this.channelList_.indexOf(channel) >= 0) { $('current-channel').textContent = loadTimeData.getStringF( @@ -370,6 +396,15 @@ $('update-status-message').innerHTML = message; } + // Show EndofLife Strings if applicable + if (eolStatus == 'device_supported') { + $('eol-message').hidden = true; + } else if (eolStatus == 'device_endoflife') { + $('eol-message').innerHTML = eolMessage; + $('eol-message').hidden = false; + } + + if (cr.isChromeOS) { $('change-channel').disabled = !this.canChangeChannel_ || status == 'nearly_updated'; @@ -392,9 +427,11 @@ // Re-enable the update button if we are in a stale 'updated' status or // update has failed, and disable it if there's an update in progress or // updates are disabled by policy. + // In addition, Update button will be disabled when device is in eol + // status $('request-update').disabled = !((this.haveNeverCheckedForUpdates_ && status == 'updated') || - status == 'failed'); + status == 'failed') || (eolStatus == 'device_endoflife'); // If updates are disabled by policy, unhide the // controlled-feature-icon. $('controlled-feature-icon').hidden = (status != 'disabled_by_admin'); @@ -413,7 +450,8 @@ if (cr.isChromeOS) { // Assume the "updated" status is stale if we haven't checked yet. if (status == 'updated' && this.haveNeverCheckedForUpdates_ || - status == 'disabled_by_admin') { + status == 'disabled_by_admin' || + eolStatus == 'device_endoflife') { container.hidden = true; } @@ -732,6 +770,11 @@ HelpPage.getInstance().setRegulatoryLabelText_(text); }; + HelpPage.updateEolMessage = function(eolStatus, eolMessage) { + assert(cr.isChromeOS); + HelpPage.getInstance().updateEolMessage_(eolStatus, eolMessage); + }; + // Export return { HelpPage: HelpPage
diff --git a/chrome/browser/resources/options/chromeos/storage_clear_drive_cache_overlay.html b/chrome/browser/resources/options/chromeos/storage_clear_drive_cache_overlay.html new file mode 100644 index 0000000..5bf2aa9 --- /dev/null +++ b/chrome/browser/resources/options/chromeos/storage_clear_drive_cache_overlay.html
@@ -0,0 +1,14 @@ +<div id="clear-drive-cache-overlay-page" class="page" role="dialog" hidden> + <div class="close-button"></div> + <h1 i18n-content="storageClearDriveCachePage"></h1> + <div class="content-area"> + <div i18n-content="storageClearDriveCacheDescription"></div> + </div> + <div class="action-area button-strip"> + <button id="clear-drive-cache-overlay-cancel-button" i18n-content="cancel"> + </button> + <button id="clear-drive-cache-overlay-delete-button" class="default-button" + i18n-content="storageDeleteAllButtonTitle"> + </button> + </div> +</div>
diff --git a/chrome/browser/resources/options/chromeos/storage_clear_drive_cache_overlay.js b/chrome/browser/resources/options/chromeos/storage_clear_drive_cache_overlay.js new file mode 100644 index 0000000..38c30720 --- /dev/null +++ b/chrome/browser/resources/options/chromeos/storage_clear_drive_cache_overlay.js
@@ -0,0 +1,37 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +cr.define('options', function() { + var Page = cr.ui.pageManager.Page; + var PageManager = cr.ui.pageManager.PageManager; + + function StorageClearDriveCacheOverlay() { + Page.call(this, 'storageClearDriveCache', + loadTimeData.getString('storageClearDriveCachePageTabTitle'), + 'clear-drive-cache-overlay-page'); + } + + cr.addSingletonGetter(StorageClearDriveCacheOverlay); + + StorageClearDriveCacheOverlay.prototype = { + __proto__: Page.prototype, + + /** @override */ + initializePage: function() { + Page.prototype.initializePage.call(this); + + $('clear-drive-cache-overlay-delete-button').onclick = function(e) { + chrome.send('clearDriveCache'); + PageManager.closeOverlay(); + }; + $('clear-drive-cache-overlay-cancel-button').onclick = function(e) { + PageManager.closeOverlay(); + }; + }, + }; + + return { + StorageClearDriveCacheOverlay: StorageClearDriveCacheOverlay + }; +});
diff --git a/chrome/browser/resources/options/chromeos/storage_manager.html b/chrome/browser/resources/options/chromeos/storage_manager.html index da5f6dd..97345b7 100644 --- a/chrome/browser/resources/options/chromeos/storage_manager.html +++ b/chrome/browser/resources/options/chromeos/storage_manager.html
@@ -21,6 +21,14 @@ class="storage-manager-item-size" i18n-content="storageSizeCalculating"></span> </div> + <div class="storage-manager-subitem"> + <a is="action-link" + id="storage-manager-label-drive-cache" + i18n-content="storageSubitemLabelDriveCache"></a> + <span id="storage-manager-size-drive-cache" + class="storage-manager-item-size" + i18n-content="storageSizeCalculating"></span> + </div> <div id="storage-manager-item-arc" class="storage-manager-subitem" hidden> <a is="action-link"
diff --git a/chrome/browser/resources/options/chromeos/storage_manager.js b/chrome/browser/resources/options/chromeos/storage_manager.js index 65aa19993..426e9a8 100644 --- a/chrome/browser/resources/options/chromeos/storage_manager.js +++ b/chrome/browser/resources/options/chromeos/storage_manager.js
@@ -34,6 +34,9 @@ $('storage-manager-label-downloads').onclick = function() { chrome.send('openDownloads'); }; + $('storage-manager-label-drive-cache').onclick = function() { + PageManager.showPageByName('storageClearDriveCache'); + }; $('storage-manager-label-arc').onclick = function() { chrome.send('openArcStorage'); }; @@ -72,6 +75,16 @@ }, /** + * Updates the size of Google Drive offline files. + * @param {string} size Formatted string of the size of Google Drive offline + * files. + * @private + */ + setDriveCacheSize_: function(size) { + $('storage-manager-size-drive-cache').textContent = size; + }, + + /** * Updates the total size of Android apps and cache. * @param {string} size Formatted string of the size of Android apps and * cache. @@ -95,6 +108,7 @@ cr.makePublic(StorageManager, [ 'setArcSize', 'setDownloadsSize', + 'setDriveCacheSize', 'setSizeStat', 'showArcItem', ]);
diff --git a/chrome/browser/resources/options/options.html b/chrome/browser/resources/options/options.html index 82b3d365..23175cf1 100644 --- a/chrome/browser/resources/options/options.html +++ b/chrome/browser/resources/options/options.html
@@ -167,6 +167,7 @@ <include src="chromeos/display_overscan.html"> <include src="chromeos/internet_detail.html"> <include src="chromeos/preferred_networks.html"> + <include src="chromeos/storage_clear_drive_cache_overlay.html"> <include src="chromeos/third_party_ime_confirm_overlay.html"> <include src="../help/channel_change_page.html"> </if>
diff --git a/chrome/browser/resources/options/options.js b/chrome/browser/resources/options/options.js index 9387495..f950327 100644 --- a/chrome/browser/resources/options/options.js +++ b/chrome/browser/resources/options/options.js
@@ -203,6 +203,8 @@ PageManager.registerOverlay(ChangePictureOptions.getInstance(), BrowserOptions.getInstance(), [$('account-picture')]); + PageManager.registerOverlay(StorageClearDriveCacheOverlay.getInstance(), + StorageManager.getInstance()); PageManager.registerOverlay(ConsumerManagementOverlay.getInstance(), BrowserOptions.getInstance()); PageManager.registerOverlay(DetailsInternetPage.getInstance(),
diff --git a/chrome/browser/resources/options/options_bundle.js b/chrome/browser/resources/options/options_bundle.js index a458baa..d6a330c 100644 --- a/chrome/browser/resources/options/options_bundle.js +++ b/chrome/browser/resources/options/options_bundle.js
@@ -39,6 +39,7 @@ <include src="chromeos/display_overscan.js"> <include src="chromeos/keyboard_overlay.js"> <include src="chromeos/pointer_overlay.js"> +<include src="chromeos/storage_clear_drive_cache_overlay.js"> <include src="chromeos/storage_manager.js"> <include src="chromeos/third_party_ime_confirm_overlay.js"> <include src="chromeos/power_overlay.js"> @@ -53,6 +54,7 @@ var KeyboardOverlay = options.KeyboardOverlay; var PointerOverlay = options.PointerOverlay; var PowerOverlay = options.PowerOverlay; +var StorageClearDriveCacheOverlay = options.StorageClearDriveCacheOverlay; var StorageManager = options.StorageManager; var UIAccountTweaks = uiAccountTweaks.UIAccountTweaks; </if>
diff --git a/chrome/browser/ui/webui/help/help_browsertest.js b/chrome/browser/ui/webui/help/help_browsertest.js index a5101e3..bc92d5cbe 100644 --- a/chrome/browser/ui/webui/help/help_browsertest.js +++ b/chrome/browser/ui/webui/help/help_browsertest.js
@@ -123,4 +123,19 @@ expectFalse(policyIcon.hidden); }); +// Test that the EndofLife String is shown and hidden properly. +TEST_F('HelpPageWebUITest', 'testUpdateEolMessage', function() { + var container = $('update-status-container'); + var update = $('request-update'); + var message = $('eol-message'); + + help.HelpPage.updateEolMessage('device_supported', ''); + expectTrue(message.hidden); + + help.HelpPage.updateEolMessage('device_endoflife', ''); + expectFalse(message.hidden); + expectTrue(update.disabled); + expectTrue(container.hidden); +}); + GEN('#endif');
diff --git a/chrome/browser/ui/webui/help/help_handler.cc b/chrome/browser/ui/webui/help/help_handler.cc index 423444a..f2050af5 100644 --- a/chrome/browser/ui/webui/help/help_handler.cc +++ b/chrome/browser/ui/webui/help/help_handler.cc
@@ -9,6 +9,7 @@ #include <string> #include "ash/common/system/chromeos/devicetype_utils.h" +#include "base/base_switches.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/command_line.h" @@ -73,6 +74,7 @@ #include "chromeos/system/statistics_provider.h" #include "components/prefs/pref_service.h" #include "components/user_manager/user_manager.h" +#include "third_party/cros_system_api/dbus/update_engine/dbus-constants.h" #endif using base::ListValue; @@ -205,6 +207,20 @@ return std::string(); } +// Returns messages that applys to this eol status +base::string16 GetEolMessage(int status) { + if (status == update_engine::EndOfLifeStatus::kSecurityOnly) { + return l10n_util::GetStringFUTF16( + IDS_ABOUT_PAGE_EOL_SECURITY_ONLY, + base::ASCIIToUTF16(chrome::kEolNotificationURL)); + + } else { + return l10n_util::GetStringFUTF16( + IDS_ABOUT_PAGE_EOL_EOL, + base::ASCIIToUTF16(chrome::kEolNotificationURL)); + } +} + #endif // defined(OS_CHROMEOS) } // namespace @@ -516,6 +532,12 @@ version_updater_->GetChannel(false, base::Bind(&HelpHandler::OnTargetChannel, weak_factory_.GetWeakPtr())); + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + chromeos::switches::kEnableEolNotification)) { + version_updater_->GetEolStatus( + base::Bind(&HelpHandler::OnEolStatus, weak_factory_.GetWeakPtr())); + } + base::PostTaskAndReplyWithResult( content::BrowserThread::GetBlockingPool(), FROM_HERE, @@ -742,4 +764,22 @@ base::StringValue(base::CollapseWhitespaceASCII(text, true))); } +void HelpHandler::OnEolStatus(const int status) { + if (status == update_engine::EndOfLifeStatus::kSupported || + IsEnterpriseManaged()) { + return; + } + + if (status == update_engine::EndOfLifeStatus::kSupported) { + web_ui()->CallJavascriptFunctionUnsafe( + "help.HelpPage.updateEolMessage", base::StringValue("device_supported"), + base::StringValue("")); + } else { + base::string16 message = GetEolMessage(status); + web_ui()->CallJavascriptFunctionUnsafe( + "help.HelpPage.updateEolMessage", base::StringValue("device_endoflife"), + base::StringValue(message)); + } +} + #endif // defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/webui/help/help_handler.h b/chrome/browser/ui/webui/help/help_handler.h index 95e41f61..3dfde200 100644 --- a/chrome/browser/ui/webui/help/help_handler.h +++ b/chrome/browser/ui/webui/help/help_handler.h
@@ -113,6 +113,9 @@ // Callback for setting the regulatory label alt text. void OnRegulatoryLabelTextRead(const std::string& text); + + // Callback for setting the eol string text. + void OnEolStatus(const int status); #endif // Specialized instance of the VersionUpdater used to update the browser.
diff --git a/chrome/browser/ui/webui/help/version_updater.h b/chrome/browser/ui/webui/help/version_updater.h index 47cb81a..87cda9e 100644 --- a/chrome/browser/ui/webui/help/version_updater.h +++ b/chrome/browser/ui/webui/help/version_updater.h
@@ -42,6 +42,7 @@ // types. #if defined(OS_CHROMEOS) typedef base::Callback<void(const std::string&)> ChannelCallback; + typedef base::Callback<void(int status)> EolStatusCallback; #endif // Used to update the client of status changes. int parameter is the progress @@ -78,6 +79,7 @@ bool is_powerwash_allowed) = 0; virtual void GetChannel(bool get_current_channel, const ChannelCallback& callback) = 0; + virtual void GetEolStatus(const EolStatusCallback& callback) = 0; #endif };
diff --git a/chrome/browser/ui/webui/help/version_updater_chromeos.cc b/chrome/browser/ui/webui/help/version_updater_chromeos.cc index 22e1c7ae..49d8391 100644 --- a/chrome/browser/ui/webui/help/version_updater_chromeos.cc +++ b/chrome/browser/ui/webui/help/version_updater_chromeos.cc
@@ -179,6 +179,14 @@ update_engine_client->GetChannel(get_current_channel, cb); } +void VersionUpdaterCros::GetEolStatus(const EolStatusCallback& cb) { + UpdateEngineClient* update_engine_client = + DBusThreadManager::Get()->GetUpdateEngineClient(); + + // Request the Eol Status. + update_engine_client->GetEolStatus(cb); +} + VersionUpdaterCros::VersionUpdaterCros(content::WebContents* web_contents) : context_(web_contents ? web_contents->GetBrowserContext() : nullptr), last_operation_(UpdateEngineClient::UPDATE_STATUS_IDLE),
diff --git a/chrome/browser/ui/webui/help/version_updater_chromeos.h b/chrome/browser/ui/webui/help/version_updater_chromeos.h index 0d4cbf9..44d4ee8 100644 --- a/chrome/browser/ui/webui/help/version_updater_chromeos.h +++ b/chrome/browser/ui/webui/help/version_updater_chromeos.h
@@ -30,6 +30,8 @@ // Gets the last update status, without triggering a new check or download. void GetUpdateStatus(const StatusCallback& callback); + void GetEolStatus(const EolStatusCallback& callback) override; + protected: friend class VersionUpdater;
diff --git a/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.cc b/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.cc index 34afd55..d821454 100644 --- a/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.cc +++ b/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.cc
@@ -10,10 +10,12 @@ #include "base/sys_info.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/arc/arc_auth_service.h" +#include "chrome/browser/chromeos/drive/file_system_util.h" #include "chrome/browser/chromeos/file_manager/path_util.h" #include "chrome/browser/platform_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/grit/generated_resources.h" +#include "components/drive/chromeos/file_system_interface.h" #include "content/public/browser/browser_thread.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/text/bytes_formatting.h" @@ -47,6 +49,8 @@ RegisterTitle(localized_strings, "storageManagerPage", IDS_OPTIONS_SETTINGS_STORAGE_MANAGER_TAB_TITLE); + RegisterTitle(localized_strings, "storageClearDriveCachePage", + IDS_OPTIONS_SETTINGS_STORAGE_CLEAR_DRIVE_CACHE_TAB_TITLE); localized_strings->SetString( "storageItemLabelCapacity", l10n_util::GetStringUTF16( @@ -61,11 +65,20 @@ "storageSubitemLabelDownloads", l10n_util::GetStringUTF16( IDS_OPTIONS_SETTINGS_STORAGE_SUBITEM_LABEL_DOWNLOADS)); localized_strings->SetString( + "storageSubitemLabelDriveCache", l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_STORAGE_SUBITEM_LABEL_DRIVE_CACHE)); + localized_strings->SetString( "storageSubitemLabelArc", l10n_util::GetStringUTF16( IDS_OPTIONS_SETTINGS_STORAGE_SUBITEM_LABEL_ARC)); localized_strings->SetString( "storageSizeCalculating", l10n_util::GetStringUTF16( IDS_OPTIONS_SETTINGS_STORAGE_SIZE_CALCULATING)); + localized_strings->SetString( + "storageClearDriveCacheDescription", l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_STORAGE_CLEAR_DRIVE_CACHE_DESCRIPTION)); + localized_strings->SetString( + "storageDeleteAllButtonTitle", l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_STORAGE_DELETE_ALL_BUTTON_TITLE)); } void StorageManagerHandler::InitializePage() { @@ -87,12 +100,17 @@ "openArcStorage", base::Bind(&StorageManagerHandler::HandleOpenArcStorage, base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "clearDriveCache", + base::Bind(&StorageManagerHandler::HandleClearDriveCache, + base::Unretained(this))); } void StorageManagerHandler::HandleUpdateStorageInfo( const base::ListValue* unused_args) { UpdateSizeStat(); UpdateDownloadsSize(); + UpdateDriveCacheSize(); UpdateArcSize(); } @@ -113,6 +131,16 @@ arc::ArcStorageManager::Get()->OpenPrivateVolumeSettings(); } +void StorageManagerHandler::HandleClearDriveCache( + const base::ListValue* unused_args) { + drive::FileSystemInterface* const file_system = + drive::util::GetFileSystemByProfile(Profile::FromWebUI(web_ui())); + file_system->FreeDiskSpaceIfNeededFor( + std::numeric_limits<int64_t>::max(), // Removes as much as possible. + base::Bind(&StorageManagerHandler::OnClearDriveCacheDone, + weak_ptr_factory_.GetWeakPtr())); +} + void StorageManagerHandler::UpdateSizeStat() { Profile* const profile = Profile::FromWebUI(web_ui()); const base::FilePath downloads_path = @@ -164,6 +192,20 @@ base::StringValue(ui::FormatBytes(size))); } +void StorageManagerHandler::UpdateDriveCacheSize() { + drive::FileSystemInterface* const file_system = + drive::util::GetFileSystemByProfile(Profile::FromWebUI(web_ui())); + file_system->CalculateCacheSize( + base::Bind(&StorageManagerHandler::OnGetDriveCacheSize, + weak_ptr_factory_.GetWeakPtr())); +} + +void StorageManagerHandler::OnGetDriveCacheSize(int64_t size) { + web_ui()->CallJavascriptFunctionUnsafe( + "options.StorageManager.setDriveCacheSize", + base::StringValue(ui::FormatBytes(size))); +} + void StorageManagerHandler::UpdateArcSize() { Profile* const profile = Profile::FromWebUI(web_ui()); if (!arc::ArcAuthService::IsAllowedForProfile(profile) || @@ -202,5 +244,9 @@ arc_size); } +void StorageManagerHandler::OnClearDriveCacheDone(bool success) { + UpdateDriveCacheSize(); +} + } // namespace options } // namespace chromeos
diff --git a/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.h b/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.h index a4f39694..a8a1fc28 100644 --- a/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.h +++ b/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.h
@@ -31,6 +31,7 @@ void HandleUpdateStorageInfo(const base::ListValue* unused_args); void HandleOpenDownloads(const base::ListValue* unused_args); void HandleOpenArcStorage(const base::ListValue* unused_args); + void HandleClearDriveCache(const base::ListValue* unused_args); // Requests updating disk space information. void UpdateSizeStat(); @@ -44,12 +45,21 @@ // Callback to update the UI about the size of Downloads directory. void OnGetDownloadsSize(int64_t size); + // Requests updating the size of Drive Cache. + void UpdateDriveCacheSize(); + + // Callback to update the UI about the size of Drive Cache. + void OnGetDriveCacheSize(int64_t size); + // Requests updating the space size used by Android apps and cache. void UpdateArcSize(); // Callback to update the UI about Android apps and cache. void OnGetArcSize(bool succeeded, arc::mojom::ApplicationsSizePtr size); + // Callback called when clearing Drive cache is done. + void OnClearDriveCacheDone(bool success); + base::WeakPtrFactory<StorageManagerHandler> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(StorageManagerHandler);
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi index ca2f15c5..adf9416d 100644 --- a/chrome/chrome_browser_chromeos.gypi +++ b/chrome/chrome_browser_chromeos.gypi
@@ -174,6 +174,8 @@ 'browser/chromeos/drive/write_on_cache_file.h', 'browser/chromeos/enrollment_dialog_view.cc', 'browser/chromeos/enrollment_dialog_view.h', + 'browser/chromeos/eol_notification.cc', + 'browser/chromeos/eol_notification.h', 'browser/chromeos/events/event_rewriter.cc', 'browser/chromeos/events/event_rewriter.h', 'browser/chromeos/events/event_rewriter_controller.cc',
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 6b8fa7e..8389fe8 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc
@@ -873,6 +873,17 @@ // The salt and hash for the pin quick unlock mechanism. const char kQuickUnlockPinSalt[] = "quick_unlock.pin.salt"; const char kQuickUnlockPinSecret[] = "quick_unlock.pin.secret"; + +// An integer pref. Holds one of several values: +// 0: Supported. Device is in supported state. +// 1: Security Only. Device is in Security-Only update (after initial 5 years). +// 2: EOL. Device is End of Life(No more updates expected). +// This value needs to be consistent with EndOfLifeStatus enum. +const char kEolStatus[] = "eol_status"; + +// Boolean pref indicating the End Of Life notification was dismissed by the +// user. +const char kEolNotificationDismissed[] = "eol_notification_dismissed"; #endif // defined(OS_CHROMEOS) // A boolean pref set to true if a Home button to open the Home pages should be
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 2510bd88..47d3a78 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -292,6 +292,8 @@ extern const char kHatsLastInteractionTimestamp[]; extern const char kQuickUnlockPinSalt[]; extern const char kQuickUnlockPinSecret[]; +extern const char kEolStatus[]; +extern const char kEolNotificationDismissed[]; #endif // defined(OS_CHROMEOS) extern const char kShowHomeButton[]; extern const char kRecentlySelectedEncoding[];
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc index 92b8408c..a502c7f0 100644 --- a/chrome/common/url_constants.cc +++ b/chrome/common/url_constants.cc
@@ -784,4 +784,8 @@ const char kChooserUsbOverviewURL[] = "https://support.google.com/chrome?p=webusb"; +#if defined(OS_CHROMEOS) +const char kEolNotificationURL[] = "https://www.google.com/chromebook/older/"; +#endif + } // namespace chrome
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h index ab0f3a0..f4eaece0 100644 --- a/chrome/common/url_constants.h +++ b/chrome/common/url_constants.h
@@ -594,6 +594,11 @@ // The URL for the WebUsb help center article. extern const char kChooserUsbOverviewURL[]; +#if defined(OS_CHROMEOS) +// The URL for EOL notification +extern const char kEolNotificationURL[]; +#endif + } // namespace chrome #endif // CHROME_COMMON_URL_CONSTANTS_H_
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 7636096..a1b8c7f4 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -8460.0.0 \ No newline at end of file +8466.0.0 \ No newline at end of file
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc index 9ad4ade..ddfe311 100644 --- a/chromeos/chromeos_switches.cc +++ b/chromeos/chromeos_switches.cc
@@ -134,6 +134,9 @@ // Enables details panel in Files app. const char kEnableFilesDetailsPanel[] = "enable-files-details-panel"; +// Enables notification when device is in end of life status. +const char kEnableEolNotification[] = "enable-eol-notification"; + // If this switch is set, the device cannot be remotely disabled by its owner. const char kDisableDeviceDisabling[] = "disable-device-disabling";
diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h index 58bf141..b900ca8 100644 --- a/chromeos/chromeos_switches.h +++ b/chromeos/chromeos_switches.h
@@ -65,6 +65,7 @@ CHROMEOS_EXPORT extern const char kEnableExperimentalAccessibilityFeatures[]; CHROMEOS_EXPORT extern const char kEnableExtensionAssetsSharing[]; CHROMEOS_EXPORT extern const char kEnableFilesDetailsPanel[]; +CHROMEOS_EXPORT extern const char kEnableEolNotification[]; CHROMEOS_EXPORT extern const char kEnableFirstRunUITransitions[]; CHROMEOS_EXPORT extern const char kEnableKioskMode[]; CHROMEOS_EXPORT extern const char kEnableNetworkPortalNotification[];
diff --git a/chromeos/dbus/fake_update_engine_client.cc b/chromeos/dbus/fake_update_engine_client.cc index a594a3e..7add923 100644 --- a/chromeos/dbus/fake_update_engine_client.cc +++ b/chromeos/dbus/fake_update_engine_client.cc
@@ -75,6 +75,9 @@ const GetChannelCallback& callback) { } +void FakeUpdateEngineClient::GetEolStatus( + const GetEolStatusCallback& callback) {} + void FakeUpdateEngineClient::set_default_status( const UpdateEngineClient::Status& status) { default_status_ = status;
diff --git a/chromeos/dbus/fake_update_engine_client.h b/chromeos/dbus/fake_update_engine_client.h index 68c0aa43..a1aa3aa 100644 --- a/chromeos/dbus/fake_update_engine_client.h +++ b/chromeos/dbus/fake_update_engine_client.h
@@ -35,6 +35,7 @@ bool is_powerwash_allowed) override; void GetChannel(bool get_current_channel, const GetChannelCallback& callback) override; + void GetEolStatus(const GetEolStatusCallback& callback) override; // Pushes UpdateEngineClient::Status in the queue to test changing status. // GetLastStatus() returns the status set by this method in FIFO order.
diff --git a/chromeos/dbus/update_engine_client.cc b/chromeos/dbus/update_engine_client.cc index fcd6ab1..12bc71e5 100644 --- a/chromeos/dbus/update_engine_client.cc +++ b/chromeos/dbus/update_engine_client.cc
@@ -207,6 +207,17 @@ callback)); } + void GetEolStatus(const GetEolStatusCallback& callback) override { + dbus::MethodCall method_call(update_engine::kUpdateEngineInterface, + update_engine::kGetEolStatus); + + VLOG(1) << "Requesting to get end of life status"; + update_engine_proxy_->CallMethod( + &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, + base::Bind(&UpdateEngineClientImpl::OnGetEolStatus, + weak_ptr_factory_.GetWeakPtr(), callback)); + } + protected: void Init(dbus::Bus* bus) override { update_engine_proxy_ = bus->GetObjectProxy( @@ -349,6 +360,34 @@ callback.Run(channel); } + // Called when a response for GetEolStatus() is received. + void OnGetEolStatus(const GetEolStatusCallback& callback, + dbus::Response* response) { + if (!response) { + LOG(ERROR) << "Failed to request getting eol status"; + callback.Run(update_engine::EndOfLifeStatus::kSupported); + return; + } + dbus::MessageReader reader(response); + int status; + if (!reader.PopInt32(&status)) { + LOG(ERROR) << "Incorrect response: " << response->ToString(); + callback.Run(update_engine::EndOfLifeStatus::kSupported); + return; + } + + // Validate the value of status + if (status > update_engine::EndOfLifeStatus::kEol || + status < update_engine::EndOfLifeStatus::kSupported) { + LOG(ERROR) << "Incorrect status value: " << status; + callback.Run(update_engine::EndOfLifeStatus::kSupported); + return; + } + + VLOG(1) << "Eol status received: " << status; + callback.Run(status); + } + // Called when a status update signal is received. void StatusUpdateReceived(dbus::Signal* signal) { VLOG(1) << "Status update signal received: " << signal->ToString(); @@ -437,6 +476,10 @@ callback.Run(target_channel_); } + void GetEolStatus(const GetEolStatusCallback& callback) override { + callback.Run(update_engine::EndOfLifeStatus::kSupported); + } + std::string current_channel_; std::string target_channel_; };
diff --git a/chromeos/dbus/update_engine_client.h b/chromeos/dbus/update_engine_client.h index 9950e213..721aaa3 100644 --- a/chromeos/dbus/update_engine_client.h +++ b/chromeos/dbus/update_engine_client.h
@@ -15,6 +15,7 @@ #include "chromeos/chromeos_export.h" #include "chromeos/dbus/dbus_client.h" #include "chromeos/dbus/dbus_client_implementation_type.h" +#include "third_party/cros_system_api/dbus/update_engine/dbus-constants.h" namespace chromeos { @@ -133,6 +134,13 @@ virtual void GetChannel(bool get_current_channel, const GetChannelCallback& callback) = 0; + // Called once GetEolStatus() is complete. Takes one parameter; + // - EolStatus: the eol status of the device. + typedef base::Callback<void(int status)> GetEolStatusCallback; + + // Get Eol status of the device and calls |callback| when completed. + virtual void GetEolStatus(const GetEolStatusCallback& callback) = 0; + // Returns an empty UpdateCheckCallback that does nothing. static UpdateCheckCallback EmptyUpdateCheckCallback();
diff --git a/content/browser/android/synchronous_compositor_host.cc b/content/browser/android/synchronous_compositor_host.cc index f5d9e58..a8a4de0 100644 --- a/content/browser/android/synchronous_compositor_host.cc +++ b/content/browser/android/synchronous_compositor_host.cc
@@ -334,7 +334,7 @@ void SynchronousCompositorHost::DidOverscroll( const DidOverscrollParams& over_scroll_params) { - client_->DidOverscroll(over_scroll_params.accumulated_overscroll, + client_->DidOverscroll(this, over_scroll_params.accumulated_overscroll, over_scroll_params.latest_overscroll_delta, over_scroll_params.current_fling_velocity); } @@ -368,13 +368,13 @@ if (need_invalidate_count_ != params.need_invalidate_count) { need_invalidate_count_ = params.need_invalidate_count; - client_->PostInvalidate(); + client_->PostInvalidate(this); } if (did_activate_pending_tree_count_ != params.did_activate_pending_tree_count) { did_activate_pending_tree_count_ = params.did_activate_pending_tree_count; - client_->DidUpdateContent(); + client_->DidUpdateContent(this); } // Ensure only valid values from compositor are sent to client. @@ -382,7 +382,7 @@ // for that case here. if (params.page_scale_factor) { client_->UpdateRootLayerState( - gfx::ScrollOffsetToVector2dF(params.total_scroll_offset), + this, gfx::ScrollOffsetToVector2dF(params.total_scroll_offset), gfx::ScrollOffsetToVector2dF(params.max_scroll_offset), params.scrollable_size, params.page_scale_factor, params.min_page_scale_factor, params.max_page_scale_factor);
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index ffa1cd1..1ecd4bd 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -57,7 +57,6 @@ #include "content/common/input_messages.h" #include "content/common/inter_process_time_ticks_converter.h" #include "content/common/navigation_params.h" -#include "content/common/render_frame_setup.mojom.h" #include "content/common/site_isolation_policy.h" #include "content/common/swapped_out_messages.h" #include "content/public/browser/ax_event_notification_details.h" @@ -246,6 +245,7 @@ pending_web_ui_type_(WebUI::kNoWebUI), should_reuse_web_ui_(false), last_navigation_lofi_state_(LOFI_UNSPECIFIED), + frame_host_binding_(this), weak_ptr_factory_(this) { frame_tree_->AddRenderViewHostRef(render_view_host_); GetProcess()->AddRoute(routing_id_, this); @@ -2384,17 +2384,13 @@ return; RegisterMojoServices(); - mojom::RenderFrameSetupPtr setup; + mojom::FrameFactoryPtr frame_factory; GetProcess()->GetServiceRegistry()->ConnectToRemoteService( - mojo::GetProxy(&setup)); + mojo::GetProxy(&frame_factory)); - shell::mojom::InterfaceProviderPtr exposed_services; - service_registry_->Bind(GetProxy(&exposed_services)); - - shell::mojom::InterfaceProviderPtr services; - setup->ExchangeInterfaceProviders(routing_id_, GetProxy(&services), - std::move(exposed_services)); - service_registry_->BindRemoteServiceProvider(std::move(services)); + frame_factory->CreateFrame(routing_id_, GetProxy(&frame_), + frame_host_binding_.CreateInterfacePtrAndBind()); + frame_->GetInterfaceProvider(service_registry_->TakeRemoteRequest()); #if defined(OS_ANDROID) service_registry_android_ = @@ -2412,6 +2408,8 @@ #endif service_registry_.reset(); + frame_.reset(); + frame_host_binding_.Close(); // Disconnect with ImageDownloader Mojo service in RenderFrame. mojo_image_downloader_.reset(); @@ -2674,6 +2672,11 @@ Send(new FrameMsg_RunFileChooserResponse(routing_id_, files)); } +void RenderFrameHostImpl::GetInterfaceProvider( + shell::mojom::InterfaceProviderRequest interfaces) { + service_registry_->Bind(std::move(interfaces)); +} + #if defined(USE_EXTERNAL_POPUP_MENU) #if defined(OS_MACOSX)
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h index 990d305..dc561b18 100644 --- a/content/browser/frame_host/render_frame_host_impl.h +++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -29,6 +29,7 @@ #include "content/common/accessibility_mode_enums.h" #include "content/common/ax_content_node_data.h" #include "content/common/content_export.h" +#include "content/common/frame.mojom.h" #include "content/common/frame_message_enums.h" #include "content/common/frame_replication_state.h" #include "content/common/image_downloader/image_downloader.mojom.h" @@ -99,9 +100,11 @@ struct Referrer; struct ResourceResponse; -class CONTENT_EXPORT RenderFrameHostImpl : public RenderFrameHost, - public BrowserAccessibilityDelegate, - public SiteInstanceImpl::Observer { +class CONTENT_EXPORT RenderFrameHostImpl + : public RenderFrameHost, + NON_EXPORTED_BASE(public mojom::FrameHost), + public BrowserAccessibilityDelegate, + public SiteInstanceImpl::Observer { public: using AXTreeSnapshotCallback = base::Callback<void( @@ -156,6 +159,10 @@ void FilesSelectedInChooser(const std::vector<FileChooserFileInfo>& files, FileChooserParams::Mode permissions) override; + // mojom::FrameHost + void GetInterfaceProvider( + shell::mojom::InterfaceProviderRequest interfaces) override; + // IPC::Sender bool Send(IPC::Message* msg) override; @@ -1019,6 +1026,9 @@ // same LoFi status as the top-level frame. LoFiState last_navigation_lofi_state_; + mojo::Binding<mojom::FrameHost> frame_host_binding_; + mojom::FramePtr frame_; + // NOTE: This must be the last member. base::WeakPtrFactory<RenderFrameHostImpl> weak_ptr_factory_;
diff --git a/content/browser/mojo/mojo_application_host.cc b/content/browser/mojo/mojo_application_host.cc index 2a70626..5bbe45a 100644 --- a/content/browser/mojo/mojo_application_host.cc +++ b/content/browser/mojo/mojo_application_host.cc
@@ -13,6 +13,8 @@ namespace content { namespace { +// TODO(beng): remove this in favor of just using shell APIs directly. +// http://crbug.com/2072603002 class ApplicationSetupImpl : public mojom::ApplicationSetup { public: ApplicationSetupImpl(ServiceRegistryImpl* service_registry, @@ -29,7 +31,8 @@ shell::mojom::InterfaceProviderRequest services, shell::mojom::InterfaceProviderPtr exposed_services) override { service_registry_->Bind(std::move(services)); - service_registry_->BindRemoteServiceProvider(std::move(exposed_services)); + mojo::FuseInterface(service_registry_->TakeRemoteRequest(), + exposed_services.PassInterface()); } mojo::Binding<mojom::ApplicationSetup> binding_;
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc index 6e26164..0dba1ed 100644 --- a/content/browser/service_worker/embedded_worker_instance.cc +++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -647,14 +647,13 @@ shell::mojom::InterfaceProviderPtr exposed_services; service_registry_->Bind(GetProxy(&exposed_services)); - shell::mojom::InterfaceProviderPtr services; - shell::mojom::InterfaceProviderRequest services_request = GetProxy(&services); + shell::mojom::InterfaceProviderRequest request = + service_registry_->TakeRemoteRequest(); BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, base::Bind(SetupMojoOnUIThread, process_id(), thread_id_, - base::Passed(&services_request), + base::Passed(&request), base::Passed(exposed_services.PassInterface()))); - service_registry_->BindRemoteServiceProvider(std::move(services)); } void EmbeddedWorkerInstance::OnScriptLoadFailed() {
diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc index 0febd11..6e22d4c 100644 --- a/content/browser/service_worker/embedded_worker_test_helper.cc +++ b/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -24,6 +24,7 @@ #include "content/public/common/push_event_payload.h" #include "content/public/test/mock_render_process_host.h" #include "content/public/test/test_browser_context.h" +#include "mojo/public/cpp/bindings/interface_request.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "testing/gtest/include/gtest/gtest.h" @@ -104,8 +105,8 @@ render_process_service_registry_.ServiceRegistry::AddService( base::Bind(&MockEmbeddedWorkerSetup::Create, weak_factory_.GetWeakPtr())); shell::mojom::InterfaceProviderPtr services; - render_process_service_registry_.Bind(mojo::GetProxy(&services)); - host_service_registry->BindRemoteServiceProvider(std::move(services)); + render_process_service_registry_.Bind( + host_service_registry->TakeRemoteRequest()); render_process_host_->SetServiceRegistry(std::move(host_service_registry)); } @@ -426,7 +427,11 @@ shell::mojom::InterfaceProviderPtr exposed_services) { std::unique_ptr<ServiceRegistryImpl> new_registry(new ServiceRegistryImpl); new_registry->Bind(std::move(services)); - new_registry->BindRemoteServiceProvider(std::move(exposed_services)); + // TODO(beng): this shouldn't be necessary once we adjust this API to look + // more like the one we've created for Frame. + // http://crbug.com/621187 + mojo::FuseInterface(new_registry->TakeRemoteRequest(), + exposed_services.PassInterface()); OnSetupMojo(new_registry.get()); thread_id_service_registry_map_.add(thread_id, std::move(new_registry)); }
diff --git a/content/child/mojo/mojo_application.cc b/content/child/mojo/mojo_application.cc index 7aa4597..ffa285f 100644 --- a/content/child/mojo/mojo_application.cc +++ b/content/child/mojo/mojo_application.cc
@@ -30,9 +30,9 @@ shell::mojom::InterfaceProviderPtr services; shell::mojom::InterfaceProviderPtr exposed_services; service_registry_.Bind(GetProxy(&exposed_services)); - application_setup->ExchangeInterfaceProviders(GetProxy(&services), - std::move(exposed_services)); - service_registry_.BindRemoteServiceProvider(std::move(services)); + application_setup->ExchangeInterfaceProviders( + service_registry_.TakeRemoteRequest(), + std::move(exposed_services)); } } // namespace content
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn index bf26441..b459439c 100644 --- a/content/common/BUILD.gn +++ b/content/common/BUILD.gn
@@ -230,10 +230,10 @@ sources = [ "application_setup.mojom", + "frame.mojom", "image_downloader/image_downloader.mojom", "leveldb_wrapper.mojom", "process_control.mojom", - "render_frame_setup.mojom", "render_widget_window_tree_client_factory.mojom", "service_worker/embedded_worker_setup.mojom", "storage_partition_service.mojom",
diff --git a/content/common/frame.mojom b/content/common/frame.mojom new file mode 100644 index 0000000..9ec9644 --- /dev/null +++ b/content/common/frame.mojom
@@ -0,0 +1,23 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module content.mojom; + +import "services/shell/public/interfaces/interface_provider.mojom"; + +// Implemented by the frame provider (e.g. renderer processes). +interface Frame { + GetInterfaceProvider(shell.mojom.InterfaceProvider& interfaces); +}; + +// Implemented by the frame server (i.e. the browser process). +interface FrameHost { + GetInterfaceProvider(shell.mojom.InterfaceProvider& interfaces); +}; + +// Implemented by a service that provides implementations of the Frame +// interface. (e.g. renderer processes). +interface FrameFactory { + CreateFrame(int32 frame_routing_id, Frame& frame, FrameHost host); +};
diff --git a/content/common/mojo/service_registry_impl.cc b/content/common/mojo/service_registry_impl.cc index 39e575a..7a16b4c9 100644 --- a/content/common/mojo/service_registry_impl.cc +++ b/content/common/mojo/service_registry_impl.cc
@@ -15,13 +15,12 @@ } ServiceRegistryImpl::ServiceRegistryImpl() - : binding_(this), weak_factory_(this) {} + : binding_(this), + weak_factory_(this) { + remote_provider_request_ = GetProxy(&remote_provider_); +} ServiceRegistryImpl::~ServiceRegistryImpl() { - while (!pending_connects_.empty()) { - mojo::CloseRaw(pending_connects_.front().second); - pending_connects_.pop(); - } } void ServiceRegistryImpl::Bind(shell::mojom::InterfaceProviderRequest request) { @@ -30,16 +29,9 @@ &ServiceRegistryImpl::OnConnectionError, base::Unretained(this))); } -void ServiceRegistryImpl::BindRemoteServiceProvider( - shell::mojom::InterfaceProviderPtr service_provider) { - CHECK(!remote_provider_); - remote_provider_ = std::move(service_provider); - while (!pending_connects_.empty()) { - remote_provider_->GetInterface( - mojo::String::From(pending_connects_.front().first), - mojo::ScopedMessagePipeHandle(pending_connects_.front().second)); - pending_connects_.pop(); - } +shell::mojom::InterfaceProviderRequest +ServiceRegistryImpl::TakeRemoteRequest() { + return std::move(remote_provider_request_); } void ServiceRegistryImpl::AddService( @@ -62,12 +54,6 @@ override_it->second.Run(std::move(handle)); return; } - - if (!remote_provider_) { - pending_connects_.push( - std::make_pair(service_name.as_string(), handle.release())); - return; - } remote_provider_->GetInterface( mojo::String::From(service_name.as_string()), std::move(handle)); }
diff --git a/content/common/mojo/service_registry_impl.h b/content/common/mojo/service_registry_impl.h index 923414e9..bf9352ba 100644 --- a/content/common/mojo/service_registry_impl.h +++ b/content/common/mojo/service_registry_impl.h
@@ -30,8 +30,7 @@ // ServiceRegistry overrides. void Bind(shell::mojom::InterfaceProviderRequest request) override; - void BindRemoteServiceProvider( - shell::mojom::InterfaceProviderPtr service_provider) override; + shell::mojom::InterfaceProviderRequest TakeRemoteRequest() override; void AddService( const std::string& service_name, const ServiceFactory& service_factory, @@ -61,13 +60,12 @@ mojo::Binding<shell::mojom::InterfaceProvider> binding_; shell::mojom::InterfaceProviderPtr remote_provider_; + shell::mojom::InterfaceProviderRequest remote_provider_request_; std::map< std::string, std::pair<ServiceFactory, scoped_refptr<base::SingleThreadTaskRunner>>> service_factories_; - std::queue<std::pair<std::string, mojo::MessagePipeHandle> > - pending_connects_; std::map<std::string, ServiceFactory> service_overrides_;
diff --git a/content/common/render_frame_setup.mojom b/content/common/render_frame_setup.mojom deleted file mode 100644 index b020f42..0000000 --- a/content/common/render_frame_setup.mojom +++ /dev/null
@@ -1,14 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -module content.mojom; - -import "services/shell/public/interfaces/interface_provider.mojom"; - -interface RenderFrameSetup { - ExchangeInterfaceProviders( - int32 frame_routing_id, - shell.mojom.InterfaceProvider& remote_interfaces, - shell.mojom.InterfaceProvider local_interfaces); -};
diff --git a/content/content_common_mojo_bindings.gyp b/content/content_common_mojo_bindings.gyp index 7708406..417cfc6 100644 --- a/content/content_common_mojo_bindings.gyp +++ b/content/content_common_mojo_bindings.gyp
@@ -12,10 +12,10 @@ 'mojom_files': [ # NOTE: Sources duplicated in //content/common/BUILD.gn:mojo_bindings. 'common/application_setup.mojom', + 'common/frame.mojom', 'common/image_downloader/image_downloader.mojom', 'common/leveldb_wrapper.mojom', 'common/process_control.mojom', - 'common/render_frame_setup.mojom', 'common/service_worker/embedded_worker_setup.mojom', 'common/storage_partition_service.mojom', ],
diff --git a/content/public/browser/android/synchronous_compositor_client.h b/content/public/browser/android/synchronous_compositor_client.h index f4343a5c..fa28023 100644 --- a/content/public/browser/android/synchronous_compositor_client.h +++ b/content/public/browser/android/synchronous_compositor_client.h
@@ -33,20 +33,22 @@ int routing_id) = 0; // See LayerScrollOffsetDelegate for details. - virtual void UpdateRootLayerState(const gfx::Vector2dF& total_scroll_offset, + virtual void UpdateRootLayerState(SynchronousCompositor* compositor, + const gfx::Vector2dF& total_scroll_offset, const gfx::Vector2dF& max_scroll_offset, const gfx::SizeF& scrollable_size, float page_scale_factor, float min_page_scale_factor, float max_page_scale_factor) = 0; - virtual void DidOverscroll(const gfx::Vector2dF& accumulated_overscroll, + virtual void DidOverscroll(SynchronousCompositor* compositor, + const gfx::Vector2dF& accumulated_overscroll, const gfx::Vector2dF& latest_overscroll_delta, const gfx::Vector2dF& current_fling_velocity) = 0; - virtual void PostInvalidate() = 0; + virtual void PostInvalidate(SynchronousCompositor* compositor) = 0; - virtual void DidUpdateContent() = 0; + virtual void DidUpdateContent(SynchronousCompositor* compositor) = 0; protected: SynchronousCompositorClient() {}
diff --git a/content/public/common/service_registry.h b/content/public/common/service_registry.h index 03f9f5a..c3852702 100644 --- a/content/public/common/service_registry.h +++ b/content/public/common/service_registry.h
@@ -31,12 +31,10 @@ // Binds this ServiceProvider implementation to a message pipe endpoint. virtual void Bind(shell::mojom::InterfaceProviderRequest request) = 0; - // Binds to a remote ServiceProvider. This will expose added services to the - // remote ServiceProvider with the corresponding handle and enable - // ConnectToRemoteService to provide access to services exposed by the remote - // ServiceProvider. - virtual void BindRemoteServiceProvider( - shell::mojom::InterfaceProviderPtr service_provider) = 0; + // ServiceRegistry is created with a bound InterfaceProviderPtr for remote + // interfaces, this is the server end of that pipe which should be passed + // to the remote end. + virtual shell::mojom::InterfaceProviderRequest TakeRemoteRequest() = 0; // Make the service created by |service_factory| available to the remote // ServiceProvider. In response to each request for a service,
diff --git a/content/public/test/mock_render_thread.cc b/content/public/test/mock_render_thread.cc index e6e6530..a3522a31 100644 --- a/content/public/test/mock_render_thread.cc +++ b/content/public/test/mock_render_thread.cc
@@ -27,8 +27,7 @@ new_window_routing_id_(0), new_window_main_frame_routing_id_(0), new_window_main_frame_widget_routing_id_(0), - new_frame_routing_id_(0), - service_registry_(new ServiceRegistryImpl) {} + new_frame_routing_id_(0) {} MockRenderThread::~MockRenderThread() { while (!filters_.empty()) { @@ -185,7 +184,8 @@ #endif // OS_WIN ServiceRegistry* MockRenderThread::GetServiceRegistry() { - DCHECK(service_registry_); + if (!service_registry_) + service_registry_.reset(new ServiceRegistryImpl); return service_registry_.get(); }
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index b57c63c..f3efae1 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -1106,6 +1106,7 @@ focused_pepper_plugin_(nullptr), pepper_last_mouse_event_target_(nullptr), #endif + frame_binding_(this), weak_factory_(this) { std::pair<RoutingIDFrameMap::iterator, bool> result = g_routing_id_frame_map.Get().insert(std::make_pair(routing_id_, this)); @@ -1599,11 +1600,11 @@ std::unique_ptr<StreamOverrideParameters>()); } -void RenderFrameImpl::BindServiceRegistry( - shell::mojom::InterfaceProviderRequest services, - shell::mojom::InterfaceProviderPtr exposed_services) { - service_registry_.Bind(std::move(services)); - service_registry_.BindRemoteServiceProvider(std::move(exposed_services)); +void RenderFrameImpl::Bind(mojom::FrameRequest request, + mojom::FrameHostPtr host) { + frame_binding_.Bind(std::move(request)); + frame_host_ = std::move(host); + frame_host_->GetInterfaceProvider(service_registry_.TakeRemoteRequest()); } ManifestManager* RenderFrameImpl::manifest_manager() { @@ -2510,6 +2511,13 @@ return is_pasting_; } +// mojom::Frame implementation ------------------------------------------------- + +void RenderFrameImpl::GetInterfaceProvider( + shell::mojom::InterfaceProviderRequest request) { + service_registry_.Bind(std::move(request)); +} + // blink::WebFrameClient implementation ---------------------------------------- blink::WebPlugin* RenderFrameImpl::createPlugin(
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index 8c2b6010..b70731504 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h
@@ -23,6 +23,7 @@ #include "base/process/process_handle.h" #include "build/build_config.h" #include "content/common/accessibility_mode_enums.h" +#include "content/common/frame.mojom.h" #include "content/common/frame_message_enums.h" #include "content/common/mojo/service_registry_impl.h" #include "content/public/common/console_message_level.h" @@ -164,6 +165,7 @@ class CONTENT_EXPORT RenderFrameImpl : public RenderFrame, + NON_EXPORTED_BASE(mojom::Frame), NON_EXPORTED_BASE(public blink::WebFrameClient), NON_EXPORTED_BASE(public blink::WebFrameSerializerClient) { public: @@ -423,6 +425,10 @@ bool IsUsingLoFi() const override; bool IsPasting() const override; + // mojom::Frame implementation: + void GetInterfaceProvider( + shell::mojom::InterfaceProviderRequest request) override; + // blink::WebFrameClient implementation: blink::WebPlugin* createPlugin(blink::WebLocalFrame* frame, const blink::WebPluginParams& params) override; @@ -633,9 +639,8 @@ blink::WebFrameSerializerClient::FrameSerializationStatus status) override; - // Binds this render frame's service registry. - void BindServiceRegistry(shell::mojom::InterfaceProviderRequest services, - shell::mojom::InterfaceProviderPtr exposed_services); + // Binds to the FrameHost in the browser. + void Bind(mojom::FrameRequest frame, mojom::FrameHostPtr frame_host); ManifestManager* manifest_manager(); @@ -1278,6 +1283,9 @@ PepperPluginInstanceImpl* pepper_last_mouse_event_target_; #endif + mojo::Binding<mojom::Frame> frame_binding_; + mojom::FrameHostPtr frame_host_; + base::WeakPtrFactory<RenderFrameImpl> weak_factory_; DISALLOW_COPY_AND_ASSIGN(RenderFrameImpl);
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index defc118..c521f601 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -74,7 +74,6 @@ #include "content/common/frame_messages.h" #include "content/common/gpu/client/context_provider_command_buffer.h" #include "content/common/gpu_process_launch_causes.h" -#include "content/common/render_frame_setup.mojom.h" #include "content/common/render_process_messages.h" #include "content/common/resource_messages.h" #include "content/common/service_worker/embedded_worker_setup.mojom.h" @@ -316,16 +315,16 @@ v8::Date::DateTimeConfigurationChangeNotification(isolate); } -class RenderFrameSetupImpl : public mojom::RenderFrameSetup { +class FrameFactoryImpl : public mojom::FrameFactory { public: - explicit RenderFrameSetupImpl( - mojo::InterfaceRequest<mojom::RenderFrameSetup> request) + explicit FrameFactoryImpl(mojom::FrameFactoryRequest request) : routing_id_highmark_(-1), binding_(this, std::move(request)) {} - void ExchangeInterfaceProviders( - int32_t frame_routing_id, - shell::mojom::InterfaceProviderRequest services, - shell::mojom::InterfaceProviderPtr exposed_services) override { + private: + // mojom::FrameFactory: + void CreateFrame(int32_t frame_routing_id, + mojom::FrameRequest frame_request, + mojom::FrameHostPtr frame_host) override { // TODO(morrita): This is for investigating http://crbug.com/415059 and // should be removed once it is fixed. CHECK_LT(routing_id_highmark_, frame_routing_id); @@ -336,23 +335,21 @@ // created due to a race between the message and a ViewMsg_New IPC that // triggers creation of the RenderFrame we want. if (!frame) { - RenderThreadImpl::current()->RegisterPendingRenderFrameConnect( - frame_routing_id, std::move(services), std::move(exposed_services)); + RenderThreadImpl::current()->RegisterPendingFrameCreate( + frame_routing_id, std::move(frame_request), std::move(frame_host)); return; } - frame->BindServiceRegistry(std::move(services), - std::move(exposed_services)); + frame->Bind(std::move(frame_request), std::move(frame_host)); } private: int32_t routing_id_highmark_; - mojo::StrongBinding<mojom::RenderFrameSetup> binding_; + mojo::StrongBinding<mojom::FrameFactory> binding_; }; -void CreateRenderFrameSetup( - mojo::InterfaceRequest<mojom::RenderFrameSetup> request) { - new RenderFrameSetupImpl(std::move(request)); +void CreateFrameFactory(mojom::FrameFactoryRequest request) { + new FrameFactoryImpl(std::move(request)); } void SetupEmbeddedWorkerOnWorkerThread( @@ -823,7 +820,7 @@ GetContentClient()->renderer()->RegisterProcessMojoServices( service_registry()); - service_registry()->AddService(base::Bind(CreateRenderFrameSetup)); + service_registry()->AddService(base::Bind(CreateFrameFactory)); service_registry()->AddService(base::Bind(CreateEmbeddedWorkerSetup)); #if defined(MOJO_SHELL_CLIENT) @@ -1024,24 +1021,17 @@ void RenderThreadImpl::AddRoute(int32_t routing_id, IPC::Listener* listener) { ChildThreadImpl::GetRouter()->AddRoute(routing_id, listener); - PendingRenderFrameConnectMap::iterator it = - pending_render_frame_connects_.find(routing_id); - if (it == pending_render_frame_connects_.end()) + auto it = pending_frame_creates_.find(routing_id); + if (it == pending_frame_creates_.end()) return; RenderFrameImpl* frame = RenderFrameImpl::FromRoutingID(routing_id); if (!frame) return; - scoped_refptr<PendingRenderFrameConnect> connection(it->second); - shell::mojom::InterfaceProviderRequest services( - std::move(connection->services())); - shell::mojom::InterfaceProviderPtr exposed_services( - std::move(connection->exposed_services())); - exposed_services.set_connection_error_handler(mojo::Closure()); - pending_render_frame_connects_.erase(it); - - frame->BindServiceRegistry(std::move(services), std::move(exposed_services)); + scoped_refptr<PendingFrameCreate> create(it->second); + frame->Bind(it->second->TakeFrameRequest(), it->second->TakeFrameHost()); + pending_frame_creates_.erase(it); } void RenderThreadImpl::RemoveRoute(int32_t routing_id) { @@ -1065,15 +1055,15 @@ } } -void RenderThreadImpl::RegisterPendingRenderFrameConnect( +void RenderThreadImpl::RegisterPendingFrameCreate( int routing_id, - shell::mojom::InterfaceProviderRequest services, - shell::mojom::InterfaceProviderPtr exposed_services) { - std::pair<PendingRenderFrameConnectMap::iterator, bool> result = - pending_render_frame_connects_.insert(std::make_pair( + mojom::FrameRequest frame_request, + mojom::FrameHostPtr frame_host) { + std::pair<PendingFrameCreateMap::iterator, bool> result = + pending_frame_creates_.insert(std::make_pair( routing_id, - make_scoped_refptr(new PendingRenderFrameConnect( - routing_id, std::move(services), std::move(exposed_services))))); + make_scoped_refptr(new PendingFrameCreate( + routing_id, std::move(frame_request), std::move(frame_host))))); CHECK(result.second) << "Inserting a duplicate item."; } @@ -2059,29 +2049,27 @@ blink::decommitFreeableMemory(); } -RenderThreadImpl::PendingRenderFrameConnect::PendingRenderFrameConnect( +RenderThreadImpl::PendingFrameCreate::PendingFrameCreate( int routing_id, - shell::mojom::InterfaceProviderRequest services, - shell::mojom::InterfaceProviderPtr exposed_services) + mojom::FrameRequest frame_request, + mojom::FrameHostPtr frame_host) : routing_id_(routing_id), - services_(std::move(services)), - exposed_services_(std::move(exposed_services)) { - // The RenderFrame may be deleted before the ExchangeInterfaceProviders - // message is received. In that case, the RenderFrameHost should close the - // connection, which is detected by setting an error handler on - // |exposed_services_|. - exposed_services_.set_connection_error_handler(base::Bind( - &RenderThreadImpl::PendingRenderFrameConnect::OnConnectionError, + frame_request_(std::move(frame_request)), + frame_host_(std::move(frame_host)) { + // The RenderFrame may be deleted before the CreateFrame message is received. + // In that case, the RenderFrameHost should cancel the create, which is + // detected by setting an error handler on |frame_host_|. + frame_host_.set_connection_error_handler(base::Bind( + &RenderThreadImpl::PendingFrameCreate::OnConnectionError, base::Unretained(this))); } -RenderThreadImpl::PendingRenderFrameConnect::~PendingRenderFrameConnect() { +RenderThreadImpl::PendingFrameCreate::~PendingFrameCreate() { } -void RenderThreadImpl::PendingRenderFrameConnect::OnConnectionError() { +void RenderThreadImpl::PendingFrameCreate::OnConnectionError() { size_t erased = - RenderThreadImpl::current()->pending_render_frame_connects_.erase( - routing_id_); + RenderThreadImpl::current()->pending_frame_creates_.erase(routing_id_); DCHECK_EQ(1u, erased); }
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h index 3fbf1d4..3c9cd7f9 100644 --- a/content/renderer/render_thread_impl.h +++ b/content/renderer/render_thread_impl.h
@@ -24,6 +24,7 @@ #include "build/build_config.h" #include "content/child/child_thread_impl.h" #include "content/common/content_export.h" +#include "content/common/frame.mojom.h" #include "content/common/frame_replication_state.h" #include "content/common/gpu_process_launch_causes.h" #include "content/common/storage_partition_service.mojom.h" @@ -436,10 +437,9 @@ void AddEmbeddedWorkerRoute(int32_t routing_id, IPC::Listener* listener); void RemoveEmbeddedWorkerRoute(int32_t routing_id); - void RegisterPendingRenderFrameConnect( - int routing_id, - shell::mojom::InterfaceProviderRequest services, - shell::mojom::InterfaceProviderPtr exposed_services); + void RegisterPendingFrameCreate(int routing_id, + mojom::FrameRequest frame, + mojom::FrameHostPtr host); mojom::StoragePartitionService* GetStoragePartitionService(); @@ -663,36 +663,34 @@ bool are_image_decode_tasks_enabled_; bool is_threaded_animation_enabled_; - class PendingRenderFrameConnect - : public base::RefCounted<PendingRenderFrameConnect> { + class PendingFrameCreate : public base::RefCounted<PendingFrameCreate> { public: - PendingRenderFrameConnect( - int routing_id, - shell::mojom::InterfaceProviderRequest services, - shell::mojom::InterfaceProviderPtr exposed_services); + PendingFrameCreate(int routing_id, + mojom::FrameRequest frame_request, + mojom::FrameHostPtr frame_host); - shell::mojom::InterfaceProviderRequest& services() { return services_; } - - shell::mojom::InterfaceProviderPtr& exposed_services() { - return exposed_services_; + mojom::FrameRequest TakeFrameRequest() { return std::move(frame_request_); } + mojom::FrameHostPtr TakeFrameHost() { + frame_host_.set_connection_error_handler(mojo::Closure()); + return std::move(frame_host_); } private: - friend class base::RefCounted<PendingRenderFrameConnect>; + friend class base::RefCounted<PendingFrameCreate>; - ~PendingRenderFrameConnect(); + ~PendingFrameCreate(); // Mojo error handler. void OnConnectionError(); int routing_id_; - shell::mojom::InterfaceProviderRequest services_; - shell::mojom::InterfaceProviderPtr exposed_services_; + mojom::FrameRequest frame_request_; + mojom::FrameHostPtr frame_host_; }; - typedef std::map<int, scoped_refptr<PendingRenderFrameConnect>> - PendingRenderFrameConnectMap; - PendingRenderFrameConnectMap pending_render_frame_connects_; + using PendingFrameCreateMap = + std::map<int, scoped_refptr<PendingFrameCreate>>; + PendingFrameCreateMap pending_frame_creates_; mojom::StoragePartitionServicePtr storage_partition_service_;
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc index d802fbae..ae08701 100644 --- a/content/renderer/service_worker/service_worker_context_client.cc +++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -43,6 +43,7 @@ #include "content/renderer/service_worker/service_worker_type_util.h" #include "ipc/ipc_message.h" #include "ipc/ipc_message_macros.h" +#include "mojo/public/cpp/bindings/interface_request.h" #include "third_party/WebKit/public/platform/URLConversion.h" #include "third_party/WebKit/public/platform/WebMessagePortChannel.h" #include "third_party/WebKit/public/platform/WebReferrerPolicy.h" @@ -276,8 +277,8 @@ shell::mojom::InterfaceProviderRequest services, shell::mojom::InterfaceProviderPtr exposed_services) { context_->service_registry.Bind(std::move(services)); - context_->service_registry.BindRemoteServiceProvider( - std::move(exposed_services)); + mojo::FuseInterface(context_->service_registry.TakeRemoteRequest(), + exposed_services.PassInterface()); } blink::WebURL ServiceWorkerContextClient::scope() const {
diff --git a/content/shell/browser/shell_mojo_test_utils_android.cc b/content/shell/browser/shell_mojo_test_utils_android.cc index 1cafe13..e51edf52 100644 --- a/content/shell/browser/shell_mojo_test_utils_android.cc +++ b/content/shell/browser/shell_mojo_test_utils_android.cc
@@ -53,11 +53,13 @@ shell::mojom::InterfaceProviderPtr exposed_services_a; registry_a->Bind(GetProxy(&exposed_services_a)); - registry_b->BindRemoteServiceProvider(std::move(exposed_services_a)); + mojo::FuseInterface(registry_b->TakeRemoteRequest(), + exposed_services_a.PassInterface()); shell::mojom::InterfaceProviderPtr exposed_services_b; registry_b->Bind(GetProxy(&exposed_services_b)); - registry_a->BindRemoteServiceProvider(std::move(exposed_services_b)); + mojo::FuseInterface(registry_a->TakeRemoteRequest(), + exposed_services_b.PassInterface()); content::ServiceRegistryAndroid* wrapper_a = ServiceRegistryAndroid::Create(registry_a).release();
diff --git a/docs/useful_urls.md b/docs/useful_urls.md index b49606cb..9366ddc 100644 --- a/docs/useful_urls.md +++ b/docs/useful_urls.md
@@ -5,45 +5,40 @@ ## Build Status -|:---------------------------------------------|:------------------------| -| http://build.chromium.org/p/chromium/console | Main buildbot waterfall | -| http://chromium-status.appspot.com/lkgr | Last Known Good Revision. Trybots pull this revision from trunk. | -| http://chromium-status.appspot.com/revisions | List of the last 100 potential LKGRs | -| http://build.chromium.org/p/chromium/lkgr-status/ | Status dashboard for LKGR | -| http://build.chromium.org/p/tryserver.chromium/waterfall?committer=developer@chromium.org | Trybot runs, by developer | -| http://chromium-status.appspot.com/status_viewer | Tree uptime stats | -| http://chromium-cq-status.appspot.com | Commit queue status | -| http://codereview.chromium.org/search?closed=3&commit=2&limit=50 | Pending commit queue jobs | -| http://chromium-build-logs.appspot.com/ | Search for historical test failures by test name | -| http://chromium-build-logs.appspot.com/list | Filterable list of most recent build logs | +* [Main buildbot waterfall](http://build.chromium.org/p/chromium/console) +* [Last Known Good Revision](http://chromium-status.appspot.com/lkgr) : Trybots pull this revision from trunk +* [List of the last 100 potential LKGRs](http://chromium-status.appspot.com/revisions) +* [Status dashboard for LKGR](http://build.chromium.org/p/chromium/lkgr-status/) +* http://build.chromium.org/p/tryserver.chromium/waterfall?committer=developer@chromium.org : Trybot runs, by developer +* [Tree uptime stats](http://chromium-status.appspot.com/status_viewer) +* [Commit queue status](http://chromium-cq-status.appspot.com) +* [Pending commit queue jobs](http://codereview.chromium.org/search?closed=3&commit=2&limit=50) +* [Search for historical test failures by test name](http://chromium-build-logs.appspot.com/) +* [Filterable list of most recent build logs](http://chromium-build-logs.appspot.com/list) ## For Sheriffs -|:---------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------| -| http://build.chromium.org/p/chromium.chromiumos/waterfall?show_events=true&reload=120&failures_only=true | List of failing bots for a waterfall (chromium.chromiumos as an example) | -| http://build.chromium.org/p/chromium.linux/waterfall?show_events=true&reload=120&builder=Linux%20Builder%20x64&builder=Linux%20Builder%20(dbg) | Monitor one or multiple bots (Linux Builder x64 and Linux Builder (dbg) on chromium.linux as an example) | -| http://build.chromium.org/p/chromium.win/waterfall/help | Customize the waterfall view for a waterfall (using chromium.win as an example) | -| http://chromium-sheriffing.appspot.com | Alternate waterfall view that helps with test failure triage | -| http://test-results.appspot.com/dashboards/flakiness_dashboard.html | Lists historical test results for the bots | +* http://build.chromium.org/p/chromium.chromiumos/waterfall?show_events=true&reload=120&failures_only=true : List of failing bots for a waterfall(chromium.chromiumos as an example) +* http://build.chromium.org/p/chromium.linux/waterfall?show_events=true&reload=120&builder=Linux%20Builder%20x64&builder=Linux%20Builder%20(dbg) : Monitor one or multiple bots(Linux Builder x64 and Linux Builder (dbg) on chromium.linux as an example) +* http://build.chromium.org/p/chromium.win/waterfall/help : Customize the waterfall view for a waterfall(using chromium.win as an example) +* [Alternate waterfall view that helps with test failure triage](http://chromium-sheriffing.appspot.com) +* [Lists historical test results for the bots](http://test-results.appspot.com/dashboards/flakiness_dashboard.html) ## Release Information -|:--------------------------------------|:---------------------------------------------------| -| https://omahaproxy.appspot.com/viewer | Current release versions of Chrome on all channels | -| https://omahaproxy.appspot.com/ | Looks up the revision of a build/release version | +* [Current release versions of Chrome on all channels](https://omahaproxy.appspot.com/viewer) +* [Looks up the revision of a build/release version](https://omahaproxy.appspot.com/) ## Source Information -|:------------------------|:------------| -| http://cs.chromium.org/ | Code Search | -| http://cs.chromium.org/SEARCH_TERM | Code Search for a specific SEARCH\_TERM | -| https://chromium.googlesource.com/chromium/src/ | Gitiles Source Code Browser | -| https://chromium.googlesource.com/chromium/src/+log/b6cfa6a..9a2e0a8?pretty=fuller | Git changes in revision range (also works for build numbers) | -| http://build.chromium.org/f/chromium/perf/dashboard/ui/changelog.html?url=/trunk/src&mode=html&range=SUCCESS_REV:FAILURE_REV | SVN changes in revision range | -| http://build.chromium.org/f/chromium/perf/dashboard/ui/changelog_blink.html?url=/trunk&mode=html&range=SUCCESS_REV:FAILURE_REV | Blink changes in revision range | +* [Code Search](http://cs.chromium.org/) +* http://cs.chromium.org/SEARCH_TERM : Code Search for a specific SEARCH\_TERM +* [Gitiles Source Code Browser](https://chromium.googlesource.com/chromium/src/) +* https://chromium.googlesource.com/chromium/src/+log/b6cfa6a..9a2e0a8?pretty=fuller : Git changes in revision range(also works for build numbers) +* http://build.chromium.org/f/chromium/perf/dashboard/ui/changelog.html?url=/trunk/src&mode=html&range=SUCCESS_REV:FAILURE_REV : SVN changes in revision range +* http://build.chromium.org/f/chromium/perf/dashboard/ui/changelog_blink.html?url=/trunk&mode=html&range=SUCCESS_REV:FAILURE_REV : Blink changes in revision range ## Communication -|:------------------------------------------------------------------|:-------------------------| -| http://groups.google.com/a/chromium.org/group/chromium-dev/topics | Chromium Developers List | -| http://groups.google.com/a/chromium.org/group/chromium-discuss/topics | Chromium Users List | +* [Chromium Developers List](http://groups.google.com/a/chromium.org/group/chromium-dev/topics) +* [Chromium Users List](http://groups.google.com/a/chromium.org/group/chromium-discuss/topics)
diff --git a/media/base/cdm_context.cc b/media/base/cdm_context.cc index 5bba924..4ad61e0 100644 --- a/media/base/cdm_context.cc +++ b/media/base/cdm_context.cc
@@ -6,6 +6,8 @@ namespace media { +const int CdmContext::kInvalidCdmId = 0; + CdmContext::CdmContext() {} CdmContext::~CdmContext() {}
diff --git a/media/base/cdm_context.h b/media/base/cdm_context.h index d41281e..d046927 100644 --- a/media/base/cdm_context.h +++ b/media/base/cdm_context.h
@@ -19,7 +19,7 @@ class MEDIA_EXPORT CdmContext { public: // Indicates an invalid CDM ID. See GetCdmId() for details. - static const int kInvalidCdmId = 0; + static const int kInvalidCdmId; virtual ~CdmContext();
diff --git a/media/base/mock_filters.cc b/media/base/mock_filters.cc index cff598ab..0a7536b 100644 --- a/media/base/mock_filters.cc +++ b/media/base/mock_filters.cc
@@ -135,7 +135,11 @@ MockCdmContext::~MockCdmContext() {} int MockCdmContext::GetCdmId() const { - return CdmContext::kInvalidCdmId; + return cdm_id_; +} + +void MockCdmContext::set_cdm_id(int cdm_id) { + cdm_id_ = cdm_id; } } // namespace media
diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h index 78d18a5..03f020a 100644 --- a/media/base/mock_filters.h +++ b/media/base/mock_filters.h
@@ -352,7 +352,11 @@ MOCK_METHOD0(GetDecryptor, Decryptor*()); int GetCdmId() const override; + void set_cdm_id(int cdm_id); + private: + int cdm_id_ = CdmContext::kInvalidCdmId; + DISALLOW_COPY_AND_ASSIGN(MockCdmContext); };
diff --git a/media/mojo/BUILD.gn b/media/mojo/BUILD.gn index 5323d73..3a867fd 100644 --- a/media/mojo/BUILD.gn +++ b/media/mojo/BUILD.gn
@@ -6,6 +6,7 @@ test("media_mojo_unittests") { sources = [ + "clients/mojo_renderer_unittest.cc", "common/media_type_converters_unittest.cc", "common/mojo_shared_buffer_video_frame_unittest.cc", "services/mojo_cdm_allocator_unittest.cc", @@ -17,6 +18,7 @@ "//media", "//media:cdm_api", "//media/base:test_support", + "//media/mojo/clients", "//media/mojo/common", "//media/mojo/interfaces", "//media/mojo/services",
diff --git a/media/mojo/clients/BUILD.gn b/media/mojo/clients/BUILD.gn index 9fd09ff..a6b264c 100644 --- a/media/mojo/clients/BUILD.gn +++ b/media/mojo/clients/BUILD.gn
@@ -7,8 +7,12 @@ visibility = [ "//content/renderer", + # TODO(xhwang): Only allow //media/mojo:media_mojo_unittests + "//media/mojo:*", + # TODO(xhwang): Only allow //media/mojo/services:media_mojo_shell_unittests "//media/mojo/services:*", + "//media/test/*", ]
diff --git a/media/mojo/clients/mojo_renderer_impl.cc b/media/mojo/clients/mojo_renderer_impl.cc index f407b89..c0e2891 100644 --- a/media/mojo/clients/mojo_renderer_impl.cc +++ b/media/mojo/clients/mojo_renderer_impl.cc
@@ -34,6 +34,8 @@ MojoRendererImpl::~MojoRendererImpl() { DVLOG(1) << __FUNCTION__; DCHECK(task_runner_->BelongsToCurrentThread()); + + CancelPendingCallbacks(); } void MojoRendererImpl::Initialize( @@ -44,8 +46,13 @@ DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(demuxer_stream_provider); + if (encountered_error_) { + task_runner_->PostTask( + FROM_HERE, base::Bind(init_cb, PIPELINE_ERROR_INITIALIZATION_FAILED)); + return; + } + demuxer_stream_provider_ = demuxer_stream_provider; - client_ = client; init_cb_ = init_cb; // Create audio and video mojom::DemuxerStream and bind its lifetime to @@ -68,10 +75,10 @@ // Using base::Unretained(this) is safe because |this| owns // |remote_renderer_|, and the callback won't be dispatched if // |remote_renderer_| is destroyed. - remote_renderer_->Initialize( - binding_.CreateInterfacePtrAndBind(), std::move(audio_stream), - std::move(video_stream), - base::Bind(&MojoRendererImpl::OnInitialized, base::Unretained(this))); + remote_renderer_->Initialize(binding_.CreateInterfacePtrAndBind(), + std::move(audio_stream), std::move(video_stream), + base::Bind(&MojoRendererImpl::OnInitialized, + base::Unretained(this), client)); } void MojoRendererImpl::SetCdm(CdmContext* cdm_context, @@ -79,24 +86,44 @@ DVLOG(1) << __FUNCTION__; DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(cdm_context); + DCHECK(!cdm_attached_cb.is_null()); + DCHECK(cdm_attached_cb_.is_null()); + + if (encountered_error_) { + task_runner_->PostTask(FROM_HERE, base::Bind(cdm_attached_cb, false)); + return; + } int32_t cdm_id = cdm_context->GetCdmId(); if (cdm_id == CdmContext::kInvalidCdmId) { DVLOG(2) << "MojoRendererImpl only works with remote CDMs but the CDM ID " "is invalid."; - cdm_attached_cb.Run(false); + task_runner_->PostTask(FROM_HERE, base::Bind(cdm_attached_cb, false)); return; } BindRemoteRendererIfNeeded(); - remote_renderer_->SetCdm(cdm_id, cdm_attached_cb); + + cdm_attached_cb_ = cdm_attached_cb; + remote_renderer_->SetCdm(cdm_id, base::Bind(&MojoRendererImpl::OnCdmAttached, + base::Unretained(this))); } void MojoRendererImpl::Flush(const base::Closure& flush_cb) { DVLOG(2) << __FUNCTION__; DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(remote_renderer_.is_bound()); - remote_renderer_->Flush(flush_cb); + DCHECK(!flush_cb.is_null()); + DCHECK(flush_cb_.is_null()); + + if (encountered_error_) { + task_runner_->PostTask(FROM_HERE, flush_cb); + return; + } + + flush_cb_ = flush_cb; + remote_renderer_->Flush( + base::Bind(&MojoRendererImpl::OnFlushed, base::Unretained(this))); } void MojoRendererImpl::StartPlayingFrom(base::TimeDelta time) { @@ -116,6 +143,7 @@ DVLOG(2) << __FUNCTION__; DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(remote_renderer_.is_bound()); + remote_renderer_->SetPlaybackRate(playback_rate); } @@ -123,6 +151,7 @@ DVLOG(2) << __FUNCTION__; DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(remote_renderer_.is_bound()); + remote_renderer_->SetVolume(volume); } @@ -135,13 +164,16 @@ bool MojoRendererImpl::HasAudio() { DVLOG(1) << __FUNCTION__; DCHECK(task_runner_->BelongsToCurrentThread()); - DCHECK(remote_renderer_.get()); // We always bind the renderer. + DCHECK(remote_renderer_.is_bound()); + return !!demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO); } bool MojoRendererImpl::HasVideo() { DVLOG(1) << __FUNCTION__; DCHECK(task_runner_->BelongsToCurrentThread()); + DCHECK(remote_renderer_.is_bound()); + return !!demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO); } @@ -170,6 +202,8 @@ DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(init_cb_.is_null()); + encountered_error_ = true; + // TODO(tim): Should we plumb error code from remote renderer? // http://crbug.com/410451. client_->OnError(PIPELINE_ERROR_DECODE); @@ -194,12 +228,11 @@ DVLOG(1) << __FUNCTION__; DCHECK(task_runner_->BelongsToCurrentThread()); - if (!init_cb_.is_null()) { - base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED); - return; - } + encountered_error_ = true; + CancelPendingCallbacks(); - client_->OnError(PIPELINE_ERROR_DECODE); + if (client_) + client_->OnError(PIPELINE_ERROR_DECODE); } void MojoRendererImpl::BindRemoteRendererIfNeeded() { @@ -207,6 +240,8 @@ DCHECK(task_runner_->BelongsToCurrentThread()); // If |remote_renderer_| has already been bound, do nothing. + // Note that after Bind() is called, |remote_renderer_| is always bound even + // after connection error. if (remote_renderer_.is_bound()) return; @@ -221,13 +256,49 @@ base::Bind(&MojoRendererImpl::OnConnectionError, base::Unretained(this))); } -void MojoRendererImpl::OnInitialized(bool success) { +void MojoRendererImpl::OnInitialized(media::RendererClient* client, + bool success) { DVLOG(1) << __FUNCTION__; DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(!init_cb_.is_null()); + // Only set |client_| after initialization succeeded. No client methods should + // be called before this. + if (success) + client_ = client; + base::ResetAndReturn(&init_cb_).Run( success ? PIPELINE_OK : PIPELINE_ERROR_INITIALIZATION_FAILED); } +void MojoRendererImpl::OnFlushed() { + DVLOG(1) << __FUNCTION__; + DCHECK(task_runner_->BelongsToCurrentThread()); + DCHECK(!flush_cb_.is_null()); + + base::ResetAndReturn(&flush_cb_).Run(); +} + +void MojoRendererImpl::OnCdmAttached(bool success) { + DVLOG(1) << __FUNCTION__; + DCHECK(task_runner_->BelongsToCurrentThread()); + DCHECK(!cdm_attached_cb_.is_null()); + + base::ResetAndReturn(&cdm_attached_cb_).Run(success); +} + +void MojoRendererImpl::CancelPendingCallbacks() { + DVLOG(1) << __FUNCTION__; + DCHECK(task_runner_->BelongsToCurrentThread()); + + if (!init_cb_.is_null()) + base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED); + + if (!flush_cb_.is_null()) + base::ResetAndReturn(&flush_cb_).Run(); + + if (!cdm_attached_cb_.is_null()) + base::ResetAndReturn(&cdm_attached_cb_).Run(false); +} + } // namespace media
diff --git a/media/mojo/clients/mojo_renderer_impl.h b/media/mojo/clients/mojo_renderer_impl.h index 9b60afe5..7ad7b11 100644 --- a/media/mojo/clients/mojo_renderer_impl.h +++ b/media/mojo/clients/mojo_renderer_impl.h
@@ -73,8 +73,12 @@ // Callback for connection error on |remote_renderer_|. void OnConnectionError(); - // Called when |remote_renderer_| has finished initializing. - void OnInitialized(bool success); + // Callbacks for |remote_renderer_| methods. + void OnInitialized(media::RendererClient* client, bool success); + void OnFlushed(); + void OnCdmAttached(bool success); + + void CancelPendingCallbacks(); // |task_runner| on which all methods are invoked, except for GetMediaTime(), // which can be called on any thread. @@ -86,14 +90,14 @@ // Video frame overlays are rendered onto this sink. // Rendering of a new overlay is only needed when video natural size changes. - VideoRendererSink* video_renderer_sink_; + VideoRendererSink* video_renderer_sink_ = nullptr; // Provider of audio/video DemuxerStreams. Must be valid throughout the // lifetime of |this|. - DemuxerStreamProvider* demuxer_stream_provider_; + DemuxerStreamProvider* demuxer_stream_provider_ = nullptr; // Client of |this| renderer passed in Initialize. - media::RendererClient* client_; + media::RendererClient* client_ = nullptr; // This class is constructed on one thread and used exclusively on another // thread. This member is used to safely pass the RendererPtr from one thread @@ -106,9 +110,11 @@ // Binding for RendererClient, bound to the |task_runner_|. mojo::Binding<RendererClient> binding_; - // Callbacks passed to Initialize() that we forward messages from - // |remote_renderer_| through. + bool encountered_error_ = false; + PipelineStatusCB init_cb_; + base::Closure flush_cb_; + CdmAttachedCB cdm_attached_cb_; // Lock used to serialize access for |time_|. mutable base::Lock lock_;
diff --git a/media/mojo/clients/mojo_renderer_unittest.cc b/media/mojo/clients/mojo_renderer_unittest.cc new file mode 100644 index 0000000..8f90d33 --- /dev/null +++ b/media/mojo/clients/mojo_renderer_unittest.cc
@@ -0,0 +1,382 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <stdint.h> + +#include "base/bind.h" +#include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/threading/platform_thread.h" +#include "media/base/cdm_config.h" +#include "media/base/cdm_context.h" +#include "media/base/gmock_callback_support.h" +#include "media/base/mock_filters.h" +#include "media/base/test_helpers.h" +#include "media/cdm/default_cdm_factory.h" +#include "media/mojo/clients/mojo_renderer_impl.h" +#include "media/mojo/common/media_type_converters.h" +#include "media/mojo/interfaces/content_decryption_module.mojom.h" +#include "media/mojo/interfaces/renderer.mojom.h" +#include "media/mojo/services/mojo_cdm_service.h" +#include "media/mojo/services/mojo_cdm_service_context.h" +#include "media/mojo/services/mojo_renderer_service.h" +#include "media/renderers/video_overlay_factory.h" +#include "mojo/public/cpp/bindings/interface_request.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::_; +using ::testing::DoAll; +using ::testing::Return; +using ::testing::SaveArg; +using ::testing::StrictMock; + +namespace media { + +const int64_t kStartPlayingTimeInMs = 100; +const char kClearKeyKeySystem[] = "org.w3.clearkey"; + +ACTION_P2(SetError, renderer_client, error) { + renderer_client->OnError(error); +} + +class MojoRendererTest : public ::testing::Test { + public: + MojoRendererTest() { + std::unique_ptr<StrictMock<MockRenderer>> mock_renderer( + new StrictMock<MockRenderer>()); + mock_renderer_ = mock_renderer.get(); + + mojom::RendererPtr remote_renderer; + + mojo_renderer_service_ = new MojoRendererService( + mojo_cdm_service_context_.GetWeakPtr(), std::move(mock_renderer), + mojo::GetProxy(&remote_renderer)); + + mojo_renderer_.reset( + new MojoRendererImpl(message_loop_.task_runner(), + std::unique_ptr<VideoOverlayFactory>(nullptr), + nullptr, std::move(remote_renderer))); + + // CreateAudioStream() and CreateVideoStream() overrides expectations for + // expected non-NULL streams. + EXPECT_CALL(demuxer_, GetStream(_)).WillRepeatedly(Return(nullptr)); + + EXPECT_CALL(*mock_renderer_, GetMediaTime()) + .WillRepeatedly(Return(base::TimeDelta())); + } + + virtual ~MojoRendererTest() {} + + void Destroy() { + mojo_renderer_.reset(); + base::RunLoop().RunUntilIdle(); + } + + // Completion callbacks. + MOCK_METHOD1(OnInitialized, void(PipelineStatus)); + MOCK_METHOD0(OnFlushed, void()); + MOCK_METHOD1(OnCdmAttached, void(bool)); + + std::unique_ptr<StrictMock<MockDemuxerStream>> CreateStream( + DemuxerStream::Type type) { + std::unique_ptr<StrictMock<MockDemuxerStream>> stream( + new StrictMock<MockDemuxerStream>(type)); + return stream; + } + + void CreateAudioStream() { + audio_stream_ = CreateStream(DemuxerStream::AUDIO); + EXPECT_CALL(demuxer_, GetStream(DemuxerStream::AUDIO)) + .WillRepeatedly(Return(audio_stream_.get())); + } + + void CreateVideoStream(bool is_encrypted = false) { + video_stream_ = CreateStream(DemuxerStream::VIDEO); + video_stream_->set_video_decoder_config( + is_encrypted ? TestVideoConfig::NormalEncrypted() + : TestVideoConfig::Normal()); + EXPECT_CALL(demuxer_, GetStream(DemuxerStream::VIDEO)) + .WillRepeatedly(Return(video_stream_.get())); + } + + void InitializeAndExpect(PipelineStatus status) { + DVLOG(1) << __FUNCTION__ << ": " << status; + EXPECT_CALL(*this, OnInitialized(status)); + mojo_renderer_->Initialize( + &demuxer_, &renderer_client_, + base::Bind(&MojoRendererTest::OnInitialized, base::Unretained(this))); + base::RunLoop().RunUntilIdle(); + } + + void Initialize() { + CreateAudioStream(); + EXPECT_CALL(*mock_renderer_, Initialize(_, _, _)) + .WillOnce(DoAll(SaveArg<1>(&remote_renderer_client_), + RunCallback<2>(PIPELINE_OK))); + InitializeAndExpect(PIPELINE_OK); + } + + void Flush() { + DVLOG(1) << __FUNCTION__; + // Flush callback should always be fired. + EXPECT_CALL(*this, OnFlushed()); + mojo_renderer_->Flush( + base::Bind(&MojoRendererTest::OnFlushed, base::Unretained(this))); + base::RunLoop().RunUntilIdle(); + } + + void SetCdmAndExpect(bool success) { + DVLOG(1) << __FUNCTION__; + // Set CDM callback should always be fired. + EXPECT_CALL(*this, OnCdmAttached(success)); + mojo_renderer_->SetCdm( + &cdm_context_, + base::Bind(&MojoRendererTest::OnCdmAttached, base::Unretained(this))); + base::RunLoop().RunUntilIdle(); + } + + // Simulates a connection error at the client side by killing the service. + // Note that |mock_renderer_| will also be destroyed, do NOT expect anything + // on it. Otherwise the test will crash. + void ConnectionError() { + DVLOG(1) << __FUNCTION__; + delete mojo_renderer_service_; + base::RunLoop().RunUntilIdle(); + } + + void OnCdmCreated(mojom::CdmPromiseResultPtr result, + int cdm_id, + mojom::DecryptorPtr decryptor) { + EXPECT_TRUE(result->success); + EXPECT_NE(CdmContext::kInvalidCdmId, cdm_id); + cdm_context_.set_cdm_id(cdm_id); + } + + void CreateCdm() { + new MojoCdmService(mojo_cdm_service_context_.GetWeakPtr(), &cdm_factory_, + mojo::GetProxy(&remote_cdm_)); + remote_cdm_->Initialize( + kClearKeyKeySystem, "https://www.test.com", + mojom::CdmConfig::From(CdmConfig()), + base::Bind(&MojoRendererTest::OnCdmCreated, base::Unretained(this))); + base::RunLoop().RunUntilIdle(); + } + + void StartPlayingFrom(base::TimeDelta start_time) { + EXPECT_CALL(*mock_renderer_, StartPlayingFrom(start_time)); + mojo_renderer_->StartPlayingFrom(start_time); + EXPECT_EQ(start_time, mojo_renderer_->GetMediaTime()); + base::RunLoop().RunUntilIdle(); + } + + void Play() { + StartPlayingFrom(base::TimeDelta::FromMilliseconds(kStartPlayingTimeInMs)); + } + + // Fixture members. + base::MessageLoop message_loop_; + + // The MojoRendererImpl that we are testing. + std::unique_ptr<MojoRendererImpl> mojo_renderer_; + + // Client side mocks and helpers. + StrictMock<MockRendererClient> renderer_client_; + StrictMock<MockCdmContext> cdm_context_; + mojom::ContentDecryptionModulePtr remote_cdm_; + + // Client side mock demuxer and demuxer streams. + StrictMock<MockDemuxer> demuxer_; + std::unique_ptr<StrictMock<MockDemuxerStream>> audio_stream_; + std::unique_ptr<StrictMock<MockDemuxerStream>> video_stream_; + + // Service side mocks and helpers. + StrictMock<MockRenderer>* mock_renderer_; + MojoCdmServiceContext mojo_cdm_service_context_; + RendererClient* remote_renderer_client_; + DefaultCdmFactory cdm_factory_; + + // Owned by the connection. But we can delete it manually to trigger a + // connection error at the client side. See ConnectionError(); + MojoRendererService* mojo_renderer_service_; + + private: + DISALLOW_COPY_AND_ASSIGN(MojoRendererTest); +}; + +TEST_F(MojoRendererTest, Initialize_Success) { + Initialize(); +} + +TEST_F(MojoRendererTest, Initialize_Failure) { + CreateAudioStream(); + // Mojo Renderer only expects a boolean result, which will be translated + // to PIPELINE_OK or PIPELINE_ERROR_INITIALIZATION_FAILED. + EXPECT_CALL(*mock_renderer_, Initialize(_, _, _)) + .WillOnce(RunCallback<2>(PIPELINE_ERROR_ABORT)); + InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED); +} + +TEST_F(MojoRendererTest, Initialize_BeforeConnectionError) { + CreateAudioStream(); + EXPECT_CALL(*mock_renderer_, Initialize(_, _, _)) + .WillOnce(InvokeWithoutArgs(this, &MojoRendererTest::ConnectionError)); + InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED); +} + +TEST_F(MojoRendererTest, Initialize_AfterConnectionError) { + ConnectionError(); + CreateAudioStream(); + InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED); +} + +TEST_F(MojoRendererTest, Flush_Success) { + Initialize(); + + EXPECT_CALL(*mock_renderer_, Flush(_)).WillOnce(RunClosure<0>()); + Flush(); +} + +TEST_F(MojoRendererTest, Flush_ConnectionError) { + Initialize(); + + // Upon connection error, OnError() should be called once and only once. + EXPECT_CALL(renderer_client_, OnError(PIPELINE_ERROR_DECODE)).Times(1); + EXPECT_CALL(*mock_renderer_, Flush(_)) + .WillOnce(InvokeWithoutArgs(this, &MojoRendererTest::ConnectionError)); + Flush(); +} + +TEST_F(MojoRendererTest, Flush_AfterConnectionError) { + Initialize(); + + // Upon connection error, OnError() should be called once and only once. + EXPECT_CALL(renderer_client_, OnError(PIPELINE_ERROR_DECODE)).Times(1); + ConnectionError(); + + Flush(); +} + +TEST_F(MojoRendererTest, SetCdm_Success) { + Initialize(); + CreateCdm(); + EXPECT_CALL(*mock_renderer_, SetCdm(_, _)).WillOnce(RunCallback<1>(true)); + SetCdmAndExpect(true); +} + +TEST_F(MojoRendererTest, SetCdm_Failure) { + Initialize(); + CreateCdm(); + EXPECT_CALL(*mock_renderer_, SetCdm(_, _)).WillOnce(RunCallback<1>(false)); + SetCdmAndExpect(false); +} + +TEST_F(MojoRendererTest, SetCdm_InvalidCdmId) { + Initialize(); + SetCdmAndExpect(false); +} + +TEST_F(MojoRendererTest, SetCdm_NonExistCdmId) { + Initialize(); + cdm_context_.set_cdm_id(1); + SetCdmAndExpect(false); +} + +TEST_F(MojoRendererTest, SetCdm_BeforeInitialize) { + CreateCdm(); + EXPECT_CALL(*mock_renderer_, SetCdm(_, _)).WillOnce(RunCallback<1>(true)); + SetCdmAndExpect(true); +} + +TEST_F(MojoRendererTest, SetCdm_AfterInitializeAndConnectionError) { + CreateCdm(); + Initialize(); + EXPECT_CALL(renderer_client_, OnError(PIPELINE_ERROR_DECODE)).Times(1); + ConnectionError(); + SetCdmAndExpect(false); +} + +TEST_F(MojoRendererTest, SetCdm_AfterConnectionErrorAndBeforeInitialize) { + CreateCdm(); + // Initialize() is not called so RendererClient::OnError() is not expected. + ConnectionError(); + SetCdmAndExpect(false); + InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED); +} + +TEST_F(MojoRendererTest, SetCdm_BeforeInitializeAndConnectionError) { + CreateCdm(); + EXPECT_CALL(*mock_renderer_, SetCdm(_, _)).WillOnce(RunCallback<1>(true)); + SetCdmAndExpect(true); + // Initialize() is not called so RendererClient::OnError() is not expected. + ConnectionError(); + CreateAudioStream(); + InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED); +} + +TEST_F(MojoRendererTest, StartPlayingFrom) { + Initialize(); + Play(); +} + +TEST_F(MojoRendererTest, GetMediaTime) { + Initialize(); + EXPECT_EQ(base::TimeDelta(), mojo_renderer_->GetMediaTime()); + + Play(); + + // Time is updated periodically with a short delay. + const base::TimeDelta kUpdatedTime = base::TimeDelta::FromMilliseconds(500); + EXPECT_CALL(*mock_renderer_, GetMediaTime()) + .WillRepeatedly(Return(kUpdatedTime)); + base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(kUpdatedTime, mojo_renderer_->GetMediaTime()); +} + +TEST_F(MojoRendererTest, OnEnded) { + Initialize(); + Play(); + + EXPECT_CALL(renderer_client_, OnEnded()).Times(1); + remote_renderer_client_->OnEnded(); + base::RunLoop().RunUntilIdle(); +} + +// TODO(xhwang): Add tests for all RendererClient methods. + +TEST_F(MojoRendererTest, Destroy_PendingInitialize) { + CreateAudioStream(); + EXPECT_CALL(*mock_renderer_, Initialize(_, _, _)) + .WillRepeatedly(RunCallback<2>(PIPELINE_ERROR_ABORT)); + EXPECT_CALL(*this, OnInitialized(PIPELINE_ERROR_INITIALIZATION_FAILED)); + mojo_renderer_->Initialize( + &demuxer_, &renderer_client_, + base::Bind(&MojoRendererTest::OnInitialized, base::Unretained(this))); + Destroy(); +} + +TEST_F(MojoRendererTest, Destroy_PendingFlush) { + EXPECT_CALL(*mock_renderer_, SetCdm(_, _)) + .WillRepeatedly(RunCallback<1>(true)); + EXPECT_CALL(*this, OnCdmAttached(false)); + mojo_renderer_->SetCdm( + &cdm_context_, + base::Bind(&MojoRendererTest::OnCdmAttached, base::Unretained(this))); + Destroy(); +} + +TEST_F(MojoRendererTest, Destroy_PendingSetCdm) { + Initialize(); + EXPECT_CALL(*mock_renderer_, Flush(_)).WillRepeatedly(RunClosure<0>()); + EXPECT_CALL(*this, OnFlushed()); + mojo_renderer_->Flush( + base::Bind(&MojoRendererTest::OnFlushed, base::Unretained(this))); + Destroy(); +} + +// TODO(xhwang): Add more tests on OnError. For example, ErrorDuringFlush, +// ErrorAfterFlush etc. + +} // namespace media
diff --git a/media/mojo/services/mojo_cdm_service.h b/media/mojo/services/mojo_cdm_service.h index 04a6f4d..2e1aa782 100644 --- a/media/mojo/services/mojo_cdm_service.h +++ b/media/mojo/services/mojo_cdm_service.h
@@ -10,6 +10,7 @@ #include <memory> #include "base/callback.h" +#include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" @@ -27,7 +28,8 @@ // A mojom::ContentDecryptionModule implementation backed by a // media::MediaKeys. -class MojoCdmService : public mojom::ContentDecryptionModule { +class MEDIA_MOJO_EXPORT MojoCdmService + : NON_EXPORTED_BASE(public mojom::ContentDecryptionModule) { public: // Get the CDM associated with |cdm_id|, which is unique per process. // Can be called on any thread. The returned CDM is not guaranteed to be @@ -37,7 +39,7 @@ // render frame the caller is associated with. In the future, we should move // all out-of-process media players into the MojoMediaApplicaiton so that we // can use MojoCdmServiceContext (per render frame) to get the CDM. - static scoped_refptr<MediaKeys> MEDIA_MOJO_EXPORT LegacyGetCdm(int cdm_id); + static scoped_refptr<MediaKeys> LegacyGetCdm(int cdm_id); // Constructs a MojoCdmService and strongly binds it to the |request|. MojoCdmService(
diff --git a/media/mojo/services/mojo_cdm_service_context.h b/media/mojo/services/mojo_cdm_service_context.h index 518d8a5..5938e9fc 100644 --- a/media/mojo/services/mojo_cdm_service_context.h +++ b/media/mojo/services/mojo_cdm_service_context.h
@@ -12,6 +12,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" +#include "media/mojo/services/media_mojo_export.h" namespace media { @@ -19,7 +20,7 @@ class MojoCdmService; // A class that creates, owns and manages all MojoCdmService instances. -class MojoCdmServiceContext { +class MEDIA_MOJO_EXPORT MojoCdmServiceContext { public: MojoCdmServiceContext(); ~MojoCdmServiceContext();
diff --git a/media/mojo/services/mojo_renderer_service.h b/media/mojo/services/mojo_renderer_service.h index ed63e58..58b1ce7 100644 --- a/media/mojo/services/mojo_renderer_service.h +++ b/media/mojo/services/mojo_renderer_service.h
@@ -17,6 +17,7 @@ #include "media/base/pipeline_status.h" #include "media/base/renderer_client.h" #include "media/mojo/interfaces/renderer.mojom.h" +#include "media/mojo/services/media_mojo_export.h" #include "mojo/public/cpp/bindings/strong_binding.h" namespace media { @@ -28,7 +29,8 @@ // A mojom::Renderer implementation that use a media::Renderer to render // media streams. -class MojoRendererService : public mojom::Renderer, public RendererClient { +class MEDIA_MOJO_EXPORT MojoRendererService : public mojom::Renderer, + public RendererClient { public: // |mojo_cdm_service_context| can be used to find the CDM to support // encrypted media. If null, encrypted media is not supported.
diff --git a/media/renderers/renderer_impl_unittest.cc b/media/renderers/renderer_impl_unittest.cc index 4c901f7..9790055 100644 --- a/media/renderers/renderer_impl_unittest.cc +++ b/media/renderers/renderer_impl_unittest.cc
@@ -68,8 +68,8 @@ video_renderer_client_(nullptr), audio_renderer_client_(nullptr), initialization_status_(PIPELINE_OK) { - // SetDemuxerExpectations() adds overriding expectations for expected - // non-NULL streams. + // CreateAudioStream() and CreateVideoStream() overrides expectations for + // expected non-NULL streams. DemuxerStream* null_pointer = NULL; EXPECT_CALL(*demuxer_, GetStream(_)) .WillRepeatedly(Return(null_pointer));
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index bac56e3..c05e163 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -42,8 +42,9 @@ crbug.com/504613 crbug.com/524248 virtual/spv2/paint/images/image-backgrounds-not-antialiased.html [ Skip ] crbug.com/502531 fast/borders/border-antialiasing.html [ Failure ] -crbug.com/600008 [ Win ] fast/repaint/window-resize-centered-inline-under-fixed-pos.html [ Failure Pass ] -crbug.com/600008 [ Win ] fast/repaint/window-resize-vertical-writing-mode.html [ Failure Pass ] +# TODO(wangxianzhu): Restore these after rebaseline. +# crbug.com/600008 [ Win ] fast/repaint/window-resize-centered-inline-under-fixed-pos.html [ Failure Pass ] +# crbug.com/600008 [ Win ] fast/repaint/window-resize-vertical-writing-mode.html [ Failure Pass ] crbug.com/600008 [ Mac Win ] fast/repaint/window-resize-background-image-non-fixed.html [ Failure Pass ] crbug.com/538697 [ Win7 Debug ] virtual/threaded/printing/webgl-oversized-printing.html [ Crash ] @@ -337,7 +338,8 @@ crbug.com/552433 [ Linux Mac Win10 Win7 ] svg/dom/length-list-parser.html [ Failure Pass ] crbug.com/552433 [ Linux Mac Win10 Win7 ] svg/transforms/text-with-pattern-with-svg-transform.svg [ Failure Pass ] crbug.com/552433 [ Linux Mac Win10 Win7 ] svg/hixie/perf/006.xml [ Failure Pass ] -crbug.com/605024 [ Mac ] svg/transforms/animated-path-inside-transformed-html.xhtml [ Failure ] +# TODO(wangxianzhu): Restore this after rebaseline. +# crbug.com/605024 [ Mac ] svg/transforms/animated-path-inside-transformed-html.xhtml [ Failure ] # This directly has manual tests that don't have to run with run-webkit-tests crbug.com/359838 http/tests/ManualTests/ [ Skip ] @@ -1218,7 +1220,8 @@ crbug.com/619103 fast/table/border-collapsing/cached-change-tbody-border-color.html [ Failure ] crbug.com/619103 paint/invalidation/invalidate-after-composited-scroll-of-window.html [ Failure ] crbug.com/619103 paint/invalidation/animated-gif-background-offscreen.html [ Pass Failure ] -crbug.com/619103 [ Win ] svg/text/text-viewbox-rescale.html [ Pass Failure ] +# TODO(wangxianzhu): Restore this after rebaseline. +# crbug.com/619103 [ Win ] svg/text/text-viewbox-rescale.html [ Pass Failure ] crbug.com/443596 media/sources-fallback-codecs.html [ Pass Failure ] @@ -1380,6 +1383,128 @@ crbug.com/594595 [ Linux ] http/tests/security/mixedContent/websocket/insecure-websocket-in-secure-page-worker-allowed.html [ Timeout Pass ] +crbug.com/619630 compositing/squashing/iframe-inside-squashed-layer.html [ NeedsRebaseline ] +crbug.com/619630 compositing/squashing/remove-squashed-layer-plus-move.html [ NeedsRebaseline ] +crbug.com/619630 css3/flexbox/repaint-on-layout.html [ NeedsRebaseline ] +crbug.com/619630 css3/flexbox/repaint.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/block-no-inflow-children.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/box-inline-resize.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/bugzilla-3509.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/bugzilla-5699.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/bugzilla-6278.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/bugzilla-7235.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/change-text-content-and-background-color.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/clip-with-layout-delta.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/clipped-relative.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/control-clip.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/crbug-371640-4.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/crbug-371640.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/delete-into-nested-block.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/gradients-em-stops-repaint.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/inline-block-resize.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/inline-focus.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/inline-outline-repaint.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/inline-reflow.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/inline-relative-positioned.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/invisible-objects.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/layout-state-relative.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/layout-state-scrolloffset.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/layout-state-scrolloffset2.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/layout-state-scrolloffset3.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/layoutstate-invalid-invalidation-inline-relative-positioned.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/line-flow-with-floats-1.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/line-flow-with-floats-10.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/line-flow-with-floats-2.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/line-flow-with-floats-3.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/line-flow-with-floats-4.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/line-flow-with-floats-5.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/line-flow-with-floats-6.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/line-flow-with-floats-7.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/line-flow-with-floats-8.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/line-flow-with-floats-9.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/line-in-scrolled-clipped-block.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/line-overflow.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/lines-with-layout-delta.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/list-marker-2.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/make-children-non-inline.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/multi-layout-one-frame.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/multicol-repaint.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/multicol-with-text.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/outline-continuations.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/overflow-delete-line.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/overflow-scroll-body-appear.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/overflow-scroll-delete.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/paint-invalidation-with-reparent-across-frame-boundaries.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/positioned-document-element.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/positioned-list-offset-change-repaint.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/quotes.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/reflection-repaint-test.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/relative-inline-positioned-movement-repaint.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/remove-block-after-layout.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/remove-inline-after-layout.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/remove-inline-block-descendant-of-flex.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/remove-inline-layer-after-layout.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/resize-scrollable-iframe.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/selection-after-delete.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/selection-after-remove.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/selection-clear.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/shift-relative-positioned-container-with-image-removal.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/stacked-diacritics.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/subtree-root-skipped.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/table-collapsed-border.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/text-append-dirty-lines.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/text-in-relative-positioned-inline.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/text-match-document-change.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/transform-layout-repaint.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/vertical-align-length1.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/vertical-align-length2.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/vertical-align1.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/vertical-align2.html [ NeedsRebaseline ] +crbug.com/619630 fast/repaint/window-resize-centered-inline-under-fixed-pos.html [ NeedsManualRebaseline ] +crbug.com/619630 fast/repaint/window-resize-vertical-writing-mode.html [ NeedsManualRebaseline ] +crbug.com/619630 fast/table/border-collapsing/cached-change-cell-sl-border-color.html [ NeedsRebaseline ] +crbug.com/619630 fast/table/resize-table-repaint-percent-size-cell.html [ NeedsRebaseline ] +crbug.com/619630 fast/table/resize-table-repaint-vertical-align-cell.html [ NeedsRebaseline ] +crbug.com/619630 fast/table/resize-table-row-repaint.html [ NeedsRebaseline ] +crbug.com/619630 svg/as-image/svg-image-change-content-size.xhtml [ NeedsRebaseline ] +crbug.com/619630 svg/as-object/embedded-svg-size-changes-no-layout-triggers.html [ NeedsRebaseline ] +crbug.com/619630 svg/as-object/nested-embedded-svg-size-changes-no-layout-triggers-1.html [ NeedsRebaseline ] +crbug.com/619630 svg/as-object/nested-embedded-svg-size-changes-no-layout-triggers-2.html [ NeedsRebaseline ] +crbug.com/619630 svg/carto.net/tabgroup.svg [ NeedsRebaseline ] +crbug.com/619630 svg/custom/absolute-sized-content-with-resources.xhtml [ NeedsRebaseline ] +crbug.com/619630 svg/custom/js-late-gradient-creation.svg [ NeedsRebaseline ] +crbug.com/619630 svg/custom/js-late-pattern-creation.svg [ NeedsRebaseline ] +crbug.com/619630 svg/custom/object-sizing-no-width-height-change-content-box-size.xhtml [ NeedsRebaseline ] +crbug.com/619630 svg/custom/relative-sized-content-with-resources.xhtml [ NeedsRebaseline ] +crbug.com/619630 svg/custom/relative-sized-inner-svg.xhtml [ NeedsRebaseline ] +crbug.com/619630 svg/custom/relative-sized-shadow-tree-content-with-symbol.xhtml [ NeedsRebaseline ] +crbug.com/619630 svg/custom/relative-sized-use-on-symbol.xhtml [ NeedsRebaseline ] +crbug.com/619630 svg/custom/relative-sized-use-without-attributes-on-symbol.xhtml [ NeedsRebaseline ] +crbug.com/619630 svg/custom/scrolling-embedded-svg-file-image-repaint-problem.html [ NeedsRebaseline ] +crbug.com/619630 svg/custom/text-dom-removal.svg [ NeedsRebaseline ] +crbug.com/619630 svg/custom/text-repaint-including-stroke.svg [ NeedsRebaseline ] +crbug.com/619630 svg/custom/text-xy-updates-SVGList.xhtml [ NeedsRebaseline ] +crbug.com/619630 svg/custom/use-clipped-hit.svg [ NeedsRebaseline ] +crbug.com/619630 svg/custom/use-detach.svg [ NeedsRebaseline ] +crbug.com/619630 svg/custom/use-setAttribute-crash.svg [ NeedsRebaseline ] +crbug.com/619630 svg/repaint/add-outline-property-on-root.html [ NeedsRebaseline ] +crbug.com/619630 svg/repaint/inner-svg-change-viewPort-relative.svg [ NeedsRebaseline ] +crbug.com/619630 svg/repaint/modify-transferred-listitem-different-attr.html [ NeedsRebaseline ] +crbug.com/619630 svg/repaint/outline-offset-text.html [ NeedsRebaseline ] +crbug.com/619630 svg/repaint/remove-outline-property-on-root.html [ NeedsRebaseline ] +crbug.com/619630 svg/repaint/repaint-non-scaling-stroke-text-decoration.html [ NeedsRebaseline ] +crbug.com/619630 svg/repaint/repaint-non-scaling-stroke-text.html [ NeedsRebaseline ] +crbug.com/619630 svg/repaint/text-mask-update.svg [ NeedsRebaseline ] +crbug.com/619630 svg/repaint/transform-text-element.html [ NeedsRebaseline ] +crbug.com/619630 svg/text/append-text-node-to-tspan.html [ NeedsRebaseline ] +crbug.com/619630 svg/text/modify-text-node-in-tspan.html [ NeedsRebaseline ] +crbug.com/619630 svg/text/remove-text-node-from-tspan.html [ NeedsRebaseline ] +crbug.com/619630 svg/text/remove-tspan-from-text.html [ NeedsRebaseline ] +crbug.com/619630 svg/text/text-rescale.html [ NeedsRebaseline ] +crbug.com/619630 svg/text/text-viewbox-rescale.html [ NeedsManualRebaseline ] +crbug.com/619630 svg/text/tspan-dynamic-positioning.svg [ NeedsRebaseline ] +crbug.com/619630 svg/transforms/animated-path-inside-transformed-html.xhtml [ NeedsManualRebaseline ] + crbug.com/453002 [ Win ] fast/text/international/text-combine-image-test.html [ Failure Pass ] crbug.com/453002 [ Win ] fast/text/international/vertical-text-glyph-test.html [ Failure Pass ] crbug.com/453002 [ Win ] fast/text/justify-ideograph-vertical.html [ Failure Pass ]
diff --git a/third_party/WebKit/Source/core/layout/line/InlineBox.cpp b/third_party/WebKit/Source/core/layout/line/InlineBox.cpp index f9e3fe6..87dc822 100644 --- a/third_party/WebKit/Source/core/layout/line/InlineBox.cpp +++ b/third_party/WebKit/Source/core/layout/line/InlineBox.cpp
@@ -63,10 +63,6 @@ void InlineBox::destroy() { - // We do not need to issue invalidations if the page is being destroyed - // since these objects will never be repainted. - if (!m_lineLayoutItem.documentBeingDestroyed()) - m_lineLayoutItem.invalidateDisplayItemClient(*this); delete this; }
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 6f72e36..020a698 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -80129,6 +80129,7 @@ <int value="546710806" label="disable-easy-signin"/> <int value="550378029" label="reset-app-list-install-state"/> <int value="567368307" label="enable-experimental-canvas-features"/> + <int value="581118445" label="enable-eol-notification"/> <int value="592050831" label="disable-slimming-paint"/> <int value="593707592" label="disable-network-portal-notification"/> <int value="598827460" label="enable-roboto-font-ui"/>
diff --git a/ui/file_manager/file_manager/foreground/elements/files_metadata_box.html b/ui/file_manager/file_manager/foreground/elements/files_metadata_box.html index f93d7e5b..311eb7d 100644 --- a/ui/file_manager/file_manager/foreground/elements/files_metadata_box.html +++ b/ui/file_manager/file_manager/foreground/elements/files_metadata_box.html
@@ -11,17 +11,30 @@ display: block; } #box { - background: white; overflow: auto; + width: 200px; + } + .category { + color: gray; + font-weight: bold; + margin-bottom: 10px; + } + .type { + color: white; + } + .value { + --webkit-margin-start: 100px; + color: white; } </style> <template> <div id="box"> <!-- TODO(oka): update appearance to match mocks. --> - <div> - size: [[size]]<br> - modificationTime: [[modificationTime]] - </div> + <div class="category" i18n-content="METADATA_BOX_GENERAL_INFO"></div> + <div class="type" i18n-content="METADATA_BOX_FILE_SIZE"></div> + <div class="value">[[size]]</div> + <div class="type" i18n-content="METADATA_BOX_MODIFICATION_TIME"></div> + <div class="value">[[modificationTime]]</div> </div> </template> </dom-module>
diff --git a/ui/file_manager/file_manager/foreground/elements/files_metadata_box.js b/ui/file_manager/file_manager/foreground/elements/files_metadata_box.js index 73f131f..e74e7b5 100644 --- a/ui/file_manager/file_manager/foreground/elements/files_metadata_box.js +++ b/ui/file_manager/file_manager/foreground/elements/files_metadata_box.js
@@ -9,7 +9,7 @@ size: String, modiifcationTime: String, /* - * TODO(oka): Add the follwoing fields. + * TODO(oka): Add the following fields. * filePath: String, * imageWidth: Number, * imageHeight: Number,
diff --git a/ui/file_manager/file_manager/foreground/elements/files_quick_view.css b/ui/file_manager/file_manager/foreground/elements/files_quick_view.css new file mode 100644 index 0000000..fe2e81c --- /dev/null +++ b/ui/file_manager/file_manager/foreground/elements/files_quick_view.css
@@ -0,0 +1,90 @@ +/* Copyright 2016 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. */ + +:host { + display: block; +} + +paper-dialog { + background: black; + height: 70%; + width: 70%; +} + +.content { + bottom: 0; + left: 0; + margin: auto; + max-height: 100%; + max-width: 100%; + position: absolute; + right: 0; + top: 0; +} + +#audio-control { + bottom: 0; + left: 0; + margin: 0; + position: absolute; + width: 100%; +} + +#toolbar { + --paper-toolbar-background: rgba(127, 127, 127, 0.5); + --paper-toolbar-height: 32px; + color: white; + margin: 0; + z-index: 1; +} + +#buttons { + position: absolute; + right: 0px; +} + +paper-button { + padding: 4px; +} + +#metadata-box { + background: rgba(0, 0, 0, 0.5); + bottom: 0; + margin: 0; + position: absolute; + right: 0; + top: 32px; + z-index: 1; +} + +#metadata-box[hidden] { + display: none; +} + +/* Large generic thumbnails, used when a file does not have a thumbnail. */ +[generic-thumbnail] { + background-image: -webkit-image-set( + url(../images/files/ui/filetype_placeholder_generic.png) 1x, + url(../images/files/ui/2x/filetype_placeholder_generic.png) 2x); + background-position: center 50px; + background-repeat: no-repeat; +} + +[generic-thumbnail='audio'] { + background-image: -webkit-image-set( + url(../images/files/ui/filetype_placeholder_audio.png) 1x, + url(../images/files/ui/2x/filetype_placeholder_audio.png) 2x); +} + +[generic-thumbnail='image'] { + background-image: -webkit-image-set( + url(../images/files/ui/filetype_placeholder_image.png) 1x, + url(../images/files/ui/2x/filetype_placeholder_image.png) 2x); +} + +[generic-thumbnail='video'] { + background-image: -webkit-image-set( + url(../images/files/ui/filetype_placeholder_video.png) 1x, + url(../images/files/ui/2x/filetype_placeholder_video.png) 2x); +}
diff --git a/ui/file_manager/file_manager/foreground/elements/files_quick_view.html b/ui/file_manager/file_manager/foreground/elements/files_quick_view.html index 2e86630..dfaf825 100644 --- a/ui/file_manager/file_manager/foreground/elements/files_quick_view.html +++ b/ui/file_manager/file_manager/foreground/elements/files_quick_view.html
@@ -12,46 +12,9 @@ <link rel="import" href="icons.html"> <dom-module id="files-quick-view"> - <style> - :host { - display: block; - } - paper-dialog { - background: black; - height: 100%; - margin: 10px; - width: 100%; - } - img, video, audio { - bottom: 0; - left: 0; - margin: auto; - max-height: 100%; - max-width: 100%; - position: absolute; - right: 0; - top: 0; - } - #toolbar { - --paper-toolbar-background: rgba(0, 0, 0, 0.5); - color: white; - margin: 0; - z-index: 1; - } - #buttons { - position: absolute; - right: 0px; - } - #metadata-box { - position: absolute; - right: 0px; - } - #metadata-box[hidden] { - display: none; - } - </style> + <link rel="import" type="css" href="files_quick_view.css"> <template> - <paper-dialog id="dialog"> + <paper-dialog id="dialog" modal> <paper-toolbar id="toolbar"> <div>[[filePath]]</div> <div id="buttons"> @@ -66,21 +29,34 @@ </paper-button> </div> </paper-toolbar> - <template class="content" is="dom-if" if="[[image]]"> - <div> - <img src="[[image]]"/> - </div> - </template> - <template class="content" is="dom-if" if="[[video]]"> - <div> - <video controls autoplay src="[[video]]" poster="[[videoPoster]]"/> - </div> - </template> - <template class="content" is="dom-if" if="[[audio]]"> - <div> - <audio autoplay controls src="[[audio]]"/> - </div> - </template> + <!-- TOOD(oka): Show default icon if image, video or audio was broken --> + <div> + <template is="dom-if" if="[[image]]"> + <div generic-thumbnail="image"> + <img class="content" src="[[image]]"> + </div> + </template> + <template is="dom-if" if="[[video]]"> + <div generic-thumbnail="video"> + <!-- TODO(oka): Stop to autoplay if video is in Drive. --> + <video class="content" controls autoplay src="[[video]]" poster="[[videoPoster]]"></video> + </div> + </template> + <template is="dom-if" if="[[audio]]"> + <template is="dom-if" if="[[contentThumbnailUrl]]"> + <img class="content" src="[[contentThumbnailUrl]]"> + </template> + <template is="dom-if" if="[[!contentThumbnailUrl]]"> + <div class="content" generic-thumbnail="audio"></div> + </template> + <!-- TODO(oka): Stop to autoplay if video is in Drive. --> + <audio id="audio-control" autoplay controls src="[[audio]]"></audio> + </template> + <!-- TODO(oka): Support folder icon --> + <template is="dom-if" if="[[unsupported]]"> + <div class="content" generic-thumbnail><div> + </template> + </div> <files-metadata-box id="metadata-box" hidden="{{!metadataBoxActive}}"></file-metadata-box> </paper-dialog> </template>
diff --git a/ui/file_manager/file_manager/foreground/elements/files_quick_view.js b/ui/file_manager/file_manager/foreground/elements/files_quick_view.js index 675c86d7..30c11e3 100644 --- a/ui/file_manager/file_manager/foreground/elements/files_quick_view.js +++ b/ui/file_manager/file_manager/foreground/elements/files_quick_view.js
@@ -11,6 +11,8 @@ video: String, videoPoster: String, audio: String, + contentThumbnailUrl: String, + unsupported: Boolean, // metadata-box-active-changed event is fired on attribute change. metadataBoxActive: { @@ -21,28 +23,16 @@ }, listeners: { - 'iron-overlay-closed': 'clear_', + 'iron-overlay-closed': 'clear', }, - setImageURL: function(url) { - this.clear_(); - this.image = url; - }, - - setVideoURL: function(url) { - this.clear_(); - this.video = url; - }, - - setAudioURL: function(url) { - this.clear_(); - this.audio = url; - }, - - clear_: function() { + clear: function() { + this.filePath = ''; this.image = ''; this.video = ''; this.audio = ''; + this.contentThumbnailUrl = ''; + this.unsupported = false; }, // Open the dialog.
diff --git a/ui/file_manager/file_manager/foreground/js/quick_view_controller.js b/ui/file_manager/file_manager/foreground/js/quick_view_controller.js index f2031bc..5c2fbb45 100644 --- a/ui/file_manager/file_manager/foreground/js/quick_view_controller.js +++ b/ui/file_manager/file_manager/foreground/js/quick_view_controller.js
@@ -168,8 +168,7 @@ var entry = (/** @type {!FileEntry} */ (this.quickViewModel_.getSelectedEntry())); assert(entry); - this.quickView_.filePath = entry.name; - return this.metadataModel_.get([entry], ['contentThumbnailUrl']) + return this.metadataModel_.get([entry], ['thumbnailUrl', 'externalFileUrl']) .then(this.onMetadataLoaded_.bind(this, entry)); }; @@ -181,15 +180,17 @@ * @private */ QuickViewController.prototype.onMetadataLoaded_ = function(entry, items) { + this.quickView_.clear(); + this.quickView_.filePath = entry.name; var item = items[0]; var type = FileType.getType(entry); - var thumbnailUrl = item.thumbnailUrl || item.croppedThumbnailUrl; + var thumbnailUrl = item.thumbnailUrl; if (type.type === 'image') { if (item.externalFileUrl) { // TODO(oka): Support Drive. } else { var url = thumbnailUrl || entry.toURL(); - this.quickView_.setImageURL(url); + this.quickView_.image = url; } } else if (type.type === 'video') { // TODO(oka): Set thumbnail. @@ -197,17 +198,23 @@ // TODO(oka): Support Drive. } else { var url = entry.toURL(); - this.quickView_.setVideoURL(url); + this.quickView_.video = url; } - this.quickView_.setVideoURL(entry.toURL()); } else if (type.type === 'audio') { - this.quickView_.setAudioURL(entry.toURL()); - // TODO(oka): Set thumbnail. if (item.externalFileUrl) { // TODO(oka): Support Drive. } else { - this.quickView_.setAudioURL(url); + var url = entry.toURL(); + this.quickView_.audio = url; + this.metadataModel_.get([entry], ['contentThumbnailUrl']) + .then(function(entry, items) { + var item = items[0]; + if (item.contentThumbnailUrl) + this.quickView_.contentThumbnailUrl = + item.contentThumbnailUrl; + }.bind(this, entry)); } - this.quickView_.setAudioURL(entry.toURL()); + } else { + this.quickView_.unsupported = true; } };
diff --git a/ui/file_manager/file_manager_resources.grd b/ui/file_manager/file_manager_resources.grd index 455352c1..753e2349 100644 --- a/ui/file_manager/file_manager_resources.grd +++ b/ui/file_manager/file_manager_resources.grd
@@ -56,6 +56,7 @@ <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_ICON_BUTTON_JS" file="file_manager/foreground/elements/files_icon_button.js" type="BINDATA" /> <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_METADATA_BOX_HTML" file="file_manager/foreground/elements/files_metadata_box.html" type="BINDATA" /> <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_METADATA_BOX_JS" file="file_manager/foreground/elements/files_metadata_box.js" type="BINDATA" /> + <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_QUICK_PREVIEW_CSS" file="file_manager/foreground/elements/files_quick_view.css" flattenhtml="true" type="BINDATA" /> <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_QUICK_PREVIEW_HTML" file="file_manager/foreground/elements/files_quick_view.html" type="BINDATA" /> <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_QUICK_PREVIEW_JS" file="file_manager/foreground/elements/files_quick_view.js" type="BINDATA" /> <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_RIPPLE_HTML" file="file_manager/foreground/elements/files_ripple.html" type="BINDATA" />