diff --git a/DEPS b/DEPS index 25fa1d1..698e765 100644 --- a/DEPS +++ b/DEPS
@@ -40,7 +40,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '8c8cb5bfc547229422a33db5c344fe1542bf00a7', + 'skia_revision': 'f55ea6a1deb21120944d406124a2984b5009260a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -52,7 +52,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': 'a818c327fe6bb770c3a3621a985c4afd698ad0ab', + 'angle_revision': 'a66779fcf2aeed8588bcc1ba6a3668d81e65bf3b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling build tools # and whatever else without interference from each other. @@ -64,7 +64,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '8d94b6687f27e1238f352939434704f75b330c1d', + 'pdfium_revision': '591ed144f8dfe4b2915f01f1cc725f584d498a3f', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -96,7 +96,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': 'fa1926f937dcec01fa9ec6658da1a7c1b8321ec3', + 'catapult_revision': 'f84aaa04d4d0bb5e902eaa8e224f2323a018e64c', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -356,19 +356,19 @@ Var('chromium_git') + '/external/github.com/swisspol/GCDWebServer.git' + '@' + '3d5fd0b8281a7224c057deb2d17709b5bea64836', 'src/ios/third_party/material_components_ios/src': - Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '079c1c9a8b040f924de2919393b65c38239890f0', + Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'b1eb638d70792b7aa06118b128e3518c20e2aaae', 'src/ios/third_party/material_font_disk_loader_ios/src': - Var('chromium_git') + '/external/github.com/material-foundation/material-font-disk-loader-ios.git' + '@' + '20c8fe37329cb18826f90159ce4ee445079e2e46', + Var('chromium_git') + '/external/github.com/material-foundation/material-font-disk-loader-ios.git' + '@' + '93acc021e3034898716028822cb802a3a816be7e', 'src/ios/third_party/material_roboto_font_loader_ios/src': Var('chromium_git') + '/external/github.com/material-foundation/material-roboto-font-loader-ios.git' + '@' + 'e9b86479540ee3a200ade154f907fac889865c72', 'src/ios/third_party/material_sprited_animation_view_ios/src': - Var('chromium_git') + '/external/github.com/material-foundation/material-sprited-animation-view-ios.git' + '@' + 'e240cdcd4538f0763ca5bd8c5afc2991eb482f1a', + Var('chromium_git') + '/external/github.com/material-foundation/material-sprited-animation-view-ios.git' + '@' + 'c6e16d06bdafd95540c62b3402d9414692fbca81', 'src/ios/third_party/material_text_accessibility_ios/src': - Var('chromium_git') + '/external/github.com/material-foundation/material-text-accessibility-ios.git' + '@' + '96d2b0f13976a897bc7a41daf67f36d9548cff94', + Var('chromium_git') + '/external/github.com/material-foundation/material-text-accessibility-ios.git' + '@' + '318d5100f2976e59c94643e5dcab69e7a830ee43', 'src/ios/third_party/ochamcrest/src': Var('chromium_git') + '/external/github.com/hamcrest/OCHamcrest.git' + '@' + 'd7ee4ecfb6bd13c3c8d364682b6228ccd86e1e1a',
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc index 7a9c62a1..9d51c8f 100644 --- a/android_webview/browser/aw_content_browser_client.cc +++ b/android_webview/browser/aw_content_browser_client.cc
@@ -474,18 +474,16 @@ void AwContentBrowserClient::GetAdditionalMappedFilesForChildProcess( const base::CommandLine& command_line, int child_process_id, - content::FileDescriptorInfo* mappings, - std::map<int, base::MemoryMappedFile::Region>* regions) { - int fd = ui::GetMainAndroidPackFd( - &(*regions)[kAndroidWebViewMainPakDescriptor]); - mappings->Share(kAndroidWebViewMainPakDescriptor, fd); + content::FileDescriptorInfo* mappings) { + base::MemoryMappedFile::Region region; + int fd = ui::GetMainAndroidPackFd(®ion); + mappings->ShareWithRegion(kAndroidWebViewMainPakDescriptor, fd, region); - fd = ui::GetCommonResourcesPackFd( - &(*regions)[kAndroidWebView100PercentPakDescriptor]); - mappings->Share(kAndroidWebView100PercentPakDescriptor, fd); + fd = ui::GetCommonResourcesPackFd(®ion); + mappings->ShareWithRegion(kAndroidWebView100PercentPakDescriptor, fd, region); - fd = ui::GetLocalePackFd(&(*regions)[kAndroidWebViewLocalePakDescriptor]); - mappings->Share(kAndroidWebViewLocalePakDescriptor, fd); + fd = ui::GetLocalePackFd(®ion); + mappings->ShareWithRegion(kAndroidWebViewLocalePakDescriptor, fd, region); base::ScopedFD crash_signal_file = breakpad::CrashMicroDumpManager::GetInstance()->CreateCrashInfoChannel(
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h index e06c99b..1c4e28a 100644 --- a/android_webview/browser/aw_content_browser_client.h +++ b/android_webview/browser/aw_content_browser_client.h
@@ -120,8 +120,7 @@ void GetAdditionalMappedFilesForChildProcess( const base::CommandLine& command_line, int child_process_id, - content::FileDescriptorInfo* mappings, - std::map<int, base::MemoryMappedFile::Region>* regions) override; + content::FileDescriptorInfo* mappings) override; void OverrideWebkitPrefs(content::RenderViewHost* rvh, content::WebPreferences* web_prefs) override; ScopedVector<content::NavigationThrottle> CreateThrottlesForNavigation(
diff --git a/ash/common/ash_constants.cc b/ash/common/ash_constants.cc index 4d483be7..e8b1434 100644 --- a/ash/common/ash_constants.cc +++ b/ash/common/ash_constants.cc
@@ -14,9 +14,7 @@ const int kResizeOutsideBoundsScaleForTouch = 5; const int kResizeInsideBoundsSize = 1; -#if defined(OS_CHROMEOS) const SkColor kChromeOsBootColor = SkColorSetRGB(0xfe, 0xfe, 0xfe); -#endif const SkColor kFocusBorderColor = SkColorSetA(gfx::kGoogleBlue500, 0x99); const float kFocusBorderThickness = 2.f;
diff --git a/ash/common/ash_constants.h b/ash/common/ash_constants.h index 1a42e28..9ff5092 100644 --- a/ash/common/ash_constants.h +++ b/ash/common/ash_constants.h
@@ -23,10 +23,8 @@ ASH_EXPORT extern const int kResizeOutsideBoundsScaleForTouch; ASH_EXPORT extern const int kResizeInsideBoundsSize; -#if defined(OS_CHROMEOS) // Background color used for the Chrome OS boot splash screen. extern const SkColor kChromeOsBootColor; -#endif // The border color of keyboard focus for launcher items and system tray. extern const SkColor kFocusBorderColor;
diff --git a/ash/common/ash_switches.cc b/ash/common/ash_switches.cc index d3d9571..e9eb255 100644 --- a/ash/common/ash_switches.cc +++ b/ash/common/ash_switches.cc
@@ -34,11 +34,9 @@ const char kAshDisableMaximizeModeWindowBackdrop[] = "ash-disable-maximize-mode-window-backdrop"; -#if defined(OS_CHROMEOS) // Disable the support for WebContents to lock the screen orientation. const char kAshDisableScreenOrientationLock[] = "ash-disable-screen-orientation-lock"; -#endif // Disable the Touch Exploration Mode. Touch Exploration Mode will no longer be // turned on automatically when spoken feedback is enabled when this flag is @@ -46,7 +44,6 @@ const char kAshDisableTouchExplorationMode[] = "ash-disable-touch-exploration-mode"; -#if defined(OS_CHROMEOS) // Enables fullscreen app list if Ash is in maximize mode. const char kAshEnableFullscreenAppList[] = "ash-enable-fullscreen-app-list"; @@ -60,7 +57,6 @@ // Enables the palette on every display, instead of only the internal one. const char kAshEnablePaletteOnAllDisplays[] = "ash-enable-palette-on-all-displays"; -#endif // Enables the observation of accelerometer events to enter touch-view mode. const char kAshEnableTouchView[] = "enable-touchview"; @@ -94,7 +90,6 @@ // instead of displaying an interactive animation. const char kAuraLegacyPowerButton[] = "aura-legacy-power-button"; -#if defined(OS_CHROMEOS) // Constrains the pointer movement within a root window on desktop. bool ConstrainPointerToRoot() { const char kAshConstrainPointerToRoot[] = "ash-constrain-pointer-to-root"; @@ -104,7 +99,5 @@ kAshConstrainPointerToRoot); } -#endif - } // namespace switches } // namespace ash
diff --git a/ash/common/ash_switches.h b/ash/common/ash_switches.h index 8a145f6..08548f6 100644 --- a/ash/common/ash_switches.h +++ b/ash/common/ash_switches.h
@@ -7,8 +7,6 @@ #include "ash/ash_export.h" -#include "build/build_config.h" - namespace ash { namespace switches { @@ -23,16 +21,12 @@ ASH_EXPORT extern const char kAshDebugShortcuts[]; ASH_EXPORT extern const char kAshDeveloperShortcuts[]; ASH_EXPORT extern const char kAshDisableMaximizeModeWindowBackdrop[]; -#if defined(OS_CHROMEOS) ASH_EXPORT extern const char kAshDisableScreenOrientationLock[]; -#endif ASH_EXPORT extern const char kAshDisableTouchExplorationMode[]; -#if defined(OS_CHROMEOS) ASH_EXPORT extern const char kAshEnableFullscreenAppList[]; ASH_EXPORT extern const char kAshEnableMagnifierKeyScroller[]; ASH_EXPORT extern const char kAshEnablePalette[]; ASH_EXPORT extern const char kAshEnablePaletteOnAllDisplays[]; -#endif ASH_EXPORT extern const char kAshEnableTouchView[]; ASH_EXPORT extern const char kAshEnableMirroredScreen[]; ASH_EXPORT extern const char kAshDisableStableOverviewOrder[]; @@ -45,10 +39,8 @@ ASH_EXPORT extern const char kAshTouchHud[]; ASH_EXPORT extern const char kAuraLegacyPowerButton[]; -#if defined(OS_CHROMEOS) // True if the pointer (cursor) position should be kept inside root windows. ASH_EXPORT bool ConstrainPointerToRoot(); -#endif } // namespace switches } // namespace ash
diff --git a/ash/common/devtools/ash_devtools_unittest.cc b/ash/common/devtools/ash_devtools_unittest.cc index 4328f9b..9226051 100644 --- a/ash/common/devtools/ash_devtools_unittest.cc +++ b/ash/common/devtools/ash_devtools_unittest.cc
@@ -400,14 +400,7 @@ ExpectChildNodeInserted(target_node->getNodeId(), sibling_node->getNodeId()); } -#if defined(OS_WIN) -#define MAYBE_WindowReorganizedChildNodeRemovedAndInserted \ - DISABLED_WindowReorganizedChildNodeRemovedAndInserted -#else -#define MAYBE_WindowReorganizedChildNodeRemovedAndInserted \ - WindowReorganizedChildNodeRemovedAndInserted -#endif // defined(OS_WIN) -TEST_F(AshDevToolsTest, MAYBE_WindowReorganizedChildNodeRemovedAndInserted) { +TEST_F(AshDevToolsTest, WindowReorganizedChildNodeRemovedAndInserted) { WmWindow* root_window = WmShell::Get()->GetPrimaryRootWindow(); WmWindow* target_window = root_window->GetChildren()[1]; WmWindow* parent_window = root_window->GetChildren()[0];
diff --git a/ash/common/mojo_interface_factory.cc b/ash/common/mojo_interface_factory.cc index 038a2dc..501c006 100644 --- a/ash/common/mojo_interface_factory.cc +++ b/ash/common/mojo_interface_factory.cc
@@ -14,6 +14,7 @@ #include "ash/common/shelf/shelf_controller.h" #include "ash/common/shell_delegate.h" #include "ash/common/shutdown_controller.h" +#include "ash/common/system/chromeos/network/vpn_list.h" #include "ash/common/system/locale/locale_notification_controller.h" #include "ash/common/system/tray/system_tray_controller.h" #include "ash/common/wallpaper/wallpaper_controller.h" @@ -23,10 +24,6 @@ #include "services/service_manager/public/cpp/interface_registry.h" #include "ui/app_list/presenter/app_list.h" -#if defined(OS_CHROMEOS) -#include "ash/common/system/chromeos/network/vpn_list.h" -#endif - namespace ash { namespace { @@ -82,11 +79,9 @@ WmShell::Get()->maximize_mode_controller()->BindRequest(std::move(request)); } -#if defined(OS_CHROMEOS) void BindVpnListRequestOnMainThread(mojom::VpnListRequest request) { WmShell::Get()->vpn_list()->BindRequest(std::move(request)); } -#endif void BindWallpaperRequestOnMainThread( mojom::WallpaperControllerRequest request) { @@ -125,10 +120,8 @@ main_thread_task_runner); registry->AddInterface(base::Bind(&BindTouchViewRequestOnMainThread), main_thread_task_runner); -#if defined(OS_CHROMEOS) registry->AddInterface(base::Bind(&BindVpnListRequestOnMainThread), main_thread_task_runner); -#endif registry->AddInterface(base::Bind(&BindWallpaperRequestOnMainThread), main_thread_task_runner); }
diff --git a/ash/common/shelf/app_list_button.cc b/ash/common/shelf/app_list_button.cc index 8847fb81..6ab78cb2 100644 --- a/ash/common/shelf/app_list_button.cc +++ b/ash/common/shelf/app_list_button.cc
@@ -288,16 +288,23 @@ } gfx::Point AppListButton::GetCenterPoint() const { - // During shelf hide/show animations, width and height may not be equal. Take - // the greater of the two as the one that represents the normal size of the - // button. - int center = std::max(width(), height()) / 2.f; - gfx::Point centroid(center, center); - // For the left shelf alignment, we need to right-justify. For other shelf - // alignments, left/top justification (i.e. no adjustments are necessary). - if (SHELF_ALIGNMENT_LEFT == wm_shelf_->GetAlignment()) - centroid.set_x(width() - center); - return centroid; + // For a bottom-aligned shelf, the button bounds could have a larger height + // than width (in the case of touch-dragging the shelf updwards) or a larger + // width than height (in the case of a shelf hide/show animation), so adjust + // the y-position of the circle's center to ensure correct layout. Similarly + // adjust the x-position for a left- or right-aligned shelf. + const int x_mid = width() / 2.f; + const int y_mid = height() / 2.f; + ShelfAlignment alignment = wm_shelf_->GetAlignment(); + if (alignment == SHELF_ALIGNMENT_BOTTOM || + alignment == SHELF_ALIGNMENT_BOTTOM_LOCKED) { + return gfx::Point(x_mid, x_mid); + } else if (alignment == SHELF_ALIGNMENT_RIGHT) { + return gfx::Point(y_mid, y_mid); + } else { + DCHECK_EQ(alignment, SHELF_ALIGNMENT_LEFT); + return gfx::Point(width() - y_mid, y_mid); + } } } // namespace ash
diff --git a/ash/common/shelf/overflow_button.cc b/ash/common/shelf/overflow_button.cc index 7d63c2e2..2bf558a 100644 --- a/ash/common/shelf/overflow_button.cc +++ b/ash/common/shelf/overflow_button.cc
@@ -172,18 +172,17 @@ gfx::Rect OverflowButton::CalculateButtonBounds() const { ShelfAlignment alignment = wm_shelf_->GetAlignment(); gfx::Rect bounds(GetContentsBounds()); - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); if (MaterialDesignController::IsShelfMaterial()) { - const int width_offset = (bounds.width() - kOverflowButtonSize) / 2; - const int height_offset = (bounds.height() - kOverflowButtonSize) / 2; - if (IsHorizontalAlignment(alignment)) { - bounds = gfx::Rect(bounds.x() + width_offset, bounds.y() + height_offset, - kOverflowButtonSize, kOverflowButtonSize); - } else { - bounds = gfx::Rect(bounds.x() + height_offset, bounds.y() + width_offset, - kOverflowButtonSize, kOverflowButtonSize); - } + // Align the button to the top of a bottom-aligned shelf, to the right edge + // a left-aligned shelf, and to the left edge of a right-aligned shelf. + const int inset = (GetShelfConstant(SHELF_SIZE) - kOverflowButtonSize) / 2; + const int x = alignment == SHELF_ALIGNMENT_LEFT + ? bounds.right() - inset - kOverflowButtonSize + : bounds.x() + inset; + bounds = gfx::Rect(x, bounds.y() + inset, kOverflowButtonSize, + kOverflowButtonSize); } else { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); const gfx::ImageSkia* background = rb.GetImageNamed(NonMaterialBackgroundImageId()).ToImageSkia(); if (alignment == SHELF_ALIGNMENT_LEFT) {
diff --git a/ash/common/shutdown_controller.cc b/ash/common/shutdown_controller.cc index 7342eb2..b40fe86 100644 --- a/ash/common/shutdown_controller.cc +++ b/ash/common/shutdown_controller.cc
@@ -6,12 +6,9 @@ #include "ash/common/shell_delegate.h" #include "ash/common/wm_shell.h" - -#if defined(OS_CHROMEOS) #include "base/sys_info.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/power_manager_client.h" -#endif namespace ash { @@ -20,20 +17,18 @@ ShutdownController::~ShutdownController() {} void ShutdownController::ShutDownOrReboot() { -#if defined(OS_CHROMEOS) - if (base::SysInfo::IsRunningOnChromeOS()) { - // Power manager handles shutdown on Chrome OS hardware. - using chromeos::DBusThreadManager; - if (reboot_on_shutdown_) - DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart(); - else - DBusThreadManager::Get()->GetPowerManagerClient()->RequestShutdown(); + // For developers on Linux desktop just exit the app. + if (!base::SysInfo::IsRunningOnChromeOS()) { + WmShell::Get()->delegate()->Exit(); return; } -#endif // defined(OS_CHROMEOS) - // On Windows and on Linux desktop just exit. - WmShell::Get()->delegate()->Exit(); + // On real Chrome OS hardware the power manager handles shutdown. + using chromeos::DBusThreadManager; + if (reboot_on_shutdown_) + DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart(); + else + DBusThreadManager::Get()->GetPowerManagerClient()->RequestShutdown(); } void ShutdownController::SetRebootOnShutdown(bool reboot_on_shutdown) {
diff --git a/ash/common/system/chromeos/palette/common_palette_tool.cc b/ash/common/system/chromeos/palette/common_palette_tool.cc index b9f39df0..fa8624c 100644 --- a/ash/common/system/chromeos/palette/common_palette_tool.cc +++ b/ash/common/system/chromeos/palette/common_palette_tool.cc
@@ -89,8 +89,7 @@ kMenuIconSize, gfx::kGoogleGreen700); highlight_view_ = new HoverHighlightView(this); - highlight_view_->SetBorder( - views::CreateEmptyBorder(0, kMenuExtraMarginFromLeftEdge, 0, 0)); + highlight_view_->SetBorder(views::CreateEmptyBorder(0, 0, 0, 0)); const int interior_button_padding = (kMenuButtonSize - kMenuIconSize) / 2; highlight_view_->AddIconAndLabelCustomSize(icon, name, false, kMenuIconSize, interior_button_padding,
diff --git a/ash/common/system/chromeos/palette/palette_tray.cc b/ash/common/system/chromeos/palette/palette_tray.cc index 179be69..0ffec05 100644 --- a/ash/common/system/chromeos/palette/palette_tray.cc +++ b/ash/common/system/chromeos/palette/palette_tray.cc
@@ -45,31 +45,21 @@ // Predefined padding for the icon used in this tray. These are to be set to the // border of the icon, depending on the current |shelf_alignment()|. -const int kHorizontalShelfHorizontalPadding = 8; -const int kHorizontalShelfVerticalPadding = 4; -const int kVerticalShelfHorizontalPadding = 2; -const int kVerticalShelfVerticalPadding = 5; +constexpr int kHorizontalShelfHorizontalPadding = 8; +constexpr int kHorizontalShelfVerticalPadding = 4; +constexpr int kVerticalShelfHorizontalPadding = 2; +constexpr int kVerticalShelfVerticalPadding = 5; // Width of the palette itself (dp). -const int kPaletteWidth = 332; +constexpr int kPaletteWidth = 332; // Padding at the top/bottom of the palette (dp). -const int kPalettePaddingOnTop = 4; -const int kPalettePaddingOnBottom = 4; - -// Size of icon in the shelf (dp). -const int kShelfIconSize = 18; - -// Vertical margin around the title view elements so that the title view height -// matches kMenuButtonSize. -const int kVerticalMarginAroundTitleView = 1; +constexpr int kPalettePaddingOnTop = 4; +constexpr int kPalettePaddingOnBottom = 2; // Margins between the title view and the edges around it (dp). -const int kPaddingBetweenTitleAndLeftEdge = 12; -const int kPaddingBetweenTitleAndSeparator = 3; - -// The distance between the title, help, and settings button in the title (dp). -const int kHorizontalPaddingBetweenTitleEntries = 2; +constexpr int kPaddingBetweenTitleAndLeftEdge = 12; +constexpr int kPaddingBetweenTitleAndSeparator = 3; // Color of the separator. const SkColor kPaletteSeparatorColor = SkColorSetARGB(0x1E, 0x00, 0x00, 0x00); @@ -90,9 +80,8 @@ explicit TitleView(PaletteTray* palette_tray) : palette_tray_(palette_tray) { // TODO(tdanderson|jdufault): Use TriView to handle the layout of the title. // See crbug.com/614453. - auto* box_layout = new views::BoxLayout( - views::BoxLayout::kHorizontal, 0, kVerticalMarginAroundTitleView, - kHorizontalPaddingBetweenTitleEntries); + auto* box_layout = + new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); SetLayoutManager(box_layout); title_label_ = @@ -431,7 +420,7 @@ icon_->SetImage(CreateVectorIcon( palette_tool_manager_->GetActiveTrayIcon( palette_tool_manager_->GetActiveTool(ash::PaletteGroup::MODE)), - kShelfIconSize, kShelfIconColor)); + kTrayIconSize, kShelfIconColor)); } void PaletteTray::OnStylusStateChanged(ui::StylusState stylus_state) {
diff --git a/ash/common/wallpaper/wallpaper_controller_unittest.cc b/ash/common/wallpaper/wallpaper_controller_unittest.cc index d24845d..72e5895 100644 --- a/ash/common/wallpaper/wallpaper_controller_unittest.cc +++ b/ash/common/wallpaper/wallpaper_controller_unittest.cc
@@ -372,13 +372,7 @@ EXPECT_TRUE(resized_image.BackedBySameObjectAs(controller_->GetWallpaper())); } -#if defined(OS_WIN) && !defined(USE_ASH) -// TODO(msw): Broken on Windows. http://crbug.com/584038 -#define MAYBE_GetMaxDisplaySize DISABLED_GetMaxDisplaySize -#else -#define MAYBE_GetMaxDisplaySize GetMaxDisplaySize -#endif -TEST_F(WallpaperControllerTest, MAYBE_GetMaxDisplaySize) { +TEST_F(WallpaperControllerTest, GetMaxDisplaySize) { // Device scale factor shouldn't affect the native size. UpdateDisplay("1000x300*2"); EXPECT_EQ("1000x300",
diff --git a/ash/common/wm/maximize_mode/maximize_mode_controller.cc b/ash/common/wm/maximize_mode/maximize_mode_controller.cc index 6901481..ef07902 100644 --- a/ash/common/wm/maximize_mode/maximize_mode_controller.cc +++ b/ash/common/wm/maximize_mode/maximize_mode_controller.cc
@@ -14,22 +14,18 @@ #include "base/metrics/histogram.h" #include "base/time/default_tick_clock.h" #include "base/time/tick_clock.h" +#include "chromeos/dbus/dbus_thread_manager.h" #include "ui/base/accelerators/accelerator.h" +#include "ui/chromeos/accelerometer/accelerometer_util.h" #include "ui/display/display.h" #include "ui/events/event.h" #include "ui/events/keycodes/keyboard_codes.h" #include "ui/gfx/geometry/vector3d_f.h" -#if defined(OS_CHROMEOS) -#include "chromeos/dbus/dbus_thread_manager.h" -#include "ui/chromeos/accelerometer/accelerometer_util.h" -#endif // OS_CHROMEOS - namespace ash { namespace { -#if defined(OS_CHROMEOS) // The hinge angle at which to enter maximize mode. const float kEnterMaximizeModeAngle = 200.0f; @@ -43,7 +39,6 @@ // vice versa). const float kMinStableAngle = 20.0f; const float kMaxStableAngle = 340.0f; -#endif // OS_CHROMEOS // The time duration to consider the lid to be recently opened. // This is used to prevent entering maximize mode if an erroneous accelerometer @@ -51,7 +46,6 @@ // lid from a closed position. const int kLidRecentlyOpenedDurationSeconds = 2; -#if defined(OS_CHROMEOS) // When the device approaches vertical orientation (i.e. portrait orientation) // the accelerometers for the base and lid approach the same values (i.e. // gravity pointing in the direction of the hinge). When this happens abrupt @@ -83,7 +77,6 @@ update.get(chromeos::ACCELEROMETER_SOURCE_SCREEN)) .Length()) <= kNoisyMagnitudeDeviation; } -#endif // OS_CHROMEOS bool IsEnabled() { return base::CommandLine::ForCurrentProcess()->HasSwitch( @@ -96,9 +89,7 @@ : have_seen_accelerometer_data_(false), touchview_usage_interval_start_time_(base::Time::Now()), tick_clock_(new base::DefaultTickClock()), -#if defined(OS_CHROMEOS) tablet_mode_switch_is_on_(false), -#endif lid_is_closed_(false) { WmShell::Get()->AddShellObserver(this); WmShell::Get()->RecordUserMetricsAction(UMA_MAXIMIZE_MODE_INITIALLY_DISABLED); @@ -111,12 +102,10 @@ if (is_enabled) WmShell::Get()->AddDisplayObserver(this); -#if defined(OS_CHROMEOS) if (is_enabled) chromeos::AccelerometerReader::GetInstance()->AddObserver(this); chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver( this); -#endif // OS_CHROMEOS } MaximizeModeController::~MaximizeModeController() { @@ -125,12 +114,10 @@ if (is_enabled) WmShell::Get()->RemoveDisplayObserver(this); -#if defined(OS_CHROMEOS) if (is_enabled) chromeos::AccelerometerReader::GetInstance()->RemoveObserver(this); chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver( this); -#endif // OS_CHROMEOS } bool MaximizeModeController::CanEnterMaximizeMode() { @@ -193,7 +180,6 @@ bindings_.AddBinding(this, std::move(request)); } -#if defined(OS_CHROMEOS) void MaximizeModeController::OnAccelerometerUpdated( scoped_refptr<const chromeos::AccelerometerUpdate> update) { bool first_accelerometer_update = !have_seen_accelerometer_data_; @@ -323,7 +309,6 @@ EnterMaximizeMode(); } } -#endif // OS_CHROMEOS void MaximizeModeController::EnterMaximizeMode() { // Always reset first to avoid creation before destruction of a previous
diff --git a/ash/common/wm/maximize_mode/maximize_mode_controller.h b/ash/common/wm/maximize_mode/maximize_mode_controller.h index 37fd472..32650fe 100644 --- a/ash/common/wm/maximize_mode/maximize_mode_controller.h +++ b/ash/common/wm/maximize_mode/maximize_mode_controller.h
@@ -14,15 +14,12 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "base/time/time.h" -#include "mojo/public/cpp/bindings/binding_set.h" -#include "mojo/public/cpp/bindings/interface_ptr_set.h" -#include "ui/gfx/geometry/vector3d_f.h" - -#if defined(OS_CHROMEOS) #include "chromeos/accelerometer/accelerometer_reader.h" #include "chromeos/accelerometer/accelerometer_types.h" #include "chromeos/dbus/power_manager_client.h" -#endif // OS_CHROMEOS +#include "mojo/public/cpp/bindings/binding_set.h" +#include "mojo/public/cpp/bindings/interface_ptr_set.h" +#include "ui/gfx/geometry/vector3d_f.h" namespace base { class TickClock; @@ -48,10 +45,8 @@ // enters and exits maximize mode when the lid is opened beyond the triggering // angle and rotates the display to match the device when in maximize mode. class ASH_EXPORT MaximizeModeController : -#if defined(OS_CHROMEOS) public chromeos::AccelerometerReader::Observer, public chromeos::PowerManagerClient::Observer, -#endif // OS_CHROMEOS NON_EXPORTED_BASE(public mojom::TouchViewManager), public ShellObserver, public WmDisplayObserver { @@ -91,7 +86,6 @@ // WmDisplayObserver: void OnDisplayConfigurationChanged() override; -#if defined(OS_CHROMEOS) // chromeos::AccelerometerReader::Observer: void OnAccelerometerUpdated( scoped_refptr<const chromeos::AccelerometerUpdate> update) override; @@ -101,7 +95,6 @@ void TabletModeEventReceived(bool on, const base::TimeTicks& time) override; void SuspendImminent() override; void SuspendDone(const base::TimeDelta& sleep_duration) override; -#endif // OS_CHROMEOS private: friend class MaximizeModeControllerTest; @@ -120,12 +113,10 @@ // artificially and deterministically control the current time. void SetTickClockForTest(std::unique_ptr<base::TickClock> tick_clock); -#if defined(OS_CHROMEOS) // Detect hinge rotation from base and lid accelerometers and automatically // start / stop maximize mode. void HandleHingeRotation( scoped_refptr<const chromeos::AccelerometerUpdate> update); -#endif // Returns true if the lid was recently opened. bool WasLidOpenedRecently() const; @@ -175,10 +166,8 @@ // Source for the current time in base::TimeTicks. std::unique_ptr<base::TickClock> tick_clock_; -#if defined(OS_CHROMEOS) // Set when tablet mode switch is on. This is used to force maximize mode. bool tablet_mode_switch_is_on_; -#endif // Tracks when the lid is closed. Used to prevent entering maximize mode. bool lid_is_closed_;
diff --git a/ash/common/wm/workspace/workspace_layout_manager_unittest.cc b/ash/common/wm/workspace/workspace_layout_manager_unittest.cc index df850df..7cd55d8a 100644 --- a/ash/common/wm/workspace/workspace_layout_manager_unittest.cc +++ b/ash/common/wm/workspace/workspace_layout_manager_unittest.cc
@@ -684,13 +684,7 @@ } // Tests maximized window size during root window resize. -#if defined(OS_WIN) && !defined(USE_ASH) -// TODO(msw): Broken on Windows. http://crbug.com/584038 -#define MAYBE_MaximizeRootWindowResize DISABLED_MaximizeRootWindowResize -#else -#define MAYBE_MaximizeRootWindowResize MaximizeRootWindowResize -#endif -TEST_F(WorkspaceLayoutManagerSoloTest, MAYBE_MaximizeRootWindowResize) { +TEST_F(WorkspaceLayoutManagerSoloTest, MaximizeRootWindowResize) { gfx::Rect bounds(100, 100, 200, 200); std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(bounds)); WmWindow* window = window_owner->window();
diff --git a/ash/common/wm_root_window_controller.cc b/ash/common/wm_root_window_controller.cc index 77dc157..f2851f6ac 100644 --- a/ash/common/wm_root_window_controller.cc +++ b/ash/common/wm_root_window_controller.cc
@@ -454,12 +454,10 @@ overlay_container->SetBoundsInScreenBehaviorForChildren( WmWindow::BoundsInScreenBehavior::USE_SCREEN_COORDINATES); -#if defined(OS_CHROMEOS) WmWindow* mouse_cursor_container = CreateContainer( kShellWindowId_MouseCursorContainer, "MouseCursorContainer", root_); mouse_cursor_container->SetBoundsInScreenBehaviorForChildren( WmWindow::BoundsInScreenBehavior::USE_SCREEN_COORDINATES); -#endif CreateContainer(kShellWindowId_PowerButtonAnimationContainer, "PowerButtonAnimationContainer", root_);
diff --git a/ash/common/wm_shell.cc b/ash/common/wm_shell.cc index 5a8c34b..9f140c18 100644 --- a/ash/common/wm_shell.cc +++ b/ash/common/wm_shell.cc
@@ -27,6 +27,10 @@ #include "ash/common/shell_delegate.h" #include "ash/common/shutdown_controller.h" #include "ash/common/system/brightness_control_delegate.h" +#include "ash/common/system/chromeos/brightness/brightness_controller_chromeos.h" +#include "ash/common/system/chromeos/keyboard_brightness_controller.h" +#include "ash/common/system/chromeos/network/vpn_list.h" +#include "ash/common/system/chromeos/session/logout_confirmation_controller.h" #include "ash/common/system/keyboard_brightness_control_delegate.h" #include "ash/common/system/locale/locale_notification_controller.h" #include "ash/common/system/toast/toast_manager.h" @@ -55,13 +59,6 @@ #include "ui/display/display.h" #include "ui/views/focus/focus_manager_factory.h" -#if defined(OS_CHROMEOS) -#include "ash/common/system/chromeos/brightness/brightness_controller_chromeos.h" -#include "ash/common/system/chromeos/keyboard_brightness_controller.h" -#include "ash/common/system/chromeos/network/vpn_list.h" -#include "ash/common/system/chromeos/session/logout_confirmation_controller.h" -#endif - namespace ash { // static @@ -251,9 +248,13 @@ WmShell::WmShell(std::unique_ptr<ShellDelegate> shell_delegate) : delegate_(std::move(shell_delegate)), app_list_(base::MakeUnique<app_list::AppList>()), + brightness_control_delegate_( + base::MakeUnique<system::BrightnessControllerChromeos>()), cast_config_(base::MakeUnique<CastConfigController>()), focus_cycler_(base::MakeUnique<FocusCycler>()), immersive_context_(base::MakeUnique<ImmersiveContextAsh>()), + keyboard_brightness_control_delegate_( + base::MakeUnique<KeyboardBrightnessController>()), locale_notification_controller_( base::MakeUnique<LocaleNotificationController>()), media_controller_(base::MakeUnique<MediaController>()), @@ -263,15 +264,11 @@ shutdown_controller_(base::MakeUnique<ShutdownController>()), system_tray_controller_(base::MakeUnique<SystemTrayController>()), system_tray_notifier_(base::MakeUnique<SystemTrayNotifier>()), + vpn_list_(base::MakeUnique<VpnList>()), wallpaper_delegate_(delegate_->CreateWallpaperDelegate()), window_cycle_controller_(base::MakeUnique<WindowCycleController>()), window_selector_controller_( base::MakeUnique<WindowSelectorController>()) { -#if defined(OS_CHROMEOS) - brightness_control_delegate_.reset(new system::BrightnessControllerChromeos); - keyboard_brightness_control_delegate_.reset(new KeyboardBrightnessController); - vpn_list_ = base::MakeUnique<VpnList>(); -#endif session_controller_->AddSessionStateObserver(this); prefs::mojom::PreferencesManagerPtr pref_manager_ptr; @@ -373,20 +370,16 @@ DCHECK(delegate); system_tray_delegate_ = std::move(delegate); system_tray_delegate_->Initialize(); -#if defined(OS_CHROMEOS) // Accesses WmShell in its constructor. logout_confirmation_controller_.reset(new LogoutConfirmationController( base::Bind(&SystemTrayController::SignOut, base::Unretained(system_tray_controller_.get())))); -#endif } void WmShell::DeleteSystemTrayDelegate() { DCHECK(system_tray_delegate_); -#if defined(OS_CHROMEOS) // Accesses WmShell in its destructor. logout_confirmation_controller_.reset(); -#endif system_tray_delegate_.reset(); }
diff --git a/ash/common/wm_shell.h b/ash/common/wm_shell.h index 45e4f5c8..46e28b5 100644 --- a/ash/common/wm_shell.h +++ b/ash/common/wm_shell.h
@@ -60,6 +60,7 @@ class KeyboardBrightnessControlDelegate; class KeyboardUI; class LocaleNotificationController; +class LogoutConfirmationController; class MaximizeModeController; class MediaController; class MruWindowTracker; @@ -79,6 +80,7 @@ class SystemTrayController; class SystemTrayNotifier; class ToastManager; +class VpnList; class WallpaperController; class WallpaperDelegate; class WindowCycleController; @@ -99,11 +101,6 @@ class WindowState; } -#if defined(OS_CHROMEOS) -class LogoutConfirmationController; -class VpnList; -#endif - // Similar to ash::Shell. Eventually the two will be merged. class ASH_EXPORT WmShell : public SessionStateObserver { public: @@ -146,6 +143,10 @@ return locale_notification_controller_.get(); } + LogoutConfirmationController* logout_confirmation_controller() { + return logout_confirmation_controller_.get(); + } + MaximizeModeController* maximize_mode_controller() { return maximize_mode_controller_.get(); } @@ -193,6 +194,8 @@ ToastManager* toast_manager() { return toast_manager_.get(); } + VpnList* vpn_list() { return vpn_list_.get(); } + WallpaperController* wallpaper_controller() { return wallpaper_controller_.get(); } @@ -207,6 +210,10 @@ return window_selector_controller_.get(); } + const scoped_refptr<base::SequencedWorkerPool>& blocking_pool() { + return blocking_pool_; + } + // Returns true when ash is running as a service_manager::Service. virtual bool IsRunningInMash() const = 0; @@ -430,23 +437,11 @@ // True if any touch points are down. virtual bool IsTouchDown() = 0; - const scoped_refptr<base::SequencedWorkerPool>& blocking_pool() { - return blocking_pool_; - } - -#if defined(OS_CHROMEOS) - LogoutConfirmationController* logout_confirmation_controller() { - return logout_confirmation_controller_.get(); - } - - VpnList* vpn_list() { return vpn_list_.get(); } - // TODO(jamescook): Remove this when VirtualKeyboardController has been moved. virtual void ToggleIgnoreExternalKeyboard() = 0; // Enable or disable the laser pointer. virtual void SetLaserPointerEnabled(bool enabled) = 0; -#endif protected: explicit WmShell(std::unique_ptr<ShellDelegate> shell_delegate); @@ -505,6 +500,7 @@ keyboard_brightness_control_delegate_; std::unique_ptr<KeyboardUI> keyboard_ui_; std::unique_ptr<LocaleNotificationController> locale_notification_controller_; + std::unique_ptr<LogoutConfirmationController> logout_confirmation_controller_; std::unique_ptr<MaximizeModeController> maximize_mode_controller_; std::unique_ptr<MediaController> media_controller_; std::unique_ptr<MruWindowTracker> mru_window_tracker_; @@ -519,6 +515,7 @@ std::unique_ptr<SystemTrayNotifier> system_tray_notifier_; std::unique_ptr<SystemTrayDelegate> system_tray_delegate_; std::unique_ptr<ToastManager> toast_manager_; + std::unique_ptr<VpnList> vpn_list_; std::unique_ptr<WallpaperController> wallpaper_controller_; std::unique_ptr<WallpaperDelegate> wallpaper_delegate_; std::unique_ptr<WindowCycleController> window_cycle_controller_; @@ -534,11 +531,6 @@ bool simulate_modal_window_open_for_testing_ = false; scoped_refptr<base::SequencedWorkerPool> blocking_pool_; - -#if defined(OS_CHROMEOS) - std::unique_ptr<LogoutConfirmationController> logout_confirmation_controller_; - std::unique_ptr<VpnList> vpn_list_; -#endif }; } // namespace ash
diff --git a/ash/mus/bridge/wm_window_mus.cc b/ash/mus/bridge/wm_window_mus.cc index 6761fbfe..3e58848 100644 --- a/ash/mus/bridge/wm_window_mus.cc +++ b/ash/mus/bridge/wm_window_mus.cc
@@ -75,15 +75,15 @@ } void WmWindowMus::CloseWidget() { - views::Widget* widget = views::Widget::GetWidgetForNativeView(aura_window()); - DCHECK(widget); - // Allow the client to service the close request for remote widgets. + // NOTE: in the FOR_CLIENT case there is not necessarily a widget associated + // with the window. Mash only creates widgets for top level windows if mash + // renders the non-client frame. if (aura_window()->GetProperty(kWidgetCreationTypeKey) == WidgetCreationType::FOR_CLIENT) { WmShellMus::Get()->window_manager()->window_manager_client()->RequestClose( aura_window()); } else { - widget->Close(); + WmWindowAura::CloseWidget(); } }
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc index 960c5cc..93a5320 100644 --- a/ash/root_window_controller.cc +++ b/ash/root_window_controller.cc
@@ -66,9 +66,6 @@ #include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_observer.h" #include "ui/aura/window_tracker.h" -#include "ui/display/display.h" -#include "ui/display/manager/display_manager.h" -#include "ui/display/screen.h" #include "ui/display/types/display_constants.h" #include "ui/keyboard/keyboard_controller.h" #include "ui/keyboard/keyboard_util.h"
diff --git a/base/task_scheduler/scheduler_worker.cc b/base/task_scheduler/scheduler_worker.cc index 5853bf6..970a7d4 100644 --- a/base/task_scheduler/scheduler_worker.cc +++ b/base/task_scheduler/scheduler_worker.cc
@@ -78,11 +78,10 @@ continue; } - std::unique_ptr<Task> task = sequence->TakeTask(); - const TaskPriority task_priority = task->traits.priority(); - const TimeDelta task_latency = TimeTicks::Now() - task->sequenced_time; - if (outer_->task_tracker_->RunTask(std::move(task), sequence->token())) - outer_->delegate_->DidRunTaskWithPriority(task_priority, task_latency); + if (outer_->task_tracker_->RunTask(sequence->TakeTask(), + sequence->token())) { + outer_->delegate_->DidRunTask(); + } const bool sequence_became_empty = sequence->Pop();
diff --git a/base/task_scheduler/scheduler_worker.h b/base/task_scheduler/scheduler_worker.h index 1b81b03..f75d45f 100644 --- a/base/task_scheduler/scheduler_worker.h +++ b/base/task_scheduler/scheduler_worker.h
@@ -53,11 +53,8 @@ // run a Task. virtual scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) = 0; - // Called by the SchedulerWorker after it ran a task with |task_priority|. - // |task_latency| is the time elapsed between when the task was posted and - // when it started to run. - virtual void DidRunTaskWithPriority(TaskPriority task_priority, - TimeDelta task_latency) = 0; + // Called by the SchedulerWorker after it ran a task. + virtual void DidRunTask() = 0; // Called when |sequence| isn't empty after the SchedulerWorker pops a Task // from it. |sequence| is the last Sequence returned by GetWork().
diff --git a/base/task_scheduler/scheduler_worker_pool_impl.cc b/base/task_scheduler/scheduler_worker_pool_impl.cc index 28f473e..912d270 100644 --- a/base/task_scheduler/scheduler_worker_pool_impl.cc +++ b/base/task_scheduler/scheduler_worker_pool_impl.cc
@@ -22,6 +22,7 @@ #include "base/task_runner.h" #include "base/task_scheduler/delayed_task_manager.h" #include "base/task_scheduler/task_tracker.h" +#include "base/task_scheduler/task_traits.h" #include "base/threading/platform_thread.h" #include "base/threading/thread_local.h" #include "base/threading/thread_restrictions.h" @@ -38,7 +39,6 @@ "TaskScheduler.NumTasksBeforeDetach."; constexpr char kNumTasksBetweenWaitsHistogramPrefix[] = "TaskScheduler.NumTasksBetweenWaits."; -constexpr char kTaskLatencyHistogramPrefix[] = "TaskScheduler.TaskLatency."; // SchedulerWorkerPool that owns the current thread, if any. LazyInstance<ThreadLocalPointer<const SchedulerWorkerPool>>::Leaky @@ -128,29 +128,6 @@ DISALLOW_COPY_AND_ASSIGN(SchedulerSequencedTaskRunner); }; -HistogramBase* GetTaskLatencyHistogram(const std::string& pool_name, - TaskPriority task_priority) { - const char* task_priority_suffix = nullptr; - switch (task_priority) { - case TaskPriority::BACKGROUND: - task_priority_suffix = ".BackgroundTaskPriority"; - break; - case TaskPriority::USER_VISIBLE: - task_priority_suffix = ".UserVisibleTaskPriority"; - break; - case TaskPriority::USER_BLOCKING: - task_priority_suffix = ".UserBlockingTaskPriority"; - break; - } - - // Mimics the UMA_HISTOGRAM_TIMES macro. - return Histogram::FactoryTimeGet(kTaskLatencyHistogramPrefix + pool_name + - kPoolNameSuffix + task_priority_suffix, - TimeDelta::FromMilliseconds(1), - TimeDelta::FromSeconds(10), 50, - HistogramBase::kUmaTargetedHistogramFlag); -} - // Only used in DCHECKs. bool ContainsWorker( const std::vector<std::unique_ptr<SchedulerWorker>>& workers, @@ -238,8 +215,7 @@ // SchedulerWorker::Delegate: void OnMainEntry(SchedulerWorker* worker) override; scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override; - void DidRunTaskWithPriority(TaskPriority task_priority, - TimeDelta task_latency) override; + void DidRunTask() override; void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override; TimeDelta GetSleepTimeout() override; bool CanDetach(SchedulerWorker* worker) override; @@ -599,28 +575,9 @@ return sequence; } -void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl:: - DidRunTaskWithPriority(TaskPriority task_priority, TimeDelta task_latency) { +void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::DidRunTask() { ++num_tasks_since_last_wait_; ++num_tasks_since_last_detach_; - - const int priority_index = static_cast<int>(task_priority); - - // As explained in the header file, histograms are allocated on demand. It - // doesn't matter if an element of |task_latency_histograms_| is set multiple - // times since GetTaskLatencyHistogram() is idempotent. As explained in the - // comment at the top of histogram_macros.h, barriers are required. - HistogramBase* task_latency_histogram = reinterpret_cast<HistogramBase*>( - subtle::Acquire_Load(&outer_->task_latency_histograms_[priority_index])); - if (!task_latency_histogram) { - task_latency_histogram = - GetTaskLatencyHistogram(outer_->name_, task_priority); - subtle::Release_Store( - &outer_->task_latency_histograms_[priority_index], - reinterpret_cast<subtle::AtomicWord>(task_latency_histogram)); - } - - task_latency_histogram->AddTime(task_latency); } void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::
diff --git a/base/task_scheduler/scheduler_worker_pool_impl.h b/base/task_scheduler/scheduler_worker_pool_impl.h index 3485995..4693d63 100644 --- a/base/task_scheduler/scheduler_worker_pool_impl.h +++ b/base/task_scheduler/scheduler_worker_pool_impl.h
@@ -11,7 +11,6 @@ #include <string> #include <vector> -#include "base/atomicops.h" #include "base/base_export.h" #include "base/callback.h" #include "base/logging.h" @@ -28,13 +27,13 @@ #include "base/task_scheduler/scheduler_worker_stack.h" #include "base/task_scheduler/sequence.h" #include "base/task_scheduler/task.h" -#include "base/task_scheduler/task_traits.h" #include "base/threading/platform_thread.h" #include "base/time/time.h" namespace base { class HistogramBase; +class TaskTraits; namespace internal { @@ -204,14 +203,6 @@ // Intentionally leaked. HistogramBase* const num_tasks_between_waits_histogram_; - // TaskScheduler.TaskLatency.[worker pool name].[task priority] histograms. - // Indexed by task priority. Histograms are allocated on demand to reduce - // memory usage (some task priorities might never run in this - // SchedulerThreadPoolImpl). Intentionally leaked. - subtle::AtomicWord - task_latency_histograms_[static_cast<int>(TaskPriority::HIGHEST) + 1] = - {}; - TaskTracker* const task_tracker_; DelayedTaskManager* const delayed_task_manager_;
diff --git a/base/task_scheduler/scheduler_worker_stack_unittest.cc b/base/task_scheduler/scheduler_worker_stack_unittest.cc index ec49420..520e52c 100644 --- a/base/task_scheduler/scheduler_worker_stack_unittest.cc +++ b/base/task_scheduler/scheduler_worker_stack_unittest.cc
@@ -26,9 +26,8 @@ scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { return nullptr; } - void DidRunTaskWithPriority(TaskPriority task_priority, - TimeDelta task_latency) override { - ADD_FAILURE() << "Unexpected call to DidRunTaskWithPriority()"; + void DidRunTask() override { + ADD_FAILURE() << "Unexpected call to DidRunTask()"; } void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override { ADD_FAILURE() << "Unexpected call to ReEnqueueSequence()";
diff --git a/base/task_scheduler/scheduler_worker_unittest.cc b/base/task_scheduler/scheduler_worker_unittest.cc index 8e82edfb..948cf1dd 100644 --- a/base/task_scheduler/scheduler_worker_unittest.cc +++ b/base/task_scheduler/scheduler_worker_unittest.cc
@@ -45,9 +45,8 @@ scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { return nullptr; } - void DidRunTaskWithPriority(TaskPriority task_priority, - TimeDelta task_latency) override { - ADD_FAILURE() << "Unexpected call to DidRunTaskWithPriority()"; + void DidRunTask() override { + ADD_FAILURE() << "Unexpected call to DidRunTask()"; } void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override { ADD_FAILURE() << "Unexpected call to ReEnqueueSequence()"; @@ -127,14 +126,14 @@ : outer_(outer) {} ~TestSchedulerWorkerDelegate() override { - EXPECT_FALSE(IsCallToDidRunTaskWithPriorityExpected()); + EXPECT_FALSE(IsCallToDidRunTaskExpected()); } // SchedulerWorker::Delegate: void OnMainEntry(SchedulerWorker* worker) override { outer_->worker_set_.Wait(); EXPECT_EQ(outer_->worker_.get(), worker); - EXPECT_FALSE(IsCallToDidRunTaskWithPriorityExpected()); + EXPECT_FALSE(IsCallToDidRunTaskExpected()); // Without synchronization, OnMainEntry() could be called twice without // generating an error. @@ -144,7 +143,7 @@ } scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { - EXPECT_FALSE(IsCallToDidRunTaskWithPriorityExpected()); + EXPECT_FALSE(IsCallToDidRunTaskExpected()); EXPECT_EQ(outer_->worker_.get(), worker); { @@ -174,7 +173,7 @@ sequence->PushTask(std::move(task)); } - ExpectCallToDidRunTaskWithPriority(sequence->PeekTaskTraits().priority()); + ExpectCallToDidRunTask(); { // Add the Sequence to the vector of created Sequences. @@ -185,13 +184,10 @@ return sequence; } - void DidRunTaskWithPriority(TaskPriority task_priority, - TimeDelta task_latency) override { - AutoSchedulerLock auto_lock(expect_did_run_task_with_priority_lock_); - EXPECT_TRUE(expect_did_run_task_with_priority_); - EXPECT_EQ(expected_task_priority_, task_priority); - EXPECT_FALSE(task_latency.is_max()); - expect_did_run_task_with_priority_ = false; + void DidRunTask() override { + AutoSchedulerLock auto_lock(expect_did_run_task_lock_); + EXPECT_TRUE(expect_did_run_task_); + expect_did_run_task_ = false; } // This override verifies that |sequence| contains the expected number of @@ -199,7 +195,7 @@ // EnqueueSequence implementation, it doesn't reinsert |sequence| into a // queue for further execution. void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override { - EXPECT_FALSE(IsCallToDidRunTaskWithPriorityExpected()); + EXPECT_FALSE(IsCallToDidRunTaskExpected()); EXPECT_GT(outer_->TasksPerSequence(), 1U); // Verify that |sequence| contains TasksPerSequence() - 1 Tasks. @@ -216,31 +212,27 @@ } private: - // Expect a call to DidRunTaskWithPriority() with |task_priority| as - // argument before the next call to any other method of this delegate. - void ExpectCallToDidRunTaskWithPriority(TaskPriority task_priority) { - AutoSchedulerLock auto_lock(expect_did_run_task_with_priority_lock_); - expect_did_run_task_with_priority_ = true; - expected_task_priority_ = task_priority; + // Expect a call to DidRunTask() before the next call to any other method of + // this delegate. + void ExpectCallToDidRunTask() { + AutoSchedulerLock auto_lock(expect_did_run_task_lock_); + expect_did_run_task_ = true; } - bool IsCallToDidRunTaskWithPriorityExpected() const { - AutoSchedulerLock auto_lock(expect_did_run_task_with_priority_lock_); - return expect_did_run_task_with_priority_; + bool IsCallToDidRunTaskExpected() const { + AutoSchedulerLock auto_lock(expect_did_run_task_lock_); + return expect_did_run_task_; } TaskSchedulerWorkerTest* outer_; - // Synchronizes access to |expect_did_run_task_with_priority_| and - // |expected_task_priority_|. - mutable SchedulerLock expect_did_run_task_with_priority_lock_; + // Synchronizes access to |expect_did_run_task_|. + mutable SchedulerLock expect_did_run_task_lock_; - // Whether the next method called on this delegate should be - // DidRunTaskWithPriority(). - bool expect_did_run_task_with_priority_ = false; + // Whether the next method called on this delegate should be DidRunTask(). + bool expect_did_run_task_ = false; - // Expected priority for the next call to DidRunTaskWithPriority(). - TaskPriority expected_task_priority_ = TaskPriority::BACKGROUND; + DISALLOW_COPY_AND_ASSIGN(TestSchedulerWorkerDelegate); }; void RunTaskCallback() { @@ -390,8 +382,7 @@ return sequence; } - void DidRunTaskWithPriority(TaskPriority task, - TimeDelta task_latency) override {} + void DidRunTask() override {} bool CanDetach(SchedulerWorker* worker) override { detach_requested_.Signal();
diff --git a/base/task_scheduler/task_tracker.cc b/base/task_scheduler/task_tracker.cc index 07b0d12..da21d5ea 100644 --- a/base/task_scheduler/task_tracker.cc +++ b/base/task_scheduler/task_tracker.cc
@@ -5,6 +5,7 @@ #include "base/task_scheduler/task_tracker.h" #include <limits> +#include <string> #include "base/callback.h" #include "base/debug/task_annotator.h" @@ -18,6 +19,7 @@ #include "base/threading/sequenced_task_runner_handle.h" #include "base/threading/thread_restrictions.h" #include "base/threading/thread_task_runner_handle.h" +#include "base/time/time.h" #include "base/trace_event/trace_event.h" #include "base/values.h" @@ -71,6 +73,14 @@ // its implementation details. const char kRunFunctionName[] = "TaskSchedulerRunTask"; +HistogramBase* GetTaskLatencyHistogram(const char* suffix) { + // Mimics the UMA_HISTOGRAM_TIMES macro. + return Histogram::FactoryTimeGet( + std::string("TaskScheduler.TaskLatency.") + suffix, + TimeDelta::FromMilliseconds(1), TimeDelta::FromSeconds(10), 50, + HistogramBase::kUmaTargetedHistogramFlag); +} + // Upper bound for the // TaskScheduler.BlockShutdownTasksPostedDuringShutdown histogram. const HistogramBase::Sample kMaxBlockShutdownTasksPostedDuringShutdown = 1000; @@ -174,7 +184,20 @@ TaskTracker::TaskTracker() : state_(new State), flush_cv_(flush_lock_.CreateConditionVariable()), - shutdown_lock_(&flush_lock_) {} + shutdown_lock_(&flush_lock_), + task_latency_histograms_{ + {GetTaskLatencyHistogram("BackgroundTaskPriority"), + GetTaskLatencyHistogram("BackgroundTaskPriority.MayBlock")}, + {GetTaskLatencyHistogram("UserVisibleTaskPriority"), + GetTaskLatencyHistogram("UserVisibleTaskPriority.MayBlock")}, + {GetTaskLatencyHistogram("UserBlockingTaskPriority"), + GetTaskLatencyHistogram("UserBlockingTaskPriority.MayBlock")}} { + // Confirm that all |task_latency_histograms_| have been initialized above. + DCHECK(*(&task_latency_histograms_[static_cast<int>(TaskPriority::HIGHEST) + + 1][0] - + 1)); +} + TaskTracker::~TaskTracker() = default; void TaskTracker::Shutdown() { @@ -220,6 +243,8 @@ const bool is_delayed = !task->delayed_run_time.is_null(); if (can_run_task) { + RecordTaskLatencyHistogram(task.get()); + const bool previous_singleton_allowed = ThreadRestrictions::SetSingletonAllowed( task->traits.shutdown_behavior() != @@ -463,5 +488,15 @@ } } +void TaskTracker::RecordTaskLatencyHistogram(Task* task) { + const TimeDelta task_latency = TimeTicks::Now() - task->sequenced_time; + task_latency_histograms_[static_cast<int>(task->traits.priority())] + [task->traits.may_block() || + task->traits.with_base_sync_primitives() + ? 1 + : 0] + ->AddTime(task_latency); +} + } // namespace internal } // namespace base
diff --git a/base/task_scheduler/task_tracker.h b/base/task_scheduler/task_tracker.h index a5caf21..14ca1f4 100644 --- a/base/task_scheduler/task_tracker.h +++ b/base/task_scheduler/task_tracker.h
@@ -21,13 +21,15 @@ namespace base { class ConditionVariable; +class HistogramBase; class SequenceToken; namespace internal { // All tasks go through the scheduler's TaskTracker when they are posted and -// when they are executed. The TaskTracker enforces shutdown semantics and takes -// care of tracing and profiling. This class is thread-safe. +// when they are executed. The TaskTracker sets up the environment to run tasks, +// enforces shutdown semantics, records metrics, and takes care of tracing and +// profiling. This class is thread-safe. class BASE_EXPORT TaskTracker { public: TaskTracker(); @@ -106,6 +108,10 @@ // it reaches zero. void DecrementNumPendingUndelayedTasks(); + // Records the TaskScheduler.TaskLatency.[task priority].[may block] histogram + // for |task|. + void RecordTaskLatencyHistogram(Task* task); + // Number of tasks blocking shutdown and boolean indicating whether shutdown // has started. const std::unique_ptr<State> state_; @@ -133,6 +139,12 @@ // completes. std::unique_ptr<WaitableEvent> shutdown_event_; + // TaskScheduler.TaskLatency.[task priority].[may block] histograms. The first + // index is a TaskPriority. The second index is 0 for non-blocking tasks, 1 + // for blocking tasks. Intentionally leaked. + HistogramBase* const + task_latency_histograms_[static_cast<int>(TaskPriority::HIGHEST) + 1][2]; + // Number of BLOCK_SHUTDOWN tasks posted during shutdown. HistogramBase::Sample num_block_shutdown_tasks_posted_during_shutdown_ = 0;
diff --git a/base/task_scheduler/task_tracker_unittest.cc b/base/task_scheduler/task_tracker_unittest.cc index 161aabb0..85378b6 100644 --- a/base/task_scheduler/task_tracker_unittest.cc +++ b/base/task_scheduler/task_tracker_unittest.cc
@@ -16,6 +16,9 @@ #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" +#include "base/metrics/histogram_base.h" +#include "base/metrics/histogram_samples.h" +#include "base/metrics/statistics_recorder.h" #include "base/sequence_token.h" #include "base/sequenced_task_runner.h" #include "base/single_thread_task_runner.h" @@ -25,6 +28,7 @@ #include "base/task_scheduler/task.h" #include "base/task_scheduler/task_traits.h" #include "base/test/gtest_util.h" +#include "base/test/histogram_tester.h" #include "base/test/test_simple_task_runner.h" #include "base/test/test_timeouts.h" #include "base/threading/platform_thread.h" @@ -885,5 +889,52 @@ wait_allowed_test_thread.Join(); } +// Verify that TaskScheduler.TaskLatency.* histograms are correctly recorded +// when a task runs. +TEST(TaskSchedulerTaskTrackerHistogramTest, TaskLatency) { + auto statistics_recorder = StatisticsRecorder::CreateTemporaryForTesting(); + + TaskTracker tracker; + + struct { + const TaskTraits traits; + const char* const expected_histogram; + } tests[] = { + {TaskTraits().WithPriority(TaskPriority::BACKGROUND), + "TaskScheduler.TaskLatency.BackgroundTaskPriority"}, + {TaskTraits().WithPriority(TaskPriority::BACKGROUND).MayBlock(), + "TaskScheduler.TaskLatency.BackgroundTaskPriority.MayBlock"}, + {TaskTraits() + .WithPriority(TaskPriority::BACKGROUND) + .WithBaseSyncPrimitives(), + "TaskScheduler.TaskLatency.BackgroundTaskPriority.MayBlock"}, + {TaskTraits().WithPriority(TaskPriority::USER_VISIBLE), + "TaskScheduler.TaskLatency.UserVisibleTaskPriority"}, + {TaskTraits().WithPriority(TaskPriority::USER_VISIBLE).MayBlock(), + "TaskScheduler.TaskLatency.UserVisibleTaskPriority.MayBlock"}, + {TaskTraits() + .WithPriority(TaskPriority::USER_VISIBLE) + .WithBaseSyncPrimitives(), + "TaskScheduler.TaskLatency.UserVisibleTaskPriority.MayBlock"}, + {TaskTraits().WithPriority(TaskPriority::USER_BLOCKING), + "TaskScheduler.TaskLatency.UserBlockingTaskPriority"}, + {TaskTraits().WithPriority(TaskPriority::USER_BLOCKING).MayBlock(), + "TaskScheduler.TaskLatency.UserBlockingTaskPriority.MayBlock"}, + {TaskTraits() + .WithPriority(TaskPriority::USER_BLOCKING) + .WithBaseSyncPrimitives(), + "TaskScheduler.TaskLatency.UserBlockingTaskPriority.MayBlock"}}; + + for (const auto& test : tests) { + auto task = + MakeUnique<Task>(FROM_HERE, Bind(&DoNothing), test.traits, TimeDelta()); + ASSERT_TRUE(tracker.WillPostTask(task.get())); + + HistogramTester tester; + EXPECT_TRUE(tracker.RunTask(std::move(task), SequenceToken::Create())); + tester.ExpectTotalCount(test.expected_histogram, 1); + } +} + } // namespace internal } // namespace base
diff --git a/chrome/VERSION b/chrome/VERSION index 13ff98b..3a0c887 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=57 MINOR=0 -BUILD=2974 +BUILD=2975 PATCH=0
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml index 2da5e07..5196282 100644 --- a/chrome/android/java/AndroidManifest.xml +++ b/chrome/android/java/AndroidManifest.xml
@@ -875,6 +875,9 @@ </intent-filter> </receiver> + <receiver android:name="org.chromium.chrome.browser.ntp.ContentSuggestionsNotificationHelper$TimeoutReceiver" + android:exported="false"/> + <receiver android:name="org.chromium.base.PowerStatusReceiver"> <intent-filter> <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java index 038bf91..6dada45 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -51,6 +51,7 @@ // Alphabetical: public static final String ANDROID_PAY_INTEGRATION_V1 = "AndroidPayIntegrationV1"; public static final String ANDROID_PAY_INTEGRATION_V2 = "AndroidPayIntegrationV2"; + public static final String ANDROID_PAYMENT_APPS = "AndroidPaymentApps"; public static final String AUTOFILL_SCAN_CARDHOLDER_NAME = "AutofillScanCardholderName"; public static final String CCT_EXTERNAL_LINK_HANDLING = "CCTExternalLinkHandling"; public static final String CCT_POST_MESSAGE_API = "CCTPostMessageAPI";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java index b3f30ef..2cd0847 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
@@ -37,6 +37,7 @@ import org.chromium.chrome.browser.init.BrowserParts; import org.chromium.chrome.browser.init.ChromeBrowserInitializer; import org.chromium.chrome.browser.init.EmptyBrowserParts; +import org.chromium.chrome.browser.notifications.NotificationConstants; import org.chromium.chrome.browser.offlinepages.downloads.OfflinePageDownloadBridge; import org.chromium.chrome.browser.util.IntentUtils; @@ -45,6 +46,7 @@ import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.concurrent.TimeUnit; /** * Service responsible for creating and updating download notifications even after @@ -73,21 +75,25 @@ public static final int INVALID_DOWNLOAD_PERCENTAGE = -1; @VisibleForTesting - static final String PENDING_DOWNLOAD_NOTIFICATIONS = "PendingDownloadNotifications"; static final String NOTIFICATION_NAMESPACE = "DownloadNotificationService"; private static final String TAG = "DownloadNotification"; - private static final String NEXT_DOWNLOAD_NOTIFICATION_ID = "NextDownloadNotificationId"; - // Notification Id starting value, to avoid conflicts from IDs used in prior versions. + + /** Notification Id starting value, to avoid conflicts from IDs used in prior versions. */ private static final int STARTING_NOTIFICATION_ID = 1000000; - private static final String AUTO_RESUMPTION_ATTEMPT_LEFT = "ResumptionAttemptLeft"; private static final int MAX_RESUMPTION_ATTEMPT_LEFT = 5; - @VisibleForTesting static final int SECONDS_PER_MINUTE = 60; - @VisibleForTesting static final int SECONDS_PER_HOUR = 60 * 60; - @VisibleForTesting static final int SECONDS_PER_DAY = 24 * 60 * 60; + @VisibleForTesting static final long SECONDS_PER_MINUTE = TimeUnit.MINUTES.toSeconds(1); + @VisibleForTesting static final long SECONDS_PER_HOUR = TimeUnit.HOURS.toSeconds(1); + @VisibleForTesting static final long SECONDS_PER_DAY = TimeUnit.DAYS.toSeconds(1); + + private static final String KEY_AUTO_RESUMPTION_ATTEMPT_LEFT = "ResumptionAttemptLeft"; + private static final String KEY_NEXT_DOWNLOAD_NOTIFICATION_ID = "NextDownloadNotificationId"; + static final String KEY_PENDING_DOWNLOAD_NOTIFICATIONS = "PendingDownloadNotifications"; + private final IBinder mBinder = new LocalBinder(); private final List<DownloadSharedPreferenceEntry> mDownloadSharedPreferenceEntries = new ArrayList<DownloadSharedPreferenceEntry>(); private final List<String> mDownloadsInProgress = new ArrayList<String>(); + private NotificationManager mNotificationManager; private SharedPreferences mSharedPrefs; private Context mContext; @@ -141,7 +147,7 @@ onBrowserKilled(); } mNextNotificationId = mSharedPrefs.getInt( - NEXT_DOWNLOAD_NOTIFICATION_ID, STARTING_NOTIFICATION_ID); + KEY_NEXT_DOWNLOAD_NOTIFICATION_ID, STARTING_NOTIFICATION_ID); } @@ -207,7 +213,7 @@ */ private void updateResumptionAttemptLeft() { SharedPreferences.Editor editor = mSharedPrefs.edit(); - editor.putInt(AUTO_RESUMPTION_ATTEMPT_LEFT, mNumAutoResumptionAttemptLeft); + editor.putInt(KEY_AUTO_RESUMPTION_ATTEMPT_LEFT, mNumAutoResumptionAttemptLeft); editor.apply(); } @@ -217,7 +223,7 @@ static void clearResumptionAttemptLeft() { SharedPreferences SharedPrefs = ContextUtils.getAppSharedPreferences(); SharedPreferences.Editor editor = SharedPrefs.edit(); - editor.remove(AUTO_RESUMPTION_ATTEMPT_LEFT); + editor.remove(KEY_AUTO_RESUMPTION_ATTEMPT_LEFT); editor.apply(); } @@ -546,7 +552,8 @@ .setSmallIcon(iconId) .setLocalOnly(true) .setAutoCancel(true) - .setContentText(contentText); + .setContentText(contentText) + .setGroup(NotificationConstants.GROUP_DOWNLOADS); return builder; } @@ -746,7 +753,7 @@ */ @VisibleForTesting void updateNotification(int id, Notification notification) { - mNotificationManager.notify(NOTIFICATION_NAMESPACE, id, notification); + mNotificationManager.notify(id, notification); } /** @@ -835,11 +842,11 @@ * left from the shared preference. */ void parseDownloadSharedPrefs() { - mNumAutoResumptionAttemptLeft = mSharedPrefs.getInt(AUTO_RESUMPTION_ATTEMPT_LEFT, + mNumAutoResumptionAttemptLeft = mSharedPrefs.getInt(KEY_AUTO_RESUMPTION_ATTEMPT_LEFT, MAX_RESUMPTION_ATTEMPT_LEFT); - if (!mSharedPrefs.contains(PENDING_DOWNLOAD_NOTIFICATIONS)) return; + if (!mSharedPrefs.contains(KEY_PENDING_DOWNLOAD_NOTIFICATIONS)) return; Set<String> entries = DownloadManagerService.getStoredDownloadInfo( - mSharedPrefs, PENDING_DOWNLOAD_NOTIFICATIONS); + mSharedPrefs, KEY_PENDING_DOWNLOAD_NOTIFICATIONS); for (String entryString : entries) { DownloadSharedPreferenceEntry entry = DownloadSharedPreferenceEntry.parseFromString(entryString); @@ -873,7 +880,7 @@ entries.add(mDownloadSharedPreferenceEntries.get(i).getSharedPreferenceString()); } DownloadManagerService.storeDownloadInfo( - mSharedPrefs, PENDING_DOWNLOAD_NOTIFICATIONS, entries); + mSharedPrefs, KEY_PENDING_DOWNLOAD_NOTIFICATIONS, entries); } /** @@ -887,7 +894,7 @@ mNextNotificationId = mNextNotificationId == Integer.MAX_VALUE ? STARTING_NOTIFICATION_ID : mNextNotificationId + 1; SharedPreferences.Editor editor = mSharedPrefs.edit(); - editor.putInt(NEXT_DOWNLOAD_NOTIFICATION_ID, mNextNotificationId); + editor.putInt(KEY_NEXT_DOWNLOAD_NOTIFICATION_ID, mNextNotificationId); editor.apply(); return notificationId; } @@ -910,15 +917,15 @@ int minutes = 0; if (secondsLong >= SECONDS_PER_DAY) { days = (int) (secondsLong / SECONDS_PER_DAY); - secondsLong -= (long) days * SECONDS_PER_DAY; + secondsLong -= days * SECONDS_PER_DAY; } if (secondsLong >= SECONDS_PER_HOUR) { hours = (int) (secondsLong / SECONDS_PER_HOUR); - secondsLong -= (long) hours * SECONDS_PER_HOUR; + secondsLong -= hours * SECONDS_PER_HOUR; } if (secondsLong >= SECONDS_PER_MINUTE) { minutes = (int) (secondsLong / SECONDS_PER_MINUTE); - secondsLong -= (long) minutes * SECONDS_PER_MINUTE; + secondsLong -= minutes * SECONDS_PER_MINUTE; } int seconds = (int) secondsLong;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunGlueImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunGlueImpl.java index 3a7f7ad..c0eab35 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunGlueImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunGlueImpl.java
@@ -24,15 +24,28 @@ private static final String CACHED_TOS_ACCEPTED_PREF = "first_run_tos_accepted"; /** - * Synchronizes first run native and Java preferences. Previous versions would - * set only the native pref so this function synchronizes that state to Java. + * Synchronizes first run native and Java preferences. * Must be called after native initialization. */ public static void cacheFirstRunPrefs() { SharedPreferences javaPrefs = ContextUtils.getAppSharedPreferences(); - if (!javaPrefs.getBoolean(CACHED_TOS_ACCEPTED_PREF, false) - && PrefServiceBridge.getInstance().isFirstRunEulaAccepted()) { - javaPrefs.edit().putBoolean(CACHED_TOS_ACCEPTED_PREF, true).apply(); + PrefServiceBridge prefsBridge = PrefServiceBridge.getInstance(); + // Set both Java and native prefs if any of the three indicators indicate ToS has been + // accepted. This needed because: + // - Old versions only set native pref, so this syncs Java pref. + // - Backup & restore does not restore native pref, so this needs to update it. + // - checkAnyUserHasSeenToS() may be true which needs to sync its state to the prefs. + boolean javaPrefValue = javaPrefs.getBoolean(CACHED_TOS_ACCEPTED_PREF, false); + boolean nativePrefValue = prefsBridge.isFirstRunEulaAccepted(); + boolean userHasSeenTos = + ToSAckedReceiver.checkAnyUserHasSeenToS(ContextUtils.getApplicationContext()); + if (javaPrefValue || nativePrefValue || userHasSeenTos) { + if (!javaPrefValue) { + javaPrefs.edit().putBoolean(CACHED_TOS_ACCEPTED_PREF, true).apply(); + } + if (!nativePrefValue) { + prefsBridge.setEulaAccepted(); + } } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationManager.java b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationManager.java index fb843214..a8e3557d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationManager.java
@@ -11,6 +11,7 @@ import org.chromium.base.ContextUtils; import org.chromium.chrome.R; +import org.chromium.chrome.browser.notifications.NotificationConstants; /** * Manages the notification indicating that there are incognito tabs opened in Document mode. @@ -37,7 +38,8 @@ .setVisibility(Notification.VISIBILITY_SECRET) .setSmallIcon(R.drawable.incognito_statusbar) .setShowWhen(false) - .setLocalOnly(true); + .setLocalOnly(true) + .setGroup(NotificationConstants.GROUP_INCOGNITO); NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); nm.notify(INCOGNITO_TABS_OPEN_TAG, INCOGNITO_TABS_OPEN_ID, builder.build());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaNotificationManager.java b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaNotificationManager.java index 8a95b7c..d7dcd05b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaNotificationManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaNotificationManager.java
@@ -37,6 +37,7 @@ import org.chromium.base.VisibleForTesting; import org.chromium.blink.mojom.MediaSessionAction; import org.chromium.chrome.R; +import org.chromium.chrome.browser.notifications.NotificationConstants; import org.chromium.content_public.common.MediaMetadata; import java.util.ArrayList; @@ -270,7 +271,6 @@ */ public static final class PlaybackListenerService extends ListenerService { private static final int NOTIFICATION_ID = R.id.media_playback_notification; - private static final String NOTIFICATION_GROUP_NAME = "MediaPlayback"; @Override public void onCreate() { @@ -310,7 +310,6 @@ */ public static final class PresentationListenerService extends ListenerService { private static final int NOTIFICATION_ID = R.id.presentation_notification; - private static final String NOTIFICATION_GROUP_NAME = "MediaPresentation"; @Override @Nullable @@ -324,7 +323,6 @@ */ public static final class CastListenerService extends ListenerService { private static final int NOTIFICATION_ID = R.id.remote_notification; - private static final String NOTIFICATION_GROUP_NAME = "MediaRemote"; @Override @Nullable @@ -399,11 +397,11 @@ // Returns the notification group name used to prevent automatic grouping. private String getNotificationGroupName() { if (mMediaNotificationInfo.id == PlaybackListenerService.NOTIFICATION_ID) { - return PlaybackListenerService.NOTIFICATION_GROUP_NAME; + return NotificationConstants.GROUP_MEDIA_PLAYBACK; } else if (mMediaNotificationInfo.id == PresentationListenerService.NOTIFICATION_ID) { - return PresentationListenerService.NOTIFICATION_GROUP_NAME; + return NotificationConstants.GROUP_MEDIA_PRESENTATION; } else if (mMediaNotificationInfo.id == CastListenerService.NOTIFICATION_ID) { - return CastListenerService.NOTIFICATION_GROUP_NAME; + return NotificationConstants.GROUP_MEDIA_REMOTE; } assert false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationConstants.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationConstants.java index 521d7de94..dc92632 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationConstants.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationConstants.java
@@ -59,4 +59,11 @@ * Key for retrieving the results of user input from notification text action intents. */ static final String KEY_TEXT_REPLY = "key_text_reply"; + + // Notification groups for features that show notifications to the user. + public static final String GROUP_DOWNLOADS = "Downloads"; + public static final String GROUP_INCOGNITO = "Incognito"; + public static final String GROUP_MEDIA_PLAYBACK = "MediaPlayback"; + public static final String GROUP_MEDIA_PRESENTATION = "MediaPresentation"; + public static final String GROUP_MEDIA_REMOTE = "MediaRemote"; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContentSuggestionsNotificationHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContentSuggestionsNotificationHelper.java index dcf20b8..337a3a9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContentSuggestionsNotificationHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContentSuggestionsNotificationHelper.java
@@ -4,13 +4,18 @@ package org.chromium.chrome.browser.ntp; +import android.annotation.TargetApi; +import android.app.AlarmManager; import android.app.NotificationManager; import android.app.PendingIntent; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; +import android.os.Build; import android.provider.Browser; +import android.service.notification.StatusBarNotification; import android.support.v4.app.NotificationCompat; import org.chromium.base.ContextUtils; @@ -27,10 +32,21 @@ */ public class ContentSuggestionsNotificationHelper { private static final String NOTIFICATION_TAG = "ContentSuggestionsNotification"; - private static final int NOTIFICATION_ID = 0; + private static final String NOTIFICATION_ID_EXTRA = "notification_id"; private ContentSuggestionsNotificationHelper() {} // Prevent instantiation + /** + * Removes the notification after a timeout period. + */ + public static final class TimeoutReceiver extends BroadcastReceiver { + public void onReceive(Context context, Intent intent) { + int id = intent.getIntExtra(NOTIFICATION_ID_EXTRA, -1); + if (id < 0) return; + hideNotification(id); + } + } + @CalledByNative private static void openUrl(String url) { Context context = ContextUtils.getApplicationContext(); @@ -45,11 +61,26 @@ context.startActivity(intent); } + @TargetApi(Build.VERSION_CODES.M) @CalledByNative - private static void showNotification(String url, String title, String text, Bitmap image) { + private static void showNotification( + String url, String title, String text, Bitmap image, long timeoutAtMillis) { + // Post notification. Context context = ContextUtils.getApplicationContext(); NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + + // Find an available notification ID. + int nextId = 0; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + for (StatusBarNotification activeNotification : manager.getActiveNotifications()) { + if (activeNotification.getTag() != NOTIFICATION_TAG) continue; + if (activeNotification.getId() >= nextId) { + nextId = activeNotification.getId() + 1; + } + } + } + Intent intent = new Intent() .setAction(Intent.ACTION_VIEW) .setData(Uri.parse(url)) @@ -65,14 +96,42 @@ .setGroup(NOTIFICATION_TAG) .setLargeIcon(image) .setSmallIcon(R.drawable.ic_chrome); - manager.notify(NOTIFICATION_TAG, NOTIFICATION_ID, builder.build()); + manager.notify(NOTIFICATION_TAG, nextId, builder.build()); + + // Set timeout. + if (timeoutAtMillis != Long.MAX_VALUE) { + AlarmManager alarmManager = + (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + Intent timeoutIntent = new Intent(context, TimeoutReceiver.class) + .setData(Uri.parse(url)) + .putExtra(NOTIFICATION_ID_EXTRA, nextId); + alarmManager.set(AlarmManager.RTC, timeoutAtMillis, + PendingIntent.getBroadcast( + context, 0, timeoutIntent, PendingIntent.FLAG_UPDATE_CURRENT)); + } } - @CalledByNative - private static void hideNotification() { + private static void hideNotification(int id) { Context context = ContextUtils.getApplicationContext(); NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - manager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID); + manager.cancel(NOTIFICATION_TAG, id); + } + + @TargetApi(Build.VERSION_CODES.M) + @CalledByNative + private static void hideAllNotifications() { + Context context = ContextUtils.getApplicationContext(); + NotificationManager manager = + (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + for (StatusBarNotification activeNotification : manager.getActiveNotifications()) { + if (activeNotification.getTag() == NOTIFICATION_TAG) { + manager.cancel(NOTIFICATION_TAG, activeNotification.getId()); + } + } + } else { + manager.cancel(NOTIFICATION_TAG, 0); + } } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentApp.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentApp.java new file mode 100644 index 0000000..b9c40de --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentApp.java
@@ -0,0 +1,222 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.payments; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.Handler; +import android.util.JsonWriter; + +import org.chromium.chrome.R; +import org.chromium.content.browser.ContentViewCore; +import org.chromium.content_public.browser.WebContents; +import org.chromium.payments.mojom.PaymentItem; +import org.chromium.payments.mojom.PaymentMethodData; +import org.chromium.ui.base.WindowAndroid; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** The point of interaction with a locally installed 3rd party native Android payment app. */ +public class AndroidPaymentApp extends PaymentInstrument implements PaymentApp, + WindowAndroid.IntentCallback { + private static final String EXTRA_METHOD_NAME = "methodName"; + private static final String EXTRA_DATA = "data"; + private static final String EXTRA_ORIGIN = "origin"; + private static final String EXTRA_DETAILS = "details"; + private static final String EXTRA_INSTRUMENT_DETAILS = "instrumentDetails"; + private static final String EMPTY_JSON_DATA = "{}"; + + private final Handler mHandler; + private final WebContents mWebContents; + private final Intent mPayIntent; + private final Set<String> mMethodNames; + private String mIsReadyToPayService; + private InstrumentDetailsCallback mInstrumentDetailsCallback; + + /** + * Builds the point of interaction with a locally installed 3rd party native Android payment + * app. + * + * @param webContents The web contents. + * @param packageName The name of the package of the payment app. + * @param activity The name of the payment activity in the payment app. + * @param label The UI label to use for the payment app. + * @param icon The icon to use in UI for the payment app. + */ + public AndroidPaymentApp(WebContents webContents, String packageName, String activity, + String label, Drawable icon) { + super(packageName, label, null, icon); + mHandler = new Handler(); + mWebContents = webContents; + mPayIntent = new Intent(); + mPayIntent.setClassName(packageName, activity); + mMethodNames = new HashSet<>(); + } + + /** @param methodName A payment method that this app supports, e.g., "https://bobpay.com". */ + public void addMethodName(String methodName) { + mMethodNames.add(methodName); + } + + /** @param service The name of the "is ready to pay" service in the payment app. */ + public void setIsReadyToPayService(String service) { + mIsReadyToPayService = service; + } + + @Override + public void getInstruments(Map<String, PaymentMethodData> methodData, String origin, + final InstrumentsCallback callback) { + mHandler.post(new Runnable() { + @Override + public void run() { + List<PaymentInstrument> instruments = new ArrayList<>(); + instruments.add(AndroidPaymentApp.this); + callback.onInstrumentsReady(AndroidPaymentApp.this, instruments); + } + }); + } + + @Override + public boolean supportsMethodsAndData(Map<String, PaymentMethodData> methodsAndData) { + assert methodsAndData != null; + Set<String> methodNames = new HashSet<>(methodsAndData.keySet()); + methodNames.retainAll(getAppMethodNames()); + return !methodNames.isEmpty(); + } + + @Override + public String getAppIdentifier() { + return getIdentifier(); + } + + @Override + public Set<String> getAppMethodNames() { + return Collections.unmodifiableSet(mMethodNames); + } + + @Override + public Set<String> getInstrumentMethodNames() { + return getAppMethodNames(); + } + + @Override + public void invokePaymentApp(String merchantName, String origin, PaymentItem total, + List<PaymentItem> cart, Map<String, PaymentMethodData> methodDataMap, + InstrumentDetailsCallback callback) { + assert !mMethodNames.isEmpty(); + Bundle extras = new Bundle(); + extras.putString(EXTRA_ORIGIN, origin); + + String methodName = mMethodNames.iterator().next(); + extras.putString(EXTRA_METHOD_NAME, methodName); + + PaymentMethodData methodData = methodDataMap.get(methodName); + extras.putString( + EXTRA_DATA, methodData == null ? EMPTY_JSON_DATA : methodData.stringifiedData); + + String details = serializeDetails(total, cart); + extras.putString(EXTRA_DETAILS, details == null ? EMPTY_JSON_DATA : details); + mPayIntent.putExtras(extras); + + mInstrumentDetailsCallback = callback; + + ContentViewCore contentView = ContentViewCore.fromWebContents(mWebContents); + if (contentView == null) { + notifyError(); + return; + } + + WindowAndroid window = contentView.getWindowAndroid(); + if (window == null) { + notifyError(); + return; + } + + if (!window.showIntent(mPayIntent, this, R.string.payments_android_app_error)) { + notifyError(); + } + } + + private void notifyError() { + mHandler.post(new Runnable() { + @Override + public void run() { + mInstrumentDetailsCallback.onInstrumentDetailsError(); + } + }); + } + + private static String serializeDetails(PaymentItem total, List<PaymentItem> cart) { + StringWriter stringWriter = new StringWriter(); + JsonWriter json = new JsonWriter(stringWriter); + try { + // details {{{ + json.beginObject(); + + // total {{{ + json.name("total"); + serializePaymentItem(json, total); + // }}} total + + // displayitems {{{ + if (cart != null) { + json.name("displayItems").beginArray(); + for (int i = 0; i < cart.size(); i++) { + serializePaymentItem(json, cart.get(i)); + } + json.endArray(); + } + // }}} displayItems + + json.endObject(); + // }}} details + } catch (IOException e) { + return null; + } + + return stringWriter.toString(); + } + + private static void serializePaymentItem(JsonWriter json, PaymentItem item) throws IOException { + // item {{{ + json.beginObject(); + json.name("label").value(item.label); + + // amount {{{ + json.name("amount").beginObject(); + json.name("currency").value(item.amount.currency); + json.name("value").value(item.amount.value); + json.endObject(); + // }}} amount + + json.endObject(); + // }}} item + } + + @Override + public void onIntentCompleted(WindowAndroid window, int resultCode, Intent data) { + window.removeIntentCallback(this); + if (data == null || data.getExtras() == null || resultCode != Activity.RESULT_OK) { + mInstrumentDetailsCallback.onInstrumentDetailsError(); + } else { + mInstrumentDetailsCallback.onInstrumentDetailsReady( + data.getExtras().getString(EXTRA_METHOD_NAME), + data.getExtras().getString(EXTRA_INSTRUMENT_DETAILS)); + } + mInstrumentDetailsCallback = null; + } + + @Override + public void dismissInstrument() {} +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFactory.java new file mode 100644 index 0000000..1914bb02 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFactory.java
@@ -0,0 +1,68 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.payments; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.net.Uri; + +import org.chromium.chrome.browser.payments.PaymentAppFactory.PaymentAppCreatedCallback; +import org.chromium.chrome.browser.payments.PaymentAppFactory.PaymentAppFactoryAddition; +import org.chromium.content_public.browser.WebContents; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** Builds instances of payment apps based on installed third party Android payment apps. */ +public class AndroidPaymentAppFactory implements PaymentAppFactoryAddition { + private static final String ACTION_PAY = "org.chromium.intent.action.PAY"; + private static final String ACTION_IS_READY_TO_PAY = + "org.chromium.intent.action.IS_READY_TO_PAY"; + private static final String METHOD_PREFIX = "https://"; + + @Override + public void create(Context context, WebContents webContents, Set<String> methods, + PaymentAppCreatedCallback callback) { + Map<String, AndroidPaymentApp> installedApps = new HashMap<>(); + PackageManager pm = context.getPackageManager(); + Intent payIntent = new Intent(ACTION_PAY); + + for (String methodName : methods) { + if (!methodName.startsWith(METHOD_PREFIX)) continue; + + payIntent.setData(Uri.parse(methodName)); + List<ResolveInfo> matches = pm.queryIntentActivities(payIntent, 0); + for (int i = 0; i < matches.size(); i++) { + ResolveInfo match = matches.get(i); + String packageName = match.activityInfo.packageName; + AndroidPaymentApp installedApp = installedApps.get(packageName); + if (installedApp == null) { + CharSequence label = match.loadLabel(pm); + installedApp = + new AndroidPaymentApp(webContents, packageName, match.activityInfo.name, + label == null ? "" : label.toString(), match.loadIcon(pm)); + callback.onPaymentAppCreated(installedApp); + installedApps.put(packageName, installedApp); + } + installedApp.addMethodName(methodName); + } + } + + List<ResolveInfo> matches = + pm.queryIntentServices(new Intent(ACTION_IS_READY_TO_PAY), 0); + for (int i = 0; i < matches.size(); i++) { + ResolveInfo match = matches.get(i); + String packageName = match.serviceInfo.packageName; + AndroidPaymentApp installedApp = installedApps.get(packageName); + if (installedApp != null) installedApp.setIsReadyToPayService(match.serviceInfo.name); + } + + callback.onAllPaymentAppsCreated(); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java index 5f6d3b4..45e3435e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java
@@ -23,6 +23,7 @@ import org.chromium.chrome.browser.preferences.autofill.AutofillProfileBridge.DropdownKeyValue; import org.chromium.content.browser.ContentViewCore; import org.chromium.content_public.browser.WebContents; +import org.chromium.ui.base.WindowAndroid; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -407,10 +408,14 @@ // Card scanner is expensive to query. if (mCardScanner == null) { - mCardScanner = CreditCardScanner.create(mContext, - ContentViewCore.fromWebContents(mWebContents).getWindowAndroid(), - this); - mCanScan = mCardScanner.canScan(); + ContentViewCore contentView = ContentViewCore.fromWebContents(mWebContents); + if (contentView != null) { + WindowAndroid window = contentView.getWindowAndroid(); + if (window != null) { + mCardScanner = CreditCardScanner.create(mContext, window, this); + mCanScan = mCardScanner.canScan(); + } + } } // Card number is validated.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentAppFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentAppFactory.java index a93ef0d..dd8af08f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentAppFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentAppFactory.java
@@ -52,14 +52,20 @@ * * @param context The application context. * @param webContents The web contents that invoked PaymentRequest. + * @param methods The methods that the merchant supports. * @param callback The callback to invoke when apps are created. */ - void create(Context context, WebContents webContents, PaymentAppCreatedCallback callback); + void create(Context context, WebContents webContents, Set<String> methods, + PaymentAppCreatedCallback callback); } private PaymentAppFactory() { mAdditionalFactories = new ArrayList<>(); + if (ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_PAYMENT_APPS)) { + mAdditionalFactories.add(new AndroidPaymentAppFactory()); + } + if (ChromeFeatureList.isEnabled(ChromeFeatureList.SERVICE_WORKER_PAYMENT_APPS)) { mAdditionalFactories.add(new ServiceWorkerPaymentAppBridge()); } @@ -88,10 +94,11 @@ * * @param context The context. * @param webContents The web contents where PaymentRequest was invoked. + * @param methods The methods that the merchant supports. * @param callback The callback to invoke when apps are created. */ - public void create( - Context context, WebContents webContents, final PaymentAppCreatedCallback callback) { + public void create(Context context, WebContents webContents, Set<String> methods, + final PaymentAppCreatedCallback callback) { callback.onPaymentAppCreated(new AutofillPaymentApp(context, webContents)); if (mAdditionalFactories.isEmpty()) { @@ -104,7 +111,7 @@ for (int i = 0; i < mAdditionalFactories.size(); i++) { final PaymentAppFactoryAddition additionalFactory = mAdditionalFactories.get(i); - additionalFactory.create(context, webContents, new PaymentAppCreatedCallback() { + PaymentAppCreatedCallback cb = new PaymentAppCreatedCallback() { @Override public void onPaymentAppCreated(PaymentApp paymentApp) { callback.onPaymentAppCreated(paymentApp); @@ -115,7 +122,8 @@ mPendingTasks.remove(additionalFactory); if (mPendingTasks.isEmpty()) callback.onAllPaymentAppsCreated(); } - }); + }; + additionalFactory.create(context, webContents, methods, cb); } } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java index f7c6cbcc4..dbe3313 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -207,6 +207,7 @@ private final Handler mHandler = new Handler(); private final ChromeActivity mContext; + private final WebContents mWebContents; private final String mMerchantName; private final String mOrigin; private final AddressEditor mAddressEditor; @@ -251,7 +252,6 @@ private SectionInformation mShippingAddressesSection; private SectionInformation mContactSection; private List<PaymentApp> mApps; - private boolean mAllAppsCreated; private List<PaymentApp> mPendingApps; private List<PaymentInstrument> mPendingInstruments; private List<PaymentInstrument> mPendingAutofillInstruments; @@ -280,8 +280,8 @@ /** * Builds the PaymentRequest service implementation. * - * @param context The context where PaymentRequest has been invoked. - * @param webContents The web contents that have invoked the PaymentRequest API. + * @param context The context where PaymentRequest has been invoked. + * @param webContents The web contents that have invoked the PaymentRequest API. */ public PaymentRequestImpl(Activity context, WebContents webContents) { assert context != null; @@ -289,6 +289,7 @@ assert context instanceof ChromeActivity; mContext = (ChromeActivity) context; + mWebContents = webContents; mMerchantName = webContents.getTitle(); // The feature is available only in secure context, so it's OK to not show HTTPS. @@ -313,7 +314,6 @@ }); mApps = new ArrayList<>(); - PaymentAppFactory.getInstance().create(mContext, webContents, this); mAddressEditor = new AddressEditor(); mCardEditor = new CardEditor(webContents, mAddressEditor, sObserverForTest); @@ -349,7 +349,8 @@ if (!parseAndValidateDetailsOrDisconnectFromClient(details)) return; - getMatchingPaymentInstruments(); + PaymentAppFactory.getInstance().create( + mContext, mWebContents, Collections.unmodifiableSet(mMethodData.keySet()), this); boolean requestShipping = options != null && options.requestShipping; boolean requestPayerName = options != null && options.requestPayerName; @@ -573,13 +574,10 @@ @Override public void onAllPaymentAppsCreated() { - mAllAppsCreated = true; - getMatchingPaymentInstruments(); - } + if (mClient == null) return; - /** Queries the installed payment apps for their instruments that merchant supports. */ - private void getMatchingPaymentInstruments() { - if (!mAllAppsCreated || mClient == null || mPendingApps != null) return; + assert mPendingApps == null; + mPendingApps = new ArrayList<>(mApps); mPendingInstruments = new ArrayList<>(); mPendingAutofillInstruments = new ArrayList<>();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java index 2f8c37e..72dbc39 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java
@@ -56,7 +56,7 @@ } @Override - public void create(Context context, WebContents webContents, + public void create(Context context, WebContents webContents, Set<String> methodNames, PaymentAppFactory.PaymentAppCreatedCallback callback) { nativeGetAllAppManifests(webContents, callback); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java index 6e80ab6..8c9f8d4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java
@@ -121,7 +121,7 @@ mPwsClient = new PwsClientImpl(this); int referer = getIntent().getIntExtra(REFERER_KEY, 0); if (savedInstanceState == null) { // Ensure this is a newly-created activity. - PhysicalWebUma.onActivityReferral(this, referer); + PhysicalWebUma.onActivityReferral(referer); } mIsInitialDisplayRecorded = false; mIsRefreshing = false; @@ -211,9 +211,9 @@ public void onPwsResults(Collection<PwsResult> pwsResults) { long duration = SystemClock.elapsedRealtime() - timestamp; if (isUserInitiated) { - PhysicalWebUma.onRefreshPwsResolution(ListUrlsActivity.this, duration); + PhysicalWebUma.onRefreshPwsResolution(duration); } else { - PhysicalWebUma.onForegroundPwsResolution(ListUrlsActivity.this, duration); + PhysicalWebUma.onForegroundPwsResolution(duration); } // filter out duplicate groups. @@ -241,7 +241,7 @@ */ @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { - PhysicalWebUma.onUrlSelected(this); + PhysicalWebUma.onUrlSelected(); UrlInfo nearestUrlInfo = null; PwsResult nearestPwsResult = mAdapter.getItem(position); String groupId = nearestPwsResult.groupId; @@ -326,9 +326,9 @@ // Record refresh-related UMA. if (!mIsInitialDisplayRecorded) { mIsInitialDisplayRecorded = true; - PhysicalWebUma.onUrlsDisplayed(this, mAdapter.getCount()); + PhysicalWebUma.onUrlsDisplayed(mAdapter.getCount()); } else if (mIsRefreshUserInitiated) { - PhysicalWebUma.onUrlsRefreshed(this, mAdapter.getCount()); + PhysicalWebUma.onUrlsRefreshed(mAdapter.getCount()); } mIsRefreshing = false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebOptInActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebOptInActivity.java index a8244ae9..2c80f0f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebOptInActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebOptInActivity.java
@@ -35,7 +35,7 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.physical_web_optin); - PhysicalWebUma.onOptInNotificationPressed(this); + PhysicalWebUma.onOptInNotificationPressed(); TextView description = (TextView) findViewById(R.id.physical_web_optin_description); description.setMovementMethod(LinkMovementMethod.getInstance()); @@ -45,7 +45,7 @@ declineButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - PhysicalWebUma.onOptInDeclineButtonPressed(PhysicalWebOptInActivity.this); + PhysicalWebUma.onOptInDeclineButtonPressed(); PrivacyPreferencesManager.getInstance().setPhysicalWebEnabled(false); finish(); } @@ -55,7 +55,7 @@ enableButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - PhysicalWebUma.onOptInEnableButtonPressed(PhysicalWebOptInActivity.this); + PhysicalWebUma.onOptInEnableButtonPressed(); PrivacyPreferencesManager.getInstance().setPhysicalWebEnabled(true); startActivity(createListUrlsIntent(PhysicalWebOptInActivity.this)); finish();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebUma.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebUma.java index 4212d7e3..35c75e37 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebUma.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebUma.java
@@ -4,18 +4,18 @@ package org.chromium.chrome.browser.physicalweb; -import android.content.Context; import android.content.SharedPreferences; import android.os.AsyncTask; +import org.json.JSONArray; +import org.json.JSONException; + import org.chromium.base.ContextUtils; import org.chromium.base.Log; import org.chromium.base.library_loader.LibraryLoader; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordUserAction; import org.chromium.components.location.LocationUtils; -import org.json.JSONArray; -import org.json.JSONException; import java.util.concurrent.TimeUnit; @@ -69,81 +69,81 @@ /** * Records a URL selection. */ - public static void onUrlSelected(Context context) { - handleAction(context, URL_SELECTED_COUNT); + public static void onUrlSelected() { + handleAction(URL_SELECTED_COUNT); } /** * Records a tap on the opt-in decline button. */ - public static void onOptInDeclineButtonPressed(Context context) { - handleAction(context, OPT_IN_DECLINE_BUTTON_PRESS_COUNT); + public static void onOptInDeclineButtonPressed() { + handleAction(OPT_IN_DECLINE_BUTTON_PRESS_COUNT); } /** * Records a tap on the opt-in enable button. */ - public static void onOptInEnableButtonPressed(Context context) { - handleAction(context, OPT_IN_ENABLE_BUTTON_PRESS_COUNT); + public static void onOptInEnableButtonPressed() { + handleAction(OPT_IN_ENABLE_BUTTON_PRESS_COUNT); } /** * Records a display of a high priority opt-in notification. */ - public static void onOptInHighPriorityNotificationShown(Context context) { - handleAction(context, OPT_IN_HIGH_PRIORITY_NOTIFICATION_COUNT); + public static void onOptInHighPriorityNotificationShown() { + handleAction(OPT_IN_HIGH_PRIORITY_NOTIFICATION_COUNT); } /** * Records a display of a min priority opt-in notification. */ - public static void onOptInMinPriorityNotificationShown(Context context) { - handleAction(context, OPT_IN_MIN_PRIORITY_NOTIFICATION_COUNT); + public static void onOptInMinPriorityNotificationShown() { + handleAction(OPT_IN_MIN_PRIORITY_NOTIFICATION_COUNT); } /** * Records a display of the opt-in activity. */ - public static void onOptInNotificationPressed(Context context) { - handleAction(context, OPT_IN_NOTIFICATION_PRESS_COUNT); + public static void onOptInNotificationPressed() { + handleAction(OPT_IN_NOTIFICATION_PRESS_COUNT); } /** * Records when the user disables the Physical Web fetaure. */ - public static void onPrefsFeatureDisabled(Context context) { - handleAction(context, PREFS_FEATURE_DISABLED_COUNT); + public static void onPrefsFeatureDisabled() { + handleAction(PREFS_FEATURE_DISABLED_COUNT); } /** * Records when the user enables the Physical Web fetaure. */ - public static void onPrefsFeatureEnabled(Context context) { - handleAction(context, PREFS_FEATURE_ENABLED_COUNT); + public static void onPrefsFeatureEnabled() { + handleAction(PREFS_FEATURE_ENABLED_COUNT); } /** * Records when the user denies the location permission when enabling the Physical Web from the * privacy settings menu. */ - public static void onPrefsLocationDenied(Context context) { - handleAction(context, PREFS_LOCATION_DENIED_COUNT); + public static void onPrefsLocationDenied() { + handleAction(PREFS_LOCATION_DENIED_COUNT); } /** * Records when the user grants the location permission when enabling the Physical Web from the * privacy settings menu. */ - public static void onPrefsLocationGranted(Context context) { - handleAction(context, PREFS_LOCATION_GRANTED_COUNT); + public static void onPrefsLocationGranted() { + handleAction(PREFS_LOCATION_GRANTED_COUNT); } /** * Records a response time from PWS for a resolution during a background scan. * @param duration The length of time PWS took to respond. */ - public static void onBackgroundPwsResolution(Context context, long duration) { - handleTime(context, PWS_BACKGROUND_RESOLVE_TIMES, duration, TimeUnit.MILLISECONDS); + public static void onBackgroundPwsResolution(long duration) { + handleTime(PWS_BACKGROUND_RESOLVE_TIMES, duration, TimeUnit.MILLISECONDS); } /** @@ -151,8 +151,8 @@ * explicitly user-initiated through a refresh. * @param duration The length of time PWS took to respond. */ - public static void onForegroundPwsResolution(Context context, long duration) { - handleTime(context, PWS_FOREGROUND_RESOLVE_TIMES, duration, TimeUnit.MILLISECONDS); + public static void onForegroundPwsResolution(long duration) { + handleTime(PWS_FOREGROUND_RESOLVE_TIMES, duration, TimeUnit.MILLISECONDS); } /** @@ -160,19 +160,19 @@ * user-initiated through a refresh. * @param duration The length of time PWS took to respond. */ - public static void onRefreshPwsResolution(Context context, long duration) { - handleTime(context, PWS_REFRESH_RESOLVE_TIMES, duration, TimeUnit.MILLISECONDS); + public static void onRefreshPwsResolution(long duration) { + handleTime(PWS_REFRESH_RESOLVE_TIMES, duration, TimeUnit.MILLISECONDS); } /** * Records number of URLs displayed to a user when the URL list is first displayed. * @param numUrls The number of URLs displayed to a user. */ - public static void onUrlsDisplayed(Context context, int numUrls) { + public static void onUrlsDisplayed(int numUrls) { if (LibraryLoader.isInitialized()) { RecordHistogram.recordCountHistogram(TOTAL_URLS_INITIAL_COUNTS, numUrls); } else { - storeValue(context, TOTAL_URLS_INITIAL_COUNTS, numUrls); + storeValue(TOTAL_URLS_INITIAL_COUNTS, numUrls); } } @@ -180,11 +180,11 @@ * Records number of URLs displayed to a user when the user refreshes the URL list. * @param numUrls The number of URLs displayed to a user. */ - public static void onUrlsRefreshed(Context context, int numUrls) { + public static void onUrlsRefreshed(int numUrls) { if (LibraryLoader.isInitialized()) { RecordHistogram.recordCountHistogram(TOTAL_URLS_REFRESH_COUNTS, numUrls); } else { - storeValue(context, TOTAL_URLS_REFRESH_COUNTS, numUrls); + storeValue(TOTAL_URLS_REFRESH_COUNTS, numUrls); } } @@ -193,24 +193,24 @@ * @param refer The type of referral. This enum is listed as PhysicalWebActivityReferer in * histograms.xml. */ - public static void onActivityReferral(Context context, int referer) { - handleEnum(context, ACTIVITY_REFERRALS, referer, ListUrlsActivity.REFERER_BOUNDARY); + public static void onActivityReferral(int referer) { + handleEnum(ACTIVITY_REFERRALS, referer, ListUrlsActivity.REFERER_BOUNDARY); switch (referer) { case ListUrlsActivity.NOTIFICATION_REFERER: - handleTime(context, STANDARD_NOTIFICATION_PRESS_DELAYS, + handleTime(STANDARD_NOTIFICATION_PRESS_DELAYS, UrlManager.getInstance().getTimeSinceNotificationUpdate(), TimeUnit.MILLISECONDS); break; case ListUrlsActivity.OPTIN_REFERER: - handleTime(context, OPT_IN_NOTIFICATION_PRESS_DELAYS, + handleTime(OPT_IN_NOTIFICATION_PRESS_DELAYS, UrlManager.getInstance().getTimeSinceNotificationUpdate(), TimeUnit.MILLISECONDS); break; case ListUrlsActivity.PREFERENCE_REFERER: - recordPhysicalWebState(context, LAUNCH_FROM_PREFERENCES); + recordPhysicalWebState(LAUNCH_FROM_PREFERENCES); break; case ListUrlsActivity.DIAGNOSTICS_REFERER: - recordPhysicalWebState(context, LAUNCH_FROM_DIAGNOSTICS); + recordPhysicalWebState(LAUNCH_FROM_DIAGNOSTICS); break; default: break; @@ -226,21 +226,21 @@ * - The data connection status * - The Physical Web preference status */ - public static void recordPhysicalWebState(Context context, String actionName) { + public static void recordPhysicalWebState(String actionName) { LocationUtils locationUtils = LocationUtils.getInstance(); - handleEnum(context, createStateString(LOCATION_SERVICES, actionName), + handleEnum(createStateString(LOCATION_SERVICES, actionName), locationUtils.isSystemLocationSettingEnabled() ? 1 : 0, BOOLEAN_BOUNDARY); - handleEnum(context, createStateString(LOCATION_PERMISSION, actionName), + handleEnum(createStateString(LOCATION_PERMISSION, actionName), locationUtils.hasAndroidLocationPermission() ? 1 : 0, BOOLEAN_BOUNDARY); - handleEnum(context, createStateString(BLUETOOTH, actionName), + handleEnum(createStateString(BLUETOOTH, actionName), Utils.getBluetoothEnabledStatus(), TRISTATE_BOUNDARY); - handleEnum(context, createStateString(DATA_CONNECTION, actionName), + handleEnum(createStateString(DATA_CONNECTION, actionName), Utils.isDataConnectionActive() ? 1 : 0, BOOLEAN_BOUNDARY); int preferenceState = 2; if (!PhysicalWeb.isOnboarding()) { preferenceState = PhysicalWeb.isPhysicalWebPreferenceEnabled() ? 1 : 0; } - handleEnum(context, createStateString(PREFERENCE, actionName), + handleEnum(createStateString(PREFERENCE, actionName), preferenceState, TRISTATE_BOUNDARY); } @@ -259,7 +259,7 @@ return PHYSICAL_WEB_STATE + "." + stateName + "." + actionName; } - private static void storeAction(Context context, String key) { + private static void storeAction(String key) { SharedPreferences prefs = ContextUtils.getAppSharedPreferences(); int count = prefs.getInt(key, 0); prefs.edit() @@ -268,7 +268,7 @@ .apply(); } - private static void storeValue(Context context, String key, Object value) { + private static void storeValue(String key, Object value) { SharedPreferences prefs = ContextUtils.getAppSharedPreferences(); SharedPreferences.Editor prefsEditor = prefs.edit(); JSONArray values = null; @@ -287,27 +287,27 @@ prefsEditor.putString(key, values.toString()).apply(); } - private static void handleAction(Context context, String key) { + private static void handleAction(String key) { if (LibraryLoader.isInitialized()) { RecordUserAction.record(key); } else { - storeAction(context, key); + storeAction(key); } } - private static void handleTime(Context context, String key, long duration, TimeUnit tu) { + private static void handleTime(String key, long duration, TimeUnit tu) { if (LibraryLoader.isInitialized()) { RecordHistogram.recordTimesHistogram(key, duration, tu); } else { - storeValue(context, key, duration); + storeValue(key, duration); } } - private static void handleEnum(Context context, String key, int value, int boundary) { + private static void handleEnum(String key, int value, int boundary) { if (LibraryLoader.isInitialized()) { RecordHistogram.recordEnumeratedHistogram(key, value, boundary); } else { - storeValue(context, key, value); + storeValue(key, value); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java index 99890d7..4fda676 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java
@@ -503,8 +503,7 @@ @Override public void onPwsResults(final Collection<PwsResult> pwsResults) { long duration = SystemClock.elapsedRealtime() - timestamp; - PhysicalWebUma.onBackgroundPwsResolution( - ContextUtils.getApplicationContext(), duration); + PhysicalWebUma.onBackgroundPwsResolution(duration); new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { @@ -556,13 +555,11 @@ // high priority notification createOptInNotification(true); PhysicalWeb.recordOptInNotification(); - PhysicalWebUma.onOptInHighPriorityNotificationShown( - ContextUtils.getApplicationContext()); + PhysicalWebUma.onOptInHighPriorityNotificationShown(); } else { // min priority notification createOptInNotification(false); - PhysicalWebUma.onOptInMinPriorityNotificationShown( - ContextUtils.getApplicationContext()); + PhysicalWebUma.onOptInMinPriorityNotificationShown(); } } else if (PhysicalWeb.isPhysicalWebPreferenceEnabled()) { createNotification();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PhysicalWebPreferenceFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PhysicalWebPreferenceFragment.java index 083aab5..f6851a37 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PhysicalWebPreferenceFragment.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PhysicalWebPreferenceFragment.java
@@ -62,11 +62,11 @@ case REQUEST_ID: if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - PhysicalWebUma.onPrefsLocationGranted(getActivity()); + PhysicalWebUma.onPrefsLocationGranted(); Log.d(TAG, "Location permission granted"); PhysicalWeb.startPhysicalWeb(); } else { - PhysicalWebUma.onPrefsLocationDenied(getActivity()); + PhysicalWebUma.onPrefsLocationDenied(); Log.d(TAG, "Location permission denied"); } break; @@ -86,10 +86,10 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { boolean enabled = (boolean) newValue; if (enabled) { - PhysicalWebUma.onPrefsFeatureEnabled(getActivity()); + PhysicalWebUma.onPrefsFeatureEnabled(); ensureLocationPermission(); } else { - PhysicalWebUma.onPrefsFeatureDisabled(getActivity()); + PhysicalWebUma.onPrefsFeatureDisabled(); } PrivacyPreferencesManager.getInstance().setPhysicalWebEnabled(enabled); return true;
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd index f619481..a98f7517 100644 --- a/chrome/android/java/strings/android_chrome_strings.grd +++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -2762,6 +2762,9 @@ <message name="IDS_PAYMENTS_UNSUPPORTED_PICKUP_ADDRESS" desc="Text implying that a user needs to choose a different pickup address, because the currently selected address is not supported. This address can be used, for example, for laundry pickup."> Unsupported pickup address. Select a different address. </message> + <message name="IDS_PAYMENTS_ANDROID_APP_ERROR" desc="Error message that is shown when an Android payment application fails to start."> + Unable to launch payment app. + </message> <!-- Migration strings --> <message name="IDS_TAB_SWITCHER_CALLOUT_HEADER" desc="Header for the Tab Switcher callout.">
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index d27f5f2e..651bdec 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -689,6 +689,8 @@ "java/src/org/chromium/chrome/browser/password_manager/AutoSigninFirstRunDialog.java", "java/src/org/chromium/chrome/browser/password_manager/Credential.java", "java/src/org/chromium/chrome/browser/payments/AddressEditor.java", + "java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFactory.java", + "java/src/org/chromium/chrome/browser/payments/AndroidPaymentApp.java", "java/src/org/chromium/chrome/browser/payments/AutofillAddress.java", "java/src/org/chromium/chrome/browser/payments/AutofillContact.java", "java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java index d762e0bee..6f8fe64 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
@@ -80,7 +80,7 @@ super.setupService(); SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences(); SharedPreferences.Editor editor = sharedPrefs.edit(); - editor.remove(DownloadNotificationService.PENDING_DOWNLOAD_NOTIFICATIONS); + editor.remove(DownloadNotificationService.KEY_PENDING_DOWNLOAD_NOTIFICATIONS); editor.apply(); super.tearDown(); } @@ -148,7 +148,7 @@ SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences(); SharedPreferences.Editor editor = sharedPrefs.edit(); editor.putStringSet( - DownloadNotificationService.PENDING_DOWNLOAD_NOTIFICATIONS, notifications); + DownloadNotificationService.KEY_PENDING_DOWNLOAD_NOTIFICATIONS, notifications); editor.apply(); startNotificationService(); assertTrue(scheduler.mScheduled); @@ -195,7 +195,7 @@ SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences(); SharedPreferences.Editor editor = sharedPrefs.edit(); editor.putStringSet( - DownloadNotificationService.PENDING_DOWNLOAD_NOTIFICATIONS, notifications); + DownloadNotificationService.KEY_PENDING_DOWNLOAD_NOTIFICATIONS, notifications); editor.apply(); startNotificationService(); assertFalse(scheduler.mScheduled); @@ -223,15 +223,15 @@ ContextUtils.getAppSharedPreferences(); SharedPreferences.Editor editor = sharedPrefs.edit(); editor.putStringSet( - DownloadNotificationService.PENDING_DOWNLOAD_NOTIFICATIONS, notifications); + DownloadNotificationService.KEY_PENDING_DOWNLOAD_NOTIFICATIONS, notifications); editor.apply(); startNotificationService(); assertTrue(getService().isPaused()); assertEquals(2, getService().getNotificationIds().size()); assertTrue(getService().getNotificationIds().contains(1)); assertTrue(getService().getNotificationIds().contains(2)); - assertTrue( - sharedPrefs.contains(DownloadNotificationService.PENDING_DOWNLOAD_NOTIFICATIONS)); + assertTrue(sharedPrefs.contains( + DownloadNotificationService.KEY_PENDING_DOWNLOAD_NOTIFICATIONS)); } /** @@ -255,7 +255,7 @@ SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences(); SharedPreferences.Editor editor = sharedPrefs.edit(); editor.putStringSet( - DownloadNotificationService.PENDING_DOWNLOAD_NOTIFICATIONS, notifications); + DownloadNotificationService.KEY_PENDING_DOWNLOAD_NOTIFICATIONS, notifications); editor.apply(); startNotificationService(); assertEquals(2, getService().getNotificationIds().size()); @@ -268,17 +268,17 @@ assertEquals(3, getService().getNotificationIds().size()); int lastNotificationId = getService().getLastAddedNotificationId(); Set<String> entries = DownloadManagerService.getStoredDownloadInfo( - sharedPrefs, DownloadNotificationService.PENDING_DOWNLOAD_NOTIFICATIONS); + sharedPrefs, DownloadNotificationService.KEY_PENDING_DOWNLOAD_NOTIFICATIONS); assertEquals(3, entries.size()); service.notifyDownloadSuccessful(guid1, "/path/to/success", "success", 100L, false, false); entries = DownloadManagerService.getStoredDownloadInfo( - sharedPrefs, DownloadNotificationService.PENDING_DOWNLOAD_NOTIFICATIONS); + sharedPrefs, DownloadNotificationService.KEY_PENDING_DOWNLOAD_NOTIFICATIONS); assertEquals(2, entries.size()); service.notifyDownloadFailed(guid2, "failed"); entries = DownloadManagerService.getStoredDownloadInfo( - sharedPrefs, DownloadNotificationService.PENDING_DOWNLOAD_NOTIFICATIONS); + sharedPrefs, DownloadNotificationService.KEY_PENDING_DOWNLOAD_NOTIFICATIONS); assertEquals(1, entries.size()); service.notifyDownloadCanceled(guid3); @@ -326,7 +326,7 @@ SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences(); SharedPreferences.Editor editor = sharedPrefs.edit(); editor.putStringSet( - DownloadNotificationService.PENDING_DOWNLOAD_NOTIFICATIONS, notifications); + DownloadNotificationService.KEY_PENDING_DOWNLOAD_NOTIFICATIONS, notifications); editor.apply(); startNotificationService(); DownloadNotificationService service = bindNotificationService(); @@ -370,12 +370,12 @@ ContextUtils.getAppSharedPreferences(); SharedPreferences.Editor editor = sharedPrefs.edit(); editor.putStringSet( - DownloadNotificationService.PENDING_DOWNLOAD_NOTIFICATIONS, notifications); + DownloadNotificationService.KEY_PENDING_DOWNLOAD_NOTIFICATIONS, notifications); editor.apply(); startNotificationService(); assertTrue(getService().isPaused()); assertFalse(sharedPrefs.contains( - DownloadNotificationService.PENDING_DOWNLOAD_NOTIFICATIONS)); + DownloadNotificationService.KEY_PENDING_DOWNLOAD_NOTIFICATIONS)); } @SmallTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java index e2efac1..d1a4650 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java
@@ -11,6 +11,7 @@ import org.chromium.content_public.browser.WebContents; import java.util.Arrays; +import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -42,6 +43,7 @@ new PaymentAppFactory.PaymentAppFactoryAddition() { @Override public void create(Context context, WebContents webContents, + Set<String> methodNames, PaymentAppFactory.PaymentAppCreatedCallback callback) { ServiceWorkerPaymentAppBridge.Manifest testManifest = new ServiceWorkerPaymentAppBridge.Manifest();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java index d423ebd..1c6045e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java
@@ -856,7 +856,7 @@ final TestPay app = new TestPay(methodName, instrumentPresence, responseSpeed); PaymentAppFactory.getInstance().addAdditionalFactory(new PaymentAppFactoryAddition() { @Override - public void create(Context context, WebContents webContents, + public void create(Context context, WebContents webContents, Set<String> methodNames, final PaymentAppFactory.PaymentAppCreatedCallback callback) { if (creationSpeed == IMMEDIATE_CREATION) { callback.onPaymentAppCreated(app);
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 16e3d17..6e7ffef 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -15394,6 +15394,12 @@ <message name="IDS_FLAGS_ENABLE_ANDROID_PAY_INTEGRATION_V2_DESCRIPTION" desc="Description for the flag to enable the second version of Android Pay integration" translateable="false"> Enable integration with Android Pay using the second version of the API </message> + <message name="IDS_FLAGS_ANDROID_PAYMENT_APPS_NAME" desc="Name of the flag to enable third party Android payment apps" translateable="false"> + Android payment apps + </message> + <message name="IDS_FLAGS_ANDROID_PAYMENT_APPS_DESCRIPTION" desc="Description for the flag to enable third party Android payment apps" translateable="false"> + Enable third party Android apps to integrate as payment apps + </message> </if> <message name="IDS_FLAGS_FEATURE_POLICY_NAME" desc="Name for the flag to enable feature policy.">
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 4b952e6d..257aa32 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -2016,6 +2016,10 @@ IDS_FLAGS_ENABLE_ANDROID_PAY_INTEGRATION_V2_NAME, IDS_FLAGS_ENABLE_ANDROID_PAY_INTEGRATION_V2_DESCRIPTION, kOsAndroid, FEATURE_VALUE_TYPE(chrome::android::kAndroidPayIntegrationV2)}, + {"android-payment-apps", + IDS_FLAGS_ANDROID_PAYMENT_APPS_NAME, + IDS_FLAGS_ANDROID_PAYMENT_APPS_DESCRIPTION, kOsAndroid, + FEATURE_VALUE_TYPE(chrome::android::kAndroidPaymentApps)}, #endif // OS_ANDROID #if defined(OS_CHROMEOS) {"disable-eol-notification", IDS_FLAGS_EOL_NOTIFICATION_NAME,
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc index 5d399dc..908982e3c 100644 --- a/chrome/browser/android/chrome_feature_list.cc +++ b/chrome/browser/android/chrome_feature_list.cc
@@ -40,6 +40,7 @@ &features::kWebPayments, &kAndroidPayIntegrationV1, &kAndroidPayIntegrationV2, + &kAndroidPaymentApps, &kCCTExternalLinkHandling, &kCCTPostMessageAPI, &kChromeHomeFeature, @@ -79,6 +80,9 @@ const base::Feature kAndroidPayIntegrationV2{"AndroidPayIntegrationV2", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kAndroidPaymentApps{"AndroidPaymentApps", + base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kCCTExternalLinkHandling{"CCTExternalLinkHandling", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h index 5641bda..44f0f07b 100644 --- a/chrome/browser/android/chrome_feature_list.h +++ b/chrome/browser/android/chrome_feature_list.h
@@ -15,6 +15,7 @@ // Alphabetical: extern const base::Feature kAndroidPayIntegrationV1; extern const base::Feature kAndroidPayIntegrationV2; +extern const base::Feature kAndroidPaymentApps; extern const base::Feature kCCTExternalLinkHandling; extern const base::Feature kCCTPostMessageAPI; extern const base::Feature kChromeHomeFeature;
diff --git a/chrome/browser/android/ntp/content_suggestions_notification_helper.cc b/chrome/browser/android/ntp/content_suggestions_notification_helper.cc index 03f4573..db5abdd3 100644 --- a/chrome/browser/android/ntp/content_suggestions_notification_helper.cc +++ b/chrome/browser/android/ntp/content_suggestions_notification_helper.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/android/ntp/content_suggestions_notification_helper.h" +#include <limits> + #include "base/android/jni_android.h" #include "base/android/jni_string.h" #include "base/strings/utf_string_conversions.h" @@ -24,22 +26,28 @@ const GURL& url, const base::string16& title, const base::string16& text, - const gfx::Image& image) { + const gfx::Image& image, + base::Time timeout_at) { JNIEnv* env = base::android::AttachCurrentThread(); SkBitmap skimage = image.AsImageSkia().GetRepresentation(1.0f).sk_bitmap(); if (skimage.empty()) return; + jint timeout_at_millis = timeout_at.ToJavaTime(); + if (timeout_at == base::Time::Max()) { + timeout_at_millis = std::numeric_limits<jint>::max(); + } + Java_ContentSuggestionsNotificationHelper_showNotification( env, base::android::ConvertUTF8ToJavaString(env, url.spec()), base::android::ConvertUTF16ToJavaString(env, title), base::android::ConvertUTF16ToJavaString(env, text), - gfx::ConvertToJavaBitmap(&skimage)); + gfx::ConvertToJavaBitmap(&skimage), timeout_at_millis); } -void ContentSuggestionsNotificationHelper::HideNotification() { +void ContentSuggestionsNotificationHelper::HideAllNotifications() { JNIEnv* env = base::android::AttachCurrentThread(); - Java_ContentSuggestionsNotificationHelper_hideNotification(env); + Java_ContentSuggestionsNotificationHelper_hideAllNotifications(env); } } // namespace ntp_snippets
diff --git a/chrome/browser/android/ntp/content_suggestions_notification_helper.h b/chrome/browser/android/ntp/content_suggestions_notification_helper.h index 97a06f2..e9c7d93c 100644 --- a/chrome/browser/android/ntp/content_suggestions_notification_helper.h +++ b/chrome/browser/android/ntp/content_suggestions_notification_helper.h
@@ -9,6 +9,7 @@ #include "base/macros.h" #include "base/strings/string16.h" +#include "base/time/time.h" #include "url/gurl.h" namespace gfx { @@ -23,8 +24,9 @@ static void SendNotification(const GURL& url, const base::string16& title, const base::string16& text, - const gfx::Image& image); - static void HideNotification(); + const gfx::Image& image, + base::Time timeout_at); + static void HideAllNotifications(); private: DISALLOW_IMPLICIT_CONSTRUCTORS(ContentSuggestionsNotificationHelper);
diff --git a/chrome/browser/android/ntp/content_suggestions_notifier_service.cc b/chrome/browser/android/ntp/content_suggestions_notifier_service.cc index 61fe726..cb7bfab 100644 --- a/chrome/browser/android/ntp/content_suggestions_notifier_service.cc +++ b/chrome/browser/android/ntp/content_suggestions_notifier_service.cc
@@ -81,12 +81,15 @@ if (!suggestion) { return; } + base::Time timeout_at = suggestion->notification_extra() + ? suggestion->notification_extra()->deadline + : base::Time::Max(); service_->FetchSuggestionImage( suggestion->id(), base::Bind(&NotifyingObserver::ImageFetched, weak_ptr_factory_.GetWeakPtr(), suggestion->id(), suggestion->url(), suggestion->title(), - suggestion->publisher_name())); + suggestion->publisher_name(), timeout_at)); } void OnCategoryStatusChanged(Category category, @@ -104,7 +107,7 @@ case CategoryStatus::LOADING_ERROR: case CategoryStatus::NOT_PROVIDED: case CategoryStatus::SIGNED_OUT: - ContentSuggestionsNotificationHelper::HideNotification(); + ContentSuggestionsNotificationHelper::HideAllNotifications(); break; } } @@ -114,16 +117,16 @@ if (suggestion_id.category().IsKnownCategory(KnownCategories::ARTICLES) && (suggestion_id.id_within_category() == prefs_->GetString(kNotificationIDWithinCategory))) { - ContentSuggestionsNotificationHelper::HideNotification(); + ContentSuggestionsNotificationHelper::HideAllNotifications(); } } void OnFullRefreshRequired() override { - ContentSuggestionsNotificationHelper::HideNotification(); + ContentSuggestionsNotificationHelper::HideAllNotifications(); } void ContentSuggestionsServiceShutdown() override { - ContentSuggestionsNotificationHelper::HideNotification(); + ContentSuggestionsNotificationHelper::HideAllNotifications(); } private: @@ -150,7 +153,7 @@ void AppStatusChanged(base::android::ApplicationState state) { if (!ShouldNotifyInState(state)) { - ContentSuggestionsNotificationHelper::HideNotification(); + ContentSuggestionsNotificationHelper::HideAllNotifications(); } } @@ -158,6 +161,7 @@ const GURL& url, const base::string16& title, const base::string16& publisher, + base::Time timeout_at, const gfx::Image& image) { if (!ShouldNotifyInState(app_status_listener_.GetState())) { return; // Became foreground while we were fetching the image; forget it. @@ -167,7 +171,7 @@ << image.Size().height() << " image for " << url.spec(); prefs_->SetString(kNotificationIDWithinCategory, id.id_within_category()); ContentSuggestionsNotificationHelper::SendNotification( - url, title, publisher, CropSquare(image)); + url, title, publisher, CropSquare(image), timeout_at); } ContentSuggestionsService* const service_;
diff --git a/chrome/browser/android/omnibox/autocomplete_controller_android.cc b/chrome/browser/android/omnibox/autocomplete_controller_android.cc index 0fa26a4a..ec11a572 100644 --- a/chrome/browser/android/omnibox/autocomplete_controller_android.cc +++ b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
@@ -185,7 +185,9 @@ // If omnibox text is empty, set it to the current URL for the purposes of // populating the verbatim match. - if (omnibox_text.empty()) + if (omnibox_text.empty() && + !current_url.SchemeIs(content::kChromeUIScheme) && + !current_url.SchemeIs(chrome::kChromeUINativeScheme)) omnibox_text = url; input_ = AutocompleteInput(
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc index 1eeea04..12d6b2f1 100644 --- a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc +++ b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
@@ -17,6 +17,7 @@ #include "chrome/browser/bitmap_fetcher/bitmap_fetcher_service.h" #include "chrome/browser/bitmap_fetcher/bitmap_fetcher_service_factory.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/history/top_sites_factory.h" @@ -153,7 +154,7 @@ physical_web::PhysicalWebDataSource* ChromeAutocompleteProviderClient::GetPhysicalWebDataSource() { - return nullptr; + return g_browser_process->GetPhysicalWebDataSource(); } std::string ChromeAutocompleteProviderClient::GetAcceptLanguages() const {
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index dbfff0a..7e894b0f 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -2798,22 +2798,21 @@ } } -#if defined(OS_ANDROID) +#if defined(OS_POSIX) && !defined(OS_MACOSX) void ChromeContentBrowserClient::GetAdditionalMappedFilesForChildProcess( const base::CommandLine& command_line, int child_process_id, - FileDescriptorInfo* mappings, - std::map<int, base::MemoryMappedFile::Region>* regions) { - int fd = ui::GetMainAndroidPackFd( - &(*regions)[kAndroidUIResourcesPakDescriptor]); - mappings->Share(kAndroidUIResourcesPakDescriptor, fd); + FileDescriptorInfo* mappings) { +#if defined(OS_ANDROID) + base::MemoryMappedFile::Region region; + int fd = ui::GetMainAndroidPackFd(®ion); + mappings->ShareWithRegion(kAndroidUIResourcesPakDescriptor, fd, region); - fd = ui::GetCommonResourcesPackFd( - &(*regions)[kAndroidChrome100PercentPakDescriptor]); - mappings->Share(kAndroidChrome100PercentPakDescriptor, fd); + fd = ui::GetCommonResourcesPackFd(®ion); + mappings->ShareWithRegion(kAndroidChrome100PercentPakDescriptor, fd, region); - fd = ui::GetLocalePackFd(&(*regions)[kAndroidLocalePakDescriptor]); - mappings->Share(kAndroidLocalePakDescriptor, fd); + fd = ui::GetLocalePackFd(®ion); + mappings->ShareWithRegion(kAndroidLocalePakDescriptor, fd, region); if (breakpad::IsCrashReporterEnabled()) { base::File file = @@ -2831,18 +2830,14 @@ base::FilePath app_data_path; PathService::Get(base::DIR_ANDROID_APP_DATA, &app_data_path); DCHECK(!app_data_path.empty()); -} -#elif defined(OS_POSIX) && !defined(OS_MACOSX) -void ChromeContentBrowserClient::GetAdditionalMappedFilesForChildProcess( - const base::CommandLine& command_line, - int child_process_id, - FileDescriptorInfo* mappings) { +#else int crash_signal_fd = GetCrashSignalFD(command_line); if (crash_signal_fd >= 0) { mappings->Share(kCrashDumpSignal, crash_signal_fd); } -} #endif // defined(OS_ANDROID) +} +#endif // defined(OS_POSIX) && !defined(OS_MACOSX) #if defined(OS_WIN) base::string16 ChromeContentBrowserClient::GetAppContainerSidForSandboxType(
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index dd23bde..6d6f8bb 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h
@@ -258,18 +258,12 @@ content::RenderFrameHost* render_frame_host, blink::WebPageVisibilityState* visibility_state) override; -#if defined(OS_ANDROID) - void GetAdditionalMappedFilesForChildProcess( - const base::CommandLine& command_line, - int child_process_id, - content::FileDescriptorInfo* mappings, - std::map<int, base::MemoryMappedFile::Region>* regions) override; -#elif defined(OS_POSIX) && !defined(OS_MACOSX) +#if defined(OS_POSIX) && !defined(OS_MACOSX) void GetAdditionalMappedFilesForChildProcess( const base::CommandLine& command_line, int child_process_id, content::FileDescriptorInfo* mappings) override; -#endif // defined(OS_ANDROID) +#endif // defined(OS_POSIX) && !defined(OS_MACOSX) #if defined(OS_WIN) bool PreSpawnRenderer(sandbox::TargetPolicy* policy) override; base::string16 GetAppContainerSidForSandboxType(
diff --git a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc index 4b1daa1..6e52ba5c 100644 --- a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc +++ b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
@@ -948,10 +948,16 @@ return function; } +// https://crbug.com/678967 +#if defined(OS_WIN) +#define MAYBE_DownloadExtensionTest_FileIcon_Active DISABLED_DownloadExtensionTest_FileIcon_Active +#else +#define MAYBE_DownloadExtensionTest_FileIcon_Active DownloadExtensionTest_FileIcon_Active +#endif // Test downloads.getFileIcon() on in-progress, finished, cancelled and deleted // download items. IN_PROC_BROWSER_TEST_F(DownloadExtensionTest, - DownloadExtensionTest_FileIcon_Active) { + MAYBE_DownloadExtensionTest_FileIcon_Active) { DownloadItem* download_item = CreateSlowTestDownload(); ASSERT_TRUE(download_item); ASSERT_FALSE(download_item->GetTargetFilePath().empty());
diff --git a/chrome/browser/media/webrtc/window_icon_util_win.cc b/chrome/browser/media/webrtc/window_icon_util_win.cc index 1a6039b..7e3b2ec 100644 --- a/chrome/browser/media/webrtc/window_icon_util_win.cc +++ b/chrome/browser/media/webrtc/window_icon_util_win.cc
@@ -36,5 +36,8 @@ std::unique_ptr<SkBitmap> icon_bitmap( IconUtil::CreateSkBitmapFromHICON(icon_handle)); + if (!icon_bitmap) + return gfx::ImageSkia(); + return gfx::ImageSkia::CreateFrom1xBitmap(*icon_bitmap); }
diff --git a/chrome/browser/memory/tab_manager_delegate_chromeos.cc b/chrome/browser/memory/tab_manager_delegate_chromeos.cc index f25d392..2d6e2866 100644 --- a/chrome/browser/memory/tab_manager_delegate_chromeos.cc +++ b/chrome/browser/memory/tab_manager_delegate_chromeos.cc
@@ -249,16 +249,24 @@ int TabManagerDelegate::MemoryStat::TargetMemoryToFreeKB() { static const int kRamVsSwapWeight = 4; static const char kMinFilelistConfig[] = "/proc/sys/vm/min_filelist_kbytes"; + static const char kMinFreeKbytes[] = "/proc/sys/vm/min_free_kbytes"; base::SystemMemoryInfoKB system_mem; base::GetSystemMemoryInfo(&system_mem); const int file_mem_kb = system_mem.active_file + system_mem.inactive_file; const int min_filelist_kb = ReadIntFromFile(kMinFilelistConfig, 0); + const int min_free_kb = ReadIntFromFile(kMinFreeKbytes, 0); // Calculate current available memory in system. // File-backed memory should be easy to reclaim, unless they're dirty. + // TODO(cylee): On ChromeOS, kernel reports low memory condition when + // available memory is low. The following formula duplicates the logic in + // kernel to calculate how much memory should be released. In the future, + // kernel should try to report the amount of memory to release directly to + // eliminate the duplication here. const int available_mem_kb = system_mem.free + file_mem_kb - system_mem.dirty - min_filelist_kb + - system_mem.swap_free / kRamVsSwapWeight; + system_mem.swap_free / kRamVsSwapWeight - + min_free_kb; return LowMemoryMarginKB() - available_mem_kb; } @@ -573,7 +581,8 @@ const TabStatsList& tab_list, const std::vector<arc::ArcProcess>& arc_processes) { - VLOG(2) << "LowMemoryKilleImpl"; + VLOG(2) << "LowMemoryKillImpl"; + const std::vector<TabManagerDelegate::Candidate> candidates = GetSortedCandidates(tab_list, arc_processes);
diff --git a/chrome/browser/payments/OWNERS b/chrome/browser/payments/OWNERS new file mode 100644 index 0000000..9e364d9 --- /dev/null +++ b/chrome/browser/payments/OWNERS
@@ -0,0 +1 @@ +file://components/payments/OWNERS \ No newline at end of file
diff --git a/chrome/browser/safe_browsing/certificate_reporting_service.cc b/chrome/browser/safe_browsing/certificate_reporting_service.cc index 9bcecb8..d0fb362c 100644 --- a/chrome/browser/safe_browsing/certificate_reporting_service.cc +++ b/chrome/browser/safe_browsing/certificate_reporting_service.cc
@@ -167,12 +167,14 @@ uint32_t server_public_key_version, size_t max_queued_report_count, base::TimeDelta max_report_age, - base::Clock* clock) + base::Clock* clock, + const base::Callback<void()>& reset_callback) : pref_service_(*profile->GetPrefs()), url_request_context_(nullptr), max_queued_report_count_(max_queued_report_count), max_report_age_(max_report_age), clock_(clock), + reset_callback_(reset_callback), server_public_key_(server_public_key), server_public_key_version_(server_public_key_version) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -188,12 +190,13 @@ base::Bind(&CertificateReportingService::OnPreferenceChanged, base::Unretained(this))); - content::BrowserThread::PostTask( + content::BrowserThread::PostTaskAndReply( content::BrowserThread::IO, FROM_HERE, base::Bind(&CertificateReportingService::InitializeOnIOThread, base::Unretained(this), true, url_request_context_getter, max_queued_report_count_, max_report_age_, clock_, - server_public_key_, server_public_key_version_)); + server_public_key_, server_public_key_version_), + reset_callback_); } CertificateReportingService::~CertificateReportingService() { @@ -253,12 +256,13 @@ if (!url_request_context_) return; - content::BrowserThread::PostTask( + content::BrowserThread::PostTaskAndReply( content::BrowserThread::IO, FROM_HERE, base::Bind(&CertificateReportingService::ResetOnIOThread, base::Unretained(this), enabled, url_request_context_, max_queued_report_count_, max_report_age_, clock_, - server_public_key_, server_public_key_version_)); + server_public_key_, server_public_key_version_), + reset_callback_); } CertificateReportingService::Reporter*
diff --git a/chrome/browser/safe_browsing/certificate_reporting_service.h b/chrome/browser/safe_browsing/certificate_reporting_service.h index 7137655..4f30f12f 100644 --- a/chrome/browser/safe_browsing/certificate_reporting_service.h +++ b/chrome/browser/safe_browsing/certificate_reporting_service.h
@@ -152,7 +152,8 @@ uint32_t server_public_key_version, size_t max_queued_report_count, base::TimeDelta max_report_age, - base::Clock* clock); + base::Clock* clock, + const base::Callback<void()>& reset_callback); ~CertificateReportingService() override; @@ -226,6 +227,9 @@ base::Clock* const clock_; + // Called when the service is reset. Used for testing. + base::Callback<void()> reset_callback_; + // Encryption parameters. uint8_t* server_public_key_; uint32_t server_public_key_version_;
diff --git a/chrome/browser/safe_browsing/certificate_reporting_service_browsertest.cc b/chrome/browser/safe_browsing/certificate_reporting_service_browsertest.cc index 89efeca0..eb5249a 100644 --- a/chrome/browser/safe_browsing/certificate_reporting_service_browsertest.cc +++ b/chrome/browser/safe_browsing/certificate_reporting_service_browsertest.cc
@@ -36,6 +36,7 @@ #include "url/scheme_host_port.h" using certificate_reporting_test_utils::CertificateReportingServiceTestHelper; +using certificate_reporting_test_utils::CertificateReportingServiceObserver; using certificate_reporting_test_utils::ReportExpectation; namespace { @@ -53,24 +54,16 @@ // These tests check the whole mechanism to send and queue invalid certificate // reports. Each test triggers reports by visiting broken SSL pages. The reports -// succeed, fail or hang indefinitely. The test waits for the URL requests -// corresponding to the reports to to be created via the URL request -// interceptor. When reports are expected to succeed or fail, test teardown -// checks that there are no in-flight or pending reports in the -// CertificateReportingService queue. When a report is to be delayed, a single -// in-flight report is expected in CertificateReportingService. Since the actual -// URL requests for reports are sent from the IO thread, the tests wait for the -// IO thread to finish before checking the expected report counts. -// -// Note that these browser tests differ from the unit tests in how they check -// expected reports: Unit tests create a network delegate and observe the -// destruction of the URL requests, whereas browser tests wait for the URL -// requests to be created instead. +// succeed, fail or hang indefinitely: +// - If a report is expected to fail or succeed, the test waits for the +// corresponding URL request jobs to be destroyed. +// - If a report is expected to hang, the test waits for the corresponding URL +// request job to be created. Only after resuming the hung request job the +// test waits for the request to be destroyed. class CertificateReportingServiceBrowserTest : public InProcessBrowserTest { public: CertificateReportingServiceBrowserTest() - : https_server_(net::EmbeddedTestServer::TYPE_HTTPS), - expect_delayed_report_on_teardown_(false) {} + : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {} void SetUpOnMainThread() override { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -80,19 +73,25 @@ https_server_.ServeFilesFromSourceDirectory("chrome/test/data"); ASSERT_TRUE(https_server_.Start()); - test_helper_.SetUpInterceptor(); + test_helper()->SetUpInterceptor(); CertificateReportingServiceFactory::GetInstance() ->SetReportEncryptionParamsForTesting( - test_helper_.server_public_key(), - test_helper_.server_public_key_version()); + test_helper()->server_public_key(), + test_helper()->server_public_key_version()); + CertificateReportingServiceFactory::GetInstance() + ->SetServiceResetCallbackForTesting( + base::Bind(&CertificateReportingServiceObserver::OnServiceReset, + base::Unretained(&service_observer_))); InProcessBrowserTest::SetUpOnMainThread(); } void TearDownOnMainThread() override { - CheckExpectedReportCounts(expect_delayed_report_on_teardown_); + test_helper()->ExpectNoRequests(service()); content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&CleanUpOnIOThread)); + EXPECT_GE(num_expected_failed_report_, 0) + << "Don't forget to set expected failed report count."; // Check the histogram as the last thing. This makes sure no in-flight // report is missed. if (num_expected_failed_report_ != 0) { @@ -138,16 +137,10 @@ // Navigate away from the interstitial to trigger report upload. ui_test_utils::NavigateToURL(browser(), GURL("about:blank")); content::WaitForInterstitialDetach(contents); - WaitForIOThread(); } void SendPendingReports() { service()->SendPending(); } - // Checks that there are no outstanding reports. - // If |expect_delayed_report_on_teardown| is true, expects a single delayed - // report. - void CheckNoReports() { CheckExpectedReportCounts(false); } - // Changes opt-in status and waits for the cert reporting service to reset. // Can only be used after the service is initialized. When changing the // value at the beginning of a test, @@ -159,119 +152,52 @@ // a task to the IO thread to reset the service. Waiting for the IO thread // ensures that the service is reset before returning from this method. void ChangeOptInAndWait(certificate_reporting_test_utils::OptIn opt_in) { + service_observer_.Clear(); certificate_reporting_test_utils::SetCertReportingOptIn(browser(), opt_in); - WaitForIOThread(); + service_observer_.WaitForReset(); } // Same as ChangeOptInAndWait, but enables/disables SafeBrowsing instead. void ToggleSafeBrowsingAndWaitForServiceReset(bool safebrowsing_enabled) { + service_observer_.Clear(); browser()->profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnabled, safebrowsing_enabled); - WaitForIOThread(); + service_observer_.WaitForReset(); } - void ShutdownServiceAndWait() { - service()->Shutdown(); - WaitForIOThread(); - } - - // Waits for a number of URL requests to be created for the reports in - // |expectation| and checks that the reports in |expectation| matches the - // reports observed by URL request interceptor. - void WaitForReports(const ReportExpectation& expectation) { - test_helper_.interceptor()->WaitForReports(expectation.num_reports()); - std::set<std::string> expected_hostnames; - CheckReports(expectation.successful_reports, - test_helper_.interceptor()->successful_reports()); - CheckReports(expectation.failed_reports, - test_helper_.interceptor()->failed_reports()); - CheckReports(expectation.delayed_reports, - test_helper_.interceptor()->delayed_reports()); - test_helper_.interceptor()->ClearObservedReports(); - } - - // Resumes the delayed request and waits for the resume task to complete which - // in turn means the response starts. - void ResumeDelayedRequestAndWait() { - base::RunLoop run_loop; - test_helper_.ResumeDelayedRequest(run_loop.QuitClosure()); - run_loop.Run(); - } - - // Tells the test to expect a delayed report during test teardown. If not set, - // the tests expect no in-flight reports during teardown. - void SetExpectDelayedReportOnTeardown() { - expect_delayed_report_on_teardown_ = true; - } - - void SetExpectedHistogramCountOnTeardown( - unsigned int num_expected_failed_report) { + void SetExpectedHistogramCountOnTeardown(int num_expected_failed_report) { num_expected_failed_report_ = num_expected_failed_report; } - private: CertificateReportingService* service() const { return CertificateReportingServiceFactory::GetForBrowserContext( browser()->profile()); } - // Waits for pending tasks on the IO thread to complete. - void WaitForIOThread() { - scoped_refptr<base::ThreadTestHelper> io_helper(new base::ThreadTestHelper( - content::BrowserThread::GetTaskRunnerForThread( - content::BrowserThread::IO) - .get())); - ASSERT_TRUE(io_helper->Run()); - } - + private: // Checks that the serialized reports in |received_reports| have the same // hostnames as |expected_hostnames|. void CheckReports(const std::set<std::string>& expected_hostnames, - const std::set<std::string>& received_reports) { + const std::set<std::string>& received_reports, + const std::string type) { std::set<std::string> received_hostnames; for (const std::string& serialized_report : received_reports) { certificate_reporting::ErrorReport report; ASSERT_TRUE(report.InitializeFromString(serialized_report)); received_hostnames.insert(report.hostname()); } - EXPECT_EQ(expected_hostnames, received_hostnames); - } - - // Checks that there are no remaining successful and failed reports observed - // by the interceptor. If |expect_delayed_report| is true, expects a single - // delayed report. Otherwise, expects no delayed reports. - void CheckExpectedReportCounts(bool expect_delayed_report) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - // Wait for the IO thread to ensure that any report-sending tasks previously - // posted to the IO thread hav run (and thus been observed by the - // interceptor). - WaitForIOThread(); - EXPECT_TRUE(test_helper_.interceptor()->successful_reports().empty()); - EXPECT_TRUE(test_helper_.interceptor()->failed_reports().empty()); - - if (expect_delayed_report) - EXPECT_EQ(1u, test_helper_.interceptor()->delayed_reports().size()); - else - EXPECT_TRUE(test_helper_.interceptor()->delayed_reports().empty()); - - if (service()->GetReporterForTesting()) { - // Reporter can be null if reporting is disabled. - size_t num_inflight_reports = expect_delayed_report ? 1u : 0u; - EXPECT_EQ(num_inflight_reports, - service() - ->GetReporterForTesting() - ->inflight_report_count_for_testing()); - } + EXPECT_EQ(expected_hostnames, received_hostnames) << type + << " comparison failed"; } net::EmbeddedTestServer https_server_; - // If true, the test will expect to see a delayed report during test teardown. - bool expect_delayed_report_on_teardown_ = false; - unsigned int num_expected_failed_report_ = 0; + int num_expected_failed_report_ = -1; CertificateReportingServiceTestHelper test_helper_; + CertificateReportingServiceObserver service_observer_; + base::HistogramTester histogram_tester_; DISALLOW_COPY_AND_ASSIGN(CertificateReportingServiceBrowserTest); @@ -307,7 +233,8 @@ // Reporting is opted in, so the report should succeed. SendReport("report0"); - WaitForReports(ReportExpectation::Successful({"report0"})); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Successful({"report0"})); } // Tests that report send attempts are not cancelled when extended reporting is @@ -325,11 +252,13 @@ // Send a failed report. SendReport("report0"); - WaitForReports(ReportExpectation::Failed({"report0"})); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Failed({"report0"})); // Send another failed report. SendReport("report1"); - WaitForReports(ReportExpectation::Failed({"report1"})); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Failed({"report1"})); // Let all report uploads complete successfully now. test_helper()->SetFailureMode(certificate_reporting_test_utils:: @@ -337,12 +266,14 @@ // Send another report. This time the report should be successfully sent. SendReport("report2"); - WaitForReports(ReportExpectation::Successful({"report2"})); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Successful({"report2"})); // Send all pending reports. The two previously failed reports should have // been queued, and now be sent successfully. SendPendingReports(); - WaitForReports(ReportExpectation::Successful({"report0", "report1"})); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Successful({"report0", "report1"})); // Try sending pending reports again. Since there is no pending report, // nothing should be sent this time. If any report is sent, test teardown @@ -364,7 +295,8 @@ // Send a failed report. SendReport("report0"); - WaitForReports(ReportExpectation::Failed({"report0"})); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Failed({"report0"})); // Disable reporting. This should clear all pending reports. ChangeOptInAndWait( @@ -388,7 +320,7 @@ // Send attempt should be cancelled since reporting is opted out. SendReport("no-report"); - CheckNoReports(); + test_helper()->ExpectNoRequests(service()); // Enable reporting. ChangeOptInAndWait( @@ -396,7 +328,8 @@ // A failed report should be observed. SendReport("report0"); - WaitForReports(ReportExpectation::Failed({"report0"})); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Failed({"report0"})); // Disable reporting. This should reset the reporting service and // clear all pending reports. @@ -405,7 +338,7 @@ // Report should be cancelled since reporting is opted out. SendReport("report1"); - CheckNoReports(); + test_helper()->ExpectNoRequests(service()); // Send pending reports. Nothing should be sent since there aren't any // pending reports. If any report is sent, test teardown will catch it. @@ -424,27 +357,30 @@ test_helper()->SetFailureMode( certificate_reporting_test_utils::ReportSendingResult::REPORTS_FAIL); - // Send a failed report. + // Send a delayed report. SendReport("report0"); - WaitForReports(ReportExpectation::Failed({"report0"})); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Failed({"report0"})); // Disable SafeBrowsing. This should clear all pending reports. ToggleSafeBrowsingAndWaitForServiceReset(false); // Send pending reports. No reports should be observed. SendPendingReports(); - CheckNoReports(); + test_helper()->ExpectNoRequests(service()); // Re-enable SafeBrowsing and trigger another report which will be queued. ToggleSafeBrowsingAndWaitForServiceReset(true); SendReport("report1"); - WaitForReports(ReportExpectation::Failed({"report1"})); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Failed({"report1"})); // Queued report should now be successfully sent. test_helper()->SetFailureMode(certificate_reporting_test_utils:: ReportSendingResult::REPORTS_SUCCESSFUL); SendPendingReports(); - WaitForReports(ReportExpectation::Successful({"report1"})); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Successful({"report1"})); } // CertificateReportingService should ignore reports older than the report TTL. @@ -469,12 +405,14 @@ // Send a failed report. SendReport("report0"); - WaitForReports(ReportExpectation::Failed({"report0"})); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Failed({"report0"})); // Advance the clock a bit and trigger another failed report. clock->Advance(base::TimeDelta::FromHours(5)); SendReport("report1"); - WaitForReports(ReportExpectation::Failed({"report1"})); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Failed({"report1"})); // Advance the clock to 20 hours, putting it 25 hours ahead of the reference // time. This makes report0 older than 24 hours. report1 is now 20 hours. @@ -483,11 +421,13 @@ // Send pending reports. report0 should be discarded since it's too old. // report1 should be queued again. SendPendingReports(); - WaitForReports(ReportExpectation::Failed({"report1"})); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Failed({"report1"})); // Trigger another failed report. SendReport("report2"); - WaitForReports(ReportExpectation::Failed({"report2"})); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Failed({"report2"})); // Advance the clock 5 hours. report1 will now be 25 hours old. clock->Advance(base::TimeDelta::FromHours(5)); @@ -495,7 +435,8 @@ // Send pending reports. report1 should be discarded since it's too old. // report2 should be queued again. SendPendingReports(); - WaitForReports(ReportExpectation::Failed({"report2"})); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Failed({"report2"})); // Advance the clock 20 hours again so that report2 is 25 hours old and is // older than max age (24 hours). @@ -531,7 +472,8 @@ // Trigger a failed report. SendReport("report0"); - WaitForReports(ReportExpectation::Failed({"report0"})); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Failed({"report0"})); // Trigger three more reports within five hours of each other. After this: // report0 is 0 hours after reference time (15 hours old). @@ -547,13 +489,15 @@ clock->Advance(base::TimeDelta::FromHours(5)); SendReport("report3"); - WaitForReports(ReportExpectation::Failed({"report1", "report2", "report3"})); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Failed({"report1", "report2", "report3"})); // Send pending reports. Four reports were generated above, but the service // only queues three reports, so report0 should be dropped since it's the // oldest. SendPendingReports(); - WaitForReports(ReportExpectation::Failed({"report1", "report2", "report3"})); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Failed({"report1", "report2", "report3"})); // Let all reports succeed. test_helper()->SetFailureMode(certificate_reporting_test_utils:: @@ -569,26 +513,8 @@ // Send pending reports. Only reports 2 and 3 should be sent, report 1 // should be ignored because it's too old. SendPendingReports(); - WaitForReports(ReportExpectation::Successful({"report2", "report3"})); -} - -// Resume a delayed report after CertificateReportingService shuts down. Should -// not crash. -IN_PROC_BROWSER_TEST_F(CertificateReportingServiceBrowserTest, - Delayed_NotResumed_ShouldNotCrash) { - SetExpectedHistogramCountOnTeardown(0); - - certificate_reporting_test_utils::SetCertReportingOptIn( - browser(), certificate_reporting_test_utils::EXTENDED_REPORTING_OPT_IN); - // Let reports hang. - test_helper()->SetFailureMode( - certificate_reporting_test_utils::ReportSendingResult::REPORTS_DELAY); - - // Navigate to and away from an interstitial to trigger a report. The report - // is triggered but hangs, so no error or success callbacks should be called. - SendReport("no-report"); - - SetExpectDelayedReportOnTeardown(); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Successful({"report2", "report3"})); } IN_PROC_BROWSER_TEST_F(CertificateReportingServiceBrowserTest, @@ -597,18 +523,21 @@ certificate_reporting_test_utils::SetCertReportingOptIn( browser(), certificate_reporting_test_utils::EXTENDED_REPORTING_OPT_IN); - // Let all reports fail. + // Let all reports hang. test_helper()->SetFailureMode( certificate_reporting_test_utils::ReportSendingResult::REPORTS_DELAY); // Trigger a report that hangs. SendReport("report0"); - WaitForReports(ReportExpectation::Delayed({"report0"})); + test_helper()->WaitForRequestsCreated( + ReportExpectation::Delayed({"report0"})); // Resume the report upload. The report upload should successfully complete. // The interceptor only observes request creations and not response // completions, so there is nothing to observe. - ResumeDelayedRequestAndWait(); + test_helper()->ResumeDelayedRequest(); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Delayed({"report0"})); } // Same as above, but the service is shut down before resuming the delayed @@ -619,21 +548,20 @@ certificate_reporting_test_utils::SetCertReportingOptIn( browser(), certificate_reporting_test_utils::EXTENDED_REPORTING_OPT_IN); - // Let all reports fail. + // Let all reports hang. test_helper()->SetFailureMode( certificate_reporting_test_utils::ReportSendingResult::REPORTS_DELAY); // Trigger a report that hangs. SendReport("report0"); - WaitForReports(ReportExpectation::Delayed({"report0"})); + test_helper()->WaitForRequestsCreated( + ReportExpectation::Delayed({"report0"})); - // Shutdown the service. Resuming the delayed request shouldn't crash. - ShutdownServiceAndWait(); - - // Resume the report upload. The report upload should successfully complete. - // The interceptor only observes request creations and not response - // completions, so there is nothing to observe. - ResumeDelayedRequestAndWait(); + // Shutdown the service and resume the report upload. Shouldn't crash. + service()->Shutdown(); + test_helper()->ResumeDelayedRequest(); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Delayed({"report0"})); } // Trigger a delayed report, then disable Safebrowsing. Certificate reporting @@ -643,34 +571,37 @@ certificate_reporting_test_utils::SetCertReportingOptIn( browser(), certificate_reporting_test_utils::EXTENDED_REPORTING_OPT_IN); - // Let all reports fail. + // Let all reports hang. test_helper()->SetFailureMode( certificate_reporting_test_utils::ReportSendingResult::REPORTS_DELAY); // Trigger a report that hangs. SendReport("report0"); - WaitForReports(ReportExpectation::Delayed({"report0"})); + test_helper()->WaitForRequestsCreated( + ReportExpectation::Delayed({"report0"})); // Disable SafeBrowsing. This should clear all pending reports. ToggleSafeBrowsingAndWaitForServiceReset(false); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Delayed({"report0"})); // Resume delayed report. No response should be observed since all pending // reports should be cleared. - ResumeDelayedRequestAndWait(); - CheckNoReports(); + test_helper()->ResumeDelayedRequest(); + test_helper()->ExpectNoRequests(service()); // Re-enable SafeBrowsing. ToggleSafeBrowsingAndWaitForServiceReset(true); // Trigger a report that hangs. SendReport("report1"); - WaitForReports(ReportExpectation::Delayed({"report1"})); + test_helper()->WaitForRequestsCreated( + ReportExpectation::Delayed({"report1"})); - // Resume delayed report. By the time the runloop is finished, the response - // will be complete and CertificateReportingService will process the - // error/success callback for the report. There will be no inflight reports - // remaining. - ResumeDelayedRequestAndWait(); + // Resume the delayed report and wait for it to complete. + test_helper()->ResumeDelayedRequest(); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Delayed({"report1"})); } } // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/certificate_reporting_service_factory.cc b/chrome/browser/safe_browsing/certificate_reporting_service_factory.cc index 606e05e..e05af7f 100644 --- a/chrome/browser/safe_browsing/certificate_reporting_service_factory.cc +++ b/chrome/browser/safe_browsing/certificate_reporting_service_factory.cc
@@ -60,6 +60,11 @@ max_queued_report_count_ = max_queued_report_count; } +void CertificateReportingServiceFactory::SetServiceResetCallbackForTesting( + const base::Callback<void()>& service_reset_callback) { + service_reset_callback_ = service_reset_callback; +} + CertificateReportingServiceFactory::CertificateReportingServiceFactory() : BrowserContextKeyedServiceFactory( "cert_reporting::Factory", @@ -68,7 +73,8 @@ server_public_key_version_(0), clock_(new base::DefaultClock()), queued_report_ttl_(base::TimeDelta::FromSeconds(kMaxReportAgeInSeconds)), - max_queued_report_count_(kMaxReportCountInQueue) {} + max_queued_report_count_(kMaxReportCountInQueue), + service_reset_callback_(base::Bind(&base::DoNothing)) {} CertificateReportingServiceFactory::~CertificateReportingServiceFactory() {} @@ -80,7 +86,7 @@ safe_browsing_service, safe_browsing_service->url_request_context(), static_cast<Profile*>(profile), server_public_key_, server_public_key_version_, max_queued_report_count_, queued_report_ttl_, - clock_.get()); + clock_.get(), service_reset_callback_); } content::BrowserContext*
diff --git a/chrome/browser/safe_browsing/certificate_reporting_service_factory.h b/chrome/browser/safe_browsing/certificate_reporting_service_factory.h index fe18a5a..63535db6 100644 --- a/chrome/browser/safe_browsing/certificate_reporting_service_factory.h +++ b/chrome/browser/safe_browsing/certificate_reporting_service_factory.h
@@ -30,6 +30,8 @@ void SetClockForTesting(std::unique_ptr<base::Clock> clock); void SetQueuedReportTTLForTesting(base::TimeDelta queued_report_ttl); void SetMaxQueuedReportCountForTesting(size_t max_report_count); + void SetServiceResetCallbackForTesting( + const base::Callback<void()>& service_reset_callback); private: friend struct base::DefaultSingletonTraits< @@ -51,6 +53,7 @@ std::unique_ptr<base::Clock> clock_; base::TimeDelta queued_report_ttl_; size_t max_queued_report_count_; + base::Callback<void()> service_reset_callback_; DISALLOW_COPY_AND_ASSIGN(CertificateReportingServiceFactory); };
diff --git a/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.cc b/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.cc index ccffd40..d7e2f4b 100644 --- a/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.cc +++ b/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.cc
@@ -6,13 +6,12 @@ #include "base/threading/thread_task_runner_handle.h" #include "components/certificate_reporting/encrypted_cert_logger.pb.h" +#include "components/certificate_reporting/error_report.h" #include "content/public/browser/browser_thread.h" #include "content/public/test/test_utils.h" #include "crypto/curve25519.h" #include "net/base/upload_bytes_element_reader.h" #include "net/base/upload_data_stream.h" -#include "net/test/url_request/url_request_failed_job.h" -#include "net/test/url_request/url_request_mock_data_job.h" #include "net/url_request/url_request_filter.h" #include "testing/gtest/include/gtest/gtest.h" @@ -55,16 +54,129 @@ return decrypted_report; } +// Checks that the serialized reports in |observed_reports| have the same +// hostnames as |expected_hostnames|. +void CompareHostnames(const std::set<std::string>& expected_hostnames, + const std::set<std::string>& observed_reports, + const std::string& comparison_type) { + std::set<std::string> observed_hostnames; + for (const std::string& serialized_report : observed_reports) { + certificate_reporting::ErrorReport report; + ASSERT_TRUE(report.InitializeFromString(serialized_report)); + observed_hostnames.insert(report.hostname()); + } + EXPECT_EQ(expected_hostnames, observed_hostnames) + << "Comparison failed for " << comparison_type << " reports."; +} + +void WaitReports( + certificate_reporting_test_utils::RequestObserver* observer, + const certificate_reporting_test_utils::ReportExpectation& expectation) { + observer->Wait(expectation.num_reports()); + CompareHostnames(expectation.successful_reports, + observer->successful_reports(), "successful"); + CompareHostnames(expectation.failed_reports, observer->failed_reports(), + "failed"); + CompareHostnames(expectation.delayed_reports, observer->delayed_reports(), + "delayed"); + observer->ClearObservedReports(); +} + } // namespace namespace certificate_reporting_test_utils { -DelayableCertReportURLRequestJob::DelayableCertReportURLRequestJob( - net::URLRequest* request, - net::NetworkDelegate* network_delegate) - : net::URLRequestJob(request, network_delegate), weak_factory_(this) {} +RequestObserver::RequestObserver() + : num_events_to_wait_for_(0u), num_received_events_(0u) {} +RequestObserver::~RequestObserver() {} -DelayableCertReportURLRequestJob::~DelayableCertReportURLRequestJob() {} +void RequestObserver::Wait(unsigned int num_events_to_wait_for) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(!run_loop_); + ASSERT_LE(num_received_events_, num_events_to_wait_for) + << "Observed unexpected report"; + + if (num_received_events_ < num_events_to_wait_for) { + num_events_to_wait_for_ = num_events_to_wait_for; + run_loop_.reset(new base::RunLoop()); + run_loop_->Run(); + run_loop_.reset(nullptr); + EXPECT_EQ(0u, num_received_events_); + EXPECT_EQ(0u, num_events_to_wait_for_); + } else if (num_received_events_ == num_events_to_wait_for) { + num_received_events_ = 0u; + num_events_to_wait_for_ = 0u; + } +} + +void RequestObserver::OnRequest(const std::string& serialized_report, + ReportSendingResult report_type) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + switch (report_type) { + case REPORTS_SUCCESSFUL: + successful_reports_.insert(serialized_report); + break; + case REPORTS_FAIL: + failed_reports_.insert(serialized_report); + break; + case REPORTS_DELAY: + delayed_reports_.insert(serialized_report); + break; + } + + num_received_events_++; + if (!run_loop_) { + return; + } + ASSERT_LE(num_received_events_, num_events_to_wait_for_) + << "Observed unexpected report"; + + if (num_received_events_ == num_events_to_wait_for_) { + num_events_to_wait_for_ = 0u; + num_received_events_ = 0u; + run_loop_->Quit(); + } +} + +const std::set<std::string>& RequestObserver::successful_reports() const { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + return successful_reports_; +} + +const std::set<std::string>& RequestObserver::failed_reports() const { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + return failed_reports_; +} + +const std::set<std::string>& RequestObserver::delayed_reports() const { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + return delayed_reports_; +} + +void RequestObserver::ClearObservedReports() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + successful_reports_.clear(); + failed_reports_.clear(); + delayed_reports_.clear(); +} + +DelayableCertReportURLRequestJob::DelayableCertReportURLRequestJob( + bool delayed, + bool should_fail, + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const base::Callback<void()>& destruction_callback) + : net::URLRequestJob(request, network_delegate), + delayed_(delayed), + should_fail_(should_fail), + started_(false), + destruction_callback_(destruction_callback), + weak_factory_(this) {} + +DelayableCertReportURLRequestJob::~DelayableCertReportURLRequestJob() { + content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, + destruction_callback_); +} base::WeakPtr<DelayableCertReportURLRequestJob> DelayableCertReportURLRequestJob::GetWeakPtr() { @@ -98,14 +210,17 @@ void DelayableCertReportURLRequestJob::Resume() { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - DCHECK(delayed_); if (!started_) { - // If Start() hasn't been called yet, then unset |delayed_| so - // that when Start() is called, the request will begin - // immediately. + // If Start() hasn't been called yet, then unset |delayed_| so that when + // Start() is called, the request will begin immediately. delayed_ = false; return; } + if (should_fail_) { + NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED, + net::ERR_SSL_PROTOCOL_ERROR)); + return; + } // Start reading asynchronously as would a normal network request. base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, @@ -136,18 +251,29 @@ expected_report_result_)); if (expected_report_result_ == REPORTS_FAIL) { - return new net::URLRequestFailedJob(request, network_delegate, - net::ERR_SSL_PROTOCOL_ERROR); + return new DelayableCertReportURLRequestJob( + false, true, request, network_delegate, + base::Bind(&CertReportJobInterceptor::RequestDestructed, + base::Unretained(this), uploaded_report, + expected_report_result_)); + } else if (expected_report_result_ == REPORTS_DELAY) { DCHECK(!delayed_request_) << "Supports only one delayed request at a time"; DelayableCertReportURLRequestJob* job = - new DelayableCertReportURLRequestJob(request, network_delegate); + new DelayableCertReportURLRequestJob( + true, false, request, network_delegate, + base::Bind(&CertReportJobInterceptor::RequestDestructed, + base::Unretained(this), uploaded_report, + expected_report_result_)); delayed_request_ = job->GetWeakPtr(); return job; } // Successful url request job. - return new net::URLRequestMockDataJob(request, network_delegate, "some data", - 1, false); + return new DelayableCertReportURLRequestJob( + false, false, request, network_delegate, + base::Bind(&CertReportJobInterceptor::RequestDestructed, + base::Unretained(this), uploaded_report, + expected_report_result_)); } void CertReportJobInterceptor::SetFailureMode( @@ -159,41 +285,22 @@ weak_factory_.GetWeakPtr(), expected_report_result)); } -void CertReportJobInterceptor::Resume(const base::Callback<void()>& callback) { +void CertReportJobInterceptor::Resume() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - content::BrowserThread::PostTaskAndReply( + content::BrowserThread::PostTask( content::BrowserThread::IO, FROM_HERE, base::Bind(&CertReportJobInterceptor::ResumeOnIOThread, - base::Unretained(this)), - callback); + base::Unretained(this))); } -const std::set<std::string>& CertReportJobInterceptor::successful_reports() - const { +RequestObserver* CertReportJobInterceptor::request_created_observer() const { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - return successful_reports_; + return &request_created_observer_; } -const std::set<std::string>& CertReportJobInterceptor::failed_reports() const { +RequestObserver* CertReportJobInterceptor::request_destroyed_observer() const { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - return failed_reports_; -} - -const std::set<std::string>& CertReportJobInterceptor::delayed_reports() const { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - return delayed_reports_; -} - -void CertReportJobInterceptor::ClearObservedReports() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - successful_reports_.clear(); - failed_reports_.clear(); - delayed_reports_.clear(); -} - -void CertReportJobInterceptor::WaitForReports(int num_reports) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - wait_helper_.Wait(num_reports); + return &request_destroyed_observer_; } void CertReportJobInterceptor::SetFailureModeOnIOThread( @@ -211,20 +318,15 @@ void CertReportJobInterceptor::RequestCreated( const std::string& uploaded_report, - ReportSendingResult expected_report_result) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - switch (expected_report_result) { - case REPORTS_SUCCESSFUL: - successful_reports_.insert(uploaded_report); - break; - case REPORTS_FAIL: - failed_reports_.insert(uploaded_report); - break; - case REPORTS_DELAY: - delayed_reports_.insert(uploaded_report); - break; - } - wait_helper_.OnEvent(); + ReportSendingResult expected_report_result) const { + request_created_observer_.OnRequest(uploaded_report, expected_report_result); +} + +void CertReportJobInterceptor::RequestDestructed( + const std::string& uploaded_report, + ReportSendingResult expected_report_result) const { + request_destroyed_observer_.OnRequest(uploaded_report, + expected_report_result); } ReportExpectation::ReportExpectation() {} @@ -262,6 +364,29 @@ delayed_reports.size(); } +CertificateReportingServiceObserver::CertificateReportingServiceObserver() {} + +CertificateReportingServiceObserver::~CertificateReportingServiceObserver() {} + +void CertificateReportingServiceObserver::Clear() { + did_reset_ = false; +} + +void CertificateReportingServiceObserver::WaitForReset() { + DCHECK(!run_loop_); + if (did_reset_) + return; + run_loop_.reset(new base::RunLoop()); + run_loop_->Run(); + run_loop_.reset(); +} + +void CertificateReportingServiceObserver::OnServiceReset() { + did_reset_ = true; + if (run_loop_) + run_loop_->Quit(); +} + CertificateReportingServiceTestHelper::CertificateReportingServiceTestHelper() { memset(server_private_key_, 1, sizeof(server_private_key_)); crypto::curve25519::ScalarBaseMult(server_private_key_, server_public_key_); @@ -281,17 +406,15 @@ url_request_interceptor_)))); } -// Changes the behavior of report uploads to fail or succeed. void CertificateReportingServiceTestHelper::SetFailureMode( ReportSendingResult expected_report_result) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); url_request_interceptor_->SetFailureMode(expected_report_result); } -void CertificateReportingServiceTestHelper::ResumeDelayedRequest( - const base::Callback<void()>& callback) { +void CertificateReportingServiceTestHelper::ResumeDelayedRequest() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - url_request_interceptor_->Resume(callback); + url_request_interceptor_->Resume(); } uint8_t* CertificateReportingServiceTestHelper::server_public_key() { @@ -303,41 +426,34 @@ return kServerPublicKeyTestVersion; } -ReportWaitHelper::ReportWaitHelper() - : num_events_to_wait_for_(0), num_received_events_(0) {} -ReportWaitHelper::~ReportWaitHelper() {} - -void ReportWaitHelper::Wait(int num_events_to_wait_for) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - DCHECK(!run_loop_); - ASSERT_LE(num_received_events_, num_events_to_wait_for) - << "Observed unexpected report"; - - if (num_received_events_ < num_events_to_wait_for) { - num_events_to_wait_for_ = num_events_to_wait_for; - run_loop_.reset(new base::RunLoop()); - run_loop_->Run(); - run_loop_.reset(nullptr); - EXPECT_EQ(0, num_received_events_); - EXPECT_EQ(0, num_events_to_wait_for_); - } else if (num_received_events_ == num_events_to_wait_for) { - num_received_events_ = 0; - num_events_to_wait_for_ = 0; - } +void CertificateReportingServiceTestHelper::WaitForRequestsCreated( + const ReportExpectation& expectation) { + WaitReports(interceptor()->request_created_observer(), expectation); } -void ReportWaitHelper::OnEvent() { +void CertificateReportingServiceTestHelper::WaitForRequestsDestroyed( + const ReportExpectation& expectation) { + WaitReports(interceptor()->request_destroyed_observer(), expectation); +} + +void CertificateReportingServiceTestHelper::ExpectNoRequests( + CertificateReportingService* service) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - num_received_events_++; - if (!run_loop_) { - return; - } - ASSERT_LE(num_received_events_, num_events_to_wait_for_) - << "Observed unexpected report"; - if (num_received_events_ == num_events_to_wait_for_) { - num_events_to_wait_for_ = 0; - num_received_events_ = 0; - run_loop_->Quit(); + // Check that all requests have been destroyed. + EXPECT_TRUE(interceptor() + ->request_destroyed_observer() + ->successful_reports() + .empty()); + EXPECT_TRUE( + interceptor()->request_destroyed_observer()->failed_reports().empty()); + EXPECT_TRUE( + interceptor()->request_destroyed_observer()->delayed_reports().empty()); + + if (service->GetReporterForTesting()) { + // Reporter can be null if reporting is disabled. + EXPECT_EQ( + 0u, + service->GetReporterForTesting()->inflight_report_count_for_testing()); } }
diff --git a/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.h b/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.h index 632bec9..33da0bd 100644 --- a/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.h +++ b/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.h
@@ -28,7 +28,7 @@ // Example: // The following expects report0 and report1 to be successfully sent and their // URL requests to be deleted: -// WaitForRequestDeletions( +// WaitForRequestsDestroyed( // ReportExpectation::Successful("report0, report1")); struct ReportExpectation { ReportExpectation(); @@ -47,23 +47,6 @@ std::set<std::string> delayed_reports; }; -// Helper class to wait for a number of events (e.g. request destroyed, report -// observed). -class ReportWaitHelper { - public: - ReportWaitHelper(); - ~ReportWaitHelper(); - // Waits for |num_events_to_wait_for|. - void Wait(int num_events_to_wait_for); - // Must be called when an event is observed. - void OnEvent(); - - private: - int num_events_to_wait_for_; - int num_received_events_; - std::unique_ptr<base::RunLoop> run_loop_; -}; - // Failure mode of the report sending attempts. enum ReportSendingResult { // Report send attempts should be successful. @@ -74,14 +57,51 @@ REPORTS_DELAY, }; +// Helper class to wait for a number of events (e.g. request destroyed, report +// observed). +class RequestObserver { + public: + RequestObserver(); + ~RequestObserver(); + + // Waits for |num_request| requests to be created or destroyed, depending on + // whichever one this class observes. + void Wait(unsigned int num_events_to_wait_for); + + // Called when a request created or destroyed, depending on whichever one this + // class observes. + void OnRequest(const std::string& serialized_report, + ReportSendingResult report_type); + + // These must be called on the UI thread. + const std::set<std::string>& successful_reports() const; + const std::set<std::string>& failed_reports() const; + const std::set<std::string>& delayed_reports() const; + void ClearObservedReports(); + + private: + unsigned int num_events_to_wait_for_; + unsigned int num_received_events_; + std::unique_ptr<base::RunLoop> run_loop_; + + std::set<std::string> successful_reports_; + std::set<std::string> failed_reports_; + std::set<std::string> delayed_reports_; +}; + // A URLRequestJob that can be delayed until Resume() is called. Returns an // empty response. If Resume() is called before a request is made, then the -// request will not be delayed. +// request will not be delayed. If not delayed, it can return a failed or a +// successful URL request job. class DelayableCertReportURLRequestJob : public net::URLRequestJob, public base::NonThreadSafe { public: - DelayableCertReportURLRequestJob(net::URLRequest* request, - net::NetworkDelegate* network_delegate); + DelayableCertReportURLRequestJob( + bool delayed, + bool should_fail, + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const base::Callback<void()>& destruction_callback); ~DelayableCertReportURLRequestJob() override; base::WeakPtr<DelayableCertReportURLRequestJob> GetWeakPtr(); @@ -98,8 +118,10 @@ void Resume(); private: - bool delayed_ = true; - bool started_ = false; + bool delayed_; + bool should_fail_; + bool started_; + base::Callback<void()> destruction_callback_; base::WeakPtrFactory<DelayableCertReportURLRequestJob> weak_factory_; DISALLOW_COPY_AND_ASSIGN(DelayableCertReportURLRequestJob); @@ -122,35 +144,30 @@ void SetFailureMode(ReportSendingResult expected_report_result); // Resumes any hanging URL request and runs callback when the request // is resumed (i.e. response starts). Must be called on the UI thread. - void Resume(const base::Closure& callback); + void Resume(); - // These must be called on the UI thread. - const std::set<std::string>& successful_reports() const; - const std::set<std::string>& failed_reports() const; - const std::set<std::string>& delayed_reports() const; - void ClearObservedReports(); - - // Waits for requests for |num_reports| reports to be created. Only used in - // browser tests. Unit tests wait for requests to be destroyed instead. - // Must be called on the UI thread. - void WaitForReports(int num_reports); + RequestObserver* request_created_observer() const; + RequestObserver* request_destroyed_observer() const; private: void SetFailureModeOnIOThread(ReportSendingResult expected_report_result); void ResumeOnIOThread(); void RequestCreated(const std::string& uploaded_report, - ReportSendingResult expected_report_result); + ReportSendingResult expected_report_result) const; + void RequestDestructed(const std::string& uploaded_report, + ReportSendingResult expected_report_result) const; - std::set<std::string> successful_reports_; - std::set<std::string> failed_reports_; - std::set<std::string> delayed_reports_; + mutable std::set<std::string> successful_reports_; + mutable std::set<std::string> failed_reports_; + mutable std::set<std::string> delayed_reports_; ReportSendingResult expected_report_result_; // Private key to decrypt certificate reports. const uint8_t* server_private_key_; - ReportWaitHelper wait_helper_; + mutable RequestObserver request_created_observer_; + mutable RequestObserver request_destroyed_observer_; mutable base::WeakPtr<DelayableCertReportURLRequestJob> delayed_request_ = nullptr; @@ -159,20 +176,24 @@ DISALLOW_COPY_AND_ASSIGN(CertReportJobInterceptor); }; -// A network delegate used to observe URL request destructions. The tests check -// that no outstanding URL request is present during tear down. -class CertificateReportingServiceTestNetworkDelegate - : public net::NetworkDelegateImpl { +// Class to wait for the CertificateReportingService to reset. +class CertificateReportingServiceObserver { public: - CertificateReportingServiceTestNetworkDelegate( - const base::Callback<void()>& url_request_destroyed_callback); - ~CertificateReportingServiceTestNetworkDelegate() override; + CertificateReportingServiceObserver(); + ~CertificateReportingServiceObserver(); - // net::NetworkDelegate method: - void OnURLRequestDestroyed(net::URLRequest* request) override; + // Clears the state of the observer. Must be called before waiting each time. + void Clear(); + + // Waits for the service to reset. + void WaitForReset(); + + // Must be called when the service is reset. + void OnServiceReset(); private: - base::Callback<void()> url_request_destroyed_callback_; + bool did_reset_ = false; + std::unique_ptr<base::RunLoop> run_loop_; }; // Base class for CertificateReportingService tests. Sets up an interceptor to @@ -189,14 +210,20 @@ // Resumes delayed report request. Failure mode should be REPORTS_DELAY when // calling this method. - void ResumeDelayedRequest(const base::Callback<void()>& callback); + void ResumeDelayedRequest(); + + void WaitForRequestsCreated(const ReportExpectation& expectation); + void WaitForRequestsDestroyed(const ReportExpectation& expectation); + + // Checks that all requests are destroyed and that there are no in-flight + // reports in |service|. + void ExpectNoRequests(CertificateReportingService* service); uint8_t* server_public_key(); uint32_t server_public_key_version() const; - CertReportJobInterceptor* interceptor() { return url_request_interceptor_; } - private: + CertReportJobInterceptor* interceptor() { return url_request_interceptor_; } void SetUpInterceptorOnIOThread(); CertReportJobInterceptor* url_request_interceptor_;
diff --git a/chrome/browser/safe_browsing/certificate_reporting_service_unittest.cc b/chrome/browser/safe_browsing/certificate_reporting_service_unittest.cc index 8ef06293d..e9a6e02 100644 --- a/chrome/browser/safe_browsing/certificate_reporting_service_unittest.cc +++ b/chrome/browser/safe_browsing/certificate_reporting_service_unittest.cc
@@ -6,6 +6,7 @@ #include <string> +#include "base/atomic_sequence_num.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/run_loop.h" @@ -19,10 +20,14 @@ #include "chrome/browser/safe_browsing/safe_browsing_service.h" #include "chrome/browser/safe_browsing/test_safe_browsing_service.h" #include "chrome/test/base/testing_profile.h" +#include "components/certificate_reporting/error_report.h" #include "content/public/browser/browser_thread.h" #include "content/public/test/test_browser_thread.h" #include "content/public/test/test_browser_thread_bundle.h" -#include "net/base/network_delegate_impl.h" +#include "crypto/rsa_private_key.h" +#include "net/cert/x509_certificate.h" +#include "net/cert/x509_util.h" +#include "net/ssl/ssl_info.h" #include "net/test/url_request/url_request_failed_job.h" #include "net/test/url_request/url_request_mock_data_job.h" #include "net/url_request/url_request_filter.h" @@ -30,6 +35,7 @@ #include "testing/gtest/include/gtest/gtest.h" using certificate_reporting_test_utils::CertificateReportingServiceTestHelper; +using certificate_reporting_test_utils::CertificateReportingServiceObserver; using certificate_reporting_test_utils::ReportExpectation; namespace { @@ -40,32 +46,41 @@ const char* kFailedReportHistogram = "SSL.CertificateErrorReportFailure"; +// NSS requires that serial numbers be unique even for the same issuer; +// as all fake certificates will contain the same issuer name, it's +// necessary to ensure the serial number is unique, as otherwise +// NSS will fail to parse. +base::StaticAtomicSequenceNumber g_serial_number; + +scoped_refptr<net::X509Certificate> CreateFakeCert() { + std::unique_ptr<crypto::RSAPrivateKey> unused_key; + std::string cert_der; + if (!net::x509_util::CreateKeyAndSelfSignedCert( + "CN=Error", static_cast<uint32_t>(g_serial_number.GetNext()), + base::Time::Now() - base::TimeDelta::FromMinutes(5), + base::Time::Now() + base::TimeDelta::FromMinutes(5), &unused_key, + &cert_der)) { + return nullptr; + } + return net::X509Certificate::CreateFromBytes(cert_der.data(), + cert_der.size()); +} + +std::string MakeReport(const std::string& hostname) { + net::SSLInfo ssl_info; + ssl_info.cert = ssl_info.unverified_cert = CreateFakeCert(); + + certificate_reporting::ErrorReport report(hostname, ssl_info); + std::string serialized_report; + EXPECT_TRUE(report.Serialize(&serialized_report)); + return serialized_report; +} + void ClearURLHandlers() { net::URLRequestFilter::GetInstance()->ClearHandlers(); } -// A network delegate used to observe URL request destructions. The tests check -// that no outstanding URL request is present during tear down. -class TestNetworkDelegate : public net::NetworkDelegateImpl { - public: - TestNetworkDelegate( - const base::Callback<void()>& url_request_destroyed_callback) - : url_request_destroyed_callback_(url_request_destroyed_callback) {} - - ~TestNetworkDelegate() override {} - - // net::NetworkDelegate method: - void OnURLRequestDestroyed(net::URLRequest* request) override { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - url_request_destroyed_callback_); - } - - private: - base::Callback<void()> url_request_destroyed_callback_; -}; - -// Base class for histogram testing. The failed report histogram is checked once +// Class for histogram testing. The failed report histogram is checked once // after teardown to ensure all in flight requests have completed. class ReportHistogramTestHelper { public: @@ -122,8 +137,7 @@ // Adding a report older than the oldest report in the list (report2) is // a no-op. list.Add(CertificateReportingService::Report( - 0, base::Time::Now() - base::TimeDelta::FromMinutes( - 10) /* 5 minutes older than report2 */, + 0, base::Time::Now() - base::TimeDelta::FromMinutes(10), std::string("report0_ten_minutes_old"))); EXPECT_EQ(2u, list.items().size()); EXPECT_EQ("report3_zero_minutes_old", list.items()[0].serialized_report); @@ -325,6 +339,7 @@ ~CertificateReportingServiceTest() override {} void SetUp() override { + service_observer_.Clear(); test_helper_.SetUpInterceptor(); WaitForIOThread(); @@ -343,19 +358,15 @@ sb_service_.get(), url_request_context_getter(), &profile_, test_helper_.server_public_key(), test_helper_.server_public_key_version(), kMaxReportCountInQueue, - base::TimeDelta::FromHours(24), clock_.get())); - // Wait for service reset. - WaitForIOThread(); + base::TimeDelta::FromHours(24), clock_.get(), + base::Bind(&CertificateReportingServiceObserver::OnServiceReset, + base::Unretained(&service_observer_)))); + service_observer_.WaitForReset(); } void TearDown() override { WaitForIOThread(); - EXPECT_TRUE(test_helper_.interceptor()->successful_reports().empty()); - EXPECT_TRUE(test_helper_.interceptor()->failed_reports().empty()); - EXPECT_TRUE(test_helper_.interceptor()->delayed_reports().empty()); - EXPECT_EQ(0u, service() - ->GetReporterForTesting() - ->inflight_report_count_for_testing()); + test_helper()->ExpectNoRequests(service()); service_->Shutdown(); WaitForIOThread(); @@ -373,17 +384,6 @@ } protected: - void WaitForRequestsDestroyed(const ReportExpectation& expectation) { - wait_helper_.Wait(expectation.num_reports()); - EXPECT_EQ(expectation.successful_reports, - test_helper_.interceptor()->successful_reports()); - EXPECT_EQ(expectation.failed_reports, - test_helper_.interceptor()->failed_reports()); - EXPECT_EQ(expectation.delayed_reports, - test_helper_.interceptor()->delayed_reports()); - test_helper_.interceptor()->ClearObservedReports(); - } - net::URLRequestContextGetter* url_request_context_getter() { return url_request_context_getter_.get(); } @@ -398,8 +398,9 @@ // Sets service enabled state and waits for a reset event. void SetServiceEnabledAndWait(bool enabled) { + service_observer_.Clear(); service()->SetEnabled(enabled); - WaitForIOThread(); + service_observer_.WaitForReset(); } void AdvanceClock(base::TimeDelta delta) { @@ -424,34 +425,19 @@ private: void SetUpURLRequestContextOnIOThread() { - network_delegate_.reset(new TestNetworkDelegate( - base::Bind(&CertificateReportingServiceTest::OnURLRequestDestroyed, - base::Unretained(this)))); - std::unique_ptr<net::TestURLRequestContext> url_request_context( - new net::TestURLRequestContext(true)); - url_request_context->set_network_delegate(network_delegate_.get()); - url_request_context->Init(); + new net::TestURLRequestContext(false)); url_request_context_getter_ = new net::TestURLRequestContextGetter( io_task_runner_, std::move(url_request_context)); } void TearDownOnIOThread() { url_request_context_getter_ = nullptr; - network_delegate_.reset(nullptr); - } - - void OnURLRequestDestroyed() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - wait_helper_.OnEvent(); } // Must be initialized before url_request_context_getter_ content::TestBrowserThreadBundle thread_bundle_; - std::unique_ptr<TestNetworkDelegate> network_delegate_; - certificate_reporting_test_utils::ReportWaitHelper wait_helper_; - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_; @@ -464,6 +450,7 @@ CertificateReportingServiceTestHelper test_helper_; ReportHistogramTestHelper histogram_test_helper_; + CertificateReportingServiceObserver service_observer_; }; TEST_F(CertificateReportingServiceTest, Send) { @@ -474,29 +461,29 @@ certificate_reporting_test_utils::ReportSendingResult::REPORTS_FAIL); // Send two reports. Both should fail and get queued. - service()->Send("report0"); - WaitForRequestsDestroyed(ReportExpectation::Failed({"report0"})); + service()->Send(MakeReport("report0")); + service()->Send(MakeReport("report1")); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Failed({"report0", "report1"})); - service()->Send("report1"); - WaitForRequestsDestroyed(ReportExpectation::Failed({"report1"})); - - // Send pending reports. Previously queued reports should be observed. They - // will also be queued again. + // Send pending reports. Previously queued reports should be queued again. service()->SendPending(); - WaitForRequestsDestroyed(ReportExpectation::Failed({"report0", "report1"})); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Failed({"report0", "report1"})); // Let all reports succeed. test_helper()->SetFailureMode(certificate_reporting_test_utils:: ReportSendingResult::REPORTS_SUCCESSFUL); // Send a third report. This should not be queued. - service()->Send("report2"); - WaitForRequestsDestroyed(ReportExpectation::Successful({"report2"})); + service()->Send(MakeReport("report2")); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Successful({"report2"})); // Send pending reports. Previously failed and queued two reports should be // observed. service()->SendPending(); - WaitForRequestsDestroyed( + test_helper()->WaitForRequestsDestroyed( ReportExpectation::Successful({"report0", "report1"})); } @@ -512,13 +499,14 @@ // Send a report. Report attempt should be cancelled and no sent reports // should be observed. - service()->Send("report0"); + service()->Send(MakeReport("report0")); // Enable the service and send a report again. It should be sent successfully. SetServiceEnabledAndWait(true); - service()->Send("report1"); - WaitForRequestsDestroyed(ReportExpectation::Successful({"report1"})); + service()->Send(MakeReport("report1")); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Successful({"report1"})); } TEST_F(CertificateReportingServiceTest, Disabled_ShouldClearPendingReports) { @@ -528,8 +516,9 @@ test_helper()->SetFailureMode( certificate_reporting_test_utils::ReportSendingResult::REPORTS_FAIL); - service()->Send("report0"); - WaitForRequestsDestroyed(ReportExpectation::Failed({"report0"})); + service()->Send(MakeReport("report0")); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Failed({"report0"})); // Disable the service. SetServiceEnabledAndWait(false); @@ -553,15 +542,12 @@ test_helper()->SetFailureMode( certificate_reporting_test_utils::ReportSendingResult::REPORTS_FAIL); - // Send a report. - service()->Send("report0"); - WaitForRequestsDestroyed(ReportExpectation::Failed({"report0"})); - - // Advance the clock a bit and trigger another report. + // Send a report, then advance the clock and send another report. + service()->Send(MakeReport("report0")); AdvanceClock(base::TimeDelta::FromHours(5)); - - service()->Send("report1"); - WaitForRequestsDestroyed(ReportExpectation::Failed({"report1"})); + service()->Send(MakeReport("report1")); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Failed({"report0", "report1"})); // Advance the clock to 20 hours, putting it 25 hours ahead of the reference // time. This makes the report0 older than max age (24 hours). The report1 is @@ -570,18 +556,21 @@ // Send pending reports. report0 should be discarded since it's too old. // report1 should be queued again. service()->SendPending(); - WaitForRequestsDestroyed(ReportExpectation::Failed({"report1"})); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Failed({"report1"})); // Send a third report. - service()->Send("report2"); - WaitForRequestsDestroyed(ReportExpectation::Failed({"report2"})); + service()->Send(MakeReport("report2")); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Failed({"report2"})); // Advance the clock 5 hours. The report1 will now be 25 hours old. AdvanceClock(base::TimeDelta::FromHours(5)); // Send pending reports. report1 should be discarded since it's too old. // report2 should be queued again. service()->SendPending(); - WaitForRequestsDestroyed(ReportExpectation::Failed({"report2"})); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Failed({"report2"})); // Advance the clock 20 hours again so that report2 is 25 hours old and is // older than max age (24 hours) @@ -599,31 +588,29 @@ test_helper()->SetFailureMode( certificate_reporting_test_utils::ReportSendingResult::REPORTS_FAIL); - // Send a failed report. - service()->Send("report0"); - WaitForRequestsDestroyed(ReportExpectation::Failed({"report0"})); - // Send three more reports within five hours of each other. After this: // report0 is 0 hours after reference time (15 hours old). // report1 is 5 hours after reference time (10 hours old). // report2 is 10 hours after reference time (5 hours old). // report3 is 15 hours after reference time (0 hours old). - AdvanceClock(base::TimeDelta::FromHours(5)); - service()->Send("report1"); + service()->Send(MakeReport("report0")); AdvanceClock(base::TimeDelta::FromHours(5)); - service()->Send("report2"); + service()->Send(MakeReport("report1")); AdvanceClock(base::TimeDelta::FromHours(5)); - service()->Send("report3"); - WaitForRequestsDestroyed( - ReportExpectation::Failed({"report1", "report2", "report3"})); + service()->Send(MakeReport("report2")); + + AdvanceClock(base::TimeDelta::FromHours(5)); + service()->Send(MakeReport("report3")); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Failed({"report0", "report1", "report2", "report3"})); // Send pending reports. Four reports were generated above, but the service // only queues three reports, so the very first one should be dropped since // it's the oldest. service()->SendPending(); - WaitForRequestsDestroyed( + test_helper()->WaitForRequestsDestroyed( ReportExpectation::Failed({"report1", "report2", "report3"})); // Let all reports succeed. @@ -639,7 +626,7 @@ // Send pending reports. Only report2 and report3 should be sent, report1 // should be ignored because it's too old. service()->SendPending(); - WaitForRequestsDestroyed( + test_helper()->WaitForRequestsDestroyed( ReportExpectation::Successful({"report2", "report3"})); // Do a final send. No reports should be sent. @@ -655,12 +642,13 @@ certificate_reporting_test_utils::ReportSendingResult::REPORTS_DELAY); // Send a report. The report upload hangs, so no error or success callbacks // should be called. - service()->Send("report0"); + service()->Send(MakeReport("report0")); // Resume the report upload and run the callbacks. The report should be // successfully sent. - test_helper()->ResumeDelayedRequest(base::Bind(&base::DoNothing)); - WaitForRequestsDestroyed(ReportExpectation::Delayed({"report0"})); + test_helper()->ResumeDelayedRequest(); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Delayed({"report0"})); } // Delayed reports should cleaned when the service is reset. @@ -672,7 +660,7 @@ certificate_reporting_test_utils::ReportSendingResult::REPORTS_DELAY); // Send a report. The report is triggered but hangs, so no error or success // callbacks should be called. - service()->Send("report0"); + service()->Send(MakeReport("report0")); // Disable the service. This should reset the reporting service and // clear all pending reports. @@ -680,8 +668,8 @@ // Resume delayed report. No report should be observed since the service // should have reset and all pending reports should be cleared. If any report - // is observed, the next WaitForRequestsDestroyed() will fail. - test_helper()->ResumeDelayedRequest(base::Bind(&base::DoNothing)); + // is observed, the next test_helper()->WaitForRequestsDestroyed() will fail. + test_helper()->ResumeDelayedRequest(); // Enable the service. SetServiceEnabledAndWait(true); @@ -689,9 +677,10 @@ // Send a report. The report is triggered but hangs, so no error or success // callbacks should be called. The report id is again 0 since the pending // report queue has been cleared above. - service()->Send("report1"); + service()->Send(MakeReport("report1")); // Resume delayed report. Two reports are successfully sent. - test_helper()->ResumeDelayedRequest(base::Bind(&base::DoNothing)); - WaitForRequestsDestroyed(ReportExpectation::Delayed({"report0", "report1"})); + test_helper()->ResumeDelayedRequest(); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Delayed({"report0", "report1"})); }
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc index bad033e..d5077fd 100644 --- a/chrome/browser/sync/chrome_sync_client.cc +++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -250,6 +250,10 @@ profile_, ServiceAccessType::EXPLICIT_ACCESS); } +bool ChromeSyncClient::HasPasswordStore() { + return password_store_ != nullptr; +} + autofill::PersonalDataManager* ChromeSyncClient::GetPersonalDataManager() { DCHECK_CURRENTLY_ON(BrowserThread::UI); return autofill::PersonalDataManagerFactory::GetForProfile(profile_);
diff --git a/chrome/browser/sync/chrome_sync_client.h b/chrome/browser/sync/chrome_sync_client.h index 483fed5..4004061 100644 --- a/chrome/browser/sync/chrome_sync_client.h +++ b/chrome/browser/sync/chrome_sync_client.h
@@ -42,6 +42,7 @@ bookmarks::BookmarkModel* GetBookmarkModel() override; favicon::FaviconService* GetFaviconService() override; history::HistoryService* GetHistoryService() override; + bool HasPasswordStore() override; base::Closure GetPasswordStateChangedCallback() override; syncer::SyncApiComponentFactory::RegisterDataTypesMethod GetRegisterPlatformTypesCallback() override;
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc index 9c9392d..bf25719 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -6,7 +6,7 @@ #include "base/memory/ptr_util.h" #include "chrome/browser/extensions/extension_app_icon_loader.h" -#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/app_list/arc/arc_app_icon_loader.h" #include "chrome/browser/ui/ash/ash_util.h" #include "chrome/browser/ui/ash/chrome_launcher_prefs.h" @@ -80,7 +80,7 @@ return; // The pref helper functions return default values for invalid display ids. - PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs(); + PrefService* prefs = profile_->GetPrefs(); for (const auto& display : display::Screen::GetScreen()->GetAllDisplays()) { shelf_controller_->SetAutoHideBehavior( ash::launcher::GetShelfAutoHideBehaviorPref(prefs, display.id()), @@ -93,7 +93,7 @@ return; // The pref helper functions return default values for invalid display ids. - PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs(); + PrefService* prefs = profile_->GetPrefs(); for (const auto& display : display::Screen::GetScreen()->GetAllDisplays()) { shelf_controller_->SetAlignment( ash::launcher::GetShelfAlignmentPref(prefs, display.id()),
diff --git a/chrome/browser/ui/libgtkui/gtk_util.cc b/chrome/browser/ui/libgtkui/gtk_util.cc index 826af71..81fefa61 100644 --- a/chrome/browser/ui/libgtkui/gtk_util.cc +++ b/chrome/browser/ui/libgtkui/gtk_util.cc
@@ -394,6 +394,13 @@ cairo_t* cairo_; }; +void RenderBackground(cairo_t* cr, GtkStyleContext* context) { + if (!context) + return; + RenderBackground(cr, gtk_style_context_get_parent(context)); + gtk_render_background(context, cr, 0, 0, 1, 1); +} + SkColor GetBgColor(const char* css_selector) { // Backgrounds are more general than solid colors (eg. gradients), // but chromium requires us to boil this down to one color. We @@ -404,7 +411,7 @@ auto context = GetStyleContextFromCss(css_selector); RemoveBorders(context); PixelSurface surface; - gtk_render_background(context, surface.cairo(), 0, 0, 1, 1); + RenderBackground(surface.cairo(), context); return surface.GetPixelValue(); } @@ -426,6 +433,7 @@ AddBorders(context); PixelSurface surface; + RenderBackground(surface.cairo(), context); gtk_render_frame(context, surface.cairo(), 0, 0, 1, 1); return surface.GetPixelValue(); }
diff --git a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc index 6ae46d3..481e367b 100644 --- a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc +++ b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
@@ -307,8 +307,8 @@ DISALLOW_COPY_AND_ASSIGN(InstantPolicyTest); }; -// Flaky on Windows in the CQ: https://crbug.com/678975 -#if defined(OS_WIN) +// Flaky on Windows in the CQ and Linux memory bot: https://crbug.com/678975 +#if defined(OS_WIN) || defined(OS_LINUX) #define MAYBE_SearchDoesntReuseInstantTab DISABLED_SearchDoesntReuseInstantTab #else #define MAYBE_SearchDoesntReuseInstantTab SearchDoesntReuseInstantTab
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc index ef876004..5ed6dc0 100644 --- a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc +++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
@@ -334,6 +334,13 @@ if (browser && browser->window()) browser->window()->Activate(); } + } else if (source.type == DesktopMediaID::TYPE_WINDOW) { +#if defined(USE_AURA) + aura::Window* window = DesktopMediaID::GetAuraWindowById(source); + Browser* browser = chrome::FindBrowserWithWindow(window); + if (browser && browser->window()) + browser->window()->Activate(); +#endif } if (parent_)
diff --git a/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc b/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc index 0f41cca..b263e5b 100644 --- a/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc +++ b/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc
@@ -173,6 +173,9 @@ private: friend class WebsiteSettingsPopupView; + // Used around icon and inside bubble border. + static constexpr int kSpacing = 12; + DISALLOW_COPY_AND_ASSIGN(InternalPageInfoPopupView); }; @@ -354,7 +357,6 @@ set_anchor_view_insets(gfx::Insets( GetLayoutConstant(LOCATION_BAR_BUBBLE_ANCHOR_VERTICAL_INSET), 0)); - const int kSpacing = 16; SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, kSpacing, kSpacing, kSpacing)); set_margins(gfx::Insets()); @@ -379,9 +381,9 @@ views::Widget* widget) { views::BubbleFrameView* frame = static_cast<views::BubbleFrameView*>( BubbleDialogDelegateView::CreateNonClientFrameView(widget)); - // 16px padding + half of icon width comes out to 24px. + // Padding around icon + half of icon width. frame->bubble_border()->set_arrow_offset( - 24 + frame->bubble_border()->GetBorderThickness()); + kSpacing + 8 + frame->bubble_border()->GetBorderThickness()); return frame; }
diff --git a/chrome/installer/linux/debian/expected_deps_ia32_jessie b/chrome/installer/linux/debian/expected_deps_ia32_jessie index 6e6d44c..600a2ea 100644 --- a/chrome/installer/linux/debian/expected_deps_ia32_jessie +++ b/chrome/installer/linux/debian/expected_deps_ia32_jessie
@@ -2,7 +2,7 @@ libasound2 (>= 1.0.16) libatk1.0-0 (>= 1.12.4) libc6 (>= 2.11) -libcairo2 (>= 1.6.0) +libcairo2 (>= 1.2.4) libcups2 (>= 1.4.0) libdbus-1-3 (>= 1.2.14) libexpat1 (>= 2.0.1)
diff --git a/chrome/installer/linux/debian/expected_deps_ia32_wheezy b/chrome/installer/linux/debian/expected_deps_ia32_wheezy index 6e6d44c..600a2ea 100644 --- a/chrome/installer/linux/debian/expected_deps_ia32_wheezy +++ b/chrome/installer/linux/debian/expected_deps_ia32_wheezy
@@ -2,7 +2,7 @@ libasound2 (>= 1.0.16) libatk1.0-0 (>= 1.12.4) libc6 (>= 2.11) -libcairo2 (>= 1.6.0) +libcairo2 (>= 1.2.4) libcups2 (>= 1.4.0) libdbus-1-3 (>= 1.2.14) libexpat1 (>= 2.0.1)
diff --git a/chrome/installer/linux/debian/expected_deps_x64_jessie b/chrome/installer/linux/debian/expected_deps_x64_jessie index 87c2fc50..ab8362a 100644 --- a/chrome/installer/linux/debian/expected_deps_x64_jessie +++ b/chrome/installer/linux/debian/expected_deps_x64_jessie
@@ -2,7 +2,7 @@ libasound2 (>= 1.0.16) libatk1.0-0 (>= 1.12.4) libc6 (>= 2.15) -libcairo2 (>= 1.6.0) +libcairo2 (>= 1.2.4) libcups2 (>= 1.4.0) libdbus-1-3 (>= 1.1.4) libexpat1 (>= 2.0.1)
diff --git a/chrome/installer/linux/debian/expected_deps_x64_wheezy b/chrome/installer/linux/debian/expected_deps_x64_wheezy index b23857d..98c6bd6 100644 --- a/chrome/installer/linux/debian/expected_deps_x64_wheezy +++ b/chrome/installer/linux/debian/expected_deps_x64_wheezy
@@ -2,7 +2,7 @@ libasound2 (>= 1.0.16) libatk1.0-0 (>= 1.12.4) libc6 (>= 2.11) -libcairo2 (>= 1.6.0) +libcairo2 (>= 1.2.4) libcups2 (>= 1.4.0) libdbus-1-3 (>= 1.1.4) libexpat1 (>= 2.0.1)
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc index c675e6ee..7e21f0d4 100644 --- a/chromecast/browser/cast_content_browser_client.cc +++ b/chromecast/browser/cast_content_browser_client.cc
@@ -163,6 +163,22 @@ DCHECK(cast_browser_main_parts_); return cast_browser_main_parts_->media_pipeline_backend_manager(); } + +::media::ScopedAudioManagerPtr CastContentBrowserClient::CreateAudioManager( + ::media::AudioLogFactory* audio_log_factory) { + return ::media::ScopedAudioManagerPtr(new media::CastAudioManager( + GetMediaTaskRunner(), GetMediaTaskRunner(), audio_log_factory, + media_pipeline_backend_manager())); +} + +std::unique_ptr<::media::CdmFactory> +CastContentBrowserClient::CreateCdmFactory() { +#if defined(ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS) + return base::MakeUnique<media::CastCdmFactory>(GetMediaTaskRunner(), + media_resource_tracker()); +#endif // defined(ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS) + return nullptr; +} #endif // !defined(OS_ANDROID) media::MediaCapsImpl* CastContentBrowserClient::media_caps() { @@ -443,19 +459,15 @@ return base::JSONReader::Read(manifest_contents); } -#if defined(OS_ANDROID) - void CastContentBrowserClient::GetAdditionalMappedFilesForChildProcess( const base::CommandLine& command_line, int child_process_id, - content::FileDescriptorInfo* mappings, - std::map<int, base::MemoryMappedFile::Region>* regions) { - mappings->Share( + content::FileDescriptorInfo* mappings) { +#if defined(OS_ANDROID) + mappings->ShareWithRegion( kAndroidPakDescriptor, - base::GlobalDescriptors::GetInstance()->Get(kAndroidPakDescriptor)); - regions->insert(std::make_pair( - kAndroidPakDescriptor, base::GlobalDescriptors::GetInstance()->GetRegion( - kAndroidPakDescriptor))); + base::GlobalDescriptors::GetInstance()->Get(kAndroidPakDescriptor), + base::GlobalDescriptors::GetInstance()->GetRegion(kAndroidPakDescriptor)); if (breakpad::IsCrashReporterEnabled()) { base::File minidump_file( @@ -469,36 +481,13 @@ base::ScopedFD(minidump_file.TakePlatformFile())); } } -} - #else -::media::ScopedAudioManagerPtr CastContentBrowserClient::CreateAudioManager( - ::media::AudioLogFactory* audio_log_factory) { - return ::media::ScopedAudioManagerPtr(new media::CastAudioManager( - GetMediaTaskRunner(), GetMediaTaskRunner(), audio_log_factory, - media_pipeline_backend_manager())); -} - -std::unique_ptr<::media::CdmFactory> -CastContentBrowserClient::CreateCdmFactory() { -#if defined(ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS) - return base::MakeUnique<media::CastCdmFactory>(GetMediaTaskRunner(), - media_resource_tracker()); -#endif // defined(ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS) - return nullptr; -} - -void CastContentBrowserClient::GetAdditionalMappedFilesForChildProcess( - const base::CommandLine& command_line, - int child_process_id, - content::FileDescriptorInfo* mappings) { - int crash_signal_fd = GetCrashSignalFD(command_line); + int crash_signal_fd = GetCrashSignalFD(command_line); if (crash_signal_fd >= 0) { mappings->Share(kCrashDumpSignal, crash_signal_fd); } -} - #endif // defined(OS_ANDROID) +} void CastContentBrowserClient::GetAdditionalWebUISchemes( std::vector<std::string>* additional_schemes) {
diff --git a/chromecast/browser/cast_content_browser_client.h b/chromecast/browser/cast_content_browser_client.h index 38f97c8d..5515558f5 100644 --- a/chromecast/browser/cast_content_browser_client.h +++ b/chromecast/browser/cast_content_browser_client.h
@@ -91,6 +91,10 @@ media::MediaResourceTracker* media_resource_tracker(); media::MediaPipelineBackendManager* media_pipeline_backend_manager(); + + ::media::ScopedAudioManagerPtr CreateAudioManager( + ::media::AudioLogFactory* audio_log_factory) override; + std::unique_ptr<::media::CdmFactory> CreateCdmFactory() override; #endif media::MediaCapsImpl* media_caps(); @@ -153,21 +157,10 @@ void RegisterInProcessServices(StaticServiceMap* services) override; std::unique_ptr<base::Value> GetServiceManifestOverlay( base::StringPiece service_name) override; -#if defined(OS_ANDROID) - void GetAdditionalMappedFilesForChildProcess( - const base::CommandLine& command_line, - int child_process_id, - content::FileDescriptorInfo* mappings, - std::map<int, base::MemoryMappedFile::Region>* regions) override; -#else - ::media::ScopedAudioManagerPtr CreateAudioManager( - ::media::AudioLogFactory* audio_log_factory) override; - std::unique_ptr<::media::CdmFactory> CreateCdmFactory() override; void GetAdditionalMappedFilesForChildProcess( const base::CommandLine& command_line, int child_process_id, content::FileDescriptorInfo* mappings) override; -#endif // defined(OS_ANDROID) void GetAdditionalWebUISchemes( std::vector<std::string>* additional_schemes) override; content::DevToolsManagerDelegate* GetDevToolsManagerDelegate() override;
diff --git a/components/autofill/core/browser/proto/BUILD.gn b/components/autofill/core/browser/proto/BUILD.gn index ad52e78..2a8069f6 100644 --- a/components/autofill/core/browser/proto/BUILD.gn +++ b/components/autofill/core/browser/proto/BUILD.gn
@@ -6,6 +6,7 @@ proto_library("proto") { sources = [ + "autofill_sync.proto", "server.proto", ] }
diff --git a/components/autofill/core/browser/proto/autofill_sync.proto b/components/autofill/core/browser/proto/autofill_sync.proto new file mode 100644 index 0000000..613bdbac --- /dev/null +++ b/components/autofill/core/browser/proto/autofill_sync.proto
@@ -0,0 +1,17 @@ +// 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. + +syntax = "proto2"; + +option optimize_for = LITE_RUNTIME; + +package autofill; + +// Used to convert between autofill::AutofillKey and a std::string that can be +// passed to sync as storage key to uniquely identify an entity of ModelType +// syncer::AUTOFILL. +message AutofillSyncStorageKey { + optional string name = 1; + optional string value = 2; +}
diff --git a/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc b/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc index 9b8e201..2edafc505 100644 --- a/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc +++ b/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
@@ -5,10 +5,13 @@ #include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h" #include <unordered_set> +#include <utility> +#include <vector> #include "base/bind.h" #include "base/memory/ptr_util.h" #include "base/strings/utf_string_conversions.h" +#include "components/autofill/core/browser/proto/autofill_sync.pb.h" #include "components/autofill/core/browser/webdata/autofill_metadata_change_list.h" #include "components/autofill/core/browser/webdata/autofill_table.h" #include "components/autofill/core/browser/webdata/autofill_webdata_backend.h" @@ -19,9 +22,12 @@ #include "components/sync/model/sync_error.h" #include "net/base/escape.h" +namespace autofill { + namespace { const char kAutocompleteEntryNamespaceTag[] = "autofill_entry|"; +const char kAutocompleteTagDelimiter[] = "|"; void* UserDataKey() { // Use the address of a static that COMDAT folding won't ever collide @@ -31,7 +37,7 @@ } std::unique_ptr<syncer::EntityData> CreateEntityData( - const autofill::AutofillEntry& entry) { + const AutofillEntry& entry) { auto entity_data = base::MakeUnique<syncer::EntityData>(); entity_data->non_unique_name = base::UTF16ToUTF8(entry.key().name()); sync_pb::AutofillSpecifics* autofill = @@ -44,9 +50,20 @@ return entity_data; } -} // namespace +std::string BuildSerializedStorageKey(const std::string& name, + const std::string& value) { + AutofillSyncStorageKey proto; + proto.set_name(name); + proto.set_value(value); + return proto.SerializeAsString(); +} -namespace autofill { +std::string GetStorageKeyFromModel(const AutofillKey& key) { + return BuildSerializedStorageKey(base::UTF16ToUTF8(key.name()), + base::UTF16ToUTF8(key.value())); +} + +} // namespace // static void AutocompleteSyncBridge::CreateForWebDataServiceAndBackend( @@ -117,7 +134,7 @@ std::vector<AutofillEntry> entries; GetAutofillTable()->GetAllAutofillEntries(&entries); for (const AutofillEntry& entry : entries) { - std::string key = GetStorageKeyFromAutofillEntry(entry); + std::string key = GetStorageKeyFromModel(entry.key()); if (keys_set.find(key) != keys_set.end()) { batch->Put(key, CreateEntityData(entry)); } @@ -131,7 +148,7 @@ std::vector<AutofillEntry> entries; GetAutofillTable()->GetAllAutofillEntries(&entries); for (const AutofillEntry& entry : entries) { - batch->Put(GetStorageKeyFromAutofillEntry(entry), CreateEntityData(entry)); + batch->Put(GetStorageKeyFromModel(entry.key()), CreateEntityData(entry)); } callback.Run(syncer::SyncError(), std::move(batch)); } @@ -139,18 +156,18 @@ std::string AutocompleteSyncBridge::GetClientTag( const syncer::EntityData& entity_data) { DCHECK(entity_data.specifics.has_autofill()); - const sync_pb::AutofillSpecifics specifics = entity_data.specifics.autofill(); - std::string storage_key = - FormatStorageKey(specifics.name(), specifics.value()); - std::string prefix(kAutocompleteEntryNamespaceTag); - return prefix + storage_key; + return std::string(kAutocompleteEntryNamespaceTag) + + net::EscapePath(specifics.name()) + + std::string(kAutocompleteTagDelimiter) + + net::EscapePath(specifics.value()); } std::string AutocompleteSyncBridge::GetStorageKey( const syncer::EntityData& entity_data) { + DCHECK(entity_data.specifics.has_autofill()); const sync_pb::AutofillSpecifics specifics = entity_data.specifics.autofill(); - return FormatStorageKey(specifics.name(), specifics.value()); + return BuildSerializedStorageKey(specifics.name(), specifics.value()); } // AutofillWebDataServiceObserverOnDBThread implementation. @@ -178,16 +195,4 @@ return AutofillTable::FromWebDatabase(web_data_backend_->GetDatabase()); } -std::string AutocompleteSyncBridge::GetStorageKeyFromAutofillEntry( - const autofill::AutofillEntry& entry) { - return FormatStorageKey(base::UTF16ToUTF8(entry.key().name()), - base::UTF16ToUTF8(entry.key().value())); -} - -// static -std::string AutocompleteSyncBridge::FormatStorageKey(const std::string& name, - const std::string& value) { - return net::EscapePath(name) + "|" + net::EscapePath(value); -} - } // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h b/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h index 00a69f1b..8bf3460 100644 --- a/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h +++ b/components/autofill/core/browser/webdata/autocomplete_sync_bridge.h
@@ -5,6 +5,9 @@ #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOCOMPLETE_SYNC_BRIDGE_H_ #define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOCOMPLETE_SYNC_BRIDGE_H_ +#include <memory> +#include <string> + #include "base/scoped_observer.h" #include "base/supports_user_data.h" #include "base/threading/non_thread_safe.h"
diff --git a/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc b/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc index de05b01..596d67d1 100644 --- a/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc +++ b/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc
@@ -4,7 +4,8 @@ #include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h" -#include <memory> +#include <map> +#include <vector> #include "base/bind.h" #include "base/files/scoped_temp_dir.h" @@ -21,10 +22,12 @@ #include "components/sync/model/fake_model_type_change_processor.h" #include "components/sync/model/metadata_batch.h" #include "components/webdata/common/web_database.h" -#include "net/base/escape.h" #include "testing/gtest/include/gtest/gtest.h" using sync_pb::AutofillSpecifics; +using sync_pb::EntitySpecifics; +using syncer::EntityDataPtr; +using syncer::EntityData; using syncer::SyncError; namespace autofill { @@ -60,6 +63,28 @@ return base::MakeUnique<syncer::FakeModelTypeChangeProcessor>(); } +AutofillEntry CreateAutofillEntry( + const sync_pb::AutofillSpecifics& autofill_specifics) { + AutofillKey key(base::UTF8ToUTF16(autofill_specifics.name()), + base::UTF8ToUTF16(autofill_specifics.value())); + base::Time date_created, date_last_used; + const google::protobuf::RepeatedField<int64_t>& timestamps = + autofill_specifics.usage_timestamp(); + if (!timestamps.empty()) { + date_created = base::Time::FromInternalValue(*timestamps.begin()); + date_last_used = base::Time::FromInternalValue(*timestamps.rbegin()); + } + return AutofillEntry(key, date_created, date_last_used); +} + +// Creates an EntityData/EntityDataPtr around a copy of the given specifics. +EntityDataPtr SpecificsToEntity(const AutofillSpecifics& specifics) { + EntityData data; + data.client_tag_hash = "ignored"; + *data.specifics.mutable_autofill() = specifics; + return data.PassToPtr(); +} + class FakeAutofillBackend : public AutofillWebDataBackend { public: FakeAutofillBackend() {} @@ -101,8 +126,7 @@ const std::vector<AutofillSpecifics>& specifics_list) { std::vector<AutofillEntry> new_entries; for (const auto& specifics : specifics_list) { - new_entries.push_back( - AutocompleteSyncBridge::CreateAutofillEntry(specifics)); + new_entries.push_back(CreateAutofillEntry(specifics)); } table_.UpdateAutofillEntries(new_entries); } @@ -116,8 +140,10 @@ } std::string GetStorageKey(const AutofillSpecifics& specifics) { - return net::EscapePath(specifics.name()) + "|" + - net::EscapePath(specifics.value()); + std::string key = + bridge()->GetStorageKey(SpecificsToEntity(specifics).value()); + EXPECT_FALSE(key.empty()); + return key; } private: @@ -131,6 +157,56 @@ DISALLOW_COPY_AND_ASSIGN(AutocompleteSyncBridgeTest); }; +TEST_F(AutocompleteSyncBridgeTest, GetClientTag) { + // TODO(skym, crbug.com/675991): Implementation. +} + +TEST_F(AutocompleteSyncBridgeTest, GetStorageKey) { + std::string key = GetStorageKey(CreateSpecifics(1)); + EXPECT_EQ(key, GetStorageKey(CreateSpecifics(1))); + EXPECT_NE(key, GetStorageKey(CreateSpecifics(2))); +} + +// Timestamps should not affect storage keys. +TEST_F(AutocompleteSyncBridgeTest, GetStorageKeyTimestamp) { + AutofillSpecifics specifics = CreateSpecifics(1); + std::string key = GetStorageKey(specifics); + + specifics.add_usage_timestamp(1); + EXPECT_EQ(key, GetStorageKey(specifics)); + + specifics.add_usage_timestamp(0); + EXPECT_EQ(key, GetStorageKey(specifics)); + + specifics.add_usage_timestamp(-1); + EXPECT_EQ(key, GetStorageKey(specifics)); +} + +// Verify that the \0 character is respected as a difference. +TEST_F(AutocompleteSyncBridgeTest, GetStorageKeyNull) { + AutofillSpecifics specifics; + std::string key = GetStorageKey(specifics); + + specifics.set_value(std::string("\0", 1)); + EXPECT_NE(key, GetStorageKey(specifics)); +} + +// The storage key should never accidentally change for existing data. This +// would cause lookups to fail and either lose or duplicate user data. It should +// be possible for the model type to migrate storage key formats, but doing so +// would need to be done very carefully. +TEST_F(AutocompleteSyncBridgeTest, GetStorageKeyFixed) { + EXPECT_EQ("\n\x6name 1\x12\avalue 1", GetStorageKey(CreateSpecifics(1))); + EXPECT_EQ("\n\x6name 2\x12\avalue 2", GetStorageKey(CreateSpecifics(2))); + // This literal contains the null terminating character, which causes + // std::string to stop copying early if we don't tell it how much to read. + EXPECT_EQ(std::string("\n\0\x12\0", 4), GetStorageKey(AutofillSpecifics())); + AutofillSpecifics specifics; + specifics.set_name("\xEC\xA4\x91"); + specifics.set_value("\xD0\x80"); + EXPECT_EQ("\n\x3\xEC\xA4\x91\x12\x2\xD0\x80", GetStorageKey(specifics)); +} + TEST_F(AutocompleteSyncBridgeTest, GetData) { const AutofillSpecifics specifics1 = CreateSpecifics(1); const AutofillSpecifics specifics2 = CreateSpecifics(2);
diff --git a/components/bookmarks/browser/BUILD.gn b/components/bookmarks/browser/BUILD.gn index a4df5f1a..b606dc4 100644 --- a/components/bookmarks/browser/BUILD.gn +++ b/components/bookmarks/browser/BUILD.gn
@@ -100,6 +100,7 @@ "bookmark_index_unittest.cc", "bookmark_model_unittest.cc", "bookmark_utils_unittest.cc", + "titled_url_match_unittest.cc", ] if (toolkit_views) {
diff --git a/components/bookmarks/browser/titled_url_index.h b/components/bookmarks/browser/titled_url_index.h index 13a6455..d6a0fba 100644 --- a/components/bookmarks/browser/titled_url_index.h +++ b/components/bookmarks/browser/titled_url_index.h
@@ -29,6 +29,9 @@ // TitledUrlNodes that contain that string in their title or URL. class TitledUrlIndex { public: + // Constructs a TitledUrlIndex. |sorter| is used to construct a sorted list + // of matches when matches are returned from the index. If null, matches are + // returned unsorted. TitledUrlIndex(std::unique_ptr<TitledUrlNodeSorter> sorter); ~TitledUrlIndex();
diff --git a/components/bookmarks/browser/titled_url_match_unittest.cc b/components/bookmarks/browser/titled_url_match_unittest.cc new file mode 100644 index 0000000..8ccd2da --- /dev/null +++ b/components/bookmarks/browser/titled_url_match_unittest.cc
@@ -0,0 +1,61 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/bookmarks/browser/titled_url_match.h" + +#include "base/macros.h" +#include "base/strings/utf_string_conversions.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace bookmarks { + +using MatchPositions = TitledUrlMatch::MatchPositions; + +TEST(TitledUrlMatchTest, EmptyOffsetsForEmptyMatchPositions) { + auto offsets = TitledUrlMatch::OffsetsFromMatchPositions(MatchPositions()); + EXPECT_TRUE(offsets.empty()); +} + +TEST(TitledUrlMatchTest, OffsetsFromMatchPositions) { + MatchPositions match_positions = {{1, 3}, {4, 5}, {10, 15}}; + std::vector<size_t> expected_offsets = {1, 3, 4, 5, 10, 15}; + auto offsets = TitledUrlMatch::OffsetsFromMatchPositions(match_positions); + EXPECT_TRUE( + std::equal(offsets.begin(), offsets.end(), expected_offsets.begin())); +} + +TEST(TitledUrlMatchTest, ReplaceOffsetsInEmptyMatchPositions) { + auto match_positions = TitledUrlMatch::ReplaceOffsetsInMatchPositions( + MatchPositions(), std::vector<size_t>()); + EXPECT_TRUE(match_positions.empty()); +} + +TEST(TitledUrlMatchTest, ReplaceOffsetsInMatchPositions) { + MatchPositions orig_match_positions = {{1, 3}, {4, 5}, {10, 15}}; + std::vector<size_t> offsets = {0, 2, 3, 4, 9, 14}; + MatchPositions expected_match_positions = {{0, 2}, {3, 4}, {9, 14}}; + auto match_positions = TitledUrlMatch::ReplaceOffsetsInMatchPositions( + orig_match_positions, offsets); + EXPECT_TRUE(std::equal(match_positions.begin(), match_positions.end(), + expected_match_positions.begin())); +} + +TEST(TitledUrlMatchTest, ReplaceOffsetsRemovesItemsWithNposOffsets) { + MatchPositions orig_match_positions = {{1, 3}, {4, 5}, {10, 15}, {17, 20}}; + std::vector<size_t> offsets = {0, + base::string16::npos, + base::string16::npos, + 4, + base::string16::npos, + base::string16::npos, + 17, + 20}; + MatchPositions expected_match_positions = {{17, 20}}; + auto match_positions = TitledUrlMatch::ReplaceOffsetsInMatchPositions( + orig_match_positions, offsets); + EXPECT_TRUE(std::equal(match_positions.begin(), match_positions.end(), + expected_match_positions.begin())); +} + +}
diff --git a/components/browser_sync/profile_sync_components_factory_impl.cc b/components/browser_sync/profile_sync_components_factory_impl.cc index 360eb4ff..93d83a74 100644 --- a/components/browser_sync/profile_sync_components_factory_impl.cc +++ b/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -304,9 +304,9 @@ const syncer::DataTypeEncryptionHandler* encryption_handler, syncer::ModelTypeConfigurer* configurer, DataTypeManagerObserver* observer) { - return new DataTypeManagerImpl(initial_types, debug_info_listener, - controllers, encryption_handler, configurer, - observer); + return new DataTypeManagerImpl(sync_client_, initial_types, + debug_info_listener, controllers, + encryption_handler, configurer, observer); } syncer::SyncEngine* ProfileSyncComponentsFactoryImpl::CreateSyncEngine(
diff --git a/components/browser_sync/profile_sync_service_autofill_unittest.cc b/components/browser_sync/profile_sync_service_autofill_unittest.cc index 77c09e3..6a37f1d 100644 --- a/components/browser_sync/profile_sync_service_autofill_unittest.cc +++ b/components/browser_sync/profile_sync_service_autofill_unittest.cc
@@ -369,9 +369,11 @@ DISALLOW_COPY_AND_ASSIGN(WebDataServiceFake); }; -ACTION_P(ReturnNewDataTypeManagerWithDebugListener, debug_listener) { - return new syncer::DataTypeManagerImpl(arg0, debug_listener, arg2, arg3, arg4, - arg5); +ACTION_P2(ReturnNewDataTypeManagerWithDebugListener, + sync_client, + debug_listener) { + return new syncer::DataTypeManagerImpl(sync_client, arg0, debug_listener, + arg2, arg3, arg4, arg5); } class MockPersonalDataManager : public PersonalDataManager { @@ -478,6 +480,7 @@ EXPECT_CALL(*profile_sync_service_bundle()->component_factory(), CreateDataTypeManager(_, _, _, _, _, _)) .WillOnce(ReturnNewDataTypeManagerWithDebugListener( + sync_client_, syncer::MakeWeakHandle(debug_ptr_factory_.GetWeakPtr()))); EXPECT_CALL(personal_data_manager(), IsDataLoaded())
diff --git a/components/browser_sync/profile_sync_service_typed_url_unittest.cc b/components/browser_sync/profile_sync_service_typed_url_unittest.cc index da6c619..440cd85 100644 --- a/components/browser_sync/profile_sync_service_typed_url_unittest.cc +++ b/components/browser_sync/profile_sync_service_typed_url_unittest.cc
@@ -60,8 +60,9 @@ // Visits with this timestamp are treated as expired. static const int EXPIRED_VISIT = -1; -ACTION(ReturnNewDataTypeManager) { - return new syncer::DataTypeManagerImpl(arg0, arg1, arg2, arg3, arg4, arg5); +ACTION_P(ReturnNewDataTypeManager, sync_client) { + return new syncer::DataTypeManagerImpl(sync_client, arg0, arg1, arg2, arg3, + arg4, arg5); } class HistoryBackendMock : public HistoryBackend { @@ -247,10 +248,10 @@ SigninManagerBase* signin = profile_sync_service_bundle()->signin_manager(); signin->SetAuthenticatedAccountInfo("gaia_id", "test"); - CreateSyncService(std::move(sync_client_), callback); EXPECT_CALL(*profile_sync_service_bundle()->component_factory(), CreateDataTypeManager(_, _, _, _, _, _)) - .WillOnce(ReturnNewDataTypeManager()); + .WillOnce(ReturnNewDataTypeManager(sync_client_.get())); + CreateSyncService(std::move(sync_client_), callback); profile_sync_service_bundle()->auth_service()->UpdateCredentials( account_id, "oauth2_login_token");
diff --git a/components/cronet/README.md b/components/cronet/README.md index a2d48aef..663cae0 100644 --- a/components/cronet/README.md +++ b/components/cronet/README.md
@@ -58,7 +58,7 @@ @Override public void onFailed(UrlRequest request, - UrlResponseInfo responseInfo, UrlRequestException error) { + UrlResponseInfo responseInfo, CronetException error) { // Request has failed. responseInfo might be null. Log.e("MyCallback", "Request failed. " + error.getMessage()); // Maybe handle error here. Typical errors include hostname
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn index 42942ae..04fa14f 100644 --- a/components/cronet/android/BUILD.gn +++ b/components/cronet/android/BUILD.gn
@@ -288,7 +288,6 @@ "api/src/org/chromium/net/UploadDataProviders.java", "api/src/org/chromium/net/UploadDataSink.java", "api/src/org/chromium/net/UrlRequest.java", - "api/src/org/chromium/net/UrlRequestException.java", "api/src/org/chromium/net/UrlResponseInfo.java", ]
diff --git a/components/cronet/android/api.txt b/components/cronet/android/api.txt index 8be7b222..b72e3dc 100644 --- a/components/cronet/android/api.txt +++ b/components/cronet/android/api.txt
@@ -231,9 +231,8 @@ public abstract void onResponseStarted(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo) throws java.lang.Exception; public abstract void onReadCompleted(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo, java.nio.ByteBuffer) throws java.lang.Exception; public abstract void onSucceeded(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo); - public void onFailed(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo, org.chromium.net.CronetException); + public abstract void onFailed(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo, org.chromium.net.CronetException); public void onCanceled(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo); - public void onFailed(org.chromium.net.UrlRequest, org.chromium.net.UrlResponseInfo, org.chromium.net.UrlRequestException); } public class org.chromium.net.UrlRequest$Status { public static final int INVALID; @@ -266,24 +265,6 @@ public abstract boolean isDone(); public abstract void getStatus(org.chromium.net.UrlRequest$StatusListener); } -public class org.chromium.net.UrlRequestException extends java.io.IOException { - public static final int ERROR_LISTENER_EXCEPTION_THROWN; - public static final int ERROR_HOSTNAME_NOT_RESOLVED; - public static final int ERROR_INTERNET_DISCONNECTED; - public static final int ERROR_NETWORK_CHANGED; - public static final int ERROR_TIMED_OUT; - public static final int ERROR_CONNECTION_CLOSED; - public static final int ERROR_CONNECTION_TIMED_OUT; - public static final int ERROR_CONNECTION_REFUSED; - public static final int ERROR_CONNECTION_RESET; - public static final int ERROR_ADDRESS_UNREACHABLE; - public static final int ERROR_QUIC_PROTOCOL_FAILED; - public static final int ERROR_OTHER; - public org.chromium.net.UrlRequestException(org.chromium.net.CronetException); - public int getErrorCode(); - public int getCronetInternalErrorCode(); - public boolean immediatelyRetryable(); -} public abstract class org.chromium.net.UrlResponseInfo$HeaderBlock { public org.chromium.net.UrlResponseInfo$HeaderBlock(); public abstract java.util.List<java.util.Map$Entry<java.lang.String, java.lang.String>> getAsList();
diff --git a/components/cronet/android/api/src/org/chromium/net/UrlRequest.java b/components/cronet/android/api/src/org/chromium/net/UrlRequest.java index 726e10ec..cf5250a 100644 --- a/components/cronet/android/api/src/org/chromium/net/UrlRequest.java +++ b/components/cronet/android/api/src/org/chromium/net/UrlRequest.java
@@ -214,11 +214,8 @@ * received. * @param error information about error. */ - public void onFailed(UrlRequest request, UrlResponseInfo info, CronetException error) { - // TODO(mef): Remove fallback to legacy api and make this method abstract - // after complete transition to CronetException. - onFailed(request, info, new UrlRequestException(error)); - } + public abstract void onFailed( + UrlRequest request, UrlResponseInfo info, CronetException error); /** * Invoked if request was canceled via {@link UrlRequest#cancel}. Once @@ -230,16 +227,6 @@ * received. */ public void onCanceled(UrlRequest request, UrlResponseInfo info) {} - - /** - * @deprecated Use {@code onFailed} instead. - * {@hide This method will be removed after complete transition to CronetException}. - */ - @Deprecated - // TODO(mef): Remove this after complete transition to CronetException. - public void onFailed(UrlRequest request, UrlResponseInfo info, UrlRequestException error) { - assert false; - } } /**
diff --git a/components/cronet/android/api/src/org/chromium/net/UrlRequestException.java b/components/cronet/android/api/src/org/chromium/net/UrlRequestException.java deleted file mode 100644 index 0bca019..0000000 --- a/components/cronet/android/api/src/org/chromium/net/UrlRequestException.java +++ /dev/null
@@ -1,140 +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. - -package org.chromium.net; - -import java.io.IOException; - -/** - * @deprecated Use {@link CronetException} instead. - * {@hide This class will be removed after complete transition to CronetException}. - */ -@Deprecated -public class UrlRequestException extends IOException { - /** - * Error code indicating this class wraps an exception thrown by {@link UrlRequest.Callback} or - * {@link UploadDataProvider}. Wrapped exception can be retrieved using - * {@link IOException#getCause}. - */ - public static final int ERROR_LISTENER_EXCEPTION_THROWN = 0; - /** - * Error code indicating the host being sent the request could not be resolved to an IP address. - */ - public static final int ERROR_HOSTNAME_NOT_RESOLVED = 1; - /** - * Error code indicating the device was not connected to any network. - */ - public static final int ERROR_INTERNET_DISCONNECTED = 2; - /** - * Error code indicating that as the request was processed the network configuration changed. - */ - public static final int ERROR_NETWORK_CHANGED = 3; - /** - * Error code indicating a timeout expired. Timeouts expiring while attempting to connect will - * be reported as the more specific {@link #ERROR_CONNECTION_TIMED_OUT}. - */ - public static final int ERROR_TIMED_OUT = 4; - /** - * Error code indicating the connection was closed unexpectedly. - */ - public static final int ERROR_CONNECTION_CLOSED = 5; - /** - * Error code indicating the connection attempt timed out. - */ - public static final int ERROR_CONNECTION_TIMED_OUT = 6; - /** - * Error code indicating the connection attempt was refused. - */ - public static final int ERROR_CONNECTION_REFUSED = 7; - /** - * Error code indicating the connection was unexpectedly reset. - */ - public static final int ERROR_CONNECTION_RESET = 8; - /** - * Error code indicating the IP address being contacted is unreachable, meaning there is no - * route to the specified host or network. - */ - public static final int ERROR_ADDRESS_UNREACHABLE = 9; - /** - * Error code indicating an error related to the <a href="https://www.chromium.org/quic"> - * QUIC</a> protocol. When {@link #getErrorCode} returns this code, this exception can be cast - * to {@link QuicException} for more information. - */ - public static final int ERROR_QUIC_PROTOCOL_FAILED = 10; - /** - * Error code indicating another type of error was encountered. - * {@link #getCronetInternalErrorCode} can be consulted to get a more specific cause. - */ - public static final int ERROR_OTHER = 11; - - // Error code, one of ERROR_* - private final int mErrorCode; - // Cronet internal error code. - private final int mCronetInternalErrorCode; - - public UrlRequestException(CronetException error) { - super(error.getMessage(), error.getCause()); - if (error instanceof NetworkException) { - mErrorCode = ((NetworkException) error).getErrorCode(); - mCronetInternalErrorCode = ((NetworkException) error).getCronetInternalErrorCode(); - } else { - mErrorCode = 0; - mCronetInternalErrorCode = ERROR_LISTENER_EXCEPTION_THROWN; - } - } - - /** - * Returns error code, one of {@link #ERROR_LISTENER_EXCEPTION_THROWN ERROR_*}. - * - * @return error code, one of {@link #ERROR_LISTENER_EXCEPTION_THROWN ERROR_*}. - */ - public int getErrorCode() { - return mErrorCode; - } - - /** - * Returns a Cronet internal error code. This may provide more specific error - * diagnosis than {@link #getErrorCode}, but the constant values are not exposed to Java and - * may change over time. See - * <a href=https://chromium.googlesource.com/chromium/src/+/master/net/base/net_error_list.h> - * here</a> for the lastest list of values. - * - * @return Cronet internal error code. - */ - public int getCronetInternalErrorCode() { - return mCronetInternalErrorCode; - } - - /** - * Returns {@code true} if retrying this request right away might succeed, {@code false} - * otherwise. For example returns {@code true} when {@link #getErrorCode} returns - * {@link #ERROR_NETWORK_CHANGED} because trying the request might succeed using the new - * network configuration, but {@code false} when {@code getErrorCode()} returns - * {@link #ERROR_INTERNET_DISCONNECTED} because retrying the request right away will - * encounter the same failure (instead retrying should be delayed until device regains - * network connectivity). Returns {@code false} when {@code getErrorCode()} returns - * {@link #ERROR_LISTENER_EXCEPTION_THROWN}. - * - * @return {@code true} if retrying this request right away might succeed, {@code false} - * otherwise. - */ - public boolean immediatelyRetryable() { - switch (mErrorCode) { - case ERROR_LISTENER_EXCEPTION_THROWN: - case ERROR_HOSTNAME_NOT_RESOLVED: - case ERROR_INTERNET_DISCONNECTED: - case ERROR_CONNECTION_REFUSED: - case ERROR_ADDRESS_UNREACHABLE: - case ERROR_OTHER: - default: - return false; - case ERROR_NETWORK_CHANGED: - case ERROR_TIMED_OUT: - case ERROR_CONNECTION_CLOSED: - case ERROR_CONNECTION_TIMED_OUT: - case ERROR_CONNECTION_RESET: - return true; - } - } -}
diff --git a/components/cronet/android/api_version.txt b/components/cronet/android/api_version.txt index 56a6051..0cfbf08 100644 --- a/components/cronet/android/api_version.txt +++ b/components/cronet/android/api_version.txt
@@ -1 +1 @@ -1 \ No newline at end of file +2
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/VersionSafeCallbacks.java b/components/cronet/android/java/src/org/chromium/net/impl/VersionSafeCallbacks.java index d0c4ace9..52854ec 100644 --- a/components/cronet/android/java/src/org/chromium/net/impl/VersionSafeCallbacks.java +++ b/components/cronet/android/java/src/org/chromium/net/impl/VersionSafeCallbacks.java
@@ -13,7 +13,6 @@ import org.chromium.net.UploadDataProvider; import org.chromium.net.UploadDataSink; import org.chromium.net.UrlRequest; -import org.chromium.net.UrlRequestException; import org.chromium.net.UrlResponseInfo; import java.io.IOException; @@ -72,11 +71,6 @@ public void onCanceled(UrlRequest request, UrlResponseInfo info) { mWrappedCallback.onCanceled(request, info); } - - @Override - public void onFailed(UrlRequest request, UrlResponseInfo info, UrlRequestException error) { - mWrappedCallback.onFailed(request, info, error); - } } /**
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java index a5afdf2..e0d06b7e 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java
@@ -2036,10 +2036,11 @@ } @Override - public void onFailed( - UrlRequest request, UrlResponseInfo info, UrlRequestException error) { - assertEquals(netError, error.getCronetInternalErrorCode()); - failedExpectation.set(error.getCronetInternalErrorCode() != netError); + public void onFailed(UrlRequest request, UrlResponseInfo info, CronetException error) { + assertTrue(error instanceof NetworkException); + assertEquals(netError, ((NetworkException) error).getCronetInternalErrorCode()); + failedExpectation.set( + ((NetworkException) error).getCronetInternalErrorCode() != netError); done.open(); }
diff --git a/components/omnibox/browser/BUILD.gn b/components/omnibox/browser/BUILD.gn index be1ac41..7ba8379 100644 --- a/components/omnibox/browser/BUILD.gn +++ b/components/omnibox/browser/BUILD.gn
@@ -95,6 +95,8 @@ "shortcuts_provider.h", "suggestion_answer.cc", "suggestion_answer.h", + "titled_url_match_utils.cc", + "titled_url_match_utils.h", "url_index_private_data.cc", "url_index_private_data.h", "url_prefix.cc", @@ -243,6 +245,7 @@ "shortcuts_database_unittest.cc", "shortcuts_provider_unittest.cc", "suggestion_answer_unittest.cc", + "titled_url_match_utils_unittest.cc", "url_prefix_unittest.cc", "zero_suggest_provider_unittest.cc", ]
diff --git a/components/omnibox/browser/autocomplete_classifier.cc b/components/omnibox/browser/autocomplete_classifier.cc index 4e50bbfd..c6e81cf 100644 --- a/components/omnibox/browser/autocomplete_classifier.cc +++ b/components/omnibox/browser/autocomplete_classifier.cc
@@ -17,8 +17,11 @@ // static const int AutocompleteClassifier::kDefaultOmniboxProviders = -#if !defined(OS_ANDROID) && !defined(OS_IOS) - // Custom search engines cannot be used on mobile.. +#if defined(OS_ANDROID) || defined(OS_IOS) + // The Physical Web currently is only implemented on mobile devices. + AutocompleteProvider::TYPE_PHYSICAL_WEB | +#else + // Custom search engines cannot be used on mobile. AutocompleteProvider::TYPE_KEYWORD | #endif #if !defined(OS_IOS) @@ -29,8 +32,6 @@ #else // "URL from clipboard" can only be used on iOS. AutocompleteProvider::TYPE_CLIPBOARD_URL | - // Physical Web omnibox results are only implemented on iOS. - AutocompleteProvider::TYPE_PHYSICAL_WEB | #endif AutocompleteProvider::TYPE_BOOKMARK | AutocompleteProvider::TYPE_HISTORY_QUICK |
diff --git a/components/omnibox/browser/bookmark_provider.cc b/components/omnibox/browser/bookmark_provider.cc index cee15775a..88cdc26 100644 --- a/components/omnibox/browser/bookmark_provider.cc +++ b/components/omnibox/browser/bookmark_provider.cc
@@ -17,40 +17,14 @@ #include "components/metrics/proto/omnibox_input_type.pb.h" #include "components/omnibox/browser/autocomplete_provider_client.h" #include "components/omnibox/browser/autocomplete_result.h" -#include "components/omnibox/browser/history_provider.h" -#include "components/omnibox/browser/url_prefix.h" +#include "components/omnibox/browser/titled_url_match_utils.h" #include "components/prefs/pref_service.h" -#include "components/url_formatter/url_formatter.h" #include "url/url_constants.h" using bookmarks::BookmarkNode; using bookmarks::TitledUrlMatch; using TitledUrlMatches = std::vector<TitledUrlMatch>; -namespace { - -// Removes leading spaces from |title| before displaying, otherwise it looks -// funny. In the process, corrects |title_match_positions| so the correct -// characters are highlighted. -void CorrectTitleAndMatchPositions( - base::string16* title, - TitledUrlMatch::MatchPositions* title_match_positions) { - size_t leading_whitespace_chars = title->length(); - base::TrimWhitespace(*title, base::TRIM_LEADING, title); - leading_whitespace_chars-= title->length(); - if (leading_whitespace_chars == 0) - return; - for (query_parser::Snippet::MatchPositions::iterator it = - title_match_positions->begin(); - it != title_match_positions->end(); ++it) { - (*it) = query_parser::Snippet::MatchPosition( - it->first - leading_whitespace_chars, - it->second - leading_whitespace_chars); - } -} - -} // namespace - // BookmarkProvider ------------------------------------------------------------ BookmarkProvider::BookmarkProvider(AutocompleteProviderClient* client) @@ -107,13 +81,15 @@ if (matches.empty()) return; // There were no matches. const base::string16 fixed_up_input(FixupUserInput(input).second); - for (TitledUrlMatches::const_iterator i = matches.begin(); i != matches.end(); - ++i) { - // Create and score the AutocompleteMatch. If its score is 0 then the - // match is discarded. - AutocompleteMatch match(TitledUrlMatchToACMatch(input, fixed_up_input, *i)); - if (match.relevance > 0) - matches_.push_back(match); + for (const auto& bookmark_match : matches) { + // Score the TitledUrlMatch. If its score is greater than 0 then the + // AutocompleteMatch is created and added to matches_. + int relevance = CalculateBookmarkMatchRelevance(bookmark_match); + if (relevance > 0) { + matches_.push_back(TitledUrlMatchToAutocompleteMatch( + bookmark_match, AutocompleteMatchType::BOOKMARK_TITLE, relevance, + this, client_->GetSchemeClassifier(), input, fixed_up_input)); + } } // Sort and clip the resulting matches. @@ -155,69 +131,8 @@ } // namespace -AutocompleteMatch BookmarkProvider::TitledUrlMatchToACMatch( - const AutocompleteInput& input, - const base::string16& fixed_up_input_text, - const TitledUrlMatch& bookmark_match) { - // The AutocompleteMatch we construct is non-deletable because the only - // way to support this would be to delete the underlying bookmark, which is - // unlikely to be what the user intends. - AutocompleteMatch match(this, 0, false, - AutocompleteMatchType::BOOKMARK_TITLE); - base::string16 title(bookmark_match.node->GetTitledUrlNodeTitle()); - TitledUrlMatch::MatchPositions new_title_match_positions = - bookmark_match.title_match_positions; - CorrectTitleAndMatchPositions(&title, &new_title_match_positions); - const GURL& url(bookmark_match.node->GetTitledUrlNodeUrl()); - const base::string16& url_utf16 = base::UTF8ToUTF16(url.spec()); - size_t inline_autocomplete_offset = URLPrefix::GetInlineAutocompleteOffset( - input.text(), fixed_up_input_text, false, url_utf16); - match.destination_url = url; - const size_t match_start = bookmark_match.url_match_positions.empty() ? - 0 : bookmark_match.url_match_positions[0].first; - const bool trim_http = !AutocompleteInput::HasHTTPScheme(input.text()) && - ((match_start == base::string16::npos) || (match_start != 0)); - std::vector<size_t> offsets = TitledUrlMatch::OffsetsFromMatchPositions( - bookmark_match.url_match_positions); - // In addition to knowing how |offsets| is transformed, we need to know how - // |inline_autocomplete_offset| is transformed. We add it to the end of - // |offsets|, compute how everything is transformed, then remove it from the - // end. - offsets.push_back(inline_autocomplete_offset); - match.contents = url_formatter::FormatUrlWithOffsets( - url, url_formatter::kFormatUrlOmitAll & - ~(trim_http ? 0 : url_formatter::kFormatUrlOmitHTTP), - net::UnescapeRule::SPACES, nullptr, nullptr, &offsets); - inline_autocomplete_offset = offsets.back(); - offsets.pop_back(); - TitledUrlMatch::MatchPositions new_url_match_positions = - TitledUrlMatch::ReplaceOffsetsInMatchPositions( - bookmark_match.url_match_positions, offsets); - match.contents_class = - ClassificationsFromMatch(new_url_match_positions, - match.contents.size(), - true); - match.fill_into_edit = - AutocompleteInput::FormattedStringWithEquivalentMeaning( - url, match.contents, client_->GetSchemeClassifier()); - if (inline_autocomplete_offset != base::string16::npos) { - // |inline_autocomplete_offset| may be beyond the end of the - // |fill_into_edit| if the user has typed an URL with a scheme and the - // last character typed is a slash. That slash is removed by the - // FormatURLWithOffsets call above. - if (inline_autocomplete_offset < match.fill_into_edit.length()) { - match.inline_autocompletion = - match.fill_into_edit.substr(inline_autocomplete_offset); - } - match.allowed_to_be_default_match = match.inline_autocompletion.empty() || - !HistoryProvider::PreventInlineAutocomplete(input); - } - match.description = title; - match.description_class = - ClassificationsFromMatch(bookmark_match.title_match_positions, - match.description.size(), - false); - +int BookmarkProvider::CalculateBookmarkMatchRelevance( + const TitledUrlMatch& bookmark_match) const { // Summary on how a relevance score is determined for the match: // // For each match within the bookmark's title or URL (or both), calculate a @@ -268,7 +183,9 @@ // and, for each additional reference beyond the one for the bookmark being // scored up to a maximum of three, the score is boosted by a fixed amount // given by |kURLCountBoost|, below. - // + + base::string16 title(bookmark_match.node->GetTitledUrlNodeTitle()); + const GURL& url(bookmark_match.node->GetTitledUrlNodeUrl()); // Pretend empty titles are identical to the URL. if (title.empty()) @@ -297,46 +214,19 @@ const int kMaxBookmarkScore = bookmarklet_without_title_match ? 799 : 1199; const double kBookmarkScoreRange = static_cast<double>(kMaxBookmarkScore - kBaseBookmarkScore); - match.relevance = static_cast<int>(normalized_sum * kBookmarkScoreRange) + - kBaseBookmarkScore; + int relevance = static_cast<int>(normalized_sum * kBookmarkScoreRange) + + kBaseBookmarkScore; // Don't waste any time searching for additional referenced URLs if we // already have a perfect title match. - if (match.relevance >= kMaxBookmarkScore) - return match; + if (relevance >= kMaxBookmarkScore) + return relevance; // Boost the score if the bookmark's URL is referenced by other bookmarks. const int kURLCountBoost[4] = { 0, 75, 125, 150 }; std::vector<const BookmarkNode*> nodes; bookmark_model_->GetNodesByURL(url, &nodes); DCHECK_GE(std::min(arraysize(kURLCountBoost), nodes.size()), 1U); - match.relevance += + relevance += kURLCountBoost[std::min(arraysize(kURLCountBoost), nodes.size()) - 1]; - match.relevance = std::min(kMaxBookmarkScore, match.relevance); - return match; -} - -// static -ACMatchClassifications BookmarkProvider::ClassificationsFromMatch( - const query_parser::Snippet::MatchPositions& positions, - size_t text_length, - bool is_url) { - ACMatchClassification::Style url_style = - is_url ? ACMatchClassification::URL : ACMatchClassification::NONE; - ACMatchClassifications classifications; - if (positions.empty()) { - if (text_length > 0) - classifications.push_back(ACMatchClassification(0, url_style)); - return classifications; - } - - for (query_parser::Snippet::MatchPositions::const_iterator i = - positions.begin(); - i != positions.end(); - ++i) { - AutocompleteMatch::ACMatchClassifications new_class; - AutocompleteMatch::ClassifyLocationInString(i->first, i->second - i->first, - text_length, url_style, &new_class); - classifications = AutocompleteMatch::MergeClassifications( - classifications, new_class); - } - return classifications; + relevance = std::min(kMaxBookmarkScore, relevance); + return relevance; }
diff --git a/components/omnibox/browser/bookmark_provider.h b/components/omnibox/browser/bookmark_provider.h index bb2c71b..25a2bcb 100644 --- a/components/omnibox/browser/bookmark_provider.h +++ b/components/omnibox/browser/bookmark_provider.h
@@ -12,9 +12,7 @@ #include "base/gtest_prod_util.h" #include "base/macros.h" #include "components/omnibox/browser/autocomplete_input.h" -#include "components/omnibox/browser/autocomplete_match.h" #include "components/omnibox/browser/autocomplete_provider.h" -#include "components/query_parser/snippet.h" class AutocompleteProviderClient; @@ -55,24 +53,9 @@ // |matches_|. void DoAutocomplete(const AutocompleteInput& input); - // Compose an AutocompleteMatch based on |match| that has 1) the URL of - // |match|'s bookmark, and 2) the bookmark's title, not the URL's page - // title, as the description. |input| is used to compute the match's - // inline_autocompletion. |fixed_up_input_text| is used in that way as well; - // it's passed separately so this function doesn't have to compute it. - AutocompleteMatch TitledUrlMatchToACMatch( - const AutocompleteInput& input, - const base::string16& fixed_up_input_text, - const bookmarks::TitledUrlMatch& match); - - // Converts |positions| into ACMatchClassifications and returns the - // classifications. |text_length| is used to determine the need to add an - // 'unhighlighted' classification span so the tail of the source string - // properly highlighted. - static ACMatchClassifications ClassificationsFromMatch( - const query_parser::Snippet::MatchPositions& positions, - size_t text_length, - bool is_url); + // Calculates the relevance score for |match|. + int CalculateBookmarkMatchRelevance( + const bookmarks::TitledUrlMatch& match) const; AutocompleteProviderClient* client_; bookmarks::BookmarkModel* bookmark_model_;
diff --git a/components/omnibox/browser/bookmark_provider_unittest.cc b/components/omnibox/browser/bookmark_provider_unittest.cc index 277f3c38..586892e 100644 --- a/components/omnibox/browser/bookmark_provider_unittest.cc +++ b/components/omnibox/browser/bookmark_provider_unittest.cc
@@ -25,6 +25,7 @@ #include "components/omnibox/browser/autocomplete_provider.h" #include "components/omnibox/browser/mock_autocomplete_provider_client.h" #include "components/omnibox/browser/test_scheme_classifier.h" +#include "components/omnibox/browser/titled_url_match_utils.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -422,8 +423,10 @@ node.SetTitle(base::ASCIIToUTF16(query_data[i].url)); TitledUrlMatch bookmark_match; bookmark_match.node = &node; - const AutocompleteMatch& ac_match = provider_->TitledUrlMatchToACMatch( - input, fixed_up_input, bookmark_match); + int relevance = provider_->CalculateBookmarkMatchRelevance(bookmark_match); + const AutocompleteMatch& ac_match = TitledUrlMatchToAutocompleteMatch( + bookmark_match, AutocompleteMatchType::BOOKMARK_TITLE, relevance, + provider_.get(), classifier_, input, fixed_up_input); EXPECT_EQ(query_data[i].allowed_to_be_default_match, ac_match.allowed_to_be_default_match) << description; EXPECT_EQ(base::ASCIIToUTF16(query_data[i].inline_autocompletion),
diff --git a/components/omnibox/browser/titled_url_match_utils.cc b/components/omnibox/browser/titled_url_match_utils.cc new file mode 100644 index 0000000..f60d0d5 --- /dev/null +++ b/components/omnibox/browser/titled_url_match_utils.cc
@@ -0,0 +1,138 @@ +// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/omnibox/browser/titled_url_match_utils.h" + +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "components/bookmarks/browser/titled_url_node.h" +#include "components/omnibox/browser/autocomplete_match.h" +#include "components/omnibox/browser/history_provider.h" +#include "components/omnibox/browser/url_prefix.h" +#include "components/url_formatter/url_formatter.h" + +namespace { + +// Converts |positions| into ACMatchClassifications and returns the +// classifications. |text_length| is used to determine the need to add an +// 'unhighlighted' classification span so the tail of the source string +// properly highlighted. +ACMatchClassifications ClassificationsFromMatchPositions( + const bookmarks::TitledUrlMatch::MatchPositions& positions, + size_t text_length, + bool is_url) { + ACMatchClassification::Style url_style = + is_url ? ACMatchClassification::URL : ACMatchClassification::NONE; + ACMatchClassifications classifications; + if (positions.empty()) { + if (text_length > 0) { + classifications.push_back(ACMatchClassification(0, url_style)); + } + return classifications; + } + + for (bookmarks::TitledUrlMatch::MatchPositions::const_iterator i = + positions.begin(); + i != positions.end(); ++i) { + AutocompleteMatch::ACMatchClassifications new_class; + AutocompleteMatch::ClassifyLocationInString( + i->first, i->second - i->first, text_length, url_style, &new_class); + classifications = + AutocompleteMatch::MergeClassifications(classifications, new_class); + } + return classifications; +} + +} // namespace + +namespace bookmarks { + +AutocompleteMatch TitledUrlMatchToAutocompleteMatch( + const TitledUrlMatch& titled_url_match, + AutocompleteMatchType::Type type, + int relevance, + AutocompleteProvider* provider, + const AutocompleteSchemeClassifier& scheme_classifier, + const AutocompleteInput& input, + const base::string16& fixed_up_input_text) { + const GURL& url = titled_url_match.node->GetTitledUrlNodeUrl(); + base::string16 title = titled_url_match.node->GetTitledUrlNodeTitle(); + + // The AutocompleteMatch we construct is non-deletable because the only way to + // support this would be to delete the underlying object that created the + // titled_url_match. E.g., for the bookmark provider this would mean deleting + // the underlying bookmark, which is unlikely to be what the user intends. + AutocompleteMatch match(provider, relevance, false, type); + TitledUrlMatch::MatchPositions new_title_match_positions = + titled_url_match.title_match_positions; + CorrectTitleAndMatchPositions(&title, &new_title_match_positions); + const base::string16& url_utf16 = base::UTF8ToUTF16(url.spec()); + size_t inline_autocomplete_offset = URLPrefix::GetInlineAutocompleteOffset( + input.text(), fixed_up_input_text, false, url_utf16); + match.destination_url = url; + const size_t match_start = + titled_url_match.url_match_positions.empty() + ? 0 + : titled_url_match.url_match_positions[0].first; + const bool trim_http = + !AutocompleteInput::HasHTTPScheme(input.text()) && + ((match_start == base::string16::npos) || (match_start != 0)); + std::vector<size_t> offsets = TitledUrlMatch::OffsetsFromMatchPositions( + titled_url_match.url_match_positions); + // In addition to knowing how |offsets| is transformed, we need to know how + // |inline_autocomplete_offset| is transformed. We add it to the end of + // |offsets|, compute how everything is transformed, then remove it from the + // end. + offsets.push_back(inline_autocomplete_offset); + match.contents = url_formatter::FormatUrlWithOffsets( + url, url_formatter::kFormatUrlOmitAll & + ~(trim_http ? 0 : url_formatter::kFormatUrlOmitHTTP), + net::UnescapeRule::SPACES, nullptr, nullptr, &offsets); + inline_autocomplete_offset = offsets.back(); + offsets.pop_back(); + TitledUrlMatch::MatchPositions new_url_match_positions = + TitledUrlMatch::ReplaceOffsetsInMatchPositions( + titled_url_match.url_match_positions, offsets); + match.contents_class = ClassificationsFromMatchPositions( + new_url_match_positions, match.contents.size(), true); + match.fill_into_edit = + AutocompleteInput::FormattedStringWithEquivalentMeaning( + url, match.contents, scheme_classifier); + if (inline_autocomplete_offset != base::string16::npos) { + // |inline_autocomplete_offset| may be beyond the end of the + // |fill_into_edit| if the user has typed an URL with a scheme and the + // last character typed is a slash. That slash is removed by the + // FormatURLWithOffsets call above. + if (inline_autocomplete_offset < match.fill_into_edit.length()) { + match.inline_autocompletion = + match.fill_into_edit.substr(inline_autocomplete_offset); + } + match.allowed_to_be_default_match = + match.inline_autocompletion.empty() || + !HistoryProvider::PreventInlineAutocomplete(input); + } + match.description = title; + match.description_class = ClassificationsFromMatchPositions( + titled_url_match.title_match_positions, match.description.size(), false); + + return match; +} + +void CorrectTitleAndMatchPositions( + base::string16* title, + TitledUrlMatch::MatchPositions* title_match_positions) { + size_t leading_whitespace_chars = title->length(); + base::TrimWhitespace(*title, base::TRIM_LEADING, title); + leading_whitespace_chars -= title->length(); + if (leading_whitespace_chars == 0) + return; + for (TitledUrlMatch::MatchPositions::iterator it = + title_match_positions->begin(); + it != title_match_positions->end(); ++it) { + it->first -= leading_whitespace_chars; + it->second -= leading_whitespace_chars; + } +} + +} // namespace bookmarks
diff --git a/components/omnibox/browser/titled_url_match_utils.h b/components/omnibox/browser/titled_url_match_utils.h new file mode 100644 index 0000000..62bb694 --- /dev/null +++ b/components/omnibox/browser/titled_url_match_utils.h
@@ -0,0 +1,42 @@ +// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_OMNIBOX_BROWSER_TITLED_URL_MATCH_UTILS_H_ +#define COMPONENTS_OMNIBOX_BROWSER_TITLED_URL_MATCH_UTILS_H_ + +#include "base/strings/string16.h" +#include "components/bookmarks/browser/titled_url_match.h" +#include "components/omnibox/browser/autocomplete_match_type.h" + +class AutocompleteInput; +class AutocompleteProvider; +class AutocompleteSchemeClassifier; +struct AutocompleteMatch; + +namespace bookmarks { + +// Compose an AutocompleteMatch based on |match| that has the match's URL and +// page title, type |type|, and relevance score |relevance|. |input| is used to +// compute the match's inline_autocompletion. |fixed_up_input_text| is used in +// that way as well; it's passed separately so this function doesn't have to +// compute it. +AutocompleteMatch TitledUrlMatchToAutocompleteMatch( + const TitledUrlMatch& match, + AutocompleteMatchType::Type type, + int relevance, + AutocompleteProvider* provider, + const AutocompleteSchemeClassifier& scheme_classifier, + const AutocompleteInput& input, + const base::string16& fixed_up_input_text); + +// Removes leading spaces from |title| before displaying, otherwise it looks +// funny. In the process, corrects |title_match_positions| so the correct +// characters are highlighted. +void CorrectTitleAndMatchPositions( + base::string16* title, + TitledUrlMatch::MatchPositions* title_match_positions); + +} // namespace bookmarks + +#endif // COMPONENTS_OMNIBOX_BROWSER_TITLED_URL_MATCH_UTILS_H_
diff --git a/components/omnibox/browser/titled_url_match_utils_unittest.cc b/components/omnibox/browser/titled_url_match_utils_unittest.cc new file mode 100644 index 0000000..bc51287 --- /dev/null +++ b/components/omnibox/browser/titled_url_match_utils_unittest.cc
@@ -0,0 +1,185 @@ +// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/omnibox/browser/titled_url_match_utils.h" + +#include "base/memory/ptr_util.h" +#include "base/strings/utf_string_conversions.h" +#include "components/bookmarks/browser/titled_url_match.h" +#include "components/bookmarks/browser/titled_url_node.h" +#include "components/metrics/proto/omnibox_event.pb.h" +#include "components/omnibox/browser/autocomplete_input.h" +#include "components/omnibox/browser/autocomplete_match.h" +#include "components/omnibox/browser/autocomplete_provider.h" +#include "components/omnibox/browser/test_scheme_classifier.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +using bookmarks::TitledUrlMatchToAutocompleteMatch; +using bookmarks::CorrectTitleAndMatchPositions; + +namespace { + +// A simple AutocompleteProvider that does nothing. +class MockAutocompleteProvider : public AutocompleteProvider { + public: + MockAutocompleteProvider(Type type) : AutocompleteProvider(type) {} + + void Start(const AutocompleteInput& input, bool minimal_changes) override {} + + private: + ~MockAutocompleteProvider() override {} +}; + +class MockTitledUrlNode : public bookmarks::TitledUrlNode { + public: + MockTitledUrlNode(const base::string16& title, const GURL& url) + : title_(title), url_(url) {} + + // TitledUrlNode + const base::string16& GetTitledUrlNodeTitle() const override { + return title_; + } + const GURL& GetTitledUrlNodeUrl() const override { return url_; } + + private: + base::string16 title_; + GURL url_; +}; + +} // namespace + +bool operator==(const ACMatchClassification& lhs, + const ACMatchClassification& rhs) { + return (lhs.offset == rhs.offset) && (lhs.style == rhs.style); +} + +TEST(TitledUrlMatchUtilsTest, TitledUrlMatchToAutocompleteMatch) { + base::string16 input_text(base::ASCIIToUTF16("goo")); + base::string16 match_title(base::ASCIIToUTF16("Google Search")); + base::string16 match_url_string( + base::ASCIIToUTF16("https://www.google.com/")); + GURL match_url(match_url_string); + bookmarks::TitledUrlMatch::MatchPositions title_match_positions = {{0, 3}}; + bookmarks::TitledUrlMatch::MatchPositions url_match_positions = {{12, 15}}; + AutocompleteMatchType::Type type = AutocompleteMatchType::BOOKMARK_TITLE; + int relevance = 123; + + MockTitledUrlNode node(match_title, match_url); + bookmarks::TitledUrlMatch titled_url_match; + titled_url_match.node = &node; + titled_url_match.title_match_positions = title_match_positions; + titled_url_match.url_match_positions = url_match_positions; + + scoped_refptr<MockAutocompleteProvider> provider = + new MockAutocompleteProvider(AutocompleteProvider::Type::TYPE_BOOKMARK); + TestSchemeClassifier classifier; + AutocompleteInput input(input_text, base::string16::npos, std::string(), + GURL(), metrics::OmniboxEventProto::NTP, false, false, + true, true, false, classifier); + const base::string16 fixed_up_input(input_text); + + AutocompleteMatch autocomplete_match = TitledUrlMatchToAutocompleteMatch( + titled_url_match, type, relevance, provider.get(), classifier, input, + fixed_up_input); + + ACMatchClassifications expected_contents_class = { + {0, ACMatchClassification::URL}, + {12, ACMatchClassification::URL | ACMatchClassification::MATCH}, + {15, ACMatchClassification::URL}, + }; + ACMatchClassifications expected_description_class = { + {0, ACMatchClassification::MATCH}, {3, ACMatchClassification::NONE}, + }; + base::string16 expected_inline_autocompletion(base::ASCIIToUTF16("gle.com")); + base::string16 expected_contents( + base::ASCIIToUTF16("https://www.google.com")); + + EXPECT_EQ(provider.get(), autocomplete_match.provider); + EXPECT_EQ(type, autocomplete_match.type); + EXPECT_EQ(relevance, autocomplete_match.relevance); + EXPECT_EQ(match_url, autocomplete_match.destination_url); + EXPECT_EQ(expected_contents, autocomplete_match.contents); + EXPECT_TRUE(std::equal(expected_contents_class.begin(), + expected_contents_class.end(), + autocomplete_match.contents_class.begin())); + EXPECT_EQ(match_title, autocomplete_match.description); + EXPECT_TRUE(std::equal(expected_description_class.begin(), + expected_description_class.end(), + autocomplete_match.description_class.begin())); + EXPECT_EQ(expected_contents, autocomplete_match.fill_into_edit); + EXPECT_TRUE(autocomplete_match.allowed_to_be_default_match); + EXPECT_EQ(expected_inline_autocompletion, + autocomplete_match.inline_autocompletion); +} + +TEST(TitledUrlMatchUtilsTest, EmptyInlineAutocompletion) { + // The search term matches the title but not the URL. Since there is no URL + // match, the inline autocompletion string will be empty. + base::string16 input_text(base::ASCIIToUTF16("goo")); + base::string16 match_title(base::ASCIIToUTF16("Email by Google")); + base::string16 match_url_string(base::ASCIIToUTF16("https://www.gmail.com/")); + GURL match_url(match_url_string); + bookmarks::TitledUrlMatch::MatchPositions title_match_positions = {{9, 12}}; + bookmarks::TitledUrlMatch::MatchPositions url_match_positions; + AutocompleteMatchType::Type type = AutocompleteMatchType::BOOKMARK_TITLE; + int relevance = 123; + + MockTitledUrlNode node(match_title, match_url); + bookmarks::TitledUrlMatch titled_url_match; + titled_url_match.node = &node; + titled_url_match.title_match_positions = title_match_positions; + titled_url_match.url_match_positions = url_match_positions; + + scoped_refptr<MockAutocompleteProvider> provider = + new MockAutocompleteProvider(AutocompleteProvider::Type::TYPE_BOOKMARK); + TestSchemeClassifier classifier; + AutocompleteInput input(input_text, base::string16::npos, std::string(), + GURL(), metrics::OmniboxEventProto::NTP, false, false, + true, true, false, classifier); + const base::string16 fixed_up_input(input_text); + + AutocompleteMatch autocomplete_match = TitledUrlMatchToAutocompleteMatch( + titled_url_match, type, relevance, provider.get(), classifier, input, + fixed_up_input); + + ACMatchClassifications expected_contents_class = { + {0, ACMatchClassification::URL}, + }; + ACMatchClassifications expected_description_class = { + {0, ACMatchClassification::NONE}, + {9, ACMatchClassification::MATCH}, + {12, ACMatchClassification::NONE}, + }; + base::string16 expected_contents(base::ASCIIToUTF16("https://www.gmail.com")); + + EXPECT_EQ(provider.get(), autocomplete_match.provider); + EXPECT_EQ(type, autocomplete_match.type); + EXPECT_EQ(relevance, autocomplete_match.relevance); + EXPECT_EQ(match_url, autocomplete_match.destination_url); + EXPECT_EQ(expected_contents, autocomplete_match.contents); + EXPECT_TRUE(std::equal(expected_contents_class.begin(), + expected_contents_class.end(), + autocomplete_match.contents_class.begin())); + EXPECT_EQ(match_title, autocomplete_match.description); + EXPECT_TRUE(std::equal(expected_description_class.begin(), + expected_description_class.end(), + autocomplete_match.description_class.begin())); + EXPECT_EQ(expected_contents, autocomplete_match.fill_into_edit); + EXPECT_FALSE(autocomplete_match.allowed_to_be_default_match); + EXPECT_TRUE(autocomplete_match.inline_autocompletion.empty()); +} + +TEST(TitledUrlMatchUtilsTest, CorrectTitleAndMatchPositions) { + bookmarks::TitledUrlMatch::MatchPositions match_positions = {{2, 6}, + {10, 15}}; + base::string16 title = base::ASCIIToUTF16(" Leading whitespace"); + bookmarks::TitledUrlMatch::MatchPositions expected_match_positions = { + {0, 4}, {8, 13}}; + base::string16 expected_title = base::ASCIIToUTF16("Leading whitespace"); + CorrectTitleAndMatchPositions(&title, &match_positions); + EXPECT_EQ(expected_title, title); + EXPECT_TRUE(std::equal(match_positions.begin(), match_positions.end(), + expected_match_positions.begin())); +}
diff --git a/components/sync/driver/data_type_manager_impl.cc b/components/sync/driver/data_type_manager_impl.cc index afd0f877..15c30f1 100644 --- a/components/sync/driver/data_type_manager_impl.cc +++ b/components/sync/driver/data_type_manager_impl.cc
@@ -19,6 +19,7 @@ #include "components/sync/driver/data_type_encryption_handler.h" #include "components/sync/driver/data_type_manager_observer.h" #include "components/sync/driver/data_type_status_table.h" +#include "components/sync/driver/sync_client.h" #include "components/sync/engine/data_type_debug_info_listener.h" namespace syncer { @@ -44,13 +45,15 @@ DataTypeManagerImpl::AssociationTypesInfo::~AssociationTypesInfo() {} DataTypeManagerImpl::DataTypeManagerImpl( + SyncClient* sync_client, ModelTypeSet initial_types, const WeakHandle<DataTypeDebugInfoListener>& debug_info_listener, const DataTypeController::TypeMap* controllers, const DataTypeEncryptionHandler* encryption_handler, ModelTypeConfigurer* configurer, DataTypeManagerObserver* observer) - : configurer_(configurer), + : sync_client_(sync_client), + configurer_(configurer), controllers_(controllers), state_(DataTypeManager::STOPPED), needs_reconfigure_(false), @@ -78,17 +81,19 @@ desired_types.PutAll(CoreTypes()); - // Only allow control types and types that have controllers. - ModelTypeSet filtered_desired_types; - for (ModelTypeSet::Iterator type = desired_types.First(); type.Good(); - type.Inc()) { - DataTypeController::TypeMap::const_iterator iter = - controllers_->find(type.Get()); - if (IsControlType(type.Get()) || iter != controllers_->end()) { - filtered_desired_types.Put(type.Get()); - } + ModelTypeSet allowed_types = ControlTypes(); + // Add types with controllers. + for (const auto& kv : *controllers_) { + allowed_types.Put(kv.first); } - ConfigureImpl(filtered_desired_types, reason); + + // Remove types we cannot sync. + if (!sync_client_->HasPasswordStore()) + allowed_types.Remove(PASSWORDS); + if (!sync_client_->GetHistoryService()) + allowed_types.Remove(TYPED_URLS); + + ConfigureImpl(Intersection(desired_types, allowed_types), reason); } void DataTypeManagerImpl::ReenableType(ModelType type) {
diff --git a/components/sync/driver/data_type_manager_impl.h b/components/sync/driver/data_type_manager_impl.h index dd6f3ce4..b20f75b 100644 --- a/components/sync/driver/data_type_manager_impl.h +++ b/components/sync/driver/data_type_manager_impl.h
@@ -26,6 +26,7 @@ class DataTypeDebugInfoListener; class DataTypeEncryptionHandler; class DataTypeManagerObserver; +class SyncClient; struct DataTypeConfigurationStats; // List of data types grouped by priority and ordered from high priority to @@ -36,6 +37,7 @@ public ModelAssociationManagerDelegate { public: DataTypeManagerImpl( + SyncClient* sync_client, ModelTypeSet initial_types, const WeakHandle<DataTypeDebugInfoListener>& debug_info_listener, const DataTypeController::TypeMap* controllers, @@ -142,7 +144,9 @@ // Returns the currently enabled types. ModelTypeSet GetEnabledTypes() const; + SyncClient* sync_client_; ModelTypeConfigurer* configurer_; + // Map of all data type controllers that are available for sync. // This list is determined at startup by various command line flags. const DataTypeController::TypeMap* controllers_;
diff --git a/components/sync/driver/data_type_manager_impl_unittest.cc b/components/sync/driver/data_type_manager_impl_unittest.cc index 039443f..b1d450ae 100644 --- a/components/sync/driver/data_type_manager_impl_unittest.cc +++ b/components/sync/driver/data_type_manager_impl_unittest.cc
@@ -14,6 +14,7 @@ #include "components/sync/driver/data_type_manager_observer.h" #include "components/sync/driver/data_type_status_table.h" #include "components/sync/driver/fake_data_type_controller.h" +#include "components/sync/driver/fake_sync_client.h" #include "components/sync/engine/activation_context.h" #include "components/sync/engine/configure_reason.h" #include "testing/gtest/include/gtest/gtest.h" @@ -60,6 +61,11 @@ return status_table; } +class TestSyncClient : public FakeSyncClient { + public: + bool HasPasswordStore() override { return true; } +}; + // Fake ModelTypeConfigurer implementation that simply stores away the // callback passed into ConfigureDataTypes. class FakeModelTypeConfigurer : public ModelTypeConfigurer { @@ -216,20 +222,7 @@ class TestDataTypeManager : public DataTypeManagerImpl { public: - TestDataTypeManager( - ModelTypeSet initial_types, - const WeakHandle<DataTypeDebugInfoListener>& debug_info_listener, - ModelTypeConfigurer* configurer, - const DataTypeController::TypeMap* controllers, - const DataTypeEncryptionHandler* encryption_handler, - DataTypeManagerObserver* observer) - : DataTypeManagerImpl(initial_types, - debug_info_listener, - controllers, - encryption_handler, - configurer, - observer), - custom_priority_types_(ControlTypes()) {} + using DataTypeManagerImpl::DataTypeManagerImpl; void set_priority_types(const ModelTypeSet& priority_types) { custom_priority_types_ = priority_types; @@ -250,7 +243,7 @@ return custom_priority_types_; } - ModelTypeSet custom_priority_types_; + ModelTypeSet custom_priority_types_ = ControlTypes(); DataTypeManager::ConfigureResult configure_result_; }; @@ -265,8 +258,8 @@ protected: void SetUp() override { dtm_ = base::MakeUnique<TestDataTypeManager>( - ModelTypeSet(), WeakHandle<DataTypeDebugInfoListener>(), &configurer_, - &controllers_, &encryption_handler_, &observer_); + &sync_client_, ModelTypeSet(), WeakHandle<DataTypeDebugInfoListener>(), + &controllers_, &encryption_handler_, &configurer_, &observer_); } void SetConfigureStartExpectation() { observer_.ExpectStart(); } @@ -333,6 +326,7 @@ base::MessageLoopForUI ui_loop_; DataTypeController::TypeMap controllers_; + TestSyncClient sync_client_; FakeModelTypeConfigurer configurer_; FakeDataTypeManagerObserver observer_; std::unique_ptr<TestDataTypeManager> dtm_;
diff --git a/components/sync/driver/fake_sync_client.cc b/components/sync/driver/fake_sync_client.cc index 3b59eab29..16a46df 100644 --- a/components/sync/driver/fake_sync_client.cc +++ b/components/sync/driver/fake_sync_client.cc
@@ -60,6 +60,10 @@ return nullptr; } +bool FakeSyncClient::HasPasswordStore() { + return false; +} + base::Closure FakeSyncClient::GetPasswordStateChangedCallback() { return base::Bind(&base::DoNothing); }
diff --git a/components/sync/driver/fake_sync_client.h b/components/sync/driver/fake_sync_client.h index b68999e..8a8928d 100644 --- a/components/sync/driver/fake_sync_client.h +++ b/components/sync/driver/fake_sync_client.h
@@ -29,6 +29,7 @@ bookmarks::BookmarkModel* GetBookmarkModel() override; favicon::FaviconService* GetFaviconService() override; history::HistoryService* GetHistoryService() override; + bool HasPasswordStore() override; base::Closure GetPasswordStateChangedCallback() override; SyncApiComponentFactory::RegisterDataTypesMethod GetRegisterPlatformTypesCallback() override;
diff --git a/components/sync/driver/sync_client.h b/components/sync/driver/sync_client.h index c514e51..bf9ab4c 100644 --- a/components/sync/driver/sync_client.h +++ b/components/sync/driver/sync_client.h
@@ -71,6 +71,7 @@ virtual bookmarks::BookmarkModel* GetBookmarkModel() = 0; virtual favicon::FaviconService* GetFaviconService() = 0; virtual history::HistoryService* GetHistoryService() = 0; + virtual bool HasPasswordStore() = 0; // Returns a callback that will register the types specific to the current // platform.
diff --git a/content/browser/android/child_process_launcher_android.cc b/content/browser/android/child_process_launcher_android.cc index 77b45d5..a196b1a 100644 --- a/content/browser/android/child_process_launcher_android.cc +++ b/content/browser/android/child_process_launcher_android.cc
@@ -113,7 +113,6 @@ const base::CommandLine::StringVector& argv, int child_process_id, std::unique_ptr<content::FileDescriptorInfo> files_to_register, - const std::map<int, base::MemoryMappedFile::Region>& regions, const StartChildProcessCallback& callback) { JNIEnv* env = AttachCurrentThread(); DCHECK(env); @@ -135,13 +134,10 @@ PCHECK(0 <= fd); int id = files_to_register->GetIDAt(i); bool auto_close = files_to_register->OwnsFD(fd); - int64_t offset = 0L; - int64_t size = 0L; - auto found_region_iter = regions.find(id); - if (found_region_iter != regions.end()) { - offset = found_region_iter->second.offset; - size = found_region_iter->second.size; - } + const base::MemoryMappedFile::Region& region = + files_to_register->GetRegionAt(i); + int64_t offset = region.offset; + int64_t size = region.size; ScopedJavaLocalRef<jobject> j_file_info = Java_ChildProcessLauncher_makeFdInfo(env, id, fd, auto_close, offset, size);
diff --git a/content/browser/android/child_process_launcher_android.h b/content/browser/android/child_process_launcher_android.h index b99fbd7..78f088a6 100644 --- a/content/browser/android/child_process_launcher_android.h +++ b/content/browser/android/child_process_launcher_android.h
@@ -29,7 +29,6 @@ const base::CommandLine::StringVector& argv, int child_process_id, const std::unique_ptr<FileDescriptorInfo> files_to_register, - const std::map<int, base::MemoryMappedFile::Region>& regions, const StartChildProcessCallback& callback); // Stops a child process based on the handle returned form
diff --git a/content/browser/battery_status/battery_monitor_integration_browsertest.cc b/content/browser/battery_status/battery_monitor_integration_browsertest.cc index e024d6d7..9856a66 100644 --- a/content/browser/battery_status/battery_monitor_integration_browsertest.cc +++ b/content/browser/battery_status/battery_monitor_integration_browsertest.cc
@@ -109,10 +109,9 @@ void GetAdditionalMappedFilesForChildProcess( const base::CommandLine& command_line, int child_process_id, - FileDescriptorInfo* mappings, - std::map<int, base::MemoryMappedFile::Region>* regions) override { + FileDescriptorInfo* mappings) override { ShellContentBrowserClient::Get()->GetAdditionalMappedFilesForChildProcess( - command_line, child_process_id, mappings, regions); + command_line, child_process_id, mappings); } #endif // defined(OS_ANDROID) };
diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc index e93bb08..51f5696 100644 --- a/content/browser/child_process_launcher.cc +++ b/content/browser/child_process_launcher.cc
@@ -174,23 +174,15 @@ #endif #if defined(OS_POSIX) && !defined(OS_MACOSX) - std::map<int, base::MemoryMappedFile::Region> regions; GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess( - *cmd_line, child_process_id, files_to_register.get() -#if defined(OS_ANDROID) - , ®ions -#endif - ); + *cmd_line, child_process_id, files_to_register.get()); #if defined(V8_USE_EXTERNAL_STARTUP_DATA) bool snapshot_loaded = false; -#if defined(OS_ANDROID) base::MemoryMappedFile::Region region; - auto maybe_register = [®ion, ®ions, &files_to_register](int key, - int fd) { - if (fd != -1) { - files_to_register->Share(key, fd); - regions.insert(std::make_pair(key, region)); - } +#if defined(OS_ANDROID) + auto maybe_register = [®ion, &files_to_register](int key, int fd) { + if (fd != -1) + files_to_register->ShareWithRegion(key, fd, region); }; maybe_register( kV8NativesDataDescriptor, @@ -205,21 +197,19 @@ snapshot_loaded = true; #else base::PlatformFile natives_pf = - gin::V8Initializer::GetOpenNativesFileForChildProcesses( - ®ions[kV8NativesDataDescriptor]); + gin::V8Initializer::GetOpenNativesFileForChildProcesses(®ion); DCHECK_GE(natives_pf, 0); - files_to_register->Share(kV8NativesDataDescriptor, natives_pf); + files_to_register->ShareWithRegion( + kV8NativesDataDescriptor, natives_pf, region); - base::MemoryMappedFile::Region snapshot_region; base::PlatformFile snapshot_pf = - gin::V8Initializer::GetOpenSnapshotFileForChildProcesses( - &snapshot_region); + gin::V8Initializer::GetOpenSnapshotFileForChildProcesses(®ion); // Failure to load the V8 snapshot is not necessarily an error. V8 can start // up (slower) without the snapshot. if (snapshot_pf != -1) { snapshot_loaded = true; - files_to_register->Share(kV8SnapshotDataDescriptor, snapshot_pf); - regions.insert(std::make_pair(kV8SnapshotDataDescriptor, snapshot_region)); + files_to_register->ShareWithRegion( + kV8SnapshotDataDescriptor, snapshot_pf, region); } #endif @@ -234,9 +224,10 @@ #if defined(OS_ANDROID) #if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE - files_to_register->Share( - kAndroidICUDataDescriptor, - base::i18n::GetIcuDataFileHandle(®ions[kAndroidICUDataDescriptor])); + base::MemoryMappedFile::Region icu_region; + base::PlatformFile icu_pf = base::i18n::GetIcuDataFileHandle(&icu_region); + files_to_register->ShareWithRegion( + kAndroidICUDataDescriptor, icu_pf, icu_region); #endif // ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE // Android WebView runs in single process, ensure that we never get here @@ -244,7 +235,7 @@ CHECK(!cmd_line->HasSwitch(switches::kSingleProcess)); StartChildProcess( - cmd_line->argv(), child_process_id, std::move(files_to_register), regions, + cmd_line->argv(), child_process_id, std::move(files_to_register), base::Bind(&OnChildProcessStartedAndroid, callback, client_thread_id, begin_launch_time, base::Passed(&mojo_fd)));
diff --git a/content/browser/compositor/software_output_device_win.cc b/content/browser/compositor/software_output_device_win.cc index 0a1bc20..4cb2d87 100644 --- a/content/browser/compositor/software_output_device_win.cc +++ b/content/browser/compositor/software_output_device_win.cc
@@ -9,6 +9,7 @@ #include "cc/resources/shared_bitmap.h" #include "content/public/browser/browser_thread.h" #include "skia/ext/platform_canvas.h" +#include "skia/ext/skia_utils_win.h" #include "ui/compositor/compositor.h" #include "ui/gfx/gdi_util.h" #include "ui/gfx/skia_util.h" @@ -165,6 +166,8 @@ if (rect.IsEmpty()) return; + HDC dib_dc = skia::GetNativeDrawingContext(contents_.get()); + if (is_hwnd_composited_) { RECT wr; GetWindowRect(hwnd_, &wr); @@ -178,14 +181,19 @@ style |= WS_EX_LAYERED; SetWindowLong(hwnd_, GWL_EXSTYLE, style); - HDC dib_dc = skia::GetNativeDrawingContext(contents_.get()); ::UpdateLayeredWindow(hwnd_, NULL, &position, &size, dib_dc, &zero, RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA); } else { HDC hdc = ::GetDC(hwnd_); RECT src_rect = rect.ToRECT(); - skia::DrawToNativeContext(contents_.get(), hdc, rect.x(), rect.y(), - &src_rect); + skia::CopyHDC(dib_dc, + hdc, + rect.x(), + rect.y(), + contents_.get()->imageInfo().isOpaque(), + src_rect, + contents_.get()->getTotalMatrix()); + ::ReleaseDC(hwnd_, hdc); } }
diff --git a/content/browser/file_descriptor_info_impl.cc b/content/browser/file_descriptor_info_impl.cc index bfab1438..3392819 100644 --- a/content/browser/file_descriptor_info_impl.cc +++ b/content/browser/file_descriptor_info_impl.cc
@@ -22,11 +22,16 @@ } void FileDescriptorInfoImpl::Share(int id, base::PlatformFile fd) { - AddToMapping(id, fd); + ShareWithRegion(id, fd, base::MemoryMappedFile::Region::kWholeFile); +} + +void FileDescriptorInfoImpl::ShareWithRegion(int id, base::PlatformFile fd, + const base::MemoryMappedFile::Region& region) { + AddToMapping(id, fd, region); } void FileDescriptorInfoImpl::Transfer(int id, base::ScopedFD fd) { - AddToMapping(id, fd.get()); + AddToMapping(id, fd.get(), base::MemoryMappedFile::Region::kWholeFile); owned_descriptors_.push_back(std::move(fd)); } @@ -38,6 +43,13 @@ return mapping_[i].second; } +const base::MemoryMappedFile::Region& FileDescriptorInfoImpl::GetRegionAt( + size_t i) const { + auto iter = ids_to_regions_.find(GetIDAt(i)); + return (iter != ids_to_regions_.end()) ? + iter->second : base::MemoryMappedFile::Region::kWholeFile; +} + size_t FileDescriptorInfoImpl::GetMappingSize() const { return mapping_.size(); } @@ -68,9 +80,12 @@ return fd; } -void FileDescriptorInfoImpl::AddToMapping(int id, base::PlatformFile fd) { +void FileDescriptorInfoImpl::AddToMapping(int id, base::PlatformFile fd, + const base::MemoryMappedFile::Region& region) { DCHECK(!HasID(id)); mapping_.push_back(std::make_pair(fd, id)); + if (region != base::MemoryMappedFile::Region::kWholeFile) + ids_to_regions_[id] = region; } const base::FileHandleMappingVector& FileDescriptorInfoImpl::GetMapping()
diff --git a/content/browser/file_descriptor_info_impl.h b/content/browser/file_descriptor_info_impl.h index 010e797..eba0937 100644 --- a/content/browser/file_descriptor_info_impl.h +++ b/content/browser/file_descriptor_info_impl.h
@@ -7,9 +7,11 @@ #include <stddef.h> +#include <map> #include <memory> #include <vector> +#include "base/files/memory_mapped_file.h" #include "content/common/content_export.h" #include "content/public/browser/file_descriptor_info.h" @@ -21,12 +23,15 @@ ~FileDescriptorInfoImpl() override; void Share(int id, base::PlatformFile fd) override; + void ShareWithRegion(int id, base::PlatformFile fd, + const base::MemoryMappedFile::Region& region) override; void Transfer(int id, base::ScopedFD fd) override; const base::FileHandleMappingVector& GetMapping() const override; base::FileHandleMappingVector GetMappingWithIDAdjustment( int delta) const override; base::PlatformFile GetFDAt(size_t i) const override; int GetIDAt(size_t i) const override; + const base::MemoryMappedFile::Region& GetRegionAt(size_t i) const override; size_t GetMappingSize() const override; bool OwnsFD(base::PlatformFile file) const override; base::ScopedFD ReleaseFD(base::PlatformFile file) override; @@ -34,9 +39,13 @@ private: FileDescriptorInfoImpl(); - void AddToMapping(int id, base::PlatformFile fd); + void AddToMapping(int id, base::PlatformFile fd, + const base::MemoryMappedFile::Region& region); bool HasID(int id) const; base::FileHandleMappingVector mapping_; + // Maps the ID of a FD to the region to use for that FD, the whole file if not + // in the map. + std::map<int, base::MemoryMappedFile::Region> ids_to_regions_; std::vector<base::ScopedFD> owned_descriptors_; }; }
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc index 5bde4bb..06c2fb1 100644 --- a/content/browser/frame_host/navigation_controller_impl.cc +++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -1240,9 +1240,11 @@ if (entry->update_virtual_url_with_url()) UpdateVirtualURLToURL(entry, params.url); - // The site instance will normally be the same except during session restore, - // when no site instance will be assigned. + // The site instance will normally be the same except + // 1) session restore, when no site instance will be assigned or + // 2) redirect, when the site instance is reset. DCHECK(entry->site_instance() == nullptr || + !entry->GetRedirectChain().empty() || entry->site_instance() == rfh->GetSiteInstance()); // Update the existing FrameNavigationEntry to ensure all of its members
diff --git a/content/browser/frame_host/navigation_controller_impl_unittest.cc b/content/browser/frame_host/navigation_controller_impl_unittest.cc index 637dec0..2fb7893 100644 --- a/content/browser/frame_host/navigation_controller_impl_unittest.cc +++ b/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -2196,12 +2196,9 @@ subframe->PrepareForCommit(); subframe->SendNavigateWithParams(¶ms); - // In UseSubframeNavigationEntries mode, we notify of a PageState update to - // the entry here rather than during UpdateState. - if (SiteIsolationPolicy::UseSubframeNavigationEntries()) - EXPECT_TRUE(notifications.Check1AndReset(NOTIFICATION_NAV_ENTRY_CHANGED)); - else - EXPECT_EQ(0U, notifications.size()); + // We notify of a PageState update here rather than during UpdateState for + // auto subframe navigations. + EXPECT_TRUE(notifications.Check1AndReset(NOTIFICATION_NAV_ENTRY_CHANGED)); } // Now do a new navigation in the frame. @@ -2236,15 +2233,9 @@ // reflect the toplevel URL). EXPECT_EQ(url1, entry->GetURL()); - // Verify subframe entries if they're enabled (e.g. in --site-per-process). - if (SiteIsolationPolicy::UseSubframeNavigationEntries()) { - // The entry should have a subframe FrameNavigationEntry. - ASSERT_EQ(1U, entry->root_node()->children.size()); - EXPECT_EQ(url2, entry->root_node()->children[0]->frame_entry->url()); - } else { - // There are no subframe FrameNavigationEntries by default. - EXPECT_EQ(0U, entry->root_node()->children.size()); - } + // The entry should have a subframe FrameNavigationEntry. + ASSERT_EQ(1U, entry->root_node()->children.size()); + EXPECT_EQ(url2, entry->root_node()->children[0]->frame_entry->url()); } // Auto subframes are ones the page loads automatically like ads. They should @@ -2286,12 +2277,9 @@ subframe->PrepareForCommit(); subframe->SendNavigateWithParams(¶ms); - // In UseSubframeNavigationEntries mode, we notify of a PageState update to - // the entry here rather than during UpdateState. - if (SiteIsolationPolicy::UseSubframeNavigationEntries()) - EXPECT_TRUE(notifications.Check1AndReset(NOTIFICATION_NAV_ENTRY_CHANGED)); - else - EXPECT_EQ(0U, notifications.size()); + // We notify of a PageState update here rather than during UpdateState for + // auto subframe navigations. + EXPECT_TRUE(notifications.Check1AndReset(NOTIFICATION_NAV_ENTRY_CHANGED)); } // There should still be only one entry. @@ -2301,17 +2289,11 @@ FrameNavigationEntry* root_entry = entry->root_node()->frame_entry.get(); EXPECT_EQ(url1, root_entry->url()); - // Verify subframe entries if they're enabled (e.g. in --site-per-process). - if (SiteIsolationPolicy::UseSubframeNavigationEntries()) { - // The entry should now have a subframe FrameNavigationEntry. - ASSERT_EQ(1U, entry->root_node()->children.size()); - FrameNavigationEntry* frame_entry = - entry->root_node()->children[0]->frame_entry.get(); - EXPECT_EQ(url2, frame_entry->url()); - } else { - // There are no subframe FrameNavigationEntries by default. - EXPECT_EQ(0U, entry->root_node()->children.size()); - } + // The entry should now have a subframe FrameNavigationEntry. + ASSERT_EQ(1U, entry->root_node()->children.size()); + FrameNavigationEntry* frame_entry = + entry->root_node()->children[0]->frame_entry.get(); + EXPECT_EQ(url2, frame_entry->url()); // Add a second subframe and navigate. std::string unique_name1("uniqueName1"); @@ -2339,12 +2321,9 @@ subframe2->PrepareForCommit(); subframe2->SendNavigateWithParams(¶ms); - // In UseSubframeNavigationEntries mode, we notify of a PageState update to - // the entry here rather than during UpdateState. - if (SiteIsolationPolicy::UseSubframeNavigationEntries()) - EXPECT_TRUE(notifications.Check1AndReset(NOTIFICATION_NAV_ENTRY_CHANGED)); - else - EXPECT_EQ(0U, notifications.size()); + // We notify of a PageState update here rather than during UpdateState for + // auto subframe navigations. + EXPECT_TRUE(notifications.Check1AndReset(NOTIFICATION_NAV_ENTRY_CHANGED)); } // There should still be only one entry, mostly unchanged. @@ -2354,17 +2333,11 @@ EXPECT_EQ(root_entry, entry->root_node()->frame_entry.get()); EXPECT_EQ(url1, root_entry->url()); - // Verify subframe entries if they're enabled (e.g. in --site-per-process). - if (SiteIsolationPolicy::UseSubframeNavigationEntries()) { - // The entry should now have 2 subframe FrameNavigationEntries. - ASSERT_EQ(2U, entry->root_node()->children.size()); - FrameNavigationEntry* new_frame_entry = - entry->root_node()->children[1]->frame_entry.get(); - EXPECT_EQ(url3, new_frame_entry->url()); - } else { - // There are no subframe FrameNavigationEntries by default. - EXPECT_EQ(0U, entry->root_node()->children.size()); - } + // The entry should now have 2 subframe FrameNavigationEntries. + ASSERT_EQ(2U, entry->root_node()->children.size()); + FrameNavigationEntry* new_frame_entry = + entry->root_node()->children[1]->frame_entry.get(); + EXPECT_EQ(url3, new_frame_entry->url()); // Add a nested subframe and navigate. std::string unique_name2("uniqueName2"); @@ -2397,12 +2370,9 @@ subframe3->PrepareForCommit(); subframe3->SendNavigateWithParams(¶ms); - // In UseSubframeNavigationEntries mode, we notify of a PageState update to - // the entry here rather than during UpdateState. - if (SiteIsolationPolicy::UseSubframeNavigationEntries()) - EXPECT_TRUE(notifications.Check1AndReset(NOTIFICATION_NAV_ENTRY_CHANGED)); - else - EXPECT_EQ(0U, notifications.size()); + // We notify of a PageState update here rather than during UpdateState for + // auto subframe navigations. + EXPECT_TRUE(notifications.Check1AndReset(NOTIFICATION_NAV_ENTRY_CHANGED)); } // There should still be only one entry, mostly unchanged. @@ -2412,18 +2382,12 @@ EXPECT_EQ(root_entry, entry->root_node()->frame_entry.get()); EXPECT_EQ(url1, root_entry->url()); - // Verify subframe entries if they're enabled (e.g. in --site-per-process). - if (SiteIsolationPolicy::UseSubframeNavigationEntries()) { - // The entry should now have a nested FrameNavigationEntry. - EXPECT_EQ(2U, entry->root_node()->children.size()); - ASSERT_EQ(1U, entry->root_node()->children[0]->children.size()); - FrameNavigationEntry* new_frame_entry = - entry->root_node()->children[0]->children[0]->frame_entry.get(); - EXPECT_EQ(url4, new_frame_entry->url()); - } else { - // There are no subframe FrameNavigationEntries by default. - EXPECT_EQ(0U, entry->root_node()->children.size()); - } + // The entry should now have a nested FrameNavigationEntry. + EXPECT_EQ(2U, entry->root_node()->children.size()); + ASSERT_EQ(1U, entry->root_node()->children[0]->children.size()); + new_frame_entry = + entry->root_node()->children[0]->children[0]->frame_entry.get(); + EXPECT_EQ(url4, new_frame_entry->url()); } // Tests navigation and then going back to a subframe navigation. @@ -2473,12 +2437,9 @@ subframe->PrepareForCommit(); subframe->SendNavigateWithParams(¶ms); - // In UseSubframeNavigationEntries mode, we notify of a PageState update to - // the entry here rather than during UpdateState. - if (SiteIsolationPolicy::UseSubframeNavigationEntries()) - EXPECT_TRUE(notifications.Check1AndReset(NOTIFICATION_NAV_ENTRY_CHANGED)); - else - EXPECT_EQ(0U, notifications.size()); + // We notify of a PageState update here rather than during UpdateState for + // auto subframe navigations. + EXPECT_TRUE(notifications.Check1AndReset(NOTIFICATION_NAV_ENTRY_CHANGED)); } // First manual subframe navigation. @@ -2508,16 +2469,9 @@ navigation_entry_committed_counter_ = 0; EXPECT_EQ(2, controller.GetEntryCount()); - // Verify subframe entries if they're enabled (e.g. in --site-per-process). - if (SiteIsolationPolicy::UseSubframeNavigationEntries()) { - // The entry should have a subframe FrameNavigationEntry. - ASSERT_EQ(1U, entry2->root_node()->children.size()); - EXPECT_EQ(url2, entry2->root_node()->children[0]->frame_entry->url()); - } else { - // There are no subframe FrameNavigationEntries by default. - EXPECT_EQ(0U, entry2->root_node()->children.size()); - } - + // The entry should have a subframe FrameNavigationEntry. + ASSERT_EQ(1U, entry2->root_node()->children.size()); + EXPECT_EQ(url2, entry2->root_node()->children[0]->frame_entry->url()); // Second manual subframe navigation should also make a new entry. const GURL url3("http://foo3"); @@ -2541,15 +2495,9 @@ EXPECT_EQ(3, controller.GetEntryCount()); EXPECT_EQ(2, controller.GetCurrentEntryIndex()); - // Verify subframe entries if they're enabled (e.g. in --site-per-process). - if (SiteIsolationPolicy::UseSubframeNavigationEntries()) { - // The entry should have a subframe FrameNavigationEntry. - ASSERT_EQ(1U, entry3->root_node()->children.size()); - EXPECT_EQ(url3, entry3->root_node()->children[0]->frame_entry->url()); - } else { - // There are no subframe FrameNavigationEntries by default. - EXPECT_EQ(0U, entry3->root_node()->children.size()); - } + // The entry should have a subframe FrameNavigationEntry. + ASSERT_EQ(1U, entry3->root_node()->children.size()); + EXPECT_EQ(url3, entry3->root_node()->children[0]->frame_entry->url()); // Go back one. controller.GoBack();
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc index 898679f2..8a1007d 100644 --- a/content/browser/frame_host/navigation_request.cc +++ b/content/browser/frame_host/navigation_request.cc
@@ -403,6 +403,10 @@ void NavigationRequest::OnRequestRedirected( const net::RedirectInfo& redirect_info, const scoped_refptr<ResourceResponse>& response) { + // If a redirect occurs, the original site instance we thought is the + // destination could change. + dest_site_instance_ = nullptr; + // If the navigation is no longer a POST, the POST data should be reset. if (redirect_info.new_method != "POST") common_params_.post_data = nullptr;
diff --git a/content/browser/permissions/permission_service_context.cc b/content/browser/permissions/permission_service_context.cc index cffb065..9292a31 100644 --- a/content/browser/permissions/permission_service_context.cc +++ b/content/browser/permissions/permission_service_context.cc
@@ -27,7 +27,15 @@ &PermissionSubscription::OnConnectionError, base::Unretained(this))); } - ~PermissionSubscription() = default; + ~PermissionSubscription() { + DCHECK_NE(id_, 0); + BrowserContext* browser_context = context_->GetBrowserContext(); + DCHECK(browser_context); + if (browser_context->GetPermissionManager()) { + browser_context->GetPermissionManager() + ->UnsubscribePermissionStatusChange(id_); + } + } void OnConnectionError() { DCHECK_NE(id_, 0); @@ -105,13 +113,6 @@ } void PermissionServiceContext::ObserverHadConnectionError(int subscription_id) { - BrowserContext* browser_context = GetBrowserContext(); - DCHECK(browser_context); - if (browser_context->GetPermissionManager()) { - browser_context->GetPermissionManager()->UnsubscribePermissionStatusChange( - subscription_id); - } - auto it = subscriptions_.find(subscription_id); DCHECK(it != subscriptions_.end()); subscriptions_.erase(it); @@ -139,13 +140,15 @@ } void PermissionServiceContext::CancelPendingOperations( - RenderFrameHost* render_frame_host) const { + RenderFrameHost* render_frame_host) { DCHECK(render_frame_host_); if (render_frame_host != render_frame_host_) return; for (const auto& service : services_) service->CancelPendingOperations(); + + subscriptions_.clear(); } BrowserContext* PermissionServiceContext::GetBrowserContext() const {
diff --git a/content/browser/permissions/permission_service_context.h b/content/browser/permissions/permission_service_context.h index 83274b4..11bcc5b 100644 --- a/content/browser/permissions/permission_service_context.h +++ b/content/browser/permissions/permission_service_context.h
@@ -70,7 +70,7 @@ const LoadCommittedDetails& details, const FrameNavigateParams& params) override; - void CancelPendingOperations(RenderFrameHost*) const; + void CancelPendingOperations(RenderFrameHost*); RenderFrameHost* render_frame_host_; RenderProcessHost* render_process_host_;
diff --git a/content/browser/permissions/permission_service_impl.cc b/content/browser/permissions/permission_service_impl.cc index 75e8a6cd..90767d0 100644 --- a/content/browser/permissions/permission_service_impl.cc +++ b/content/browser/permissions/permission_service_impl.cc
@@ -257,11 +257,6 @@ last_known_status = current_status; } - BrowserContext* browser_context = context_->GetBrowserContext(); - DCHECK(browser_context); - if (!browser_context->GetPermissionManager()) - return; - context_->CreateSubscription(PermissionDescriptorToPermissionType(permission), origin, std::move(observer)); }
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index 18976390..343b875 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h
@@ -764,18 +764,12 @@ // Populates |mappings| with all files that need to be mapped before launching // a child process. -#if defined(OS_ANDROID) - virtual void GetAdditionalMappedFilesForChildProcess( - const base::CommandLine& command_line, - int child_process_id, - content::FileDescriptorInfo* mappings, - std::map<int, base::MemoryMappedFile::Region>* regions) {} -#elif defined(OS_POSIX) && !defined(OS_MACOSX) +#if defined(OS_POSIX) && !defined(OS_MACOSX) virtual void GetAdditionalMappedFilesForChildProcess( const base::CommandLine& command_line, int child_process_id, content::FileDescriptorInfo* mappings) {} -#endif // defined(OS_ANDROID) +#endif // defined(OS_POSIX) && !defined(OS_MACOSX) #if defined(OS_WIN) // This is called on the PROCESS_LAUNCHER thread before the renderer process
diff --git a/content/public/browser/file_descriptor_info.h b/content/public/browser/file_descriptor_info.h index 255ac2c..4fc686b 100644 --- a/content/public/browser/file_descriptor_info.h +++ b/content/public/browser/file_descriptor_info.h
@@ -8,45 +8,51 @@ #include <stddef.h> #include "base/files/file.h" +#include "base/files/memory_mapped_file.h" #include "base/process/launch.h" namespace content { -// FileDescriptorInfo is a collection of file descriptors which is -// needed to launch a process. You should tell FileDescriptorInfo -// which FD should be closed and which shouldn't so that it can take care -// of the lifetime of FDs. +// FileDescriptorInfo is a collection of file descriptors which is needed to +// launch a process. You should tell FileDescriptorInfo which FDs should be +// closed and which shouldn't so that it can take care of the lifetime of FDs. // -// See base/process/launcher.h for more details about launching a -// process. +// See base/process/launcher.h for more details about launching a process. class FileDescriptorInfo { public: virtual ~FileDescriptorInfo() {} - // Add an FD associated with an ID, without delegating the ownerhip - // of ID. + // Adds an FD associated with an ID, without delegating the ownerhip of ID. virtual void Share(int id, base::PlatformFile fd) = 0; - // Add an FD associated with an ID, passing the FD ownership to + // Similar to Share but also provides a region in that file that should be + // read in the launched process (accessible with GetRegionAt()). + virtual void ShareWithRegion( + int id, + base::PlatformFile fd, + const base::MemoryMappedFile::Region& region) = 0; + + // Adds an FD associated with an ID, passing the FD ownership to // FileDescriptorInfo. virtual void Transfer(int id, base::ScopedFD fd) = 0; - // A vecotr backed map of registered ID-FD pairs. + // A vector backed map of registered ID-FD pairs. virtual const base::FileHandleMappingVector& GetMapping() const = 0; - // A GetMapping() variant what adjusts the ID value by |delta|. + // A GetMapping() variant that adjusts the ID value by |delta|. // Some environments need this trick. virtual base::FileHandleMappingVector GetMappingWithIDAdjustment( int delta) const = 0; - // API for iterating registered ID-FD pairs. + // API for iterating over the registered ID-FD pairs. virtual base::PlatformFile GetFDAt(size_t i) const = 0; virtual int GetIDAt(size_t i) const = 0; + virtual const base::MemoryMappedFile::Region& GetRegionAt(size_t i) const = 0; virtual size_t GetMappingSize() const = 0; - // True if |this| has an ownership of |file|. + // Returns true if |this| has ownership of |file|. virtual bool OwnsFD(base::PlatformFile file) const = 0; - // Assuming |OwnsFD(file)|, release the ownership. + // Assuming |OwnsFD(file)|, releases the ownership. virtual base::ScopedFD ReleaseFD(base::PlatformFile file) = 0; };
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc index 5e5695af..6ecd9f2 100644 --- a/content/renderer/render_view_browsertest.cc +++ b/content/renderer/render_view_browsertest.cc
@@ -592,13 +592,8 @@ "document.getElementById('elt_text').value = 'foo';"); ProcessPendingMessages(); - if (SiteIsolationPolicy::UseSubframeNavigationEntries()) { - EXPECT_TRUE(render_thread_->sink().GetUniqueMessageMatching( - FrameHostMsg_UpdateState::ID)); - } else { - EXPECT_TRUE(render_thread_->sink().GetUniqueMessageMatching( - ViewHostMsg_UpdateState::ID)); - } + EXPECT_TRUE(render_thread_->sink().GetUniqueMessageMatching( + FrameHostMsg_UpdateState::ID)); } TEST_F(RenderViewImplTest, OnNavigationHttpPost) {
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc index 3783b3c..323544f 100644 --- a/content/shell/browser/shell_content_browser_client.cc +++ b/content/shell/browser/shell_content_browser_client.cc
@@ -330,18 +330,16 @@ gfx::Size())->web_contents()); } -#if defined(OS_ANDROID) +#if defined(OS_POSIX) && !defined(OS_MACOSX) void ShellContentBrowserClient::GetAdditionalMappedFilesForChildProcess( const base::CommandLine& command_line, int child_process_id, - content::FileDescriptorInfo* mappings, - std::map<int, base::MemoryMappedFile::Region>* regions) { - mappings->Share( + content::FileDescriptorInfo* mappings) { +#if defined(OS_ANDROID) + mappings->ShareWithRegion( kShellPakDescriptor, - base::GlobalDescriptors::GetInstance()->Get(kShellPakDescriptor)); - regions->insert(std::make_pair( - kShellPakDescriptor, - base::GlobalDescriptors::GetInstance()->GetRegion(kShellPakDescriptor))); + base::GlobalDescriptors::GetInstance()->Get(kShellPakDescriptor), + base::GlobalDescriptors::GetInstance()->GetRegion(kShellPakDescriptor)); if (breakpad::IsCrashReporterEnabled()) { base::File f(breakpad::CrashDumpManager::GetInstance()->CreateMinidumpFile( @@ -354,18 +352,15 @@ base::ScopedFD(f.TakePlatformFile())); } } -} -#elif defined(OS_POSIX) && !defined(OS_MACOSX) -void ShellContentBrowserClient::GetAdditionalMappedFilesForChildProcess( - const base::CommandLine& command_line, - int child_process_id, - content::FileDescriptorInfo* mappings) { + +#else int crash_signal_fd = GetCrashSignalFD(command_line); if (crash_signal_fd >= 0) { mappings->Share(kCrashDumpSignal, crash_signal_fd); } -} #endif // defined(OS_ANDROID) +} +#endif // defined(OS_POSIX) && !defined(OS_MACOSX) #if defined(OS_WIN) bool ShellContentBrowserClient::PreSpawnRenderer(
diff --git a/content/shell/browser/shell_content_browser_client.h b/content/shell/browser/shell_content_browser_client.h index 7b9d9d8..cd788ad7 100644 --- a/content/shell/browser/shell_content_browser_client.h +++ b/content/shell/browser/shell_content_browser_client.h
@@ -63,18 +63,12 @@ const OpenURLParams& params, const base::Callback<void(WebContents*)>& callback) override; -#if defined(OS_ANDROID) - void GetAdditionalMappedFilesForChildProcess( - const base::CommandLine& command_line, - int child_process_id, - content::FileDescriptorInfo* mappings, - std::map<int, base::MemoryMappedFile::Region>* regions) override; -#elif defined(OS_POSIX) && !defined(OS_MACOSX) +#if defined(OS_POSIX) && !defined(OS_MACOSX) void GetAdditionalMappedFilesForChildProcess( const base::CommandLine& command_line, int child_process_id, content::FileDescriptorInfo* mappings) override; -#endif // defined(OS_ANDROID) +#endif // defined(OS_POSIX) && !defined(OS_MACOSX) #if defined(OS_WIN) bool PreSpawnRenderer(sandbox::TargetPolicy* policy) override; #endif
diff --git a/extensions/renderer/api_binding.cc b/extensions/renderer/api_binding.cc index 7e596719..9856a81 100644 --- a/extensions/renderer/api_binding.cc +++ b/extensions/renderer/api_binding.cc
@@ -200,12 +200,10 @@ { v8::TryCatch try_catch(isolate); APIBindingHooks::RequestResult hooks_result = - APIBindingHooks::RequestResult::NOT_HANDLED; - hooks_result = binding_hooks_->HandleRequest(api_name_, name, context, - signature, &argument_list, - *type_refs_); + binding_hooks_->HandleRequest(api_name_, name, context, + signature, &argument_list, *type_refs_); - switch (hooks_result) { + switch (hooks_result.code) { case APIBindingHooks::RequestResult::INVALID_INVOCATION: invalid_invocation = true; // Throw a type error below so that it's not caught by our try-catch. @@ -215,6 +213,8 @@ try_catch.ReThrow(); return; case APIBindingHooks::RequestResult::HANDLED: + if (!hooks_result.return_value.IsEmpty()) + arguments->Return(hooks_result.return_value); return; // Our work here is done. case APIBindingHooks::RequestResult::NOT_HANDLED: break; // Handle in the default manner.
diff --git a/extensions/renderer/api_binding_hooks.cc b/extensions/renderer/api_binding_hooks.cc index b46d785..c4bc12c 100644 --- a/extensions/renderer/api_binding_hooks.cc +++ b/extensions/renderer/api_binding_hooks.cc
@@ -164,6 +164,11 @@ } // namespace +APIBindingHooks::RequestResult::RequestResult(ResultCode code) : code(code) {} +APIBindingHooks::RequestResult::~RequestResult() {} +APIBindingHooks::RequestResult::RequestResult(const RequestResult& other) = + default; + APIBindingHooks::APIBindingHooks(const binding::RunJSFunctionSync& run_js) : run_js_(run_js) {} APIBindingHooks::~APIBindingHooks() {} @@ -195,7 +200,7 @@ signature, context, arguments, type_refs); // Right now, it doesn't make sense to register a request handler that // doesn't handle the request. - DCHECK_NE(RequestResult::NOT_HANDLED, result); + DCHECK_NE(RequestResult::NOT_HANDLED, result.code); return result; } @@ -204,7 +209,7 @@ v8::Local<v8::Object> hook_interface_object = GetJSHookInterfaceObject(api_name, context, false); if (hook_interface_object.IsEmpty()) - return RequestResult::NOT_HANDLED; + return RequestResult(RequestResult::NOT_HANDLED); v8::Isolate* isolate = context->GetIsolate(); @@ -223,7 +228,7 @@ UpdateArguments(pre_validate_hook, context, arguments); if (try_catch.HasCaught()) { try_catch.ReThrow(); - return RequestResult::THROWN; + return RequestResult(RequestResult::THROWN); } } @@ -237,17 +242,25 @@ &parsed_v8_args, &error); if (try_catch.HasCaught()) { try_catch.ReThrow(); - return RequestResult::THROWN; + return RequestResult(RequestResult::THROWN); } if (!success) - return RequestResult::INVALID_INVOCATION; + return RequestResult(RequestResult::INVALID_INVOCATION); - run_js_.Run(handle_request, context, parsed_v8_args.size(), - parsed_v8_args.data()); - return RequestResult::HANDLED; + v8::Global<v8::Value> global_result = + run_js_.Run(handle_request, context, parsed_v8_args.size(), + parsed_v8_args.data()); + if (try_catch.HasCaught()) { + try_catch.ReThrow(); + return RequestResult(RequestResult::THROWN); + } + RequestResult result(RequestResult::HANDLED); + if (!global_result.IsEmpty()) + result.return_value = global_result.Get(isolate); + return result; } - return RequestResult::NOT_HANDLED; + return RequestResult(RequestResult::NOT_HANDLED); } void APIBindingHooks::InitializeInContext(
diff --git a/extensions/renderer/api_binding_hooks.h b/extensions/renderer/api_binding_hooks.h index d6620275..e326d8cf 100644 --- a/extensions/renderer/api_binding_hooks.h +++ b/extensions/renderer/api_binding_hooks.h
@@ -30,11 +30,21 @@ class APIBindingHooks { public: // The result of checking for hooks to handle a request. - enum class RequestResult { - HANDLED, // A custom hook handled the request. - THROWN, // An exception was thrown during parsing or handling. - INVALID_INVOCATION, // The request was called with invalid arguments. - NOT_HANDLED, // The request was not handled. + struct RequestResult { + enum ResultCode { + HANDLED, // A custom hook handled the request. + THROWN, // An exception was thrown during parsing or + // handling. + INVALID_INVOCATION, // The request was called with invalid arguments. + NOT_HANDLED, // The request was not handled. + }; + + explicit RequestResult(ResultCode code); + RequestResult(const RequestResult& other); + ~RequestResult(); + + ResultCode code; + v8::Local<v8::Value> return_value; // Only valid if code == HANDLED. }; // The callback to handle an API method. We pass in the expected signature @@ -68,8 +78,7 @@ const std::string& api_name); // Looks for a custom hook to handle the given request and, if one exists, - // runs it. Returns the result of trying to run the hook, or NOT_HANDLED if no - // hook was found. + // runs it. Returns the result of running the hook, if any. RequestResult HandleRequest(const std::string& api_name, const std::string& method_name, v8::Local<v8::Context> context,
diff --git a/extensions/renderer/api_binding_unittest.cc b/extensions/renderer/api_binding_unittest.cc index d526b7d..a210705 100644 --- a/extensions/renderer/api_binding_unittest.cc +++ b/extensions/renderer/api_binding_unittest.cc
@@ -478,12 +478,14 @@ std::vector<v8::Local<v8::Value>>* arguments, const ArgumentSpec::RefMap& ref_map) { *did_call = true; - if (arguments->size() != 1u) { + APIBindingHooks::RequestResult result( + APIBindingHooks::RequestResult::HANDLED); + if (arguments->size() != 1u) { // ASSERT* messes with the return type. EXPECT_EQ(1u, arguments->size()); - return APIBindingHooks::RequestResult::HANDLED; + return result; } EXPECT_EQ("foo", gin::V8ToString(arguments->at(0))); - return APIBindingHooks::RequestResult::HANDLED; + return result; }; hooks->RegisterHandleRequest("test.oneString", base::Bind(hook, &did_call)); @@ -691,4 +693,195 @@ ExpectPass(binding_object, "obj.stringAndInt('foo', 42);", "['foo',42]"); } +// Tests that custom JS hooks can return results synchronously. +TEST_F(APIBindingUnittest, TestReturningResultFromCustomJSHook) { + // Register a hook for the test.oneString method. + auto hooks = base::MakeUnique<APIBindingHooks>( + base::Bind(&RunFunctionOnGlobalAndReturnHandle)); + + v8::HandleScope handle_scope(isolate()); + v8::Local<v8::Context> context = ContextLocal(); + const char kRegisterHook[] = + "(function(hooks) {\n" + " hooks.setHandleRequest('oneString', str => {\n" + " return str + ' pong';\n" + " });\n" + "})"; + v8::Local<v8::String> source_string = + gin::StringToV8(isolate(), kRegisterHook); + v8::Local<v8::String> source_name = + gin::StringToV8(isolate(), "custom_hook"); + hooks->RegisterJsSource( + v8::Global<v8::String>(isolate(), source_string), + v8::Global<v8::String>(isolate(), source_name)); + + std::unique_ptr<base::ListValue> functions = ListValueFromString(kFunctions); + ASSERT_TRUE(functions); + ArgumentSpec::RefMap refs; + + APIBinding binding( + "test", functions.get(), nullptr, nullptr, + base::Bind(&APIBindingUnittest::OnFunctionCall, base::Unretained(this)), + std::move(hooks), &refs); + EXPECT_TRUE(refs.empty()); + + APIEventHandler event_handler( + base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); + v8::Local<v8::Object> binding_object = binding.CreateInstance( + context, isolate(), &event_handler, base::Bind(&AllowAllAPIs)); + + v8::Local<v8::Function> function = + FunctionFromString(context, + "(function(obj) { return obj.oneString('ping'); })"); + v8::Local<v8::Value> args[] = {binding_object}; + v8::Local<v8::Value> result = + RunFunction(function, context, arraysize(args), args); + ASSERT_FALSE(result.IsEmpty()); + std::unique_ptr<base::Value> json_result = V8ToBaseValue(result, context); + ASSERT_TRUE(json_result); + EXPECT_EQ("\"ping pong\"", ValueToString(*json_result)); +} + +// Tests that JS custom hooks can throw exceptions for bad invocations. +TEST_F(APIBindingUnittest, TestThrowingFromCustomJSHook) { + // Our testing handlers for running functions expect a pre-determined success + // or failure. Since we're testing throwing exceptions here, we need a way of + // running that allows exceptions to be thrown, but we still expect most JS + // calls to succeed. + // TODO(devlin): This is a bit clunky. If we need to do this enough, we could + // figure out a different solution, like having a stack object for allowing + // errors/exceptions. But given this is the only place we need it so far, this + // is sufficient. + auto run_js_and_expect_error = [](v8::Local<v8::Function> function, + v8::Local<v8::Context> context, + int argc, + v8::Local<v8::Value> argv[]) { + v8::MaybeLocal<v8::Value> maybe_result = + function->Call(context, context->Global(), argc, argv); + v8::Global<v8::Value> result; + v8::Local<v8::Value> local; + if (maybe_result.ToLocal(&local)) + result.Reset(context->GetIsolate(), local); + return result; + }; + // Register a hook for the test.oneString method. + auto hooks = base::MakeUnique<APIBindingHooks>( + base::Bind(run_js_and_expect_error)); + + v8::HandleScope handle_scope(isolate()); + v8::Local<v8::Context> context = ContextLocal(); + const char kRegisterHook[] = + "(function(hooks) {\n" + " hooks.setHandleRequest('oneString', str => {\n" + " throw new Error('Custom Hook Error');\n" + " });\n" + "})"; + v8::Local<v8::String> source_string = + gin::StringToV8(isolate(), kRegisterHook); + v8::Local<v8::String> source_name = + gin::StringToV8(isolate(), "custom_hook"); + hooks->RegisterJsSource( + v8::Global<v8::String>(isolate(), source_string), + v8::Global<v8::String>(isolate(), source_name)); + + std::unique_ptr<base::ListValue> functions = ListValueFromString(kFunctions); + ASSERT_TRUE(functions); + ArgumentSpec::RefMap refs; + + APIBinding binding( + "test", functions.get(), nullptr, nullptr, + base::Bind(&APIBindingUnittest::OnFunctionCall, base::Unretained(this)), + std::move(hooks), &refs); + EXPECT_TRUE(refs.empty()); + + APIEventHandler event_handler( + base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); + v8::Local<v8::Object> binding_object = binding.CreateInstance( + context, isolate(), &event_handler, base::Bind(&AllowAllAPIs)); + + v8::Local<v8::Function> function = + FunctionFromString(context, + "(function(obj) { return obj.oneString('ping'); })"); + v8::Local<v8::Value> args[] = {binding_object}; + RunFunctionAndExpectError(function, context, v8::Undefined(isolate()), + arraysize(args), args, + "Uncaught Error: Custom Hook Error"); +} + +// Tests that native custom hooks can return results synchronously, or throw +// exceptions for bad invocations. +TEST_F(APIBindingUnittest, + TestReturningResultAndThrowingExceptionFromCustomNativeHook) { + v8::HandleScope handle_scope(isolate()); + v8::Local<v8::Context> context = ContextLocal(); + + // Register a hook for the test.oneString method. + auto hooks = base::MakeUnique<APIBindingHooks>( + base::Bind(&RunFunctionOnGlobalAndReturnHandle)); + bool did_call = false; + auto hook = [](bool* did_call, const APISignature* signature, + v8::Local<v8::Context> context, + std::vector<v8::Local<v8::Value>>* arguments, + const ArgumentSpec::RefMap& ref_map) { + APIBindingHooks::RequestResult result( + APIBindingHooks::RequestResult::HANDLED); + if (arguments->size() != 1u) { // ASSERT* messes with the return type. + EXPECT_EQ(1u, arguments->size()); + return result; + } + v8::Isolate* isolate = context->GetIsolate(); + std::string arg_value = gin::V8ToString(arguments->at(0)); + if (arg_value == "throw") { + isolate->ThrowException(v8::Exception::Error( + gin::StringToV8(isolate, "Custom Hook Error"))); + result.code = APIBindingHooks::RequestResult::THROWN; + return result; + } + result.return_value = + gin::StringToV8(context->GetIsolate(), arg_value + " pong"); + return result; + }; + hooks->RegisterHandleRequest("test.oneString", base::Bind(hook, &did_call)); + + std::unique_ptr<base::ListValue> functions = ListValueFromString(kFunctions); + ASSERT_TRUE(functions); + ArgumentSpec::RefMap refs; + + APIBinding binding( + "test", functions.get(), nullptr, nullptr, + base::Bind(&APIBindingUnittest::OnFunctionCall, base::Unretained(this)), + std::move(hooks), &refs); + EXPECT_TRUE(refs.empty()); + + APIEventHandler event_handler( + base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); + v8::Local<v8::Object> binding_object = binding.CreateInstance( + context, isolate(), &event_handler, base::Bind(&AllowAllAPIs)); + + { + // Test an invocation that we expect to throw an exception. + v8::Local<v8::Function> function = + FunctionFromString( + context, "(function(obj) { return obj.oneString('throw'); })"); + v8::Local<v8::Value> args[] = {binding_object}; + RunFunctionAndExpectError(function, context, v8::Undefined(isolate()), + arraysize(args), args, + "Uncaught Error: Custom Hook Error"); + } + + { + // Test an invocation we expect to succeed. + v8::Local<v8::Function> function = + FunctionFromString(context, + "(function(obj) { return obj.oneString('ping'); })"); + v8::Local<v8::Value> args[] = {binding_object}; + v8::Local<v8::Value> result = + RunFunction(function, context, arraysize(args), args); + ASSERT_FALSE(result.IsEmpty()); + std::unique_ptr<base::Value> json_result = V8ToBaseValue(result, context); + ASSERT_TRUE(json_result); + EXPECT_EQ("\"ping pong\"", ValueToString(*json_result)); + } +} + } // namespace extensions
diff --git a/extensions/renderer/api_bindings_system_unittest.cc b/extensions/renderer/api_bindings_system_unittest.cc index 2390607..37ac5e064 100644 --- a/extensions/renderer/api_bindings_system_unittest.cc +++ b/extensions/renderer/api_bindings_system_unittest.cc
@@ -300,22 +300,24 @@ std::vector<v8::Local<v8::Value>>* arguments, const ArgumentSpec::RefMap& type_refs) { *did_call = true; + APIBindingHooks::RequestResult result( + APIBindingHooks::RequestResult::HANDLED); if (arguments->size() != 2) { // ASSERT* messes with the return type. EXPECT_EQ(2u, arguments->size()); - return APIBindingHooks::RequestResult::HANDLED; + return result; } std::string argument; EXPECT_EQ("foo", gin::V8ToString(arguments->at(0))); if (!arguments->at(1)->IsFunction()) { EXPECT_TRUE(arguments->at(1)->IsFunction()); - return APIBindingHooks::RequestResult::HANDLED; + return result; } v8::Local<v8::String> response = gin::StringToV8(context->GetIsolate(), "bar"); v8::Local<v8::Value> response_args[] = {response}; RunFunctionOnGlobal(arguments->at(1).As<v8::Function>(), context, 1, response_args); - return APIBindingHooks::RequestResult::HANDLED; + return result; }; APIBindingHooks* hooks = bindings_system()->GetHooksForAPI(kAlphaAPIName);
diff --git a/gpu/config/gpu_driver_bug_list_json.cc b/gpu/config/gpu_driver_bug_list_json.cc index 1875024..399beb8 100644 --- a/gpu/config/gpu_driver_bug_list_json.cc +++ b/gpu/config/gpu_driver_bug_list_json.cc
@@ -19,7 +19,7 @@ { "name": "gpu driver bug list", // Please update the version number whenever you change this file. - "version": "9.27", + "version": "9.28", "entries": [ { "id": 1, @@ -2313,6 +2313,16 @@ "features": [ "disable_program_caching_for_transform_feedback" ] + }, + { + "id": 213, + "description": "The Mali-Gxx driver does not guarantee flush ordering", + "cr_bugs": [678508], + "gl_vendor": "ARM.*", + "gl_renderer": "Mali-G.*", + "features": [ + "use_virtualized_gl_contexts" + ] } ] // Please update the version number at beginning of this file whenever you
diff --git a/ios/chrome/browser/application_context_impl.cc b/ios/chrome/browser/application_context_impl.cc index 88bc2271..43e89458 100644 --- a/ios/chrome/browser/application_context_impl.cc +++ b/ios/chrome/browser/application_context_impl.cc
@@ -289,7 +289,8 @@ ApplicationContextImpl::GetPhysicalWebDataSource() { DCHECK(thread_checker_.CalledOnValidThread()); if (!physical_web_data_source_) { - physical_web_data_source_ = CreateIOSChromePhysicalWebDataSource(); + physical_web_data_source_ = + CreateIOSChromePhysicalWebDataSource(GetLocalState()); DCHECK(physical_web_data_source_); } return physical_web_data_source_.get();
diff --git a/ios/chrome/browser/physical_web/BUILD.gn b/ios/chrome/browser/physical_web/BUILD.gn index f7d034e..832f113 100644 --- a/ios/chrome/browser/physical_web/BUILD.gn +++ b/ios/chrome/browser/physical_web/BUILD.gn
@@ -9,6 +9,8 @@ "ios_chrome_physical_web_data_source.h", "ios_chrome_physical_web_data_source.mm", "physical_web_constants.h", + "physical_web_initial_state_recorder.h", + "physical_web_initial_state_recorder.mm", "physical_web_prefs_registration.cc", "physical_web_prefs_registration.h", "start_physical_web_discovery.h",
diff --git a/ios/chrome/browser/physical_web/create_physical_web_data_source.h b/ios/chrome/browser/physical_web/create_physical_web_data_source.h index 7ecddef..4646959 100644 --- a/ios/chrome/browser/physical_web/create_physical_web_data_source.h +++ b/ios/chrome/browser/physical_web/create_physical_web_data_source.h
@@ -10,10 +10,11 @@ namespace physical_web { class PhysicalWebDataSource; } +class PrefService; // Creates a new instance of IOSChromePhysicalWebDataSource. The returned object // is fully initialized and can be registered as global singleton. std::unique_ptr<physical_web::PhysicalWebDataSource> -CreateIOSChromePhysicalWebDataSource(); +CreateIOSChromePhysicalWebDataSource(PrefService* prefService); #endif // IOS_CHROME_BROWSER_PHYSICAL_WEB_CREATE_PHYSICAL_WEB_DATA_SOURCE_H_
diff --git a/ios/chrome/browser/physical_web/create_physical_web_data_source.mm b/ios/chrome/browser/physical_web/create_physical_web_data_source.mm index 8ea22fab..5844c61f 100644 --- a/ios/chrome/browser/physical_web/create_physical_web_data_source.mm +++ b/ios/chrome/browser/physical_web/create_physical_web_data_source.mm
@@ -8,8 +8,6 @@ #import "ios/chrome/browser/physical_web/ios_chrome_physical_web_data_source.h" std::unique_ptr<physical_web::PhysicalWebDataSource> -CreateIOSChromePhysicalWebDataSource() { - std::unique_ptr<physical_web::PhysicalWebDataSource> datasource = - base::MakeUnique<IOSChromePhysicalWebDataSource>(); - return datasource; +CreateIOSChromePhysicalWebDataSource(PrefService* prefService) { + return base::MakeUnique<IOSChromePhysicalWebDataSource>(prefService); }
diff --git a/ios/chrome/browser/physical_web/ios_chrome_physical_web_data_source.h b/ios/chrome/browser/physical_web/ios_chrome_physical_web_data_source.h index 40d0ebb..20d0756b 100644 --- a/ios/chrome/browser/physical_web/ios_chrome_physical_web_data_source.h +++ b/ios/chrome/browser/physical_web/ios_chrome_physical_web_data_source.h
@@ -12,14 +12,16 @@ namespace base { class ListValue; } +class PrefService; @class PhysicalWebScanner; +@class PhysicalWebInitialStateRecorder; // iOS implementation of PhysicalWebDataSource class IOSChromePhysicalWebDataSource : public physical_web::PhysicalWebDataSourceImpl { public: - IOSChromePhysicalWebDataSource(); + IOSChromePhysicalWebDataSource(PrefService* pref_service); ~IOSChromePhysicalWebDataSource() override; // Starts scanning for Physical Web URLs. If |network_request_enabled| is @@ -41,6 +43,9 @@ // Scanner for nearby Physical Web URL devices. base::scoped_nsobject<PhysicalWebScanner> scanner_; + // Utility for fetching initial application state for logging purposes. + base::scoped_nsobject<PhysicalWebInitialStateRecorder> initialStateRecorder_; + DISALLOW_COPY_AND_ASSIGN(IOSChromePhysicalWebDataSource); };
diff --git a/ios/chrome/browser/physical_web/ios_chrome_physical_web_data_source.mm b/ios/chrome/browser/physical_web/ios_chrome_physical_web_data_source.mm index 80c0744..f2dcdee 100644 --- a/ios/chrome/browser/physical_web/ios_chrome_physical_web_data_source.mm +++ b/ios/chrome/browser/physical_web/ios_chrome_physical_web_data_source.mm
@@ -6,11 +6,18 @@ #include "base/memory/ptr_util.h" #include "base/values.h" +#import "ios/chrome/browser/physical_web/physical_web_initial_state_recorder.h" #import "ios/chrome/common/physical_web/physical_web_scanner.h" -IOSChromePhysicalWebDataSource::IOSChromePhysicalWebDataSource() {} +IOSChromePhysicalWebDataSource::IOSChromePhysicalWebDataSource( + PrefService* pref_service) { + initialStateRecorder_.reset([[PhysicalWebInitialStateRecorder alloc] + initWithPrefService:pref_service]); + [initialStateRecorder_ collectAndRecordState]; +} IOSChromePhysicalWebDataSource::~IOSChromePhysicalWebDataSource() { + [initialStateRecorder_ invalidate]; StopDiscovery(); }
diff --git a/ios/chrome/browser/physical_web/physical_web_initial_state_recorder.h b/ios/chrome/browser/physical_web/physical_web_initial_state_recorder.h new file mode 100644 index 0000000..1d0aabfb --- /dev/null +++ b/ios/chrome/browser/physical_web/physical_web_initial_state_recorder.h
@@ -0,0 +1,29 @@ +// 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 IOS_CHROME_BROWSER_PHYSICAL_WEB_PHYSICAL_WEB_INITIAL_STATE_RECORDER_H_ +#define IOS_CHROME_BROWSER_PHYSICAL_WEB_PHYSICAL_WEB_INITIAL_STATE_RECORDER_H_ + +#import <CoreBluetooth/CoreBluetooth.h> + +class PrefService; + +@interface PhysicalWebInitialStateRecorder : NSObject<CBCentralManagerDelegate> + +- (instancetype)initWithPrefService:(PrefService*)prefService + NS_DESIGNATED_INITIALIZER; + +- (instancetype)init NS_UNAVAILABLE; + +// Fetches and logs the current state of settings relevant to the Physical Web +// feature. +- (void)collectAndRecordState; + +// If the initial state has not yet been recorded, abort collection and +// invalidate the timer. +- (void)invalidate; + +@end + +#endif // IOS_CHROME_BROWSER_PHYSICAL_WEB_PHYSICAL_WEB_INITIAL_STATE_RECORDER_H_
diff --git a/ios/chrome/browser/physical_web/physical_web_initial_state_recorder.mm b/ios/chrome/browser/physical_web/physical_web_initial_state_recorder.mm new file mode 100644 index 0000000..623a8ef8 --- /dev/null +++ b/ios/chrome/browser/physical_web/physical_web_initial_state_recorder.mm
@@ -0,0 +1,170 @@ +// 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. + +#import "ios/chrome/browser/physical_web/physical_web_initial_state_recorder.h" + +#import <CoreBluetooth/CoreBluetooth.h> +#import <CoreLocation/CoreLocation.h> + +#include "base/mac/scoped_nsobject.h" +#include "base/metrics/histogram.h" +#include "components/prefs/pref_service.h" +#include "ios/chrome/browser/physical_web/physical_web_constants.h" +#include "ios/chrome/browser/pref_names.h" + +namespace { + +const double kStartupDelaySeconds = 10.0; + +// Initial state of settings relevant to the Physical Web feature. These are +// ordered so that bits 2:0 encode the Bluetooth enabled state, the Location +// Services enabled state, and whether Chrome has been granted the Location app +// permission. Bits 4:3 encode the Physical Web preference tristate. +// This enum is used in a user metrics histogram. The states should not be +// reordered or removed. +enum PhysicalWebInitialStateIosChrome { + OPTOUT_BTOFF_LOCOFF_UNAUTH, + OPTOUT_BTOFF_LOCOFF_AUTH, + OPTOUT_BTOFF_LOCON_UNAUTH, + OPTOUT_BTOFF_LOCON_AUTH, + OPTOUT_BTON_LOCOFF_UNAUTH, + OPTOUT_BTON_LOCOFF_AUTH, + OPTOUT_BTON_LOCON_UNAUTH, + OPTOUT_BTON_LOCON_AUTH, + OPTIN_BTOFF_LOCOFF_UNAUTH, + OPTIN_BTOFF_LOCOFF_AUTH, + OPTIN_BTOFF_LOCON_UNAUTH, + OPTIN_BTOFF_LOCON_AUTH, + OPTIN_BTON_LOCOFF_UNAUTH, + OPTIN_BTON_LOCOFF_AUTH, + OPTIN_BTON_LOCON_UNAUTH, + OPTIN_BTON_LOCON_AUTH, + ONBOARDING_BTOFF_LOCOFF_UNAUTH, + ONBOARDING_BTOFF_LOCOFF_AUTH, + ONBOARDING_BTOFF_LOCON_UNAUTH, + ONBOARDING_BTOFF_LOCON_AUTH, + ONBOARDING_BTON_LOCOFF_UNAUTH, + ONBOARDING_BTON_LOCOFF_AUTH, + ONBOARDING_BTON_LOCON_UNAUTH, + ONBOARDING_BTON_LOCON_AUTH, + PHYSICAL_WEB_INITIAL_STATE_COUNT, + + // Helper flag values + LOCATION_AUTHORIZED_FLAG = 1 << 0, + LOCATION_SERVICES_FLAG = 1 << 1, + BLUETOOTH_FLAG = 1 << 2, + OPTIN_FLAG = 1 << 3, + ONBOARDING_FLAG = 1 << 4, +}; +} // namespace + +@implementation PhysicalWebInitialStateRecorder { + int preferenceState_; + BOOL recordedState_; + base::scoped_nsobject<NSTimer> startupDelayTimer_; + base::scoped_nsobject<CBCentralManager> centralManager_; +} + +- (instancetype)initWithPrefService:(PrefService*)prefService { + self = [super init]; + if (self) { + preferenceState_ = prefService->GetInteger(prefs::kIosPhysicalWebEnabled); + } + return self; +} + +- (instancetype)init { + NOTREACHED(); + return nil; +} + +- (void)dealloc { + [self invalidate]; + [super dealloc]; +} + +- (void)invalidate { + if (startupDelayTimer_.get()) { + [startupDelayTimer_ invalidate]; + startupDelayTimer_.reset(); + } + [centralManager_ setDelegate:nil]; + centralManager_.reset(); +} + +- (void)centralManagerDidUpdateState:(CBCentralManager*)central { + [centralManager_ setDelegate:nil]; + centralManager_.reset(); + + BOOL bluetoothEnabled = [centralManager_ state] == CBManagerStatePoweredOn; + + BOOL locationServicesEnabled = [CLLocationManager locationServicesEnabled]; + + CLAuthorizationStatus authStatus = [CLLocationManager authorizationStatus]; + BOOL locationAuthorized = + authStatus == kCLAuthorizationStatusAuthorizedWhenInUse || + authStatus == kCLAuthorizationStatusAuthorizedAlways; + + [self recordStateWithPreferenceState:preferenceState_ + bluetoothEnabled:bluetoothEnabled + locationServicesEnabled:locationServicesEnabled + locationAuthorized:locationAuthorized]; +} + +- (void)collectAndRecordState { + if (recordedState_) { + return; + } + recordedState_ = YES; + startupDelayTimer_.reset( + [[NSTimer scheduledTimerWithTimeInterval:kStartupDelaySeconds + target:self + selector:@selector(startupDelayElapsed:) + userInfo:nil + repeats:NO] retain]); +} + +- (void)startupDelayElapsed:(NSTimer*)timer { + startupDelayTimer_.reset(); + + // The Bluetooth enabled state must be checked asynchronously. When the state + // is ready, it will call our centralManagerDidUpdateState method. + centralManager_.reset([[CBCentralManager alloc] + initWithDelegate:self + queue:dispatch_get_main_queue() + options:@{ + // By default, creating a CBCentralManager object with + // Bluetooth disabled will prompt the user to enable Bluetooth. + // Passing ShowPowerAlert=NO disables the prompt so we can + // check the Bluetooth enabled state silently. + CBCentralManagerOptionShowPowerAlertKey : @NO + }]); +} + +- (void)recordStateWithPreferenceState:(int)preferenceState + bluetoothEnabled:(BOOL)bluetoothEnabled + locationServicesEnabled:(BOOL)locationServicesEnabled + locationAuthorized:(BOOL)locationAuthorized { + int state = 0; + if (preferenceState == physical_web::kPhysicalWebOn) { + state |= OPTIN_FLAG; + } else if (preferenceState == physical_web::kPhysicalWebOnboarding) { + state |= ONBOARDING_FLAG; + } + if (locationServicesEnabled) { + state |= LOCATION_SERVICES_FLAG; + } + if (locationAuthorized) { + state |= LOCATION_AUTHORIZED_FLAG; + } + if (bluetoothEnabled) { + state |= BLUETOOTH_FLAG; + } + + DCHECK(state < PHYSICAL_WEB_INITIAL_STATE_COUNT); + UMA_HISTOGRAM_ENUMERATION("PhysicalWeb.InitialState.IosChrome", state, + PHYSICAL_WEB_INITIAL_STATE_COUNT); +} + +@end
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.h b/ios/chrome/browser/sync/ios_chrome_sync_client.h index 013c5e4..48c5f6e 100644 --- a/ios/chrome/browser/sync/ios_chrome_sync_client.h +++ b/ios/chrome/browser/sync/ios_chrome_sync_client.h
@@ -42,6 +42,7 @@ bookmarks::BookmarkModel* GetBookmarkModel() override; favicon::FaviconService* GetFaviconService() override; history::HistoryService* GetHistoryService() override; + bool HasPasswordStore() override; base::Closure GetPasswordStateChangedCallback() override; syncer::SyncApiComponentFactory::RegisterDataTypesMethod GetRegisterPlatformTypesCallback() override;
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm index 79d38cd..5ed9a2b 100644 --- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm +++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -202,6 +202,11 @@ browser_state_, ServiceAccessType::EXPLICIT_ACCESS); } +bool IOSChromeSyncClient::HasPasswordStore() { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + return password_store_ != nullptr; +} + autofill::PersonalDataManager* IOSChromeSyncClient::GetPersonalDataManager() { DCHECK_CURRENTLY_ON(web::WebThread::UI); return autofill::PersonalDataManagerFactory::GetForBrowserState(
diff --git a/ios/third_party/material_components_ios/README.chromium b/ios/third_party/material_components_ios/README.chromium index 6c6a2a9..23cdb8e3 100644 --- a/ios/third_party/material_components_ios/README.chromium +++ b/ios/third_party/material_components_ios/README.chromium
@@ -1,7 +1,7 @@ Name: Material Components for iOS URL: https://github.com/material-components/material-components-ios Version: 0 -Revision: 4e5a18715bedf3ada7fd35ba9d2d41082fbf7437 +Revision: b1eb638d70792b7aa06118b128e3518c20e2aaae License: Apache 2.0 License File: LICENSE Security Critical: yes @@ -16,4 +16,4 @@ http://www.google.com/design/spec/material-design/introduction.html Local Modifications: -None +None \ No newline at end of file
diff --git a/ios/third_party/material_font_disk_loader_ios/README.chromium b/ios/third_party/material_font_disk_loader_ios/README.chromium index e29a1dc..0e21813e 100644 --- a/ios/third_party/material_font_disk_loader_ios/README.chromium +++ b/ios/third_party/material_font_disk_loader_ios/README.chromium
@@ -1,7 +1,7 @@ Name: Material Font Disk Loader iOS URL: https://github.com/material-foundation/material-font-disk-loader-ios Version: 0 -Revision: 20c8fe37329cb18826f90159ce4ee445079e2e46 +Revision: 93acc021e3034898716028822cb802a3a816be7e License: Apache 2.0 License File: LICENSE Security Critical: yes @@ -10,4 +10,4 @@ Registers a single custom font asset from disk. Local Modifications: -None +None \ No newline at end of file
diff --git a/ios/third_party/material_sprited_animation_view_ios/README.chromium b/ios/third_party/material_sprited_animation_view_ios/README.chromium index 268f933..a1f29d9 100644 --- a/ios/third_party/material_sprited_animation_view_ios/README.chromium +++ b/ios/third_party/material_sprited_animation_view_ios/README.chromium
@@ -1,7 +1,7 @@ Name: Material Sprited Animation View URL: https://github.com/material-foundation/material-sprited-animation-view-ios Version: 0 -Revision: e240cdcd4538f0763ca5bd8c5afc2991eb482f1a +Revision: c6e16d06bdafd95540c62b3402d9414692fbca81 License: Apache 2.0 License File: LICENSE Security Critical: yes @@ -12,4 +12,4 @@ and animation simply consists of updating the layer contentsRect. Local Modifications: -None +None \ No newline at end of file
diff --git a/ios/third_party/material_text_accessibility_ios/README.chromium b/ios/third_party/material_text_accessibility_ios/README.chromium index 256c030..6b142c7 100644 --- a/ios/third_party/material_text_accessibility_ios/README.chromium +++ b/ios/third_party/material_text_accessibility_ios/README.chromium
@@ -1,7 +1,7 @@ Name: Material Text Accessibility iOS URL: https://github.com/material-foundation/material-text-accessibility-ios Version: 0 -Revision: 96d2b0f13976a897bc7a41daf67f36d9548cff94 +Revision: 318d5100f2976e59c94643e5dcab69e7a830ee43 License: Apache 2.0 License File: LICENSE Security Critical: yes @@ -11,4 +11,4 @@ standards for accessibility. Local Modifications: -None +None \ No newline at end of file
diff --git a/ios/web/public/web_state/crw_web_user_interface_delegate.h b/ios/web/public/web_state/crw_web_user_interface_delegate.h index f5b2748..39cc3bb 100644 --- a/ios/web/public/web_state/crw_web_user_interface_delegate.h +++ b/ios/web/public/web_state/crw_web_user_interface_delegate.h
@@ -8,7 +8,6 @@ #import <Foundation/Foundation.h> @class CRWWebController; -class GURL; // DEPRECATED, do not conform to this protocol and do not add any methods to it. // Use web::WebStateDelegate instead. @@ -16,47 +15,6 @@ @protocol CRWWebUserInterfaceDelegate<NSObject> @optional -// The JavaScript panel selectors below are only called by the web controller -// for builds with WKWebView enabled. - -// Displays a JavaScript alert with an OK button, showing the provided message. -// |completionHandler| is called after the OK button on the alert is tapped. -// If this selector isn't implemented, the completion handler provided by the -// web view will be called without any UI displayed. If this method is -// implemented, but |completionHandler| is not called then -// NSInternalInconsistencyException will be thrown. -- (void)webController:(CRWWebController*)webController - runJavaScriptAlertPanelWithMessage:(NSString*)message - requestURL:(const GURL&)requestURL - completionHandler:(void (^)(void))completionHandler; - -// Displays a JavaScript confirm alert with an OK and Cancel button, showing the -// provided message. |completionHandler| is called after a button is pressed, -// with |isConfirmed| indicating whether OK was pressed. If this selector isn't -// implemented, the completion handler provided by the web view will be called -// with |isConfirmed| = NO. If this method is implemented, but -// |completionHandler| is not called then NSInternalInconsistencyException will -// be thrown. -- (void)webController:(CRWWebController*)webController - runJavaScriptConfirmPanelWithMessage:(NSString*)message - requestURL:(const GURL&)requestURL - completionHandler: - (void (^)(BOOL isConfirmed))completionHandler; - -// Displays a JavaScript input alert with an OK and Cancel button, showing the -// provided message and default text. |completionHandler| is called after a -// button is pressed. If the OK button is pressed, |input| contains the user -// text. If the cancel but is pressed, |input| will be nil. If this selector -// isn't implemented, the completion handler provided by the web view will be -// called with |input| = nil. If this method is implemented, but -// |completionHandler| is not called then NSInternalInconsistencyException will -// be thrown. -- (void)webController:(CRWWebController*)webController - runJavaScriptTextInputPanelWithPrompt:(NSString*)message - defaultText:(NSString*)defaultText - requestURL:(const GURL&)requestURL - completionHandler: - (void (^)(NSString* input))completionHandler; // Displays an HTTP authentication dialog. |completionHandler| should be called // with non-nil |username| and |password| if embedder wants to proceed with
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index 7aabe25b..df53e2a 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -3872,6 +3872,13 @@ message:(NSString*)message defaultText:(NSString*)defaultText completion:(void (^)(BOOL, NSString*))completionHandler { + DCHECK(completionHandler); + if (self.shouldSuppressDialogs) { + [self didSuppressDialog]; + completionHandler(NO, nil); + return; + } + self.webStateImpl->RunJavaScriptDialog( net::GURLWithNSURL(frame.request.URL), type, message, defaultText, base::BindBlock(^(bool success, NSString* input) { @@ -4947,30 +4954,13 @@ runJavaScriptAlertPanelWithMessage:(NSString*)message initiatedByFrame:(WKFrameInfo*)frame completionHandler:(void (^)())completionHandler { - if (self.shouldSuppressDialogs) { - [self didSuppressDialog]; - completionHandler(); - return; - } - - SEL alertSelector = @selector(webController: - runJavaScriptAlertPanelWithMessage: - requestURL: - completionHandler:); - if ([self.UIDelegate respondsToSelector:alertSelector]) { - [self.UIDelegate webController:self - runJavaScriptAlertPanelWithMessage:message - requestURL:net::GURLWithNSURL(frame.request.URL) - completionHandler:completionHandler]; - } else { - [self runJavaScriptDialogOfType:web::JAVASCRIPT_DIALOG_TYPE_ALERT - initiatedByFrame:frame - message:message - defaultText:nil - completion:^(BOOL, NSString*) { - completionHandler(); - }]; - } + [self runJavaScriptDialogOfType:web::JAVASCRIPT_DIALOG_TYPE_ALERT + initiatedByFrame:frame + message:message + defaultText:nil + completion:^(BOOL, NSString*) { + completionHandler(); + }]; } - (void)webView:(WKWebView*)webView @@ -4978,33 +4968,15 @@ initiatedByFrame:(WKFrameInfo*)frame completionHandler: (void (^)(BOOL result))completionHandler { - if (self.shouldSuppressDialogs) { - [self didSuppressDialog]; - completionHandler(NO); - return; - } - - SEL confirmationSelector = @selector(webController: - runJavaScriptConfirmPanelWithMessage: - requestURL: - completionHandler:); - if ([self.UIDelegate respondsToSelector:confirmationSelector]) { - [self.UIDelegate webController:self - runJavaScriptConfirmPanelWithMessage:message - requestURL:net::GURLWithNSURL( - frame.request.URL) - completionHandler:completionHandler]; - } else { - [self runJavaScriptDialogOfType:web::JAVASCRIPT_DIALOG_TYPE_CONFIRM - initiatedByFrame:frame - message:message - defaultText:nil - completion:^(BOOL success, NSString*) { - if (completionHandler) { - completionHandler(success); - } - }]; - } + [self runJavaScriptDialogOfType:web::JAVASCRIPT_DIALOG_TYPE_CONFIRM + initiatedByFrame:frame + message:message + defaultText:nil + completion:^(BOOL success, NSString*) { + if (completionHandler) { + completionHandler(success); + } + }]; } - (void)webView:(WKWebView*)webView @@ -5021,35 +4993,15 @@ return; } - if (self.shouldSuppressDialogs) { - [self didSuppressDialog]; - completionHandler(nil); - return; - } - - SEL textInputSelector = @selector(webController: - runJavaScriptTextInputPanelWithPrompt: - defaultText: - requestURL: - completionHandler:); - if ([self.UIDelegate respondsToSelector:textInputSelector]) { - GURL requestURL = net::GURLWithNSURL(frame.request.URL); - [self.UIDelegate webController:self - runJavaScriptTextInputPanelWithPrompt:prompt - defaultText:defaultText - requestURL:requestURL - completionHandler:completionHandler]; - } else { - [self runJavaScriptDialogOfType:web::JAVASCRIPT_DIALOG_TYPE_PROMPT - initiatedByFrame:frame - message:prompt - defaultText:defaultText - completion:^(BOOL, NSString* input) { - if (completionHandler) { - completionHandler(input); - } - }]; - } + [self runJavaScriptDialogOfType:web::JAVASCRIPT_DIALOG_TYPE_PROMPT + initiatedByFrame:frame + message:prompt + defaultText:defaultText + completion:^(BOOL, NSString* input) { + if (completionHandler) { + completionHandler(input); + } + }]; } #pragma mark - @@ -5175,6 +5127,19 @@ [self registerLoadRequest:webViewURL]; } } + + if (![self currentSessionEntry]) { + // In this state CRWWebController will crash in |didCommitNavigation:| + // (crbug.com/676458). It's unclear if web controller could get into this + // state but it's one of the guesses for crbug.com/676458 root cause. Report + // UMA historgam if that happens. + // TODO(crbug.com/677552): Remove this historgam. + UMA_HISTOGRAM_BOOLEAN( + "WebController." + "StartProvisionalNavigationExitedWithEmptyNavigationManager", + true); + } + // Ensure the URL is registered and loadPhase is as expected. DCHECK(_lastRegisteredRequestURL == webViewURL); DCHECK(self.loadPhase == web::LOAD_REQUESTED);
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm index 18f93671..836bd30 100644 --- a/ios/web/web_state/ui/crw_web_controller_unittest.mm +++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -20,6 +20,7 @@ #import "ios/web/public/test/fakes/test_native_content.h" #import "ios/web/public/test/fakes/test_native_content_provider.h" #import "ios/web/public/test/fakes/test_web_client.h" +#import "ios/web/public/test/fakes/test_web_state_delegate.h" #import "ios/web/public/test/fakes/test_web_view_content_view.h" #import "ios/web/public/web_state/crw_web_controller_observer.h" #import "ios/web/public/web_state/ui/crw_content_view.h" @@ -75,63 +76,6 @@ : OCMockComplexTypeHelper<CRWWebUserInterfaceDelegate> @end -@implementation CRWWebUserInterfaceDelegateStub - -- (void)webController:(CRWWebController*)webController - runJavaScriptAlertPanelWithMessage:(NSString*)message - requestURL:(const GURL&)requestURL - completionHandler:(void (^)(void))completionHandler { - void (^stubBlock)(CRWWebController*, NSString*, const GURL&, id) = - [self blockForSelector:_cmd]; - stubBlock(webController, message, requestURL, completionHandler); -} - -- (void)webController:(CRWWebController*)webController - runJavaScriptConfirmPanelWithMessage:(NSString*)message - requestURL:(const GURL&)requestURL - completionHandler:(void (^)(BOOL))completionHandler { - void (^stubBlock)(CRWWebController*, NSString*, const GURL&, id) = - [self blockForSelector:_cmd]; - stubBlock(webController, message, requestURL, completionHandler); -} - -- (void)webController:(CRWWebController*)webController - runJavaScriptTextInputPanelWithPrompt:(NSString*)message - defaultText:(NSString*)defaultText - requestURL:(const GURL&)requestURL - completionHandler: - (void (^)(NSString* input))completionHandler { - void (^stubBlock)(CRWWebController*, NSString*, NSString*, const GURL&, id) = - [self blockForSelector:_cmd]; - stubBlock(webController, message, defaultText, requestURL, completionHandler); -} - -- (BOOL)respondsToSelector:(SEL)selector { - // OCMockComplexTypeHelper DCHECKs when respondsToSelector: is called for - // expected selector. - if (selector == @selector(webController: - runJavaScriptAlertPanelWithMessage: - requestURL: - completionHandler:)) { - return YES; - } - if (selector == @selector(webController: - runJavaScriptConfirmPanelWithMessage: - requestURL: - completionHandler:)) { - return YES; - } - if (selector == @selector(webController: - runJavaScriptTextInputPanelWithPrompt: - defaultText: - requestURL: - completionHandler:)) { - return YES; - } - return [super respondsToSelector:selector]; -} -@end - @implementation MockInteractionLoader { // Backs up the property with the same name. std::unique_ptr<web::BlockedPopupInfo> _blockedPopupInfo; @@ -458,39 +402,37 @@ class CRWWebControllerPageDialogOpenPolicyTest : public web::WebTestWithWebController { protected: + CRWWebControllerPageDialogOpenPolicyTest() + : page_url_("https://chromium.test/") {} void SetUp() override { web::WebTestWithWebController::SetUp(); - LoadHtml(@"<html><body></body></html>"); + LoadHtml(@"<html><body></body></html>", page_url_); web_delegate_mock_.reset( [[OCMockObject mockForProtocol:@protocol(CRWWebDelegate)] retain]); [web_controller() setDelegate:web_delegate_mock_]; - id ui_delegate_oc_mock = - [OCMockObject mockForProtocol:@protocol(CRWWebUserInterfaceDelegate)]; - ui_delegate_mock_.reset([[CRWWebUserInterfaceDelegateStub alloc] - initWithRepresentedObject:ui_delegate_oc_mock]); - [web_controller() setUIDelegate:ui_delegate_mock_]; - // Web Controller cancels all dialogs on |close|. - [[ui_delegate_mock_ stub] cancelDialogsForWebController:web_controller()]; + web_state()->SetDelegate(&test_web_delegate_); } void TearDown() override { WaitForBackgroundTasks(); EXPECT_OCMOCK_VERIFY(web_delegate_mock_); - EXPECT_OCMOCK_VERIFY(ui_delegate_mock_); [web_controller() setDelegate:nil]; - [web_controller() setUIDelegate:nil]; + web_state()->SetDelegate(nullptr); web::WebTestWithWebController::TearDown(); } - // Returns CRWWebDelegate mock object. id web_delegate_mock() { return web_delegate_mock_; }; - // Returns CRWWebUserInterfaceDelegate mock object. - id ui_delegate_mock() { return ui_delegate_mock_; }; + web::TestJavaScriptDialogPresenter* js_dialog_presenter() { + return test_web_delegate_.GetTestJavaScriptDialogPresenter(); + } + const std::vector<web::TestJavaScriptDialog>& requested_dialogs() { + return js_dialog_presenter()->requested_dialogs(); + } + const GURL& page_url() { return page_url_; } private: - // Mocks CRWWebDelegate object. + web::TestWebStateDelegate test_web_delegate_; base::scoped_nsprotocol<id> web_delegate_mock_; - // Mocks CRWWebUserInterfaceDelegate object. - base::scoped_nsprotocol<id> ui_delegate_mock_; + GURL page_url_; }; // Tests that window.alert dialog is suppressed for DIALOG_POLICY_SUPPRESS. @@ -503,109 +445,98 @@ // Tests that window.alert dialog is shown for DIALOG_POLICY_ALLOW. TEST_F(CRWWebControllerPageDialogOpenPolicyTest, AllowAlert) { - SEL selector = @selector(webController: - runJavaScriptAlertPanelWithMessage: - requestURL: - completionHandler:); - [ui_delegate_mock() onSelector:selector - callBlockExpectation:^(CRWWebController* controller, - NSString* message, const GURL& url, - ProceduralBlock completion_handler) { - EXPECT_NSEQ(web_controller(), controller); - EXPECT_NSEQ(@"test", message); - web::URLVerificationTrustLevel unused; - EXPECT_EQ([controller currentURLWithTrustLevel:&unused], url); - completion_handler(); - }]; + ASSERT_TRUE(requested_dialogs().empty()); [web_controller() setShouldSuppressDialogs:NO]; ExecuteJavaScript(@"alert('test')"); + + ASSERT_EQ(1U, requested_dialogs().size()); + web::TestJavaScriptDialog dialog = requested_dialogs()[0]; + EXPECT_EQ(web_state(), dialog.web_state); + EXPECT_EQ(page_url(), dialog.origin_url); + EXPECT_EQ(web::JAVASCRIPT_DIALOG_TYPE_ALERT, dialog.java_script_dialog_type); + EXPECT_NSEQ(@"test", dialog.message_text); + EXPECT_FALSE(dialog.default_prompt_text); }; // Tests that window.confirm dialog is suppressed for DIALOG_POLICY_SUPPRESS. TEST_F(CRWWebControllerPageDialogOpenPolicyTest, SuppressConfirm) { + ASSERT_TRUE(requested_dialogs().empty()); + [[web_delegate_mock() expect] webControllerDidSuppressDialog:web_controller()]; [web_controller() setShouldSuppressDialogs:YES]; EXPECT_NSEQ(@NO, ExecuteJavaScript(@"confirm('test')")); + + ASSERT_TRUE(requested_dialogs().empty()); }; // Tests that window.confirm dialog is shown for DIALOG_POLICY_ALLOW and // it's result is true. TEST_F(CRWWebControllerPageDialogOpenPolicyTest, AllowConfirmWithTrue) { - SEL selector = @selector(webController: - runJavaScriptConfirmPanelWithMessage: - requestURL: - completionHandler:); - [ui_delegate_mock() - onSelector:selector - callBlockExpectation:^(CRWWebController* controller, NSString* message, - const GURL& url, id completion_handler) { - EXPECT_NSEQ(web_controller(), controller); - EXPECT_NSEQ(@"test", message); - web::URLVerificationTrustLevel unused; - EXPECT_EQ([controller currentURLWithTrustLevel:&unused], url); - void (^callable_block)(BOOL) = completion_handler; - callable_block(YES); - }]; + ASSERT_TRUE(requested_dialogs().empty()); + + js_dialog_presenter()->set_callback_success_argument(true); [web_controller() setShouldSuppressDialogs:NO]; EXPECT_NSEQ(@YES, ExecuteJavaScript(@"confirm('test')")); + + ASSERT_EQ(1U, requested_dialogs().size()); + web::TestJavaScriptDialog dialog = requested_dialogs()[0]; + EXPECT_EQ(web_state(), dialog.web_state); + EXPECT_EQ(page_url(), dialog.origin_url); + EXPECT_EQ(web::JAVASCRIPT_DIALOG_TYPE_CONFIRM, + dialog.java_script_dialog_type); + EXPECT_NSEQ(@"test", dialog.message_text); + EXPECT_FALSE(dialog.default_prompt_text); } // Tests that window.confirm dialog is shown for DIALOG_POLICY_ALLOW and // it's result is false. TEST_F(CRWWebControllerPageDialogOpenPolicyTest, AllowConfirmWithFalse) { - SEL selector = @selector(webController: - runJavaScriptConfirmPanelWithMessage: - requestURL: - completionHandler:); - [ui_delegate_mock() - onSelector:selector - callBlockExpectation:^(CRWWebController* controller, NSString* message, - const GURL& url, id completion_handler) { - EXPECT_NSEQ(web_controller(), controller); - EXPECT_NSEQ(@"test", message); - web::URLVerificationTrustLevel unused; - EXPECT_EQ([controller currentURLWithTrustLevel:&unused], url); - void (^callable_block)(BOOL) = completion_handler; - callable_block(NO); - }]; + ASSERT_TRUE(requested_dialogs().empty()); [web_controller() setShouldSuppressDialogs:NO]; EXPECT_NSEQ(@NO, ExecuteJavaScript(@"confirm('test')")); + + ASSERT_EQ(1U, requested_dialogs().size()); + web::TestJavaScriptDialog dialog = requested_dialogs()[0]; + EXPECT_EQ(web_state(), dialog.web_state); + EXPECT_EQ(page_url(), dialog.origin_url); + EXPECT_EQ(web::JAVASCRIPT_DIALOG_TYPE_CONFIRM, + dialog.java_script_dialog_type); + EXPECT_NSEQ(@"test", dialog.message_text); + EXPECT_FALSE(dialog.default_prompt_text); } // Tests that window.prompt dialog is suppressed for DIALOG_POLICY_SUPPRESS. TEST_F(CRWWebControllerPageDialogOpenPolicyTest, SuppressPrompt) { + ASSERT_TRUE(requested_dialogs().empty()); + [[web_delegate_mock() expect] webControllerDidSuppressDialog:web_controller()]; [web_controller() setShouldSuppressDialogs:YES]; EXPECT_EQ([NSNull null], ExecuteJavaScript(@"prompt('Yes?', 'No')")); + + ASSERT_TRUE(requested_dialogs().empty()); } // Tests that window.prompt dialog is shown for DIALOG_POLICY_ALLOW. TEST_F(CRWWebControllerPageDialogOpenPolicyTest, AllowPrompt) { - SEL selector = @selector(webController: - runJavaScriptTextInputPanelWithPrompt: - defaultText: - requestURL: - completionHandler:); - [ui_delegate_mock() onSelector:selector - callBlockExpectation:^(CRWWebController* controller, - NSString* message, NSString* default_text, - const GURL& url, id completion_handler) { - EXPECT_NSEQ(web_controller(), controller); - EXPECT_NSEQ(@"Yes?", message); - EXPECT_NSEQ(@"No", default_text); - web::URLVerificationTrustLevel unused; - EXPECT_EQ([controller currentURLWithTrustLevel:&unused], url); - void (^callable_block)(NSString*) = completion_handler; - callable_block(@"Maybe"); - }]; + ASSERT_TRUE(requested_dialogs().empty()); + + js_dialog_presenter()->set_callback_user_input_argument(@"Maybe"); [web_controller() setShouldSuppressDialogs:NO]; EXPECT_NSEQ(@"Maybe", ExecuteJavaScript(@"prompt('Yes?', 'No')")); + + ASSERT_EQ(1U, requested_dialogs().size()); + web::TestJavaScriptDialog dialog = requested_dialogs()[0]; + EXPECT_EQ(web_state(), dialog.web_state); + EXPECT_EQ(page_url(), dialog.origin_url); + EXPECT_EQ(web::JAVASCRIPT_DIALOG_TYPE_PROMPT, dialog.java_script_dialog_type); + EXPECT_NSEQ(@"Yes?", dialog.message_text); + EXPECT_NSEQ(@"No", dialog.default_prompt_text); } // Tests that geolocation dialog is suppressed for DIALOG_POLICY_SUPPRESS.
diff --git a/ios/web/web_state/web_state_impl_unittest.mm b/ios/web/web_state/web_state_impl_unittest.mm index f6180e0..13dd7915 100644 --- a/ios/web/web_state/web_state_impl_unittest.mm +++ b/ios/web/web_state/web_state_impl_unittest.mm
@@ -603,15 +603,17 @@ // Execute script with callback. __block std::unique_ptr<base::Value> execution_result; + __block bool execution_complete = false; web_state_->ExecuteJavaScript(base::UTF8ToUTF16("window.foo"), base::BindBlock(^(const base::Value* value) { - ASSERT_TRUE(value); execution_result = value->CreateDeepCopy(); + execution_complete = true; })); - base::test::ios::WaitUntilCondition(^bool() { - return execution_result.get(); + base::test::ios::WaitUntilCondition(^{ + return execution_complete; }); + ASSERT_TRUE(execution_result); std::string string_result; execution_result->GetAsString(&string_result); EXPECT_EQ("bar", string_result);
diff --git a/ipc/BUILD.gn b/ipc/BUILD.gn index 859efbb..07b878a 100644 --- a/ipc/BUILD.gn +++ b/ipc/BUILD.gn
@@ -206,12 +206,14 @@ deps = [ ":ipc", + ":test_interfaces", ":test_support", "//base", "//base:i18n", "//base/test:test_support", "//mojo/edk/system", "//mojo/edk/test:test_support", + "//mojo/edk/test:test_support_impl", "//testing/gtest", ] } @@ -219,8 +221,6 @@ static_library("test_support") { testonly = true sources = [ - "ipc_perftest_support.cc", - "ipc_perftest_support.h", "ipc_security_test_util.cc", "ipc_security_test_util.h", "ipc_test_base.cc",
diff --git a/ipc/ipc_mojo_perftest.cc b/ipc/ipc_mojo_perftest.cc index 0fcb8ba81..4c0990a9 100644 --- a/ipc/ipc_mojo_perftest.cc +++ b/ipc/ipc_mojo_perftest.cc
@@ -8,36 +8,408 @@ #include "base/memory/ptr_util.h" #include "base/process/process_metrics.h" #include "base/run_loop.h" +#include "base/strings/stringprintf.h" +#include "base/test/perf_time_logger.h" +#include "base/test/test_io_thread.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "ipc/ipc_channel_mojo.h" -#include "ipc/ipc_perftest_support.h" +#include "ipc/ipc_test.mojom.h" +#include "ipc/ipc_test_base.h" #include "mojo/edk/embedder/embedder.h" #include "mojo/edk/embedder/platform_channel_pair.h" +#include "mojo/edk/test/mojo_test_base.h" #include "mojo/edk/test/multiprocess_test_helper.h" #include "mojo/edk/test/scoped_ipc_support.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/system/message_pipe.h" namespace IPC { namespace { -class MojoChannelPerfTest : public test::IPCChannelPerfTestBase { +// This class simply collects stats about abstract "events" (each of which has a +// start time and an end time). +class EventTimeTracker { public: - void TearDown() override { - test::IPCChannelPerfTestBase::TearDown(); + explicit EventTimeTracker(const char* name) + : name_(name), + count_(0) { } - mojo::edk::test::MultiprocessTestHelper helper_; + void AddEvent(const base::TimeTicks& start, const base::TimeTicks& end) { + DCHECK(end >= start); + count_++; + base::TimeDelta duration = end - start; + total_duration_ += duration; + max_duration_ = std::max(max_duration_, duration); + } + + void ShowResults() const { + VLOG(1) << name_ << " count: " << count_; + VLOG(1) << name_ << " total duration: " + << total_duration_.InMillisecondsF() << " ms"; + VLOG(1) << name_ << " average duration: " + << (total_duration_.InMillisecondsF() / static_cast<double>(count_)) + << " ms"; + VLOG(1) << name_ << " maximum duration: " + << max_duration_.InMillisecondsF() << " ms"; + } + + void Reset() { + count_ = 0; + total_duration_ = base::TimeDelta(); + max_duration_ = base::TimeDelta(); + } + + private: + const std::string name_; + + uint64_t count_; + base::TimeDelta total_duration_; + base::TimeDelta max_duration_; + + DISALLOW_COPY_AND_ASSIGN(EventTimeTracker); +}; + +class PerformanceChannelListener : public Listener { + public: + explicit PerformanceChannelListener(const std::string& label) + : label_(label), + sender_(NULL), + msg_count_(0), + msg_size_(0), + count_down_(0), + latency_tracker_("Server messages") { + VLOG(1) << "Server listener up"; + } + + ~PerformanceChannelListener() override { + VLOG(1) << "Server listener down"; + } + + void Init(Sender* sender) { + DCHECK(!sender_); + sender_ = sender; + } + + // Call this before running the message loop. + void SetTestParams(int msg_count, size_t msg_size) { + DCHECK_EQ(0, count_down_); + msg_count_ = msg_count; + msg_size_ = msg_size; + count_down_ = msg_count_; + payload_ = std::string(msg_size_, 'a'); + } + + bool OnMessageReceived(const Message& message) override { + CHECK(sender_); + + base::PickleIterator iter(message); + int64_t time_internal; + EXPECT_TRUE(iter.ReadInt64(&time_internal)); + int msgid; + EXPECT_TRUE(iter.ReadInt(&msgid)); + std::string reflected_payload; + EXPECT_TRUE(iter.ReadString(&reflected_payload)); + + // Include message deserialization in latency. + base::TimeTicks now = base::TimeTicks::Now(); + + if (reflected_payload == "hello") { + // Start timing on hello. + latency_tracker_.Reset(); + DCHECK(!perf_logger_.get()); + std::string test_name = + base::StringPrintf("IPC_%s_Perf_%dx_%u", + label_.c_str(), + msg_count_, + static_cast<unsigned>(msg_size_)); + perf_logger_.reset(new base::PerfTimeLogger(test_name.c_str())); + } else { + DCHECK_EQ(payload_.size(), reflected_payload.size()); + + latency_tracker_.AddEvent( + base::TimeTicks::FromInternalValue(time_internal), now); + + CHECK(count_down_ > 0); + count_down_--; + if (count_down_ == 0) { + perf_logger_.reset(); // Stop the perf timer now. + latency_tracker_.ShowResults(); + base::MessageLoop::current()->QuitWhenIdle(); + return true; + } + } + + Message* msg = new Message(0, 2, Message::PRIORITY_NORMAL); + msg->WriteInt64(base::TimeTicks::Now().ToInternalValue()); + msg->WriteInt(count_down_); + msg->WriteString(payload_); + sender_->Send(msg); + return true; + } + + private: + std::string label_; + Sender* sender_; + int msg_count_; + size_t msg_size_; + + int count_down_; + std::string payload_; + EventTimeTracker latency_tracker_; + std::unique_ptr<base::PerfTimeLogger> perf_logger_; +}; + +// This channel listener just replies to all messages with the exact same +// message. It assumes each message has one string parameter. When the string +// "quit" is sent, it will exit. +class ChannelReflectorListener : public Listener { + public: + ChannelReflectorListener() + : channel_(NULL), + latency_tracker_("Client messages") { + VLOG(1) << "Client listener up"; + } + + ~ChannelReflectorListener() override { + VLOG(1) << "Client listener down"; + latency_tracker_.ShowResults(); + } + + void Init(Channel* channel) { + DCHECK(!channel_); + channel_ = channel; + } + + bool OnMessageReceived(const Message& message) override { + CHECK(channel_); + + base::PickleIterator iter(message); + int64_t time_internal; + EXPECT_TRUE(iter.ReadInt64(&time_internal)); + int msgid; + EXPECT_TRUE(iter.ReadInt(&msgid)); + base::StringPiece payload; + EXPECT_TRUE(iter.ReadStringPiece(&payload)); + + // Include message deserialization in latency. + base::TimeTicks now = base::TimeTicks::Now(); + + if (payload == "hello") { + latency_tracker_.Reset(); + } else if (payload == "quit") { + latency_tracker_.ShowResults(); + base::MessageLoop::current()->QuitWhenIdle(); + return true; + } else { + // Don't track hello and quit messages. + latency_tracker_.AddEvent( + base::TimeTicks::FromInternalValue(time_internal), now); + } + + Message* msg = new Message(0, 2, Message::PRIORITY_NORMAL); + msg->WriteInt64(base::TimeTicks::Now().ToInternalValue()); + msg->WriteInt(msgid); + msg->WriteString(payload); + channel_->Send(msg); + return true; + } + + private: + Channel* channel_; + EventTimeTracker latency_tracker_; +}; + +// This class locks the current thread to a particular CPU core. This is +// important because otherwise the different threads and processes of these +// tests end up on different CPU cores which means that all of the cores are +// lightly loaded so the OS (Windows and Linux) fails to ramp up the CPU +// frequency, leading to unpredictable and often poor performance. +class LockThreadAffinity { + public: + explicit LockThreadAffinity(int cpu_number) : affinity_set_ok_(false) { +#if defined(OS_WIN) + const DWORD_PTR thread_mask = static_cast<DWORD_PTR>(1) << cpu_number; + old_affinity_ = SetThreadAffinityMask(GetCurrentThread(), thread_mask); + affinity_set_ok_ = old_affinity_ != 0; +#elif defined(OS_LINUX) + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(cpu_number, &cpuset); + auto get_result = sched_getaffinity(0, sizeof(old_cpuset_), &old_cpuset_); + DCHECK_EQ(0, get_result); + auto set_result = sched_setaffinity(0, sizeof(cpuset), &cpuset); + // Check for get_result failure, even though it should always succeed. + affinity_set_ok_ = (set_result == 0) && (get_result == 0); +#endif + if (!affinity_set_ok_) + LOG(WARNING) << "Failed to set thread affinity to CPU " << cpu_number; + } + + ~LockThreadAffinity() { + if (!affinity_set_ok_) + return; +#if defined(OS_WIN) + auto set_result = SetThreadAffinityMask(GetCurrentThread(), old_affinity_); + DCHECK_NE(0u, set_result); +#elif defined(OS_LINUX) + auto set_result = sched_setaffinity(0, sizeof(old_cpuset_), &old_cpuset_); + DCHECK_EQ(0, set_result); +#endif + } + + private: + bool affinity_set_ok_; +#if defined(OS_WIN) + DWORD_PTR old_affinity_; +#elif defined(OS_LINUX) + cpu_set_t old_cpuset_; +#endif + + DISALLOW_COPY_AND_ASSIGN(LockThreadAffinity); +}; + +class PingPongTestParams { + public: + PingPongTestParams(size_t size, int count) + : message_size_(size), message_count_(count) { + } + + size_t message_size() const { return message_size_; } + int message_count() const { return message_count_; } + + private: + size_t message_size_; + int message_count_; +}; + +std::vector<PingPongTestParams> GetDefaultTestParams() { + // Test several sizes. We use 12^N for message size, and limit the message + // count to keep the test duration reasonable. +#ifdef NDEBUG + const int kMultiplier = 100; +#else + // Debug builds on Windows run these tests orders of magnitude more slowly. + const int kMultiplier = 1; +#endif + std::vector<PingPongTestParams> list; + list.push_back(PingPongTestParams(12, 500 * kMultiplier)); + list.push_back(PingPongTestParams(144, 500 * kMultiplier)); + list.push_back(PingPongTestParams(1728, 500 * kMultiplier)); + list.push_back(PingPongTestParams(20736, 120 * kMultiplier)); + list.push_back(PingPongTestParams(248832, 10 * kMultiplier)); + return list; +} + +// Avoid core 0 due to conflicts with Intel's Power Gadget. +// Setting thread affinity will fail harmlessly on single/dual core machines. +const int kSharedCore = 2; + +class MojoChannelPerfTest : public IPCChannelMojoTestBase { + public: + MojoChannelPerfTest() = default; + ~MojoChannelPerfTest() override = default; + + void RunTestChannelPingPong() { + Init("MojoPerfTestClient"); + + // Set up IPC channel and start client. + PerformanceChannelListener listener("Channel"); + CreateChannel(&listener); + listener.Init(channel()); + ASSERT_TRUE(ConnectChannel()); + + LockThreadAffinity thread_locker(kSharedCore); + std::vector<PingPongTestParams> params = GetDefaultTestParams(); + for (size_t i = 0; i < params.size(); i++) { + listener.SetTestParams(params[i].message_count(), + params[i].message_size()); + + // This initial message will kick-start the ping-pong of messages. + Message* message = + new Message(0, 2, Message::PRIORITY_NORMAL); + message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); + message->WriteInt(-1); + message->WriteString("hello"); + sender()->Send(message); + + // Run message loop. + base::RunLoop().Run(); + } + + // Send quit message. + Message* message = new Message(0, 2, Message::PRIORITY_NORMAL); + message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); + message->WriteInt(-1); + message->WriteString("quit"); + sender()->Send(message); + + EXPECT_TRUE(WaitForClientShutdown()); + DestroyChannel(); +} + + void RunTestChannelProxyPingPong() { + io_thread_.reset(new base::TestIOThread(base::TestIOThread::kAutoStart)); + + Init("MojoPerfTestClient"); + + // Set up IPC channel and start client. + PerformanceChannelListener listener("ChannelProxy"); + auto channel_proxy = IPC::ChannelProxy::Create( + TakeHandle().release(), IPC::Channel::MODE_SERVER, &listener, + io_thread_->task_runner()); + listener.Init(channel_proxy.get()); + + LockThreadAffinity thread_locker(kSharedCore); + std::vector<PingPongTestParams> params = GetDefaultTestParams(); + for (size_t i = 0; i < params.size(); i++) { + listener.SetTestParams(params[i].message_count(), + params[i].message_size()); + + // This initial message will kick-start the ping-pong of messages. + Message* message = new Message(0, 2, Message::PRIORITY_NORMAL); + message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); + message->WriteInt(-1); + message->WriteString("hello"); + channel_proxy->Send(message); + + // Run message loop. + base::RunLoop().Run(); + } + + // Send quit message. + Message* message = new Message(0, 2, Message::PRIORITY_NORMAL); + message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); + message->WriteInt(-1); + message->WriteString("quit"); + channel_proxy->Send(message); + + EXPECT_TRUE(WaitForClientShutdown()); + channel_proxy.reset(); + + io_thread_.reset(); + } + + scoped_refptr<base::TaskRunner> io_task_runner() { + if (io_thread_) + return io_thread_->task_runner(); + return base::ThreadTaskRunnerHandle::Get(); + } + + private: + std::unique_ptr<base::TestIOThread> io_thread_; }; TEST_F(MojoChannelPerfTest, ChannelPingPong) { - RunTestChannelPingPong(GetDefaultTestParams()); + RunTestChannelPingPong(); base::RunLoop run_loop; run_loop.RunUntilIdle(); } TEST_F(MojoChannelPerfTest, ChannelProxyPingPong) { - RunTestChannelProxyPingPong(GetDefaultTestParams()); + RunTestChannelProxyPingPong(); base::RunLoop run_loop; run_loop.RunUntilIdle(); @@ -57,36 +429,34 @@ } } -class MojoPerfTestClient : public test::PingPongTestClient { +class MojoPerfTestClient { public: - typedef test::PingPongTestClient SuperType; + MojoPerfTestClient() + : listener_(new ChannelReflectorListener()) { + mojo::edk::test::MultiprocessTestHelper::ChildSetup(); + } - MojoPerfTestClient(); + ~MojoPerfTestClient() = default; - std::unique_ptr<Channel> CreateChannel(Listener* listener) override; + int Run(MojoHandle handle) { + handle_ = mojo::MakeScopedHandle(mojo::MessagePipeHandle(handle)); + LockThreadAffinity thread_locker(kSharedCore); + std::unique_ptr<Channel> channel = ChannelMojo::Create( + std::move(handle_), Channel::MODE_CLIENT, listener_.get()); + listener_->Init(channel.get()); + CHECK(channel->Connect()); - int Run(MojoHandle handle); + base::RunLoop().Run(); + return 0; + } private: - mojo::edk::test::ScopedIPCSupport ipc_support_; + base::MessageLoopForIO main_message_loop_; + std::unique_ptr<ChannelReflectorListener> listener_; + std::unique_ptr<Channel> channel_; mojo::ScopedMessagePipeHandle handle_; }; -MojoPerfTestClient::MojoPerfTestClient() - : ipc_support_(base::ThreadTaskRunnerHandle::Get()) { - mojo::edk::test::MultiprocessTestHelper::ChildSetup(); -} - -std::unique_ptr<Channel> MojoPerfTestClient::CreateChannel(Listener* listener) { - return ChannelMojo::Create(std::move(handle_), Channel::MODE_CLIENT, - listener); -} - -int MojoPerfTestClient::Run(MojoHandle handle) { - handle_ = mojo::MakeScopedHandle(mojo::MessagePipeHandle(handle)); - return RunMain(); -} - MULTIPROCESS_TEST_MAIN(MojoPerfTestClientTestChildMain) { MojoPerfTestClient client; int rv = mojo::edk::test::MultiprocessTestHelper::RunClientMain( @@ -98,5 +468,208 @@ return rv; } +class ReflectorImpl : public IPC::mojom::Reflector { + public: + explicit ReflectorImpl(mojo::ScopedMessagePipeHandle handle) + : binding_(this, std::move(handle)) {} + ~ReflectorImpl() override { + ignore_result(binding_.Unbind().PassMessagePipe().release()); + } + + private: + // IPC::mojom::Reflector: + void Ping(const std::string& value, const PingCallback& callback) override { + callback.Run(value); + } + + void Quit() override { + base::MessageLoop::current()->QuitWhenIdle(); + } + + mojo::Binding<IPC::mojom::Reflector> binding_; +}; + +class MojoInterfacePerfTest : public mojo::edk::test::MojoTestBase { + public: + MojoInterfacePerfTest() : message_count_(0), count_down_(0) {} + + protected: + void RunPingPongServer(MojoHandle mp, const std::string& label) { + base::MessageLoop main_message_loop; + label_ = label; + + mojo::MessagePipeHandle mp_handle(mp); + mojo::ScopedMessagePipeHandle scoped_mp(mp_handle); + ping_receiver_.Bind(IPC::mojom::ReflectorPtrInfo( + std::move(scoped_mp), 0u)); + + LockThreadAffinity thread_locker(kSharedCore); + std::vector<PingPongTestParams> params = GetDefaultTestParams(); + for (size_t i = 0; i < params.size(); i++) { + ping_receiver_->Ping( + "hello", + base::Bind(&MojoInterfacePerfTest::OnPong, base::Unretained(this))); + message_count_ = count_down_ = params[i].message_count(); + payload_ = std::string(params[i].message_size(), 'a'); + + base::RunLoop().Run(); + } + + ping_receiver_->Quit(); + + ignore_result(ping_receiver_.PassInterface().PassHandle().release()); + } + + void OnPong(const std::string& value) { + if (value == "hello") { + DCHECK(!perf_logger_.get()); + std::string test_name = + base::StringPrintf("IPC_%s_Perf_%dx_%zu", + label_.c_str(), + message_count_, + payload_.size()); + perf_logger_.reset(new base::PerfTimeLogger(test_name.c_str())); + } else { + DCHECK_EQ(payload_.size(), value.size()); + + CHECK(count_down_ > 0); + count_down_--; + if (count_down_ == 0) { + perf_logger_.reset(); + base::MessageLoop::current()->QuitWhenIdle(); + return; + } + } + + ping_receiver_->Ping( + payload_, + base::Bind(&MojoInterfacePerfTest::OnPong, base::Unretained(this))); + } + + static int RunPingPongClient(MojoHandle mp) { + mojo::MessagePipeHandle mp_handle(mp); + mojo::ScopedMessagePipeHandle scoped_mp(mp_handle); + + // In single process mode, this is running in a task and by default other + // tasks (in particular, the binding) won't run. To keep the single process + // and multi-process code paths the same, enable nestable tasks. + base::MessageLoop::ScopedNestableTaskAllower nest_loop( + base::MessageLoop::current()); + + LockThreadAffinity thread_locker(kSharedCore); + ReflectorImpl impl(std::move(scoped_mp)); + base::RunLoop().Run(); + return 0; + } + + private: + int message_count_; + int count_down_; + std::string label_; + std::string payload_; + IPC::mojom::ReflectorPtr ping_receiver_; + std::unique_ptr<base::PerfTimeLogger> perf_logger_; + + DISALLOW_COPY_AND_ASSIGN(MojoInterfacePerfTest); +}; + +DEFINE_TEST_CLIENT_WITH_PIPE(PingPongClient, MojoInterfacePerfTest, h) { + base::MessageLoop main_message_loop; + return RunPingPongClient(h); +} + +// Similar to MojoChannelPerfTest above, but uses a Mojo interface instead of +// raw IPC::Messages. +TEST_F(MojoInterfacePerfTest, MultiprocessPingPong) { + RUN_CHILD_ON_PIPE(PingPongClient, h) + RunPingPongServer(h, "MultiProcess"); + END_CHILD() +} + +// A single process version of the above test. +TEST_F(MojoInterfacePerfTest, SingleProcessPingPong) { + MojoHandle server_handle, client_handle; + CreateMessagePipe(&server_handle, &client_handle); + + base::Thread client_thread("PingPongClient"); + client_thread.Start(); + client_thread.task_runner()->PostTask( + FROM_HERE, + base::Bind(base::IgnoreResult(&RunPingPongClient), client_handle)); + + RunPingPongServer(server_handle, "SingleProcess"); +} + +class CallbackPerfTest : public testing::Test { + public: + CallbackPerfTest() + : client_thread_("PingPongClient"), message_count_(0), count_down_(0) {} + + protected: + void RunPingPongServer() { + client_thread_.Start(); + + LockThreadAffinity thread_locker(kSharedCore); + std::vector<PingPongTestParams> params = GetDefaultTestParams(); + for (size_t i = 0; i < params.size(); i++) { + std::string hello("hello"); + client_thread_.task_runner()->PostTask( + FROM_HERE, + base::Bind(&CallbackPerfTest::Ping, base::Unretained(this), hello)); + message_count_ = count_down_ = params[i].message_count(); + payload_ = std::string(params[i].message_size(), 'a'); + + base::RunLoop().Run(); + } + } + + void Ping(const std::string& value) { + main_message_loop.task_runner()->PostTask( + FROM_HERE, + base::Bind(&CallbackPerfTest::OnPong, base::Unretained(this), + value)); + } + + void OnPong(const std::string& value) { + if (value == "hello") { + DCHECK(!perf_logger_.get()); + std::string test_name = + base::StringPrintf("Callback_Perf_%dx_%zu", + message_count_, + payload_.size()); + perf_logger_.reset(new base::PerfTimeLogger(test_name.c_str())); + } else { + DCHECK_EQ(payload_.size(), value.size()); + + CHECK(count_down_ > 0); + count_down_--; + if (count_down_ == 0) { + perf_logger_.reset(); + base::MessageLoop::current()->QuitWhenIdle(); + return; + } + } + + client_thread_.task_runner()->PostTask( + FROM_HERE, + base::Bind(&CallbackPerfTest::Ping, base::Unretained(this), payload_)); + } + + private: + base::Thread client_thread_; + base::MessageLoop main_message_loop; + int message_count_; + int count_down_; + std::string payload_; + std::unique_ptr<base::PerfTimeLogger> perf_logger_; + + DISALLOW_COPY_AND_ASSIGN(CallbackPerfTest); +}; + +// Sends the same data as above using PostTask instead of IPCs for comparison. +TEST_F(CallbackPerfTest, PingPong) { + RunPingPongServer(); +} + } // namespace } // namespace IPC
diff --git a/ipc/ipc_perftest_support.cc b/ipc/ipc_perftest_support.cc deleted file mode 100644 index 10516bc..0000000 --- a/ipc/ipc_perftest_support.cc +++ /dev/null
@@ -1,396 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ipc/ipc_perftest_support.h" - -#include <stddef.h> -#include <stdint.h> - -#include <algorithm> -#include <memory> -#include <string> - -#include "base/logging.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/pickle.h" -#include "base/run_loop.h" -#include "base/strings/stringprintf.h" -#include "base/test/perf_time_logger.h" -#include "base/test/test_io_thread.h" -#include "base/threading/thread.h" -#include "base/threading/thread_task_runner_handle.h" -#include "base/time/time.h" -#include "build/build_config.h" -#include "ipc/ipc_channel.h" -#include "ipc/ipc_channel_proxy.h" -#include "ipc/ipc_descriptors.h" -#include "ipc/ipc_message_utils.h" -#include "ipc/ipc_sender.h" -#include "mojo/edk/test/scoped_ipc_support.h" - -namespace IPC { -namespace test { - -// Avoid core 0 due to conflicts with Intel's Power Gadget. -// Setting thread affinity will fail harmlessly on single/dual core machines. -const int kSharedCore = 2; - -// This class simply collects stats about abstract "events" (each of which has a -// start time and an end time). -class EventTimeTracker { - public: - explicit EventTimeTracker(const char* name) - : name_(name), - count_(0) { - } - - void AddEvent(const base::TimeTicks& start, const base::TimeTicks& end) { - DCHECK(end >= start); - count_++; - base::TimeDelta duration = end - start; - total_duration_ += duration; - max_duration_ = std::max(max_duration_, duration); - } - - void ShowResults() const { - VLOG(1) << name_ << " count: " << count_; - VLOG(1) << name_ << " total duration: " - << total_duration_.InMillisecondsF() << " ms"; - VLOG(1) << name_ << " average duration: " - << (total_duration_.InMillisecondsF() / static_cast<double>(count_)) - << " ms"; - VLOG(1) << name_ << " maximum duration: " - << max_duration_.InMillisecondsF() << " ms"; - } - - void Reset() { - count_ = 0; - total_duration_ = base::TimeDelta(); - max_duration_ = base::TimeDelta(); - } - - private: - const std::string name_; - - uint64_t count_; - base::TimeDelta total_duration_; - base::TimeDelta max_duration_; - - DISALLOW_COPY_AND_ASSIGN(EventTimeTracker); -}; - -// This channel listener just replies to all messages with the exact same -// message. It assumes each message has one string parameter. When the string -// "quit" is sent, it will exit. -class ChannelReflectorListener : public Listener { - public: - ChannelReflectorListener() - : channel_(NULL), - latency_tracker_("Client messages") { - VLOG(1) << "Client listener up"; - } - - ~ChannelReflectorListener() override { - VLOG(1) << "Client listener down"; - latency_tracker_.ShowResults(); - } - - void Init(Channel* channel) { - DCHECK(!channel_); - channel_ = channel; - } - - bool OnMessageReceived(const Message& message) override { - CHECK(channel_); - - base::PickleIterator iter(message); - int64_t time_internal; - EXPECT_TRUE(iter.ReadInt64(&time_internal)); - int msgid; - EXPECT_TRUE(iter.ReadInt(&msgid)); - base::StringPiece payload; - EXPECT_TRUE(iter.ReadStringPiece(&payload)); - - // Include message deserialization in latency. - base::TimeTicks now = base::TimeTicks::Now(); - - if (payload == "hello") { - latency_tracker_.Reset(); - } else if (payload == "quit") { - latency_tracker_.ShowResults(); - base::MessageLoop::current()->QuitWhenIdle(); - return true; - } else { - // Don't track hello and quit messages. - latency_tracker_.AddEvent( - base::TimeTicks::FromInternalValue(time_internal), now); - } - - Message* msg = new Message(0, 2, Message::PRIORITY_NORMAL); - msg->WriteInt64(base::TimeTicks::Now().ToInternalValue()); - msg->WriteInt(msgid); - msg->WriteString(payload); - channel_->Send(msg); - return true; - } - - private: - Channel* channel_; - EventTimeTracker latency_tracker_; -}; - -class PerformanceChannelListener : public Listener { - public: - explicit PerformanceChannelListener(const std::string& label) - : label_(label), - sender_(NULL), - msg_count_(0), - msg_size_(0), - count_down_(0), - latency_tracker_("Server messages") { - VLOG(1) << "Server listener up"; - } - - ~PerformanceChannelListener() override { - VLOG(1) << "Server listener down"; - } - - void Init(Sender* sender) { - DCHECK(!sender_); - sender_ = sender; - } - - // Call this before running the message loop. - void SetTestParams(int msg_count, size_t msg_size) { - DCHECK_EQ(0, count_down_); - msg_count_ = msg_count; - msg_size_ = msg_size; - count_down_ = msg_count_; - payload_ = std::string(msg_size_, 'a'); - } - - bool OnMessageReceived(const Message& message) override { - CHECK(sender_); - - base::PickleIterator iter(message); - int64_t time_internal; - EXPECT_TRUE(iter.ReadInt64(&time_internal)); - int msgid; - EXPECT_TRUE(iter.ReadInt(&msgid)); - std::string reflected_payload; - EXPECT_TRUE(iter.ReadString(&reflected_payload)); - - // Include message deserialization in latency. - base::TimeTicks now = base::TimeTicks::Now(); - - if (reflected_payload == "hello") { - // Start timing on hello. - latency_tracker_.Reset(); - DCHECK(!perf_logger_.get()); - std::string test_name = - base::StringPrintf("IPC_%s_Perf_%dx_%u", - label_.c_str(), - msg_count_, - static_cast<unsigned>(msg_size_)); - perf_logger_.reset(new base::PerfTimeLogger(test_name.c_str())); - } else { - DCHECK_EQ(payload_.size(), reflected_payload.size()); - - latency_tracker_.AddEvent( - base::TimeTicks::FromInternalValue(time_internal), now); - - CHECK(count_down_ > 0); - count_down_--; - if (count_down_ == 0) { - perf_logger_.reset(); // Stop the perf timer now. - latency_tracker_.ShowResults(); - base::MessageLoop::current()->QuitWhenIdle(); - return true; - } - } - - Message* msg = new Message(0, 2, Message::PRIORITY_NORMAL); - msg->WriteInt64(base::TimeTicks::Now().ToInternalValue()); - msg->WriteInt(count_down_); - msg->WriteString(payload_); - sender_->Send(msg); - return true; - } - - private: - std::string label_; - Sender* sender_; - int msg_count_; - size_t msg_size_; - - int count_down_; - std::string payload_; - EventTimeTracker latency_tracker_; - std::unique_ptr<base::PerfTimeLogger> perf_logger_; -}; - -IPCChannelPerfTestBase::IPCChannelPerfTestBase() = default; -IPCChannelPerfTestBase::~IPCChannelPerfTestBase() = default; - -std::vector<PingPongTestParams> -IPCChannelPerfTestBase::GetDefaultTestParams() { - // Test several sizes. We use 12^N for message size, and limit the message - // count to keep the test duration reasonable. -#ifdef NDEBUG - const int kMultiplier = 100; -#else - // Debug builds on Windows run these tests orders of magnitude more slowly. - const int kMultiplier = 1; -#endif - std::vector<PingPongTestParams> list; - list.push_back(PingPongTestParams(12, 500 * kMultiplier)); - list.push_back(PingPongTestParams(144, 500 * kMultiplier)); - list.push_back(PingPongTestParams(1728, 500 * kMultiplier)); - list.push_back(PingPongTestParams(20736, 120 * kMultiplier)); - list.push_back(PingPongTestParams(248832, 10 * kMultiplier)); - return list; -} - -void IPCChannelPerfTestBase::RunTestChannelPingPong( - const std::vector<PingPongTestParams>& params) { - auto message_loop = base::MakeUnique<base::MessageLoopForIO>(); - mojo::edk::test::ScopedIPCSupport ipc_support(message_loop->task_runner()); - InitWithCustomMessageLoop("MojoPerfTestClient", std::move(message_loop)); - - // Set up IPC channel and start client. - PerformanceChannelListener listener("Channel"); - CreateChannel(&listener); - listener.Init(channel()); - ASSERT_TRUE(ConnectChannel()); - - LockThreadAffinity thread_locker(kSharedCore); - for (size_t i = 0; i < params.size(); i++) { - listener.SetTestParams(params[i].message_count(), - params[i].message_size()); - - // This initial message will kick-start the ping-pong of messages. - Message* message = - new Message(0, 2, Message::PRIORITY_NORMAL); - message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); - message->WriteInt(-1); - message->WriteString("hello"); - sender()->Send(message); - - // Run message loop. - base::RunLoop().Run(); - } - - // Send quit message. - Message* message = new Message(0, 2, Message::PRIORITY_NORMAL); - message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); - message->WriteInt(-1); - message->WriteString("quit"); - sender()->Send(message); - - EXPECT_TRUE(WaitForClientShutdown()); - DestroyChannel(); -} - -void IPCChannelPerfTestBase::RunTestChannelProxyPingPong( - const std::vector<PingPongTestParams>& params) { - io_thread_.reset(new base::TestIOThread(base::TestIOThread::kAutoStart)); - { - auto message_loop = base::MakeUnique<base::MessageLoopForIO>(); - mojo::edk::test::ScopedIPCSupport ipc_support(io_thread_->task_runner()); - InitWithCustomMessageLoop("MojoPerfTestClient", std::move(message_loop)); - - // Set up IPC channel and start client. - PerformanceChannelListener listener("ChannelProxy"); - auto channel_proxy = IPC::ChannelProxy::Create( - TakeHandle().release(), IPC::Channel::MODE_SERVER, &listener, - io_thread_->task_runner()); - listener.Init(channel_proxy.get()); - - LockThreadAffinity thread_locker(kSharedCore); - for (size_t i = 0; i < params.size(); i++) { - listener.SetTestParams(params[i].message_count(), - params[i].message_size()); - - // This initial message will kick-start the ping-pong of messages. - Message* message = new Message(0, 2, Message::PRIORITY_NORMAL); - message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); - message->WriteInt(-1); - message->WriteString("hello"); - channel_proxy->Send(message); - - // Run message loop. - base::RunLoop().Run(); - } - - // Send quit message. - Message* message = new Message(0, 2, Message::PRIORITY_NORMAL); - message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); - message->WriteInt(-1); - message->WriteString("quit"); - channel_proxy->Send(message); - - EXPECT_TRUE(WaitForClientShutdown()); - channel_proxy.reset(); - } - - io_thread_.reset(); -} - - -PingPongTestClient::PingPongTestClient() - : listener_(new ChannelReflectorListener()) { -} - -PingPongTestClient::~PingPongTestClient() { -} - -int PingPongTestClient::RunMain() { - LockThreadAffinity thread_locker(kSharedCore); - std::unique_ptr<Channel> channel = CreateChannel(listener_.get()); - listener_->Init(channel.get()); - CHECK(channel->Connect()); - - base::RunLoop().Run(); - return 0; -} - -scoped_refptr<base::TaskRunner> PingPongTestClient::task_runner() { - return main_message_loop_.task_runner(); -} - -LockThreadAffinity::LockThreadAffinity(int cpu_number) - : affinity_set_ok_(false) { -#if defined(OS_WIN) - const DWORD_PTR thread_mask = static_cast<DWORD_PTR>(1) << cpu_number; - old_affinity_ = SetThreadAffinityMask(GetCurrentThread(), thread_mask); - affinity_set_ok_ = old_affinity_ != 0; -#elif defined(OS_LINUX) - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - CPU_SET(cpu_number, &cpuset); - auto get_result = sched_getaffinity(0, sizeof(old_cpuset_), &old_cpuset_); - DCHECK_EQ(0, get_result); - auto set_result = sched_setaffinity(0, sizeof(cpuset), &cpuset); - // Check for get_result failure, even though it should always succeed. - affinity_set_ok_ = (set_result == 0) && (get_result == 0); -#endif - if (!affinity_set_ok_) - LOG(WARNING) << "Failed to set thread affinity to CPU " << cpu_number; -} - -LockThreadAffinity::~LockThreadAffinity() { - if (!affinity_set_ok_) - return; -#if defined(OS_WIN) - auto set_result = SetThreadAffinityMask(GetCurrentThread(), old_affinity_); - DCHECK_NE(0u, set_result); -#elif defined(OS_LINUX) - auto set_result = sched_setaffinity(0, sizeof(old_cpuset_), &old_cpuset_); - DCHECK_EQ(0, set_result); -#endif -} - -} // namespace test -} // namespace IPC
diff --git a/ipc/ipc_perftest_support.h b/ipc/ipc_perftest_support.h deleted file mode 100644 index f98496f7..0000000 --- a/ipc/ipc_perftest_support.h +++ /dev/null
@@ -1,99 +0,0 @@ -// Copyright (c) 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IPC_IPC_PERFTEST_SUPPORT_H_ -#define IPC_IPC_PERFTEST_SUPPORT_H_ - -#include <stddef.h> - -#include <memory> -#include <vector> - -#include "base/macros.h" -#include "base/test/test_io_thread.h" -#include "base/threading/thread_task_runner_handle.h" -#include "build/build_config.h" -#include "ipc/ipc_test_base.h" - -namespace IPC { -namespace test { - -class ChannelReflectorListener; - -class PingPongTestParams { - public: - PingPongTestParams(size_t size, int count) - : message_size_(size), message_count_(count) { - } - - size_t message_size() const { return message_size_; } - int message_count() const { return message_count_; } - - private: - size_t message_size_; - int message_count_; -}; - -class IPCChannelPerfTestBase : public IPCChannelMojoTestBase { - public: - IPCChannelPerfTestBase(); - ~IPCChannelPerfTestBase() override; - - static std::vector<PingPongTestParams> GetDefaultTestParams(); - - void RunTestChannelPingPong( - const std::vector<PingPongTestParams>& params_list); - void RunTestChannelProxyPingPong( - const std::vector<PingPongTestParams>& params_list); - - scoped_refptr<base::TaskRunner> io_task_runner() { - if (io_thread_) - return io_thread_->task_runner(); - return base::ThreadTaskRunnerHandle::Get(); - } - - private: - std::unique_ptr<base::TestIOThread> io_thread_; -}; - -class PingPongTestClient { - public: - PingPongTestClient(); - virtual ~PingPongTestClient(); - - virtual std::unique_ptr<Channel> CreateChannel(Listener* listener) = 0; - int RunMain(); - scoped_refptr<base::TaskRunner> task_runner(); - - private: - base::MessageLoopForIO main_message_loop_; - std::unique_ptr<ChannelReflectorListener> listener_; - std::unique_ptr<Channel> channel_; -}; - -// This class locks the current thread to a particular CPU core. This is -// important because otherwise the different threads and processes of these -// tests end up on different CPU cores which means that all of the cores are -// lightly loaded so the OS (Windows and Linux) fails to ramp up the CPU -// frequency, leading to unpredictable and often poor performance. -class LockThreadAffinity { - public: - explicit LockThreadAffinity(int cpu_number); - ~LockThreadAffinity(); - - private: - bool affinity_set_ok_; -#if defined(OS_WIN) - DWORD_PTR old_affinity_; -#elif defined(OS_LINUX) - cpu_set_t old_cpuset_; -#endif - - DISALLOW_COPY_AND_ASSIGN(LockThreadAffinity); -}; - -} -} - -#endif // IPC_IPC_PERFTEST_SUPPORT_H_
diff --git a/ipc/ipc_test.mojom b/ipc/ipc_test.mojom index 8c246d567..a4edfc9 100644 --- a/ipc/ipc_test.mojom +++ b/ipc/ipc_test.mojom
@@ -28,3 +28,8 @@ interface IndirectTestDriver { GetPingReceiver(associated PingReceiver& request); }; + +interface Reflector { + Ping(string value) => (string value); + Quit(); +};
diff --git a/ipc/run_all_perftests.cc b/ipc/run_all_perftests.cc index a942b8b5..1e3d91f 100644 --- a/ipc/run_all_perftests.cc +++ b/ipc/run_all_perftests.cc
@@ -6,12 +6,18 @@ #include "base/command_line.h" #include "base/test/perf_test_suite.h" +#include "base/test/test_io_thread.h" #include "mojo/edk/embedder/embedder.h" +#include "mojo/edk/test/scoped_ipc_support.h" +#include "mojo/edk/test/test_support_impl.h" int main(int argc, char** argv) { base::PerfTestSuite test(argc, argv); mojo::edk::Init(); + base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart); + mojo::edk::test::ScopedIPCSupport ipc_support(test_io_thread.task_runner()); + mojo::test::TestSupport::Init(new mojo::edk::test::TestSupportImpl()); return test.Run(); }
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java b/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java index 954cc28..892e8d9 100644 --- a/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java +++ b/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java
@@ -281,7 +281,7 @@ // We copy blacklisting patterns from software_renderin_list_json.cc // although they are broader than the bugs they refer to. - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) { // Samsung Galaxy Note 2, http://crbug.com/308721. if (Build.MODEL.startsWith("GT-")) return false; @@ -290,12 +290,21 @@ // Samsung Galaxy Tab, http://crbug.com/408353. if (Build.MODEL.startsWith("SM-T")) return false; + + // http://crbug.com/600454 + if (Build.MODEL.startsWith("SM-G")) return false; } } // MediaTek decoders do not work properly on vp8. See http://crbug.com/446974 and // http://crbug.com/597836. if (Build.HARDWARE.startsWith("mt")) return false; + + // http://crbug.com/600454 + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT + && Build.MODEL.startsWith("Lenovo A6000")) { + return false; + } } else if (mime.equals("video/x-vnd.on2.vp9")) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return false;
diff --git a/media/blink/renderer_media_player_interface.h b/media/blink/renderer_media_player_interface.h index 0f1bc34..6202613 100644 --- a/media/blink/renderer_media_player_interface.h +++ b/media/blink/renderer_media_player_interface.h
@@ -61,12 +61,6 @@ virtual void OnRemoteRouteAvailabilityChanged( blink::WebRemotePlaybackAvailability availability) = 0; - // Getters of playback state. - virtual bool paused() const = 0; - - // True if the loaded media has a playable video track. - virtual bool hasVideo() const = 0; - // This function is called by the RendererMediaPlayerManager to pause the // video and release the media player and surface texture when we switch tabs. // However, the actual GlTexture is not released to keep the video screenshot.
diff --git a/media/blink/webmediaplayer_cast_android.cc b/media/blink/webmediaplayer_cast_android.cc index 3ea8fe01..1d698f57 100644 --- a/media/blink/webmediaplayer_cast_android.cc +++ b/media/blink/webmediaplayer_cast_android.cc
@@ -339,14 +339,6 @@ void WebMediaPlayerCast::SuspendAndReleaseResources() {} -bool WebMediaPlayerCast::hasVideo() const { - return true; -} - -bool WebMediaPlayerCast::paused() const { - return paused_; -} - void WebMediaPlayerCast::SetDeviceScaleFactor(float scale_factor) { device_scale_factor_ = scale_factor; }
diff --git a/media/blink/webmediaplayer_cast_android.h b/media/blink/webmediaplayer_cast_android.h index 3a82b94..ff94c16 100644 --- a/media/blink/webmediaplayer_cast_android.h +++ b/media/blink/webmediaplayer_cast_android.h
@@ -45,6 +45,7 @@ void SetMediaPlayerManager( RendererMediaPlayerManagerInterface* media_player_manager); bool isRemote() const { return is_remote_; } + bool IsPaused() const { return paused_; } double currentTime() const; void play(); @@ -82,20 +83,11 @@ void OnRemoteRouteAvailabilityChanged( blink::WebRemotePlaybackAvailability availability) override; - // Getters of playback state. - // bool paused() const override; - - // True if the loaded media has a playable video track. - // bool hasVideo() const override; - // This function is called by the RendererMediaPlayerManager to pause the // video and release the media player and surface texture when we switch tabs. // However, the actual GlTexture is not released to keep the video screenshot. void SuspendAndReleaseResources() override; - bool paused() const override; - bool hasVideo() const override; - void SetDeviceScaleFactor(float scale_factor); scoped_refptr<VideoFrame> GetCastingBanner(); void setPoster(const blink::WebURL& poster);
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc index a1d7bb8e..c9b8f8a 100644 --- a/media/blink/webmediaplayer_impl.cc +++ b/media/blink/webmediaplayer_impl.cc
@@ -689,7 +689,7 @@ #if defined(OS_ANDROID) // WMPI_CAST if (isRemote()) - return cast_impl_.paused(); + return cast_impl_.IsPaused(); #endif return pipeline_.GetPlaybackRate() == 0.0f;
diff --git a/mojo/edk/test/run_all_perftests.cc b/mojo/edk/test/run_all_perftests.cc index 50c41d7a..f426a2a 100644 --- a/mojo/edk/test/run_all_perftests.cc +++ b/mojo/edk/test/run_all_perftests.cc
@@ -21,10 +21,7 @@ mojo::edk::Init(); base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart); - // Leak this because its destructor calls mojo::edk::ShutdownIPCSupport which - // really does nothing in the new EDK but does depend on the current message - // loop, which is destructed inside base::LaunchUnitTests. - new mojo::edk::test::ScopedIPCSupport(test_io_thread.task_runner()); + mojo::edk::test::ScopedIPCSupport ipc_support(test_io_thread.task_runner()); mojo::test::TestSupport::Init(new mojo::edk::test::TestSupportImpl()); return test.Run();
diff --git a/net/data/ftp/dir-listing-ls-34 b/net/data/ftp/dir-listing-ls-34 new file mode 100644 index 0000000..6286ed1 --- /dev/null +++ b/net/data/ftp/dir-listing-ls-34
@@ -0,0 +1,2 @@ +-rw-rw-r-- 1 ftpuser ftpusers 1761280 Dec 20 2002 controle_embarqu‚_avec_labview_real_time_et_compactfieldpoint.ppt +-rw-rw-r-- 1 ftpuser ftpusers 329216 Dec 20 2002 optimisez_l'acquisition_de_donn‚es_sous_labview.ppt
diff --git a/net/data/ftp/dir-listing-ls-34.expected b/net/data/ftp/dir-listing-ls-34.expected new file mode 100644 index 0000000..77aed17 --- /dev/null +++ b/net/data/ftp/dir-listing-ls-34.expected
@@ -0,0 +1,17 @@ +- +controle_embarqu�_avec_labview_real_time_et_compactfieldpoint.ppt +1761280 +2002 +12 +20 +0 +0 + +- +optimisez_l'acquisition_de_donnFs_sous_labview.ppt +329216 +2002 +12 +20 +0 +0
diff --git a/net/ftp/ftp_directory_listing_parser.cc b/net/ftp/ftp_directory_listing_parser.cc index 151c1b9..1096ae0 100644 --- a/net/ftp/ftp_directory_listing_parser.cc +++ b/net/ftp/ftp_directory_listing_parser.cc
@@ -28,7 +28,7 @@ std::vector<FtpDirectoryListingEntry>* entries) { for (size_t i = 0; i < entries->size(); i++) { if (!base::UTF16ToCodepage(entries->at(i).name, encoding.c_str(), - base::OnStringConversionError::FAIL, + base::OnStringConversionError::SUBSTITUTE, &entries->at(i).raw_name)) { return ERR_ENCODING_CONVERSION_FAILED; } @@ -91,7 +91,7 @@ base::string16 converted_text; if (base::CodepageToUTF16(text, encoding_name, - base::OnStringConversionError::FAIL, + base::OnStringConversionError::SUBSTITUTE, &converted_text)) { const char* const kNewlineSeparators[] = {"\n", "\r\n"};
diff --git a/net/ftp/ftp_directory_listing_parser_unittest.cc b/net/ftp/ftp_directory_listing_parser_unittest.cc index dc75ade5..a7f5bcf 100644 --- a/net/ftp/ftp_directory_listing_parser_unittest.cc +++ b/net/ftp/ftp_directory_listing_parser_unittest.cc
@@ -158,6 +158,7 @@ {"dir-listing-ls-31", OK}, {"dir-listing-ls-32", OK}, // busybox {"dir-listing-ls-33", OK}, + {"dir-listing-ls-34", OK}, // Broken encoding. Should not fail. {"dir-listing-netware-1", OK}, {"dir-listing-netware-2", OK},
diff --git a/services/ui/gpu/gpu_service.cc b/services/ui/gpu/gpu_service.cc index 0be4a879..ac657e8 100644 --- a/services/ui/gpu/gpu_service.cc +++ b/services/ui/gpu/gpu_service.cc
@@ -144,7 +144,7 @@ void GpuService::SendAcceleratedSurfaceCreatedChildWindow( gpu::SurfaceHandle parent_window, gpu::SurfaceHandle child_window) { - ::SetParent(child_window, parent_window); + gpu_host_->SetChildSurface(parent_window, child_window); } #endif
diff --git a/services/ui/gpu/interfaces/gpu_host.mojom b/services/ui/gpu/interfaces/gpu_host.mojom index cd84b9e..b4baab5 100644 --- a/services/ui/gpu/interfaces/gpu_host.mojom +++ b/services/ui/gpu/interfaces/gpu_host.mojom
@@ -5,6 +5,7 @@ module ui.mojom; import "gpu/ipc/common/gpu_info.mojom"; +import "gpu/ipc/common/surface_handle.mojom"; import "services/ui/gpu/interfaces/context_lost_reason.mojom"; import "url/mojo/url.mojom"; @@ -18,5 +19,7 @@ ContextLostReason reason, url.mojom.Url active_url); + SetChildSurface(gpu.mojom.SurfaceHandle parent, + gpu.mojom.SurfaceHandle child); StoreShaderToDisk(int32 client_id, string key, string shader); };
diff --git a/services/ui/ws/display_manager.cc b/services/ui/ws/display_manager.cc index 2d9abf3..f8d6271 100644 --- a/services/ui/ws/display_manager.cc +++ b/services/ui/ws/display_manager.cc
@@ -63,6 +63,7 @@ DCHECK(displays_.count(display)); displays_.erase(display); + window_server_->OnDisplayDestroyed(display); } delete display;
diff --git a/services/ui/ws/gpu_host.cc b/services/ui/ws/gpu_host.cc index d8b4eb7..ac2c22fa6 100644 --- a/services/ui/ws/gpu_host.cc +++ b/services/ui/ws/gpu_host.cc
@@ -19,6 +19,10 @@ #include "services/ui/ws/gpu_host_delegate.h" #include "ui/gfx/buffer_format_util.h" +#if defined(OS_WIN) +#include "ui/gfx/win/rendering_window_manager.h" +#endif + namespace ui { namespace ws { @@ -99,10 +103,10 @@ next_client_id_(kInternalGpuChannelClientId + 1), main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()), gpu_host_binding_(this) { - gpu_main_impl_ = base::MakeUnique<GpuMain>(MakeRequest(&gpu_main_)); - gpu_main_impl_->OnStart(); // TODO(sad): Once GPU process is split, this would look like: // connector->ConnectToInterface("gpu", &gpu_main_); + gpu_main_impl_ = base::MakeUnique<GpuMain>(MakeRequest(&gpu_main_)); + gpu_main_impl_->OnStart(); gpu_main_->CreateGpuService(MakeRequest(&gpu_service_), gpu_host_binding_.CreateInterfacePtrAndBind()); gpu_memory_buffer_manager_ = base::MakeUnique<ServerGpuMemoryBufferManager>( @@ -119,12 +123,30 @@ std::move(request)); } +void GpuHost::OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget) { +#if defined(OS_WIN) + gfx::RenderingWindowManager::GetInstance()->RegisterParent(widget); +#endif +} + +void GpuHost::OnAcceleratedWidgetDestroyed(gfx::AcceleratedWidget widget) { +#if defined(OS_WIN) + gfx::RenderingWindowManager::GetInstance()->UnregisterParent(widget); +#endif +} + void GpuHost::CreateDisplayCompositor( cc::mojom::DisplayCompositorRequest request, cc::mojom::DisplayCompositorClientPtr client) { gpu_main_->CreateDisplayCompositor(std::move(request), std::move(client)); } +void GpuHost::OnBadMessageFromGpu() { + // TODO(sad): Received some unexpected message from the gpu process. We + // should kill the process and restart it. + NOTIMPLEMENTED(); +} + void GpuHost::DidInitialize(const gpu::GPUInfo& gpu_info) { gpu_info_ = gpu_info; delegate_->OnGpuServiceInitialized(); @@ -140,6 +162,28 @@ gpu::error::ContextLostReason reason, const GURL& active_url) {} +void GpuHost::SetChildSurface(gpu::SurfaceHandle parent, + gpu::SurfaceHandle child) { +#if defined(OS_WIN) + // Verify that |parent| was created by the window server. + DWORD process_id = 0; + DWORD thread_id = GetWindowThreadProcessId(parent, &process_id); + if (!thread_id || process_id != ::GetCurrentProcessId()) { + OnBadMessageFromGpu(); + return; + } + + // TODO(sad): Also verify that |child| was created by the mus-gpu process. + + if (!gfx::RenderingWindowManager::GetInstance()->RegisterChild(parent, + child)) { + OnBadMessageFromGpu(); + } +#else + NOTREACHED(); +#endif +} + void GpuHost::StoreShaderToDisk(int32_t client_id, const std::string& key, const std::string& shader) {}
diff --git a/services/ui/ws/gpu_host.h b/services/ui/ws/gpu_host.h index a2511c2..b937266 100644 --- a/services/ui/ws/gpu_host.h +++ b/services/ui/ws/gpu_host.h
@@ -34,11 +34,16 @@ void Add(mojom::GpuRequest request); + void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget); + void OnAcceleratedWidgetDestroyed(gfx::AcceleratedWidget widget); + // Requests a cc::mojom::DisplayCompositor interface from mus-gpu. void CreateDisplayCompositor(cc::mojom::DisplayCompositorRequest request, cc::mojom::DisplayCompositorClientPtr client); private: + void OnBadMessageFromGpu(); + // mojom::GpuHost: void DidInitialize(const gpu::GPUInfo& gpu_info) override; void DidCreateOffscreenContext(const GURL& url) override; @@ -47,6 +52,8 @@ void DidLoseContext(bool offscreen, gpu::error::ContextLostReason reason, const GURL& active_url) override; + void SetChildSurface(gpu::SurfaceHandle parent, + gpu::SurfaceHandle child) override; void StoreShaderToDisk(int32_t client_id, const std::string& key, const std::string& shader) override;
diff --git a/services/ui/ws/platform_display.h b/services/ui/ws/platform_display.h index 96b1ca9..39299ae 100644 --- a/services/ui/ws/platform_display.h +++ b/services/ui/ws/platform_display.h
@@ -13,6 +13,7 @@ #include "base/strings/string16.h" #include "services/ui/display/viewport_metrics.h" #include "services/ui/public/interfaces/cursor.mojom.h" +#include "ui/gfx/native_widget_types.h" namespace gfx { class Rect; @@ -63,6 +64,10 @@ virtual const display::ViewportMetrics& GetViewportMetrics() const = 0; + // Returns the AcceleratedWidget associated with the Display. It can return + // kNullAcceleratedWidget if the accelerated widget is not available yet. + virtual gfx::AcceleratedWidget GetAcceleratedWidget() const = 0; + virtual FrameGenerator* GetFrameGenerator() = 0; // Overrides factory for testing. Default (NULL) value indicates regular
diff --git a/services/ui/ws/platform_display_default.cc b/services/ui/ws/platform_display_default.cc index e69588ed..ba50d30 100644 --- a/services/ui/ws/platform_display_default.cc +++ b/services/ui/ws/platform_display_default.cc
@@ -36,7 +36,8 @@ image_cursors_(new ImageCursors), #endif frame_generator_(new FrameGenerator(this, init_params.root_window)), - metrics_(init_params.metrics) { + metrics_(init_params.metrics), + widget_(gfx::kNullAcceleratedWidget) { frame_generator_->set_device_scale_factor( init_params.metrics.device_scale_factor); } @@ -157,6 +158,10 @@ return metrics_; } +gfx::AcceleratedWidget PlatformDisplayDefault::GetAcceleratedWidget() const { + return widget_; +} + void PlatformDisplayDefault::UpdateEventRootLocation(ui::LocatedEvent* event) { gfx::Point location = event->location(); location.Offset(metrics_.bounds.x(), metrics_.bounds.y()); @@ -238,6 +243,8 @@ // This will get called after Init() is called, either synchronously as part // of the Init() callstack or async after Init() has returned, depending on // the platform. + DCHECK_EQ(gfx::kNullAcceleratedWidget, widget_); + widget_ = widget; delegate_->OnAcceleratedWidgetAvailable(); frame_generator_->OnAcceleratedWidgetAvailable(widget); }
diff --git a/services/ui/ws/platform_display_default.h b/services/ui/ws/platform_display_default.h index 8636c2b..f0f5326 100644 --- a/services/ui/ws/platform_display_default.h +++ b/services/ui/ws/platform_display_default.h
@@ -44,6 +44,7 @@ gfx::Rect GetBounds() const override; bool UpdateViewportMetrics(const display::ViewportMetrics& metrics) override; const display::ViewportMetrics& GetViewportMetrics() const override; + gfx::AcceleratedWidget GetAcceleratedWidget() const override; FrameGenerator* GetFrameGenerator() override; private: @@ -82,6 +83,7 @@ display::ViewportMetrics metrics_; std::unique_ptr<ui::PlatformWindow> platform_window_; + gfx::AcceleratedWidget widget_; DISALLOW_COPY_AND_ASSIGN(PlatformDisplayDefault); };
diff --git a/services/ui/ws/test_utils.cc b/services/ui/ws/test_utils.cc index 5c50fae..a1822059 100644 --- a/services/ui/ws/test_utils.cc +++ b/services/ui/ws/test_utils.cc
@@ -63,6 +63,9 @@ const display::ViewportMetrics& GetViewportMetrics() const override { return display_metrics_; } + gfx::AcceleratedWidget GetAcceleratedWidget() const override { + return gfx::kNullAcceleratedWidget; + } FrameGenerator* GetFrameGenerator() override { return nullptr; } private:
diff --git a/services/ui/ws/window_server.cc b/services/ui/ws/window_server.cc index 651eb15..7e8d355e 100644 --- a/services/ui/ws/window_server.cc +++ b/services/ui/ws/window_server.cc
@@ -509,6 +509,13 @@ void WindowServer::OnDisplayReady(Display* display, bool is_first) { if (is_first) delegate_->OnFirstDisplayReady(); + gpu_host_->OnAcceleratedWidgetAvailable( + display->platform_display()->GetAcceleratedWidget()); +} + +void WindowServer::OnDisplayDestroyed(Display* display) { + gpu_host_->OnAcceleratedWidgetDestroyed( + display->platform_display()->GetAcceleratedWidget()); } void WindowServer::OnNoMoreDisplays() {
diff --git a/services/ui/ws/window_server.h b/services/ui/ws/window_server.h index da21f65..9e8a43cf 100644 --- a/services/ui/ws/window_server.h +++ b/services/ui/ws/window_server.h
@@ -223,6 +223,7 @@ bool in_drag_loop() const { return !!current_drag_loop_; } void OnDisplayReady(Display* display, bool is_first); + void OnDisplayDestroyed(Display* display); void OnNoMoreDisplays(); WindowManagerState* GetWindowManagerStateForUser(const UserId& user_id);
diff --git a/skia/BUILD.gn b/skia/BUILD.gn index 64bc750..db9b5423 100644 --- a/skia/BUILD.gn +++ b/skia/BUILD.gn
@@ -367,10 +367,6 @@ # Select the right BitmapPlatformDevice. if (is_win) { sources += [ "ext/bitmap_platform_device_win.cc" ] - } else if (is_mac) { - sources += [ "ext/bitmap_platform_device_mac.cc" ] - } else if (use_cairo) { - sources += [ "ext/bitmap_platform_device_cairo.cc" ] } else if (!is_ios) { sources += [ "ext/bitmap_platform_device_skia.cc" ] }
diff --git a/skia/ext/bitmap_platform_device.h b/skia/ext/bitmap_platform_device.h deleted file mode 100644 index 1ca5f7e..0000000 --- a/skia/ext/bitmap_platform_device.h +++ /dev/null
@@ -1,23 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SKIA_EXT_BITMAP_PLATFORM_DEVICE_H_ -#define SKIA_EXT_BITMAP_PLATFORM_DEVICE_H_ - -// This file provides an easy way to include the appropriate -// BitmapPlatformDevice header file for your platform. - -#include <stdint.h> - -#if defined(WIN32) -#include "skia/ext/bitmap_platform_device_win.h" -#elif defined(__APPLE__) -#include "skia/ext/bitmap_platform_device_mac.h" -#elif defined(USE_CAIRO) -#include "skia/ext/bitmap_platform_device_cairo.h" -#else -#include "skia/ext/bitmap_platform_device_skia.h" -#endif - -#endif // SKIA_EXT_BITMAP_PLATFORM_DEVICE_H_
diff --git a/skia/ext/bitmap_platform_device_cairo.cc b/skia/ext/bitmap_platform_device_cairo.cc deleted file mode 100644 index 261228b..0000000 --- a/skia/ext/bitmap_platform_device_cairo.cc +++ /dev/null
@@ -1,180 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "build/build_config.h" -#include "skia/ext/bitmap_platform_device_cairo.h" -#include "skia/ext/platform_canvas.h" - -#if defined(OS_OPENBSD) -#include <cairo.h> -#else -#include <cairo/cairo.h> -#endif - -namespace skia { - -namespace { - -void CairoSurfaceReleaseProc(void*, void* context) { - SkASSERT(context); - cairo_surface_destroy(static_cast<cairo_surface_t*>(context)); -} - -// Back the destination bitmap by a Cairo surface. The bitmap's -// pixelRef takes ownership of the passed-in surface and will call -// cairo_surface_destroy() upon destruction. -// -// Note: it may immediately destroy the surface, if it fails to create a bitmap -// with pixels, thus the caller must either ref() the surface before hand, or -// it must not refer to the surface after this call. -bool InstallCairoSurfacePixels(SkBitmap* dst, - cairo_surface_t* surface, - bool is_opaque) { - SkASSERT(dst); - if (!surface) { - return false; - } - SkImageInfo info - = SkImageInfo::MakeN32(cairo_image_surface_get_width(surface), - cairo_image_surface_get_height(surface), - is_opaque ? kOpaque_SkAlphaType - : kPremul_SkAlphaType); - return dst->installPixels(info, - cairo_image_surface_get_data(surface), - cairo_image_surface_get_stride(surface), - NULL, - &CairoSurfaceReleaseProc, - static_cast<void*>(surface)); -} - -void LoadMatrixToContext(cairo_t* context, const SkMatrix& matrix) { - cairo_matrix_t cairo_matrix; - cairo_matrix_init(&cairo_matrix, - SkScalarToFloat(matrix.getScaleX()), - SkScalarToFloat(matrix.getSkewY()), - SkScalarToFloat(matrix.getSkewX()), - SkScalarToFloat(matrix.getScaleY()), - SkScalarToFloat(matrix.getTranslateX()), - SkScalarToFloat(matrix.getTranslateY())); - cairo_set_matrix(context, &cairo_matrix); -} - -void LoadClipToContext(cairo_t* context, const SkIRect& clip_bounds) { - cairo_reset_clip(context); - - cairo_rectangle(context, clip_bounds.fLeft, clip_bounds.fTop, - clip_bounds.width(), clip_bounds.height()); - cairo_clip(context); -} - -} // namespace - -void BitmapPlatformDevice::LoadConfig(const SkMatrix& transform, - const SkIRect& clip_bounds) { - if (!cairo_) - return; // Nothing to do. - - LoadClipToContext(cairo_, clip_bounds); - LoadMatrixToContext(cairo_, transform); -} - -// We use this static factory function instead of the regular constructor so -// that we can create the pixel data before calling the constructor. This is -// required so that we can call the base class' constructor with the pixel -// data. -BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height, - bool is_opaque, - cairo_surface_t* surface) { - if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { - cairo_surface_destroy(surface); - return NULL; - } - - // must call this before trying to install the surface, since that may result - // in the surface being destroyed. - cairo_t* cairo = cairo_create(surface); - - SkBitmap bitmap; - if (!InstallCairoSurfacePixels(&bitmap, surface, is_opaque)) { - cairo_destroy(cairo); - return NULL; - } - - // The device object will take ownership of the graphics context. - return new BitmapPlatformDevice(bitmap, cairo); -} - -BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height, - bool is_opaque) { - // This initializes the bitmap to all zeros. - cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - width, height); - - BitmapPlatformDevice* device = Create(width, height, is_opaque, surface); - -#ifndef NDEBUG - if (device && is_opaque) // Fill with bright bluish green - SkCanvas(device).drawColor(0xFF00FF80); -#endif - - return device; -} - -BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height, - bool is_opaque, - uint8_t* data) { - cairo_surface_t* surface = cairo_image_surface_create_for_data( - data, CAIRO_FORMAT_ARGB32, width, height, - cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width)); - - return Create(width, height, is_opaque, surface); -} - -// Ownership of the cairo object is transferred. -BitmapPlatformDevice::BitmapPlatformDevice( - const SkBitmap& bitmap, - cairo_t* cairo) - : SkBitmapDevice(bitmap), - cairo_(cairo) { - SetPlatformDevice(this, this); -} - -BitmapPlatformDevice::~BitmapPlatformDevice() { - cairo_destroy(cairo_); -} - -SkBaseDevice* BitmapPlatformDevice::onCreateDevice(const CreateInfo& info, - const SkPaint*) { - SkASSERT(info.fInfo.colorType() == kN32_SkColorType); - return BitmapPlatformDevice::Create(info.fInfo.width(), info.fInfo.height(), - info.fInfo.isOpaque()); -} - -cairo_t* BitmapPlatformDevice::BeginPlatformPaint( - const SkMatrix& transform, - const SkIRect& clip_bounds) { - LoadConfig(transform, clip_bounds); - cairo_surface_t* surface = cairo_get_target(cairo_); - // Tell cairo to flush anything it has pending. - cairo_surface_flush(surface); - // Tell Cairo that we (probably) modified (actually, will modify) its pixel - // buffer directly. - cairo_surface_mark_dirty(surface); - return cairo_; -} - -// PlatformCanvas impl - -std::unique_ptr<SkCanvas> CreatePlatformCanvasWithPixels( - int width, - int height, - bool is_opaque, - uint8_t* data, - OnFailureType failureType) { - sk_sp<SkBaseDevice> dev( - BitmapPlatformDevice::Create(width, height, is_opaque, data)); - return CreateCanvas(dev, failureType); -} - -} // namespace skia
diff --git a/skia/ext/bitmap_platform_device_cairo.h b/skia/ext/bitmap_platform_device_cairo.h deleted file mode 100644 index 5e6a6f3..0000000 --- a/skia/ext/bitmap_platform_device_cairo.h +++ /dev/null
@@ -1,104 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SKIA_EXT_BITMAP_PLATFORM_DEVICE_CAIRO_H_ -#define SKIA_EXT_BITMAP_PLATFORM_DEVICE_CAIRO_H_ - -#include <stdint.h> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "skia/ext/platform_device.h" - -typedef struct _cairo_surface cairo_surface_t; - -// ----------------------------------------------------------------------------- -// Image byte ordering on Linux: -// -// Pixels are packed into 32-bit words these days. Even for 24-bit images, -// often 8-bits will be left unused for alignment reasons. Thus, when you see -// ARGB as the byte order you have to wonder if that's in memory order or -// little-endian order. Here I'll write A.R.G.B to specifiy the memory order. -// -// GdkPixbuf's provide a nice backing store and defaults to R.G.B.A order. -// They'll do the needed byte swapping to match the X server when drawn. -// -// Skia can be controled in skia/include/corecg/SkUserConfig.h (see bits about -// SK_R32_SHIFT). For Linux we define it to be ARGB in registers. For little -// endian machines that means B.G.R.A in memory. -// -// The image loaders are controlled in -// webkit/port/platform/image-decoders/ImageDecoder.h (see setRGBA). These are -// also configured for ARGB in registers. -// -// Cairo's only 32-bit mode is ARGB in registers. -// -// X servers commonly have a 32-bit visual with xRGB in registers (since they -// typically don't do alpha blending of drawables at the user level. Composite -// extensions aside.) -// -// We don't use GdkPixbuf because its byte order differs from the rest. Most -// importantly, it differs from Cairo which, being a system library, is -// something that we can't easily change. -// ----------------------------------------------------------------------------- - -namespace skia { - -// ----------------------------------------------------------------------------- -// This is the Linux bitmap backing for Skia. We create a Cairo image surface -// to store the backing buffer. This buffer is BGRA in memory (on little-endian -// machines). -// -// For now we are also using Cairo to paint to the Drawables so we provide an -// accessor for getting the surface. -// -// This is all quite ok for test_shell. In the future we will want to use -// shared memory between the renderer and the main process at least. In this -// case we'll probably create the buffer from a precreated region of memory. -// ----------------------------------------------------------------------------- -class BitmapPlatformDevice : public SkBitmapDevice, public PlatformDevice { - public: - // Create a BitmapPlatformDeviceLinux from an already constructed bitmap; - // you should probably be using Create(). This may become private later if - // we ever have to share state between some native drawing UI and Skia, like - // the Windows and Mac versions of this class do. - // - // This object takes ownership of @cairo. - BitmapPlatformDevice(const SkBitmap& other, cairo_t* cairo); - ~BitmapPlatformDevice() override; - - // Constructs a device with size |width| * |height| with contents initialized - // to zero. |is_opaque| should be set if the caller knows the bitmap will be - // completely opaque and allows some optimizations. - static BitmapPlatformDevice* Create(int width, int height, bool is_opaque); - - // This doesn't take ownership of |data|. If |data| is NULL, the contents - // of the device are initialized to 0. - static BitmapPlatformDevice* Create(int width, int height, bool is_opaque, - uint8_t* data); - - protected: - SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override; - - private: - // Overridden from PlatformDevice: - cairo_t* BeginPlatformPaint(const SkMatrix& transform, - const SkIRect& clip_bounds) override; - - static BitmapPlatformDevice* Create(int width, int height, bool is_opaque, - cairo_surface_t* surface); - - // Loads the current transform and clip into the context. - void LoadConfig(const SkMatrix& transform, const SkIRect& clip_bounds); - - // Graphics context used to draw into the surface. - cairo_t* cairo_; - - DISALLOW_COPY_AND_ASSIGN(BitmapPlatformDevice); -}; - -} // namespace skia - -#endif // SKIA_EXT_BITMAP_PLATFORM_DEVICE_CAIRO_H_
diff --git a/skia/ext/bitmap_platform_device_mac.cc b/skia/ext/bitmap_platform_device_mac.cc deleted file mode 100644 index 67ad2a9..0000000 --- a/skia/ext/bitmap_platform_device_mac.cc +++ /dev/null
@@ -1,275 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "skia/ext/bitmap_platform_device_mac.h" - -#import <ApplicationServices/ApplicationServices.h> -#include <stddef.h> -#include <time.h> - -#include "base/mac/mac_util.h" -#include "base/memory/ref_counted.h" -#include "skia/ext/bitmap_platform_device.h" -#include "skia/ext/platform_canvas.h" -#include "skia/ext/skia_utils_mac.h" -#include "third_party/skia/include/core/SkMatrix.h" -#include "third_party/skia/include/core/SkPath.h" -#include "third_party/skia/include/core/SkRect.h" -#include "third_party/skia/include/core/SkTypes.h" - -namespace skia { - -namespace { - -// Returns true if it is unsafe to attempt to allocate an offscreen buffer -// given these dimensions. -bool RasterDeviceTooBigToAllocate(int width, int height) { - -#ifndef SKIA_EXT_RASTER_DEVICE_ALLOCATION_MAX -#define SKIA_EXT_RASTER_DEVICE_ALLOCATION_MAX (2 * 256 * 1024 * 1024) -#endif - - int bytesPerPixel = 4; - int64_t bytes = (int64_t)width * height * bytesPerPixel; - return bytes > SKIA_EXT_RASTER_DEVICE_ALLOCATION_MAX; -} - -static CGContextRef CGContextForData(void* data, int width, int height) { -#define HAS_ARGB_SHIFTS(a, r, g, b) \ - (SK_A32_SHIFT == (a) && SK_R32_SHIFT == (r) \ - && SK_G32_SHIFT == (g) && SK_B32_SHIFT == (b)) -#if defined(SK_CPU_LENDIAN) && HAS_ARGB_SHIFTS(24, 16, 8, 0) - // Allocate a bitmap context with 4 components per pixel (BGRA). Apple - // recommends these flags for improved CG performance. - - // CGBitmapContextCreate returns NULL if width/height are 0. However, our - // callers expect to get a canvas back (which they later resize/reallocate) - // so we pin the dimensions here. - width = SkMax32(1, width); - height = SkMax32(1, height); - CGContextRef context = - CGBitmapContextCreate(data, width, height, 8, width * 4, - base::mac::GetSystemColorSpace(), - kCGImageAlphaPremultipliedFirst | - kCGBitmapByteOrder32Host); -#else -#error We require that Skia's and CoreGraphics's recommended \ - image memory layout match. -#endif -#undef HAS_ARGB_SHIFTS - - if (!context) - return NULL; - - // Change the coordinate system to match WebCore's - CGContextTranslateCTM(context, 0, height); - CGContextScaleCTM(context, 1.0, -1.0); - - return context; -} - -} // namespace - -void BitmapPlatformDevice::ReleaseBitmapContext() { - SkASSERT(bitmap_context_); - CGContextRelease(bitmap_context_); - bitmap_context_ = NULL; -} - -// Loads the specified Skia transform into the device context -static void LoadTransformToCGContext(CGContextRef context, - const SkMatrix& matrix) { - // CoreGraphics can concatenate transforms, but not reset the current one. - // So in order to get the required behavior here, we need to first make - // the current transformation matrix identity and only then load the new one. - - // Reset matrix to identity. - CGAffineTransform orig_cg_matrix = CGContextGetCTM(context); - CGAffineTransform orig_cg_matrix_inv = - CGAffineTransformInvert(orig_cg_matrix); - CGContextConcatCTM(context, orig_cg_matrix_inv); - - // assert that we have indeed returned to the identity Matrix. - SkASSERT(CGAffineTransformIsIdentity(CGContextGetCTM(context))); - - // Convert xform to CG-land. - // Our coordinate system is flipped to match WebKit's so we need to modify - // the xform to match that. - SkMatrix transformed_matrix = matrix; - SkScalar sy = -matrix.getScaleY(); - transformed_matrix.setScaleY(sy); - size_t height = CGBitmapContextGetHeight(context); - SkScalar ty = -matrix.getTranslateY(); // y axis is flipped. - transformed_matrix.setTranslateY(ty + (SkScalar)height); - - CGAffineTransform cg_matrix = - skia::SkMatrixToCGAffineTransform(transformed_matrix); - - // Load final transform into context. - CGContextConcatCTM(context, cg_matrix); -} - -static void LoadClippingRegionToCGContext(CGContextRef context, - const SkIRect& clip_bounds, - const SkMatrix& transformation) { - // CoreGraphics applies the current transform to clip rects, which is - // unwanted. Inverse-transform the rect before sending it to CG. This only - // works for translations and scaling, but not for rotations (but the - // viewport is never rotated anyway). - SkMatrix t; - bool did_invert = transformation.invert(&t); - if (!did_invert) - t.reset(); - - SkRect rect = SkRect::Make(clip_bounds); - t.mapRect(&rect); - SkIRect irect; - rect.round(&irect); - CGContextClipToRect(context, skia::SkIRectToCGRect(irect)); -} - -void BitmapPlatformDevice::LoadConfig(const SkMatrix& transform, - const SkIRect& clip_bounds) { - if (!bitmap_context_) - return; // Nothing to do. - - // We must restore and then save the state of the graphics context since the - // calls to Load the clipping region to the context are strictly cummulative, - // i.e., you can't replace a clip rect, other than with a save/restore. - // But this implies that no other changes to the state are done elsewhere. - // If we ever get to need to change this, then we must replace the clip rect - // calls in LoadClippingRegionToCGContext() with an image mask instead. - CGContextRestoreGState(bitmap_context_); - CGContextSaveGState(bitmap_context_); - LoadTransformToCGContext(bitmap_context_, transform); - LoadClippingRegionToCGContext(bitmap_context_, clip_bounds, transform); -} - - -// We use this static factory function instead of the regular constructor so -// that we can create the pixel data before calling the constructor. This is -// required so that we can call the base class' constructor with the pixel -// data. -BitmapPlatformDevice* BitmapPlatformDevice::Create(CGContextRef context, - int width, - int height, - bool is_opaque, - bool do_clear) { - if (RasterDeviceTooBigToAllocate(width, height)) - return NULL; - - SkBitmap bitmap; - // TODO: verify that the CG Context's pixels will have tight rowbytes or pass in the correct - // rowbytes for the case when context != NULL. - bitmap.setInfo(SkImageInfo::MakeN32(width, height, is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType)); - - void* data; - if (context) { - data = CGBitmapContextGetData(context); - bitmap.setPixels(data); - } else { - if (!bitmap.tryAllocPixels()) - return NULL; - data = bitmap.getPixels(); - } - if (do_clear) - memset(data, 0, bitmap.getSafeSize()); - - // If we were given data, then don't clobber it! -#ifndef NDEBUG - if (!context && is_opaque) { - // To aid in finding bugs, we set the background color to something - // obviously wrong so it will be noticable when it is not cleared - bitmap.eraseARGB(255, 0, 255, 128); // bright bluish green - } -#endif - - if (!context) { - context = CGContextForData(data, width, height); - if (!context) - return NULL; - } else - CGContextRetain(context); - - BitmapPlatformDevice* rv = new BitmapPlatformDevice(context, bitmap); - - // The device object took ownership of the graphics context with its own - // CGContextRetain call. - CGContextRelease(context); - - return rv; -} - -BitmapPlatformDevice* BitmapPlatformDevice::CreateWithData(uint8_t* data, - int width, - int height, - bool is_opaque) { - CGContextRef context = NULL; - if (data) - context = CGContextForData(data, width, height); - - BitmapPlatformDevice* rv = Create(context, width, height, is_opaque, false); - - // The device object took ownership of the graphics context with its own - // CGContextRetain call. - if (context) - CGContextRelease(context); - - return rv; -} - -// The device will own the bitmap, which corresponds to also owning the pixel -// data. Therefore, we do not transfer ownership to the SkBitmapDevice's bitmap. -BitmapPlatformDevice::BitmapPlatformDevice( - CGContextRef context, const SkBitmap& bitmap) - : SkBitmapDevice(bitmap), - bitmap_context_(context) { - SetPlatformDevice(this, this); - SkASSERT(bitmap_context_); - // Initialize the clip region to the entire bitmap. - - SkIRect rect; - rect.set(0, 0, - CGBitmapContextGetWidth(bitmap_context_), - CGBitmapContextGetHeight(bitmap_context_)); - CGContextRetain(bitmap_context_); - // We must save the state once so that we can use the restore/save trick - // in LoadConfig(). - CGContextSaveGState(bitmap_context_); -} - -BitmapPlatformDevice::~BitmapPlatformDevice() { - if (bitmap_context_) - CGContextRelease(bitmap_context_); -} - -NativeDrawingContext BitmapPlatformDevice::BeginPlatformPaint( - const SkMatrix& transform, - const SkIRect& clip_bounds) { - LoadConfig(transform, clip_bounds); - return bitmap_context_; -} - -SkBaseDevice* BitmapPlatformDevice::onCreateDevice(const CreateInfo& cinfo, - const SkPaint*) { - const SkImageInfo& info = cinfo.fInfo; - const bool do_clear = !info.isOpaque(); - SkASSERT(info.colorType() == kN32_SkColorType); - return Create(NULL, info.width(), info.height(), info.isOpaque(), do_clear); -} - -// PlatformCanvas impl - -std::unique_ptr<SkCanvas> CreatePlatformCanvasWithPixels( - int width, - int height, - bool is_opaque, - uint8_t* data, - OnFailureType failureType) { - sk_sp<SkBaseDevice> dev( - BitmapPlatformDevice::CreateWithData(data, width, height, is_opaque)); - return CreateCanvas(dev, failureType); -} - -} // namespace skia
diff --git a/skia/ext/bitmap_platform_device_mac.h b/skia/ext/bitmap_platform_device_mac.h deleted file mode 100644 index 10dce7fe..0000000 --- a/skia/ext/bitmap_platform_device_mac.h +++ /dev/null
@@ -1,73 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SKIA_EXT_BITMAP_PLATFORM_DEVICE_MAC_H_ -#define SKIA_EXT_BITMAP_PLATFORM_DEVICE_MAC_H_ - -#include <stdint.h> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "skia/ext/platform_device.h" - -namespace skia { - -// A device is basically a wrapper around SkBitmap that provides a surface for -// SkCanvas to draw into. Our device provides a surface CoreGraphics can also -// write to. BitmapPlatformDevice creates a bitmap using -// CGCreateBitmapContext() in a format that Skia supports and can then use this -// to draw text into, etc. This pixel data is provided to the bitmap that the -// device contains so that it can be shared. -// -// The device owns the pixel data, when the device goes away, the pixel data -// also becomes invalid. THIS IS DIFFERENT THAN NORMAL SKIA which uses -// reference counting for the pixel data. In normal Skia, you could assign -// another bitmap to this device's bitmap and everything will work properly. -// For us, that other bitmap will become invalid as soon as the device becomes -// invalid, which may lead to subtle bugs. Therefore, DO NOT ASSIGN THE -// DEVICE'S PIXEL DATA TO ANOTHER BITMAP, make sure you copy instead. -class SK_API BitmapPlatformDevice : public SkBitmapDevice, public PlatformDevice { - public: - // Creates a BitmapPlatformDevice instance. |is_opaque| should be set if the - // caller knows the bitmap will be completely opaque and allows some - // optimizations. - // |context| may be NULL. If |context| is NULL, then the bitmap backing store - // is not initialized. - static BitmapPlatformDevice* Create(CGContextRef context, - int width, int height, - bool is_opaque, bool do_clear = false); - - // Creates a context for |data| and calls Create. - // If |data| is NULL, then the bitmap backing store is not initialized. - static BitmapPlatformDevice* CreateWithData(uint8_t* data, - int width, int height, - bool is_opaque); - - ~BitmapPlatformDevice() override; - - protected: - BitmapPlatformDevice(CGContextRef context, - const SkBitmap& bitmap); - - SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override; - - private: - NativeDrawingContext BeginPlatformPaint(const SkMatrix& transform, - const SkIRect& clip_bounds) override; - - void ReleaseBitmapContext(); - - // Loads the current transform and clip into the context. Can be called even - // when |bitmap_context_| is NULL (will be a NOP). - void LoadConfig(const SkMatrix& transform, const SkIRect& clip_bounds); - - // Lazily-created graphics context used to draw into the bitmap. - CGContextRef bitmap_context_; - - DISALLOW_COPY_AND_ASSIGN(BitmapPlatformDevice); -}; - -} // namespace skia - -#endif // SKIA_EXT_BITMAP_PLATFORM_DEVICE_MAC_H_
diff --git a/skia/ext/bitmap_platform_device_skia.cc b/skia/ext/bitmap_platform_device_skia.cc index a39e5d71..5904d6f2 100644 --- a/skia/ext/bitmap_platform_device_skia.cc +++ b/skia/ext/bitmap_platform_device_skia.cc
@@ -9,15 +9,7 @@ BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height, bool is_opaque) { - SkBitmap bitmap; - if (bitmap.tryAllocN32Pixels(width, height, is_opaque)) { - // Follow the logic in SkCanvas::createDevice(), initialize the bitmap if it - // is not opaque. - if (!is_opaque) - bitmap.eraseARGB(0, 0, 0, 0); - return new BitmapPlatformDevice(bitmap); - } - return NULL; + return Create(width, height, is_opaque, nullptr); } BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height, @@ -26,10 +18,17 @@ SkBitmap bitmap; bitmap.setInfo(SkImageInfo::MakeN32(width, height, is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType)); - if (data) + + if (data) { bitmap.setPixels(data); - else if (!bitmap.tryAllocPixels()) - return NULL; + } else { + if (!bitmap.tryAllocPixels()) + return nullptr; + // Follow the logic in SkCanvas::createDevice(), initialize the bitmap if + // it is not opaque. + if (!is_opaque) + bitmap.eraseARGB(0, 0, 0, 0); + } return new BitmapPlatformDevice(bitmap); } @@ -49,15 +48,6 @@ info.fInfo.isOpaque()); } -NativeDrawingContext BitmapPlatformDevice::BeginPlatformPaint( - const SkMatrix& transform, - const SkIRect& clip_bounds) { - // TODO(zhenghao): What should we return? The ptr to the address of the - // pixels? Maybe this won't be called at all. - SkPixmap pixmap; - return accessPixels(&pixmap) ? pixmap.writable_addr() : nullptr; -} - // PlatformCanvas impl std::unique_ptr<SkCanvas> CreatePlatformCanvasWithPixels(
diff --git a/skia/ext/bitmap_platform_device_skia.h b/skia/ext/bitmap_platform_device_skia.h index 024064f..42a3be1 100644 --- a/skia/ext/bitmap_platform_device_skia.h +++ b/skia/ext/bitmap_platform_device_skia.h
@@ -21,15 +21,21 @@ // shared memory between the renderer and the main process at least. In this // case we'll probably create the buffer from a precreated region of memory. // ----------------------------------------------------------------------------- -class BitmapPlatformDevice : public SkBitmapDevice, public PlatformDevice { +class BitmapPlatformDevice final : public SkBitmapDevice, + public PlatformDevice { public: // Construct a BitmapPlatformDevice. |is_opaque| should be set if the caller - // knows the bitmap will be completely opaque and allows some optimizations. - // The bitmap is not initialized. + // knows the bitmap will be completely opaque and allows some optimizations + // (the bitmap is not initialized to 0 when is_opaque == true). static BitmapPlatformDevice* Create(int width, int height, bool is_opaque); - // This doesn't take ownership of |data|. If |data| is null, the bitmap - // is not initialized to 0. + // This doesn't take ownership of |data|. If |data| is null and |is_opaque| + // is false, the bitmap is initialized to 0. + // + // Note: historicaly, BitmapPlatformDevice impls have had diverging + // initialization behavior for null |data| (Cairo used to initialize, while + // the others did not). For now we stick to the more conservative Cairo + // behavior. static BitmapPlatformDevice* Create(int width, int height, bool is_opaque, uint8_t* data); @@ -44,9 +50,6 @@ SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override; private: - NativeDrawingContext BeginPlatformPaint(const SkMatrix& transform, - const SkIRect& clip_bounds) override; - DISALLOW_COPY_AND_ASSIGN(BitmapPlatformDevice); };
diff --git a/skia/ext/bitmap_platform_device_win.cc b/skia/ext/bitmap_platform_device_win.cc index d537ca06..34b7e2f 100644 --- a/skia/ext/bitmap_platform_device_win.cc +++ b/skia/ext/bitmap_platform_device_win.cc
@@ -33,21 +33,6 @@ namespace skia { -void DrawToNativeContext(SkCanvas* canvas, HDC destination_hdc, int x, int y, - const RECT* src_rect) { - RECT temp_rect; - if (!src_rect) { - temp_rect.left = 0; - temp_rect.right = canvas->imageInfo().width(); - temp_rect.top = 0; - temp_rect.bottom = canvas->imageInfo().height(); - src_rect = &temp_rect; - } - skia::CopyHDC(skia::GetNativeDrawingContext(canvas), destination_hdc, x, y, - canvas->imageInfo().isOpaque(), *src_rect, - canvas->getTotalMatrix()); -} - HDC GetNativeDrawingContext(SkCanvas* canvas) { PlatformDevice* platform_device = GetPlatformDevice(canvas->getTopDevice(true)); if (!platform_device)
diff --git a/skia/ext/bitmap_platform_device_win.h b/skia/ext/bitmap_platform_device_win.h index 82f17ff3..6f359e2 100644 --- a/skia/ext/bitmap_platform_device_win.h +++ b/skia/ext/bitmap_platform_device_win.h
@@ -17,8 +17,8 @@ // format that Skia supports and can then use this to draw ClearType into, etc. // This pixel data is provided to the bitmap that the device contains so that it // can be shared. -class SK_API BitmapPlatformDevice : public SkBitmapDevice, - public PlatformDevice { +class SK_API BitmapPlatformDevice final : public SkBitmapDevice, + public PlatformDevice { public: // Factory function. is_opaque should be set if the caller knows the bitmap // will be completely opaque and allows some optimizations.
diff --git a/skia/ext/platform_canvas.h b/skia/ext/platform_canvas.h index 1436ec1..dea8ae82 100644 --- a/skia/ext/platform_canvas.h +++ b/skia/ext/platform_canvas.h
@@ -52,16 +52,6 @@ HANDLE shared_section, OnFailureType failure_type); -// Draws the top layer of the canvas into the specified HDC. Only works -// with a SkCanvas with a BitmapPlatformDevice. Will create a temporary -// HDC to back the canvas if one doesn't already exist, tearing it down -// before returning. If |src_rect| is null, copies the entire canvas. -SK_API void DrawToNativeContext(SkCanvas* canvas, - HDC hdc, - int x, - int y, - const RECT* src_rect); - // Returns the NativeDrawingContext to use for native platform drawing calls. SK_API HDC GetNativeDrawingContext(SkCanvas* canvas);
diff --git a/skia/ext/platform_device.h b/skia/ext/platform_device.h index b756aa6..f349a49 100644 --- a/skia/ext/platform_device.h +++ b/skia/ext/platform_device.h
@@ -46,11 +46,14 @@ public: virtual ~PlatformDevice(); +// Only implemented in bitmap_platform_device_win. +#if defined(WIN32) // The DC that corresponds to the bitmap, used for GDI operations drawing // into the bitmap. This is possibly heavyweight, so it should be existant // only during one pass of rendering. virtual NativeDrawingContext BeginPlatformPaint(const SkMatrix& transform, const SkIRect& clip_bounds) = 0; +#endif }; } // namespace skia
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 19709af..d32b89e2d 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -214,6 +214,7 @@ { "name": "Default", "params": { + "RedirectHistoryService": "true", "RedirectSequencedWorkerPools": "true" } },
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-convertToBlob-noIdleTask-worker.html b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-convertToBlob-noIdleTask-worker.html new file mode 100644 index 0000000..e03af52 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-convertToBlob-noIdleTask-worker.html
@@ -0,0 +1,58 @@ +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script id="myWorker" type="text/worker"> +self.onmessage = function(e) { + var offscreenCanvas = new OffscreenCanvas(4, 4); + var ctx = offscreenCanvas.getContext("2d"); + ctx.fillStyle = "#FF0102"; + ctx.fillRect(0, 0, 4, 4); + + offscreenCanvas.convertToBlob().then(function(blob) { + self.postMessage(blob); + }); + +}; +</script> +<script type = 'text/javascript'> +// In blink Layout Tests, flag "--enable-threaded-compositing", which is +// essential for idle task running, is not turned on by default. This makes +// it convenient to test the case when CanvasAsyncBlobCreator is idling for +// too long and switching to forcing encoding in a normal task. +// Passing this test means that the enforcing mechanism in +// CanvasAsyncBlobCreator for OffscreenCanvas case is working as expected. +var w = 4; +var h = 4; + +var newImg = new Image(); +function imageLoaded() { + var canvas2 = document.createElement("canvas"); + canvas2.width = w; + canvas2.height = h; + var ctx2 = canvas2.getContext("2d"); + ctx2.drawImage(newImg, 0, 0, w, h); + + var imageData = ctx2.getImageData(0, 0, w, h).data; + assert_equals(imageData[0], 255); + assert_equals(imageData[1], 1); + assert_equals(imageData[2], 2); + assert_equals(imageData[3], 255); + testImageFromOffscreen.done(); +} + +var workerBlob = new Blob([document.getElementById('myWorker').textContent]); +var worker = new Worker(URL.createObjectURL(workerBlob)); +worker.addEventListener("message", function(msg) { + var blob = msg.data; + newImg.src = URL.createObjectURL(blob); +}); + +var testImageFromOffscreen = async_test( + "Check if the image loaded from blob returned by " + + "OffscreenCanvas.convertToBlob() have expected image data values."); + +testImageFromOffscreen.step(function() { + newImg.onload = testImageFromOffscreen.step_func(imageLoaded); + worker.postMessage(""); +}); + +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-convertToBlob-noIdleTask.html b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-convertToBlob-noIdleTask.html new file mode 100644 index 0000000..ce48f18 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-convertToBlob-noIdleTask.html
@@ -0,0 +1,46 @@ +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script type = 'text/javascript'> +// In blink Layout Tests, flag "--enable-threaded-compositing", which is +// essential for idle task running, is not turned on by default. This makes +// it convenient to test the case when CanvasAsyncBlobCreator is idling for +// too long and switching to forcing encoding in a normal task. +// Passing this test means that the enforcing mechanism in +// CanvasAsyncBlobCreator for OffscreenCanvas case is working as expected. +var w = 4; +var h = 4; + +var newImg = new Image(); +function imageLoaded() { + var canvas2 = document.createElement("canvas"); + canvas2.width = w; + canvas2.height = h; + var ctx2 = canvas2.getContext("2d"); + ctx2.drawImage(newImg, 0, 0, w, h); + + var imageData = ctx2.getImageData(0, 0, w, h).data; + assert_equals(imageData[0], 255); + assert_equals(imageData[1], 1); + assert_equals(imageData[2], 2); + assert_equals(imageData[3], 255); + testImageFromOffscreen.done(); +} + +var testImageFromOffscreen = async_test( + "Check if the image loaded from blob returned by " + + "OffscreenCanvas.convertToBlob() have expected image data values."); + +testImageFromOffscreen.step(function() { + newImg.onload = testImageFromOffscreen.step_func(imageLoaded); + + var offscreenCanvas = new OffscreenCanvas(w, h); + var ctx = offscreenCanvas.getContext("2d"); + ctx.fillStyle = "#FF0102"; + ctx.fillRect(0, 0, w, h); + + offscreenCanvas.convertToBlob().then(function(blob) { + newImg.src = URL.createObjectURL(blob); + }); +}); + +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/move-shadow-host-to-child-iframe-crash.html b/third_party/WebKit/LayoutTests/fast/dom/shadow/move-shadow-host-to-child-iframe-crash.html new file mode 100644 index 0000000..7cdc19df --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/move-shadow-host-to-child-iframe-crash.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<div id="host"> + <iframe id="iframe"></iframe> +</div> +<script> + test(() => { + host.attachShadow({mode:"open"}).innerHTML = "<style></style>"; + iframe.contentDocument.documentElement.appendChild(host); + }, "Inserting a shadow host with an iframe child into that iframes document should not crash or assert."); +</script>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/float-under-composited-inline-expected.html b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/float-under-composited-inline-expected.html new file mode 100644 index 0000000..03f5276 --- /dev/null +++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/float-under-composited-inline-expected.html
@@ -0,0 +1,3 @@ +<!DOCTYPE html> +<div style="width: 100px; height: 100px; background-color: green"></div> +
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/float-under-composited-inline-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/float-under-composited-inline-expected.txt new file mode 100644 index 0000000..00574e1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/float-under-composited-inline-expected.txt
@@ -0,0 +1,29 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutBlockFlow (floating) DIV id='float'", + "rect": [8, 8, 100, 100], + "reason": "style change" + } + ] + }, + { + "name": "LayoutInline (relative positioned) SPAN", + "position": [108, 108], + "drawsContent": true + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutBlockFlow (floating) DIV id='float'", + "reason": "style change" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/float-under-composited-inline.html b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/float-under-composited-inline.html new file mode 100644 index 0000000..2cee1533 --- /dev/null +++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/float-under-composited-inline.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +<span style="position: relative; top: 100px; left: 100px; will-change: transform"> + <div id="float" style="float: left; width: 100px; height: 100px; background-color: red"></div> +</span> +<script src="../resources/text-based-repaint.js"></script> +<script> +function repaintTest() { + float.style.backgroundColor = 'green'; +} +onload = runRepaintAndPixelTest; +</script> +
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/newly-composited-repaint-rect.html b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/newly-composited-repaint-rect.html index 29dcf6deec..51598ba 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/newly-composited-repaint-rect.html +++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/newly-composited-repaint-rect.html
@@ -60,7 +60,7 @@ function repaintTest() { runAfterLayoutAndPaint(function() { - // Changing the position will cause the scrolldiv to become composited becuase it overlaps another compostied element. + // Changing the position will cause the scrolldiv to become composited because it overlaps another compostied element. changeDivPosition(); // Force DumpRenderTree to do a layout and repaint here, this is where the repaintRect
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/invalidation-after-opacity-change-subtree.html b/third_party/WebKit/LayoutTests/paint/invalidation/invalidation-after-opacity-change-subtree.html index cb19e441..8adf8bbf 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/invalidation-after-opacity-change-subtree.html +++ b/third_party/WebKit/LayoutTests/paint/invalidation/invalidation-after-opacity-change-subtree.html
@@ -8,7 +8,7 @@ #absolute { position: absolute; top: 2000px; - font: 50px/1 Sherif; + font: 50px/1 Sheriff; } </style> <div id="container">
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/opacity-change-on-overflow-float-expected.html b/third_party/WebKit/LayoutTests/paint/invalidation/opacity-change-on-overflow-float-expected.html index abcd81ec..da9e2ce 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/opacity-change-on-overflow-float-expected.html +++ b/third_party/WebKit/LayoutTests/paint/invalidation/opacity-change-on-overflow-float-expected.html
@@ -15,7 +15,7 @@ </head> <body> <p>Repaint test for <rdar><!-- -An explaination as to why this is here. In the beginning, there was an +An explanation as to why this is here. In the beginning, there was an <rdar:://problem/6869687> link to rdar. However, that link was invisible because it was enclosed in angle brackets.
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/opacity-change-on-overflow-float.html b/third_party/WebKit/LayoutTests/paint/invalidation/opacity-change-on-overflow-float.html index 540942ab..8eceebaa 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/opacity-change-on-overflow-float.html +++ b/third_party/WebKit/LayoutTests/paint/invalidation/opacity-change-on-overflow-float.html
@@ -28,7 +28,7 @@ </head> <body onload="runRepaintAndPixelTest()"> <p>Repaint test for <rdar><!-- -An explaination as to why this is here. In the beginning, there was an +An explanation as to why this is here. In the beginning, there was an <rdar:://problem/6869687> link to rdar. However, that link was invisible because it was enclosed in angle brackets.
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/text-selection-text-05-t.svg b/third_party/WebKit/LayoutTests/paint/invalidation/svg/text-selection-text-05-t.svg index 4d377036..e9c3b7e 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/svg/text-selection-text-05-t.svg +++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/text-selection-text-05-t.svg
@@ -35,8 +35,8 @@ <!--======================================================================--> <g id="test-body-content" font-size="16"> <defs> - <font id="embeded" horiz-adv-x="224"> -<font-face font-family="embeded" units-per-em="1000" panose-1="0 0 0 0 0 0 0 0 0 0" ascent="917" descent="-250" alphabetic="0"/> + <font id="embedded" horiz-adv-x="224"> +<font-face font-family="embedded" units-per-em="1000" panose-1="0 0 0 0 0 0 0 0 0 0" ascent="917" descent="-250" alphabetic="0"/> <missing-glyph horiz-adv-x="800" d="M50 0V800H750V0H50ZM700 50V750H100V50H700Z"/> <glyph unicode="1" glyph-name="gl_1" horiz-adv-x="1500" d="M 0 0 L 250 0 L 250 250 L 0 250 Z"/> <glyph unicode="2" glyph-name="gl_2" horiz-adv-x="1500" d="M 0 0 L 500 0 L 500 500 L 0 500 Z"/> @@ -73,19 +73,19 @@ <g id="textContent"> <!-- 1.x 1.y --> <use y="30" xlink:href="#marker" fill="#8888ff"/> - <text x="0" y="30" font-family="embeded" font-size="10">1234</text> + <text x="0" y="30" font-family="embedded" font-size="10">1234</text> <!-- 4.x 1.y : four text chunks --> <use x="10" y="60" xlink:href="#marker" fill="#8888ff"/> <use x="20" y="60" xlink:href="#marker" fill="#8888ff"/> <use x="30" y="60" xlink:href="#marker" fill="#8888ff"/> <use x="40" y="60" xlink:href="#marker" fill="#8888ff"/> - <text x="10 20 30 40" y="60" font-family="embeded" font-size="10">1234</text> + <text x="10 20 30 40" y="60" font-family="embedded" font-size="10">1234</text> <!-- 2.x 1.y : two text chunks --> <use x="10" y="90" xlink:href="#marker" fill="#8888ff"/> <use x="60" y="90" xlink:href="#marker" fill="#8888ff"/> - <text x="10 60" y="90" font-family="embeded" font-size="10">1234</text> + <text x="10 60" y="90" font-family="embedded" font-size="10">1234</text> <!-- 1.x 4.y : four text chunks --> <g transform="translate(0, 120)"> @@ -93,7 +93,7 @@ <use x="15" y="-5" xlink:href="#marker" fill="#8888ff"/> <use x="30" y="5" xlink:href="#marker" fill="#8888ff"/> <use x="45" y="10" xlink:href="#marker" fill="#8888ff"/> - <text x="0" y="-10 -5 5 10" font-family="embeded" font-size="10">1234</text> + <text x="0" y="-10 -5 5 10" font-family="embedded" font-size="10">1234</text> </g> <!-- 4.x 4.y : four text chunks --> @@ -102,7 +102,7 @@ <use x="20" y="-5" xlink:href="#marker" fill="#8888ff"/> <use x="30" y="5" xlink:href="#marker" fill="#8888ff"/> <use x="40" y="10" xlink:href="#marker" fill="#8888ff"/> - <text x="10 20 30 40" y="-10 -5 5 10" font-family="embeded" font-size="10">1234</text> + <text x="10 20 30 40" y="-10 -5 5 10" font-family="embedded" font-size="10">1234</text> </g> <!-- 2.x 4.y : four text chunks --> @@ -111,14 +111,14 @@ <use x="20" y="-5" xlink:href="#marker" fill="#8888ff"/> <use x="35" y="5" xlink:href="#marker" fill="#8888ff"/> <use x="50" y="10" xlink:href="#marker" fill="#8888ff"/> - <text x="10 20" y="-10 -5 5 10" font-family="embeded" font-size="10">1234</text> + <text x="10 20" y="-10 -5 5 10" font-family="embedded" font-size="10">1234</text> </g> <!-- 1.x 2.y : two text chunks --> <g transform="translate(0, 210)"> <use x="0" y="-10" xlink:href="#marker" fill="#8888ff"/> <use x="15" y="5" xlink:href="#marker" fill="#8888ff"/> - <text x="0" y="-10 5" font-family="embeded" font-size="10">1234</text> + <text x="0" y="-10 5" font-family="embedded" font-size="10">1234</text> </g> <!-- 4.x 2.y : four text chunks --> @@ -127,14 +127,14 @@ <use x="20" y="-5" xlink:href="#marker" fill="#8888ff"/> <use x="30" y="-5" xlink:href="#marker" fill="#8888ff"/> <use x="40" y="-5" xlink:href="#marker" fill="#8888ff"/> - <text x="10 20 30 40" y="-10 -5" font-family="embeded" font-size="10">1234</text> + <text x="10 20 30 40" y="-10 -5" font-family="embedded" font-size="10">1234</text> </g> <!-- 2.x 2.y : two text chunks --> <g transform="translate(0, 270)"> <use x="10" y="-10" xlink:href="#marker" fill="#8888ff"/> <use x="60" y="-5" xlink:href="#marker" fill="#8888ff"/> - <text x="10 60" y="-10 -5" font-family="embeded" font-size="10">1234</text> + <text x="10 60" y="-10 -5" font-family="embedded" font-size="10">1234</text> </g> </g>
diff --git a/third_party/WebKit/Source/core/dom/StyleEngine.cpp b/third_party/WebKit/Source/core/dom/StyleEngine.cpp index 6726705f..57e5ed0 100644 --- a/third_party/WebKit/Source/core/dom/StyleEngine.cpp +++ b/third_party/WebKit/Source/core/dom/StyleEngine.cpp
@@ -169,7 +169,7 @@ void StyleEngine::removePendingSheet(Node& styleSheetCandidateNode, const StyleEngineContext& context) { if (styleSheetCandidateNode.isConnected()) - markTreeScopeDirty(styleSheetCandidateNode.treeScope()); + setNeedsActiveStyleUpdate(styleSheetCandidateNode.treeScope()); if (context.addedPendingSheetBeforeBody()) { DCHECK_GT(m_pendingRenderBlockingStylesheets, 0); @@ -203,7 +203,7 @@ DCHECK(collection); collection->addStyleSheetCandidateNode(node); - markTreeScopeDirty(treeScope); + setNeedsActiveStyleUpdate(treeScope); if (treeScope != m_document) m_activeTreeScopes.add(&treeScope); } @@ -227,12 +227,12 @@ return; collection->removeStyleSheetCandidateNode(node); - markTreeScopeDirty(treeScope); + setNeedsActiveStyleUpdate(treeScope); } void StyleEngine::modifiedStyleSheetCandidateNode(Node& node) { if (node.isConnected()) - markTreeScopeDirty(node.treeScope()); + setNeedsActiveStyleUpdate(node.treeScope()); } void StyleEngine::mediaQueriesChangedInScope(TreeScope& treeScope) {
diff --git a/third_party/WebKit/Source/core/frame/BrowserControls.h b/third_party/WebKit/Source/core/frame/BrowserControls.h index 10c1f86a..cbabd91 100644 --- a/third_party/WebKit/Source/core/frame/BrowserControls.h +++ b/third_party/WebKit/Source/core/frame/BrowserControls.h
@@ -49,6 +49,8 @@ // scroll amount. FloatSize scrollBy(FloatSize scrollDelta); + WebBrowserControlsState permittedState() const { return m_permittedState; } + private: explicit BrowserControls(const FrameHost&); void resetBaseline();
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp index 9435eef..d1c191d 100644 --- a/third_party/WebKit/Source/core/frame/FrameView.cpp +++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -1378,9 +1378,9 @@ // height, compensating for page scale as well, since we want to use the // viewport with browser controls hidden for vh (to match Safari). BrowserControls& browserControls = m_frame->host()->browserControls(); - if (m_frame->isMainFrame() && size.width()) { - float pageScaleAtLayoutWidth = - m_frame->host()->visualViewport().size().width() / size.width(); + int viewportWidth = m_frame->host()->visualViewport().size().width(); + if (m_frame->isMainFrame() && size.width() && viewportWidth) { + float pageScaleAtLayoutWidth = viewportWidth / size.width(); size.expand(0, browserControls.height() / pageScaleAtLayoutWidth); }
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.cpp b/third_party/WebKit/Source/core/frame/LocalFrame.cpp index 7f72739..9e40e7b1 100644 --- a/third_party/WebKit/Source/core/frame/LocalFrame.cpp +++ b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
@@ -94,6 +94,7 @@ #include "public/platform/WebScreenInfo.h" #include "public/platform/WebViewScheduler.h" #include "third_party/skia/include/core/SkImage.h" +#include "third_party/skia/include/core/SkSurface.h" #include "wtf/PtrUtil.h" #include "wtf/StdLibExtras.h" #include <memory> @@ -143,10 +144,15 @@ // TODO(fmalita): endRecording() should return a non-const SKP. sk_sp<SkPicture> recording( const_cast<SkPicture*>(m_pictureBuilder->endRecording().release())); - sk_sp<SkImage> skImage = SkImage::MakeFromPicture( - std::move(recording), - SkISize::Make(m_bounds.width(), m_bounds.height()), nullptr, nullptr); - RefPtr<Image> image = StaticBitmapImage::create(std::move(skImage)); + + // Rasterize upfront, since DragImage::create() is going to do it anyway + // (SkImage::asLegacyBitmap). + sk_sp<SkSurface> surface = + SkSurface::MakeRasterN32Premul(m_bounds.width(), m_bounds.height()); + surface->getCanvas()->drawPicture(recording); + RefPtr<Image> image = + StaticBitmapImage::create(surface->makeImageSnapshot()); + float screenDeviceScaleFactor = m_localFrame->page()->chromeClient().screenInfo().deviceScaleFactor;
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp index 562b718..6d1eff20 100644 --- a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp +++ b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp
@@ -275,17 +275,13 @@ NOTREACHED(); } - // TODO: Enforce OffscreenCanvas.convertToBlob to finish within deadline. - // See crbug.com/657102. - if (m_functionType == HTMLCanvasToBlobCallback) { - // We post the below task to check if the above idle task isn't late. - // There's no risk of concurrency as both tasks are on main thread. - this->postDelayedTaskToMainThread( - BLINK_FROM_HERE, - WTF::bind(&CanvasAsyncBlobCreator::idleTaskStartTimeoutEvent, - wrapPersistent(this), quality), - IdleTaskStartTimeoutDelay); - } + // We post the below task to check if the above idle task isn't late. + // There's no risk of concurrency as both tasks are on the same thread. + this->postDelayedTaskToCurrentThread( + BLINK_FROM_HERE, + WTF::bind(&CanvasAsyncBlobCreator::idleTaskStartTimeoutEvent, + wrapPersistent(this), quality), + IdleTaskStartTimeoutDelay); } } @@ -412,7 +408,7 @@ } } -void CanvasAsyncBlobCreator::encodeRowsPngOnMainThread() { +void CanvasAsyncBlobCreator::forceEncodeRowsPngOnCurrentThread() { DCHECK(m_idleTaskStatus == IdleTaskSwitchedToImmediateTask); // Continue encoding from the last completed row @@ -423,20 +419,39 @@ inputPixels += m_pixelRowStride; } PNGImageEncoder::finalizePng(m_pngEncoderState.get()); - this->createBlobAndReturnResult(); + + if (isMainThread()) { + this->createBlobAndReturnResult(); + } else { + TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) + ->postTask( + BLINK_FROM_HERE, + crossThreadBind(&CanvasAsyncBlobCreator::createBlobAndReturnResult, + wrapCrossThreadPersistent(this))); + } this->signalAlternativeCodePathFinishedForTesting(); } -void CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread() { +void CanvasAsyncBlobCreator::forceEncodeRowsJpegOnCurrentThread() { DCHECK(m_idleTaskStatus == IdleTaskSwitchedToImmediateTask); // Continue encoding from the last completed row + void (CanvasAsyncBlobCreator::*functionToBeCalled)(void); if (JPEGImageEncoder::encodeWithPreInitializedState( std::move(m_jpegEncoderState), m_data->data(), m_numRowsCompleted)) { - this->createBlobAndReturnResult(); + functionToBeCalled = &CanvasAsyncBlobCreator::createBlobAndReturnResult; } else { - this->createNullAndReturnResult(); + functionToBeCalled = &CanvasAsyncBlobCreator::createNullAndReturnResult; + } + + if (isMainThread()) { + (this->*functionToBeCalled)(); + } else { + TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) + ->postTask(BLINK_FROM_HERE, + crossThreadBind(functionToBeCalled, + wrapCrossThreadPersistent(this))); } this->signalAlternativeCodePathFinishedForTesting(); @@ -523,7 +538,7 @@ void CanvasAsyncBlobCreator::idleTaskStartTimeoutEvent(double quality) { if (m_idleTaskStatus == IdleTaskStarted) { // Even if the task started quickly, we still want to ensure completion - this->postDelayedTaskToMainThread( + this->postDelayedTaskToCurrentThread( BLINK_FROM_HERE, WTF::bind(&CanvasAsyncBlobCreator::idleTaskCompleteTimeoutEvent, wrapPersistent(this)), @@ -540,8 +555,9 @@ TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) ->postTask( BLINK_FROM_HERE, - WTF::bind(&CanvasAsyncBlobCreator::encodeRowsPngOnMainThread, - wrapPersistent(this))); + WTF::bind( + &CanvasAsyncBlobCreator::forceEncodeRowsPngOnCurrentThread, + wrapPersistent(this))); } else { // Failing in initialization of png struct this->signalAlternativeCodePathFinishedForTesting(); @@ -552,8 +568,9 @@ TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) ->postTask( BLINK_FROM_HERE, - WTF::bind(&CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread, - wrapPersistent(this))); + WTF::bind( + &CanvasAsyncBlobCreator::forceEncodeRowsJpegOnCurrentThread, + wrapPersistent(this))); } else { // Failing in initialization of jpeg struct this->signalAlternativeCodePathFinishedForTesting(); @@ -578,15 +595,17 @@ TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) ->postTask( BLINK_FROM_HERE, - WTF::bind(&CanvasAsyncBlobCreator::encodeRowsPngOnMainThread, - wrapPersistent(this))); + WTF::bind( + &CanvasAsyncBlobCreator::forceEncodeRowsPngOnCurrentThread, + wrapPersistent(this))); } else { DCHECK(m_mimeType == MimeTypeJpeg); TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) ->postTask( BLINK_FROM_HERE, - WTF::bind(&CanvasAsyncBlobCreator::encodeRowsJpegOnMainThread, - wrapPersistent(this))); + WTF::bind( + &CanvasAsyncBlobCreator::forceEncodeRowsJpegOnCurrentThread, + wrapPersistent(this))); } } else { DCHECK(m_idleTaskStatus == IdleTaskFailed || @@ -595,11 +614,10 @@ } } -void CanvasAsyncBlobCreator::postDelayedTaskToMainThread( +void CanvasAsyncBlobCreator::postDelayedTaskToCurrentThread( const WebTraceLocation& location, std::unique_ptr<WTF::Closure> task, double delayMs) { - DCHECK(isMainThread()); TaskRunnerHelper::get(TaskType::CanvasBlobSerialization, m_document) ->postDelayedTask(location, std::move(task), delayMs); }
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h index ca2fff6..ae4caa2 100644 --- a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h +++ b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h
@@ -83,9 +83,9 @@ virtual void scheduleInitiateJpegEncoding(const double&); virtual void idleEncodeRowsPng(double deadlineSeconds); virtual void idleEncodeRowsJpeg(double deadlineSeconds); - virtual void postDelayedTaskToMainThread(const WebTraceLocation&, - std::unique_ptr<WTF::Closure>, - double delayMs); + virtual void postDelayedTaskToCurrentThread(const WebTraceLocation&, + std::unique_ptr<WTF::Closure>, + double delayMs); virtual void signalAlternativeCodePathFinishedForTesting() {} virtual void createBlobAndReturnResult(); virtual void createNullAndReturnResult(); @@ -126,13 +126,14 @@ // PNG bool initializePngStruct(); - void - encodeRowsPngOnMainThread(); // Similar to idleEncodeRowsPng without deadline + void forceEncodeRowsPngOnCurrentThread(); // Similar to idleEncodeRowsPng + // without deadline // JPEG bool initializeJpegStruct(double quality); - void encodeRowsJpegOnMainThread(); // Similar to idleEncodeRowsJpeg without - // deadline + void forceEncodeRowsJpegOnCurrentThread(); // Similar to idleEncodeRowsJpeg + // without + // deadline // WEBP void encodeImageOnEncoderThread(double quality);
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreatorTest.cpp b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreatorTest.cpp index f803460..6a771c1 100644 --- a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreatorTest.cpp +++ b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreatorTest.cpp
@@ -41,16 +41,16 @@ void createBlobAndReturnResult() override{}; void createNullAndReturnResult() override{}; void signalAlternativeCodePathFinishedForTesting() override; - void postDelayedTaskToMainThread(const WebTraceLocation&, - std::unique_ptr<WTF::Closure>, - double delayMs) override; + void postDelayedTaskToCurrentThread(const WebTraceLocation&, + std::unique_ptr<WTF::Closure>, + double delayMs) override; }; void MockCanvasAsyncBlobCreator::signalAlternativeCodePathFinishedForTesting() { testing::exitRunLoop(); } -void MockCanvasAsyncBlobCreator::postDelayedTaskToMainThread( +void MockCanvasAsyncBlobCreator::postDelayedTaskToCurrentThread( const WebTraceLocation& location, std::unique_ptr<WTF::Closure> task, double delayMs) {
diff --git a/third_party/WebKit/Source/core/layout/LayoutGeometryMap.cpp b/third_party/WebKit/Source/core/layout/LayoutGeometryMap.cpp index a088fbd..ee0f643b 100644 --- a/third_party/WebKit/Source/core/layout/LayoutGeometryMap.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutGeometryMap.cpp
@@ -204,6 +204,10 @@ if (current == ancestor) break; + + if (current->isFloating() && current->parent() && + !current->parent()->isLayoutBlock()) + return false; } return true;
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.cpp b/third_party/WebKit/Source/core/layout/LayoutObject.cpp index 96512719..d2a508f42 100644 --- a/third_party/WebKit/Source/core/layout/LayoutObject.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
@@ -613,7 +613,11 @@ PaintLayer* LayoutObject::paintingLayer() const { for (const LayoutObject* current = this; current; - current = current->paintInvalidationParent()) { + // Use containingBlock instead of paintInvalidationParent for floating + // object to omit any self-painting layers of inline objects that don't + // paint the floating object. + current = current->isFloating() ? current->containingBlock() + : current->paintInvalidationParent()) { if (current->hasLayer() && toLayoutBoxModelObject(current)->layer()->isSelfPaintingLayer()) return toLayoutBoxModelObject(current)->layer(); @@ -893,53 +897,69 @@ return toLayoutBlock(object); } -LayoutBlock* LayoutObject::containingBlockForAbsolutePosition() const { - LayoutObject* o = containerForAbsolutePosition(); +LayoutBlock* LayoutObject::containingBlockForAbsolutePosition( + const LayoutBoxModelObject* ancestor, + bool* ancestorSkipped, + bool* filterSkipped) const { + LayoutObject* object = + containerForAbsolutePosition(ancestor, ancestorSkipped, filterSkipped); // For relpositioned inlines, we return the nearest non-anonymous enclosing // block. We don't try to return the inline itself. This allows us to avoid // having a positioned objects list in all LayoutInlines and lets us return a // strongly-typed LayoutBlock* result from this method. The container() method // can actually be used to obtain the inline directly. - if (o && o->isInline() && !o->isAtomicInlineLevel()) { - ASSERT(o->style()->hasInFlowPosition()); - o = o->containingBlock(); + if (object && object->isInline() && !object->isAtomicInlineLevel()) { + DCHECK(object->style()->hasInFlowPosition()); + object = object->containingBlock(ancestor, ancestorSkipped, filterSkipped); } - if (o && !o->isLayoutBlock()) - o = o->containingBlock(); + if (object && !object->isLayoutBlock()) + object = object->containingBlock(ancestor, ancestorSkipped, filterSkipped); - while (o && o->isAnonymousBlock()) - o = o->containingBlock(); + while (object && object->isAnonymousBlock()) + object = object->containingBlock(ancestor, ancestorSkipped, filterSkipped); - if (!o || !o->isLayoutBlock()) + if (!object || !object->isLayoutBlock()) return nullptr; // This can still happen in case of an orphaned tree - return toLayoutBlock(o); + return toLayoutBlock(object); } -LayoutBlock* LayoutObject::containingBlock() const { - LayoutObject* o = parent(); - if (!o && isLayoutScrollbarPart()) - o = toLayoutScrollbarPart(this)->layoutObjectOwningScrollbar(); +LayoutBlock* LayoutObject::containingBlock(const LayoutBoxModelObject* ancestor, + bool* ancestorSkipped, + bool* filterSkipped) const { + LayoutObject* object = parent(); + if (!object && isLayoutScrollbarPart()) + object = toLayoutScrollbarPart(this)->layoutObjectOwningScrollbar(); if (!isTextOrSVGChild()) { - if (m_style->position() == FixedPosition) - return containerForFixedPosition(); - if (m_style->position() == AbsolutePosition) - return containingBlockForAbsolutePosition(); + if (m_style->position() == FixedPosition) { + return containerForFixedPosition(ancestor, ancestorSkipped, + filterSkipped); + } + if (m_style->position() == AbsolutePosition) { + return containingBlockForAbsolutePosition(ancestor, ancestorSkipped, + filterSkipped); + } } if (isColumnSpanAll()) { - o = spannerPlaceholder()->containingBlock(); + object = spannerPlaceholder()->containingBlock(); } else { - while (o && ((o->isInline() && !o->isAtomicInlineLevel()) || - !o->isLayoutBlock())) - o = o->parent(); + while (object && ((object->isInline() && !object->isAtomicInlineLevel()) || + !object->isLayoutBlock())) { + if (ancestorSkipped && object == ancestor) + *ancestorSkipped = true; + + if (filterSkipped && object->hasFilterInducingProperty()) + *filterSkipped = true; + object = object->parent(); + } } - if (!o || !o->isLayoutBlock()) + if (!object || !object->isLayoutBlock()) return nullptr; // This can still happen in case of an orphaned tree - return toLayoutBlock(o); + return toLayoutBlock(object); } FloatRect LayoutObject::absoluteBoundingBoxFloatRect() const { @@ -1030,7 +1050,7 @@ const LayoutBoxModelObject& LayoutObject::containerForPaintInvalidation() const { - RELEASE_ASSERT(isRooted()); + CHECK(isRooted()); if (const LayoutBoxModelObject* paintInvalidationContainer = enclosingCompositedContainer()) @@ -1039,12 +1059,11 @@ // If the current frame is not composited, we send just return the main // frame's LayoutView so that we generate invalidations on the window. const LayoutView* layoutView = view(); - while ( - LayoutAPIShim::layoutObjectFrom(layoutView->frame()->ownerLayoutItem())) - layoutView = - LayoutAPIShim::layoutObjectFrom(layoutView->frame()->ownerLayoutItem()) - ->view(); - ASSERT(layoutView); + while (const LayoutObject* ownerObject = LayoutAPIShim::constLayoutObjectFrom( + layoutView->frame()->ownerLayoutItem())) + layoutView = ownerObject->view(); + + DCHECK(layoutView); return *layoutView; } @@ -2498,18 +2517,17 @@ if (filterSkipped) *filterSkipped = false; - LayoutObject* o = parent(); - if (isTextOrSVGChild()) - return o; + return parent(); EPosition pos = m_style->position(); if (pos == FixedPosition) return containerForFixedPosition(ancestor, ancestorSkipped, filterSkipped); - if (pos == AbsolutePosition) + if (pos == AbsolutePosition) { return containerForAbsolutePosition(ancestor, ancestorSkipped, filterSkipped); + } if (isColumnSpanAll()) { LayoutObject* multicolContainer = spannerPlaceholder()->container(); @@ -2527,7 +2545,10 @@ return multicolContainer; } - return o; + if (isFloating()) + return containingBlock(ancestor, ancestorSkipped, filterSkipped); + + return parent(); } inline LayoutObject* LayoutObject::paintInvalidationParent() const {
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.h b/third_party/WebKit/Source/core/layout/LayoutObject.h index 9cd19a3..cda782a6 100644 --- a/third_party/WebKit/Source/core/layout/LayoutObject.h +++ b/third_party/WebKit/Source/core/layout/LayoutObject.h
@@ -901,15 +901,15 @@ // // This method is extremely similar to containingBlock(), but with a few // notable exceptions. - // (1) It can be used on orphaned subtrees, i.e., it can be called safely - // even when the object is not part of the primary document subtree yet. - // (2) For normal flow elements, it just returns the parent. - // (3) For absolute positioned elements, it will return a relative + // (1) For normal flow elements, it just returns the parent. + // (2) For absolute positioned elements, it will return a relative // positioned inline. containingBlock() simply skips relpositioned inlines // and lets an enclosing block handle the layout of the positioned object. // This does mean that computePositionedLogicalWidth and // computePositionedLogicalHeight have to use container(). // + // Note that floating objects don't belong to either of the above exceptions. + // // This function should be used for any invalidation as it would correctly // walk the containing block chain. See e.g. markContainerChainForLayout. // It is also used for correctly sizing absolutely positioned elements @@ -927,7 +927,10 @@ bool* ancestorSkipped = nullptr, bool* filterSkipped = nullptr) const; // Finds the containing block as if this object is absolute-position. - LayoutBlock* containingBlockForAbsolutePosition() const; + LayoutBlock* containingBlockForAbsolutePosition( + const LayoutBoxModelObject* ancestor = nullptr, + bool* ancestorSkipped = nullptr, + bool* filterSkipped = nullptr) const; virtual LayoutObject* hoverAncestor() const { return parent(); } @@ -1116,7 +1119,9 @@ // // See container() for the function that returns the containing block. // See LayoutBlock.h for some extra explanations on containing blocks. - LayoutBlock* containingBlock() const; + LayoutBlock* containingBlock(const LayoutBoxModelObject* ancestor = nullptr, + bool* ancestorSkipped = nullptr, + bool* filterSkipped = nullptr) const; bool canContainAbsolutePositionObjects() const { return m_style->canContainAbsolutePositionObjects() ||
diff --git a/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp b/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp index ca872f5b..e870cd1 100644 --- a/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp
@@ -125,6 +125,59 @@ EXPECT_EQ(columns->layer(), overflowClipObject->paintingLayer()); } +TEST_F(LayoutObjectTest, FloatUnderBlock) { + setBodyInnerHTML( + "<div id='layered-div' style='position: absolute'>" + " <div id='container'>" + " <div id='floating' style='float: left'>FLOAT</div>" + " </div>" + "</div>"); + + LayoutBoxModelObject* layeredDiv = + toLayoutBoxModelObject(getLayoutObjectByElementId("layered-div")); + LayoutBoxModelObject* container = + toLayoutBoxModelObject(getLayoutObjectByElementId("container")); + LayoutObject* floating = getLayoutObjectByElementId("floating"); + + EXPECT_EQ(layeredDiv->layer(), layeredDiv->paintingLayer()); + EXPECT_EQ(layeredDiv->layer(), floating->paintingLayer()); + EXPECT_EQ(container, floating->container()); + EXPECT_EQ(container, floating->containingBlock()); +} + +TEST_F(LayoutObjectTest, FloatUnderInline) { + setBodyInnerHTML( + "<div id='layered-div' style='position: absolute'>" + " <div id='container'>" + " <span id='layered-span' style='position: relative'>" + " <div id='floating' style='float: left'>FLOAT</div>" + " </span>" + " </div>" + "</div>"); + + LayoutBoxModelObject* layeredDiv = + toLayoutBoxModelObject(getLayoutObjectByElementId("layered-div")); + LayoutBoxModelObject* container = + toLayoutBoxModelObject(getLayoutObjectByElementId("container")); + LayoutBoxModelObject* layeredSpan = + toLayoutBoxModelObject(getLayoutObjectByElementId("layered-span")); + LayoutObject* floating = getLayoutObjectByElementId("floating"); + + EXPECT_EQ(layeredDiv->layer(), layeredDiv->paintingLayer()); + EXPECT_EQ(layeredSpan->layer(), layeredSpan->paintingLayer()); + EXPECT_EQ(layeredDiv->layer(), floating->paintingLayer()); + EXPECT_EQ(container, floating->container()); + EXPECT_EQ(container, floating->containingBlock()); + + bool ancestorSkipped = false; + EXPECT_EQ(container, floating->container(layeredSpan, &ancestorSkipped)); + EXPECT_TRUE(ancestorSkipped); + + ancestorSkipped = false; + EXPECT_EQ(container, floating->container(container, &ancestorSkipped)); + EXPECT_FALSE(ancestorSkipped); +} + TEST_F(LayoutObjectTest, MutableForPaintingClearPaintFlags) { LayoutObject* object = document().body()->layoutObject(); object->setShouldDoFullPaintInvalidation();
diff --git a/third_party/WebKit/Source/core/layout/PaintInvalidationState.cpp b/third_party/WebKit/Source/core/layout/PaintInvalidationState.cpp index 421e3ed..fe434f3 100644 --- a/third_party/WebKit/Source/core/layout/PaintInvalidationState.cpp +++ b/third_party/WebKit/Source/core/layout/PaintInvalidationState.cpp
@@ -98,11 +98,7 @@ m_svgTransform(parentState.m_svgTransform), m_pendingDelayedPaintInvalidations( parentState.m_pendingDelayedPaintInvalidations), - m_paintingLayer( - currentObject.hasLayer() && - toLayoutBoxModelObject(currentObject).hasSelfPaintingLayer() - ? *toLayoutBoxModelObject(currentObject).layer() - : parentState.m_paintingLayer) + m_paintingLayer(parentState.childPaintingLayer(currentObject)) #if ENABLE(ASSERT) , m_didUpdateForChildren(false) @@ -145,6 +141,12 @@ // paintInvalidationContainer. m_paintInvalidationContainerForStackedContents = m_paintInvalidationContainer; + } else if (currentObject.isFloating() && + !currentObject.parent()->isLayoutBlock()) { + // See LayoutObject::paintingLayer() for specialty of floating objects. + m_paintInvalidationContainer = + ¤tObject.containerForPaintInvalidation(); + m_cachedOffsetsEnabled = false; } else if (currentObject.styleRef().isStacked() && // This is to exclude some objects (e.g. LayoutText) inheriting // stacked style from parent but aren't actually stacked. @@ -230,6 +232,16 @@ updateForCurrentObject(parentState); } +PaintLayer& PaintInvalidationState::childPaintingLayer( + const LayoutObject& child) const { + if (child.hasLayer() && toLayoutBoxModelObject(child).hasSelfPaintingLayer()) + return *toLayoutBoxModelObject(child).layer(); + // See LayoutObject::paintingLayer() for specialty of floating objects. + if (child.isFloating() && !m_currentObject.isLayoutBlock()) + return *child.paintingLayer(); + return m_paintingLayer; +} + void PaintInvalidationState::updateForCurrentObject( const PaintInvalidationState& parentState) { if (!m_cachedOffsetsEnabled)
diff --git a/third_party/WebKit/Source/core/layout/PaintInvalidationState.h b/third_party/WebKit/Source/core/layout/PaintInvalidationState.h index cded1752..c887b12 100644 --- a/third_party/WebKit/Source/core/layout/PaintInvalidationState.h +++ b/third_party/WebKit/Source/core/layout/PaintInvalidationState.h
@@ -108,6 +108,8 @@ friend class VisualRectMappingTest; friend class PaintInvalidatorContextAdapter; + inline PaintLayer& childPaintingLayer(const LayoutObject& child) const; + void mapLocalRectToPaintInvalidationContainer(LayoutRect&) const; void updateForCurrentObject(const PaintInvalidationState& parentState);
diff --git a/third_party/WebKit/Source/core/layout/VisualRectMappingTest.cpp b/third_party/WebKit/Source/core/layout/VisualRectMappingTest.cpp index d305494..0ff8052 100644 --- a/third_party/WebKit/Source/core/layout/VisualRectMappingTest.cpp +++ b/third_party/WebKit/Source/core/layout/VisualRectMappingTest.cpp
@@ -674,4 +674,30 @@ EXPECT_EQ(rect, target->visualRect()); } +TEST_F(VisualRectMappingTest, FloatUnderInline) { + setBodyInnerHTML( + "<div style='position: absolute; top: 55px; left: 66px'>" + " <span id='span' style='position: relative; top: 100px; left: 200px'>" + " <div id='target' style='float: left; width: 33px; height: 44px'>" + " </div>" + " </span>" + "</div>"); + + LayoutBoxModelObject* span = + toLayoutBoxModelObject(getLayoutObjectByElementId("span")); + LayoutBox* target = toLayoutBox(getLayoutObjectByElementId("target")); + + LayoutRect targetVisualRect = target->localVisualRect(); + EXPECT_EQ(LayoutRect(0, 0, 33, 44), targetVisualRect); + + LayoutRect rect = targetVisualRect; + EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(&layoutView(), rect)); + EXPECT_EQ(LayoutRect(66, 55, 33, 44), rect); + EXPECT_EQ(rect, target->visualRect()); + + rect = targetVisualRect; + EXPECT_TRUE(target->mapToVisualRectInAncestorSpace(span, rect)); + EXPECT_EQ(LayoutRect(-200, -100, 33, 44), rect); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.cpp index eb4b6f3..8510203 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.cpp
@@ -70,6 +70,11 @@ LayoutBlockFlow::willBeDestroyed(); } +void LayoutSVGBlock::updateFromStyle() { + LayoutBlockFlow::updateFromStyle(); + setFloating(false); +} + void LayoutSVGBlock::styleDidChange(StyleDifference diff, const ComputedStyle* oldStyle) { if (diff.needsFullLayout()) {
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.h index 56077911..9ac0a9d 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.h +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.h
@@ -74,6 +74,7 @@ void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const final; + void updateFromStyle() final; void styleDidChange(StyleDifference, const ComputedStyle* oldStyle) final; bool nodeAtPoint(HitTestResult&,
diff --git a/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp index 64ef222..53bb1b95 100644 --- a/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp +++ b/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp
@@ -198,8 +198,12 @@ void PaintInvalidator::updatePaintingLayer(const LayoutObject& object, PaintInvalidatorContext& context) { if (object.hasLayer() && - toLayoutBoxModelObject(object).hasSelfPaintingLayer()) + toLayoutBoxModelObject(object).hasSelfPaintingLayer()) { context.paintingLayer = toLayoutBoxModelObject(object).layer(); + } else if (object.isFloating() && !object.parent()->isLayoutBlock()) { + // See LayoutObject::paintingLayer() for specialty of floating objects. + context.paintingLayer = object.paintingLayer(); + } if (object.isLayoutBlockFlow() && toLayoutBlockFlow(object).containsFloats()) context.paintingLayer->setNeedsPaintPhaseFloat(); @@ -281,6 +285,10 @@ if (!RuntimeEnabledFeatures::rootLayerScrollingEnabled()) undoFrameViewContentClipAndScroll.emplace( *toLayoutView(object).frameView(), context); + } else if (object.isFloating() && !object.parent()->isLayoutBlock()) { + // See LayoutObject::paintingLayer() for specialty of floating objects. + context.paintInvalidationContainer = + &object.containerForPaintInvalidation(); } else if (object.styleRef().isStacked() && // This is to exclude some objects (e.g. LayoutText) inheriting // stacked style from parent but aren't actually stacked.
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp b/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp index 3f8a6de6..05403b5 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp
@@ -177,28 +177,32 @@ return storeClipRectsInCache(context, parentClipRects, *clipRects); } -void PaintLayerClipper::clearClipRectsIncludingDescendants() { +void PaintLayerClipper::clearCache(ClipRectsCacheSlot cacheSlot) { + if (cacheSlot == NumberOfClipRectsCacheSlots) + m_layer.clearClipRectsCache(); + else if (ClipRectsCache* cache = m_layer.clipRectsCache()) + cache->clear(cacheSlot); + if (m_geometryMapper) m_geometryMapper.reset(new GeometryMapper); - m_layer.clearClipRectsCache(); +} - for (PaintLayer* layer = m_layer.firstChild(); layer; - layer = layer->nextSibling()) { - layer->clipper().clearClipRectsIncludingDescendants(); - } +void PaintLayerClipper::clearClipRectsIncludingDescendants() { + clearClipRectsIncludingDescendants(NumberOfClipRectsCacheSlots); } void PaintLayerClipper::clearClipRectsIncludingDescendants( ClipRectsCacheSlot cacheSlot) { - if (m_geometryMapper) - m_geometryMapper.reset(new GeometryMapper); + std::stack<const PaintLayer*> layers; + layers.push(&m_layer); - if (ClipRectsCache* cache = m_layer.clipRectsCache()) - cache->clear(cacheSlot); - - for (PaintLayer* layer = m_layer.firstChild(); layer; - layer = layer->nextSibling()) { - layer->clipper().clearClipRectsIncludingDescendants(cacheSlot); + while (!layers.empty()) { + const PaintLayer* currentLayer = layers.top(); + layers.pop(); + currentLayer->clipper().clearCache(cacheSlot); + for (const PaintLayer* layer = currentLayer->firstChild(); layer; + layer = layer->nextSibling()) + layers.push(layer); } }
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerClipper.h b/third_party/WebKit/Source/core/paint/PaintLayerClipper.h index df71e64..f3dd97d 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerClipper.h +++ b/third_party/WebKit/Source/core/paint/PaintLayerClipper.h
@@ -200,6 +200,7 @@ const LayoutSize& subpixelAccumulation) const; private: + void clearCache(ClipRectsCacheSlot); ClipRects& getClipRects(const ClipRectsContext&) const; void calculateClipRects(const ClipRectsContext&, ClipRects&) const;
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerClipperTest.cpp b/third_party/WebKit/Source/core/paint/PaintLayerClipperTest.cpp index 8cacaeb8a2..b773345 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerClipperTest.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayerClipperTest.cpp
@@ -144,4 +144,92 @@ fixed->clipper().localClipRect(transformed)); } +TEST_F(PaintLayerClipperTest, ClearClipRectsRecursive) { + setBodyInnerHTML( + "<style>" + "div { " + " width: 5px; height: 5px; background: blue;" + " position: relative;" + "}" + "</style>" + "<div id='parent'>" + " <div id='child'>" + " <div id='grandchild'></div>" + " </div>" + "</div>"); + + PaintLayer* parent = + toLayoutBoxModelObject(getLayoutObjectByElementId("parent"))->layer(); + PaintLayer* child = + toLayoutBoxModelObject(getLayoutObjectByElementId("child"))->layer(); + + EXPECT_TRUE(parent->clipRectsCache()); + EXPECT_TRUE(child->clipRectsCache()); + + parent->clipper().clearClipRectsIncludingDescendants(); + + EXPECT_FALSE(parent->clipRectsCache()); + EXPECT_FALSE(child->clipRectsCache()); +} + +TEST_F(PaintLayerClipperTest, ClearClipRectsRecursiveChild) { + setBodyInnerHTML( + "<style>" + "div { " + " width: 5px; height: 5px; background: blue;" + " position: relative;" + "}" + "</style>" + "<div id='parent'>" + " <div id='child'>" + " <div id='grandchild'></div>" + " </div>" + "</div>"); + + PaintLayer* parent = + toLayoutBoxModelObject(getLayoutObjectByElementId("parent"))->layer(); + PaintLayer* child = + toLayoutBoxModelObject(getLayoutObjectByElementId("child"))->layer(); + + EXPECT_TRUE(parent->clipRectsCache()); + EXPECT_TRUE(child->clipRectsCache()); + + child->clipper().clearClipRectsIncludingDescendants(); + + EXPECT_TRUE(parent->clipRectsCache()); + EXPECT_FALSE(child->clipRectsCache()); +} + +TEST_F(PaintLayerClipperTest, ClearClipRectsRecursiveOneType) { + setBodyInnerHTML( + "<style>" + "div { " + " width: 5px; height: 5px; background: blue;" + " position: relative;" + "}" + "</style>" + "<div id='parent'>" + " <div id='child'>" + " <div id='grandchild'></div>" + " </div>" + "</div>"); + + PaintLayer* parent = + toLayoutBoxModelObject(getLayoutObjectByElementId("parent"))->layer(); + PaintLayer* child = + toLayoutBoxModelObject(getLayoutObjectByElementId("child"))->layer(); + + EXPECT_TRUE(parent->clipRectsCache()); + EXPECT_TRUE(child->clipRectsCache()); + EXPECT_TRUE(parent->clipRectsCache()->get(AbsoluteClipRects).root); + EXPECT_TRUE(child->clipRectsCache()->get(AbsoluteClipRects).root); + + parent->clipper().clearClipRectsIncludingDescendants(AbsoluteClipRects); + + EXPECT_TRUE(parent->clipRectsCache()); + EXPECT_TRUE(child->clipRectsCache()); + EXPECT_FALSE(parent->clipRectsCache()->get(AbsoluteClipRects).root); + EXPECT_FALSE(parent->clipRectsCache()->get(AbsoluteClipRects).root); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp index 57fc3e2..4ebf106 100644 --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
@@ -803,6 +803,9 @@ void PaintPropertyTreeBuilder::updateOutOfFlowContext( const LayoutObject& object, PaintPropertyTreeBuilderContext& context) { + if (object.isLayoutBlock()) + context.paintOffsetForFloat = context.current.paintOffset; + if (object.canContainAbsolutePositionObjects()) { context.absolutePosition = context.current; context.containerForAbsolutePosition = &object; @@ -897,6 +900,10 @@ return; const LayoutBoxModelObject& boxModelObject = toLayoutBoxModelObject(object); + + if (boxModelObject.isFloating()) + context.current.paintOffset = context.paintOffsetForFloat; + switch (object.styleRef().position()) { case StaticPosition: break;
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h index 3f2f6c9..f3a9112b8 100644 --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h
@@ -65,6 +65,11 @@ ContainingBlockContext fixedPosition; + // This is the same as current.paintOffset except when a floating object has + // non-block ancestors under its containing block. Paint offsets of the + // non-block ancestors should not be accumulated for the floating object. + LayoutPoint paintOffsetForFloat; + // The effect hierarchy is applied by the stacking context tree. It is // guaranteed that every DOM descendant is also a stacking context descendant. // Therefore, we don't need extra bookkeeping for effect nodes and can
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp index e7480ff..573872eb 100644 --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
@@ -3196,4 +3196,27 @@ EXPECT_NE(CompositorElementId(), properties->effect()->compositorElementId()); } +TEST_P(PaintPropertyTreeBuilderTest, FloatUnderInline) { + setBodyInnerHTML( + "<div style='position: absolute; top: 55px; left: 66px'>" + " <span id='span'" + " style='position: relative; top: 100px; left: 200px; opacity: 0.5'>" + " <div id='target' style='float: left; width: 33px; height: 44px'>" + " </div>" + " </span" + "</div>"); + + LayoutObject* span = getLayoutObjectByElementId("span"); + const auto* effect = span->paintProperties()->effect(); + ASSERT_TRUE(effect); + EXPECT_EQ(0.5f, effect->opacity()); + + LayoutObject* target = getLayoutObjectByElementId("target"); + const auto* localBorderBoxProperties = + target->paintProperties()->localBorderBoxProperties(); + ASSERT_TRUE(localBorderBoxProperties); + EXPECT_EQ(LayoutPoint(66, 55), localBorderBoxProperties->paintOffset); + EXPECT_EQ(effect, localBorderBoxProperties->propertyTreeState.effect()); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/devtools/front_end/platform/utilities.js b/third_party/WebKit/Source/devtools/front_end/platform/utilities.js index 1edf9b9..9c1413b 100644 --- a/third_party/WebKit/Source/devtools/front_end/platform/utilities.js +++ b/third_party/WebKit/Source/devtools/front_end/platform/utilities.js
@@ -1367,7 +1367,8 @@ * @return {number} */ self.setImmediate = function(callback) { - Promise.resolve().then(callback); + const args = [...arguments].slice(1); + Promise.resolve().then(() => callback(...args)); return 0; };
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/CookieItemsView.js b/third_party/WebKit/Source/devtools/front_end/resources/CookieItemsView.js index 42c424c..8344131 100644 --- a/third_party/WebKit/Source/devtools/front_end/resources/CookieItemsView.js +++ b/third_party/WebKit/Source/devtools/front_end/resources/CookieItemsView.js
@@ -36,17 +36,23 @@ this.element.classList.add('storage-view'); - this._deleteButton = new UI.ToolbarButton(Common.UIString('Delete'), 'largeicon-delete'); - this._deleteButton.setVisible(false); + this._deleteButton = new UI.ToolbarButton(Common.UIString('Delete Selected'), 'largeicon-delete'); this._deleteButton.addEventListener(UI.ToolbarButton.Events.Click, this._deleteButtonClicked, this); - this._clearButton = new UI.ToolbarButton(Common.UIString('Clear'), 'largeicon-clear'); - this._clearButton.setVisible(false); + this._clearButton = new UI.ToolbarButton(Common.UIString('Clear All'), 'largeicon-clear'); this._clearButton.addEventListener(UI.ToolbarButton.Events.Click, this._clearButtonClicked, this); this._refreshButton = new UI.ToolbarButton(Common.UIString('Refresh'), 'largeicon-refresh'); this._refreshButton.addEventListener(UI.ToolbarButton.Events.Click, this._refreshButtonClicked, this); + this._filterBar = new UI.FilterBar('cookiesPanel', true); + this._textFilterUI = new UI.TextFilterUI(true); + this._textFilterUI.addEventListener(UI.FilterUI.Events.FilterChanged, this._filterChanged, this); + this._filterBar.addFilter(this._textFilterUI); + + this._filterSeparator = new UI.ToolbarSeparator(); + this._filterButton = this._filterBar.filterButton(); + this._treeElement = treeElement; this._cookieDomain = cookieDomain; @@ -65,7 +71,10 @@ * @return {!Array.<!UI.ToolbarItem>} */ syncToolbarItems() { - return [this._refreshButton, this._clearButton, this._deleteButton]; + return [ + this._refreshButton, this._clearButton, this._deleteButton, + this._filterSeparator, this._filterButton + ]; } /** @@ -79,7 +88,16 @@ * @override */ willHide() { - this._deleteButton.setVisible(false); + this._deleteButton.setEnabled(false); + } + + /** + * @param {!Common.Event} event + */ + _filterChanged(event) { + var text = this._textFilterUI.value(); + this._filterRegex = text && new RegExp(text.escapeForRegExp(), 'i'); + this._update(); } _update() { @@ -95,8 +113,9 @@ if (!this._cookies.length) { // Nothing to show. this._emptyWidget.show(this.element); - this._clearButton.setVisible(false); - this._deleteButton.setVisible(false); + this._filterButton.setEnabled(false); + this._clearButton.setEnabled(false); + this._deleteButton.setEnabled(false); if (this._cookiesTable) this._cookiesTable.detach(); return; @@ -104,19 +123,35 @@ if (!this._cookiesTable) { this._cookiesTable = - new Components.CookiesTable(false, this._update.bind(this), this._showDeleteButton.bind(this)); + new Components.CookiesTable(false, this._update.bind(this), this._enableDeleteButton.bind(this)); } - this._cookiesTable.setCookies(this._cookies); + var shownCookies = this._filterCookiesForFilters(this._cookies); + this._cookiesTable.setCookies(shownCookies); this._emptyWidget.detach(); this._cookiesTable.show(this.element); + this._filterBar.show(this.element); this._treeElement.subtitle = String.sprintf(Common.UIString('%d cookies (%s)'), this._cookies.length, Number.bytesToString(this._totalSize)); - this._clearButton.setVisible(true); - this._deleteButton.setVisible(!!this._cookiesTable.selectedCookie()); + this._filterButton.setEnabled(true); + this._clearButton.setEnabled(true); + this._deleteButton.setEnabled(!!this._cookiesTable.selectedCookie()); } /** + * @param {!Array.<!SDK.Cookie>} cookies + */ + _filterCookiesForFilters(cookies) { + if (!this._filterRegex) + return cookies; + + return cookies.filter(cookie => { + const candidate = `${cookie.name()} ${cookie.value()} ${cookie.domain()}`; + return this._filterRegex.test(candidate); + }); + } + + /** * @param {!Array.<!SDK.Cookie>} allCookies */ _filterCookiesForDomain(allCookies) { @@ -163,8 +198,8 @@ this.clear(); } - _showDeleteButton() { - this._deleteButton.setVisible(true); + _enableDeleteButton() { + this._deleteButton.setEnabled(true); } /**
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/resourcesPanel.css b/third_party/WebKit/Source/devtools/front_end/resources/resourcesPanel.css index b620be29d..70e82bd1 100644 --- a/third_party/WebKit/Source/devtools/front_end/resources/resourcesPanel.css +++ b/third_party/WebKit/Source/devtools/front_end/resources/resourcesPanel.css
@@ -80,6 +80,11 @@ overflow-x: hidden; } +.storage-view .filter-bar { + border-bottom: none; + border-top: 1px solid #dadada; +} + .database-query-prompt { position: relative; padding: 1px 22px 1px 24px;
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/TextPrompt.js b/third_party/WebKit/Source/devtools/front_end/ui/TextPrompt.js index 862dd38d..5afcdec 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/TextPrompt.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/TextPrompt.js
@@ -199,7 +199,10 @@ * @param {string} placeholder */ setPlaceholder(placeholder) { - this._element.setAttribute('data-placeholder', placeholder); + if (placeholder) + this._element.setAttribute('data-placeholder', placeholder); + else + this._element.removeAttribute('data-placeholder'); } _removeFromElement() {
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/textPrompt.css b/third_party/WebKit/Source/devtools/front_end/ui/textPrompt.css index 25602a2..a39597a 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/textPrompt.css +++ b/third_party/WebKit/Source/devtools/front_end/ui/textPrompt.css
@@ -35,7 +35,7 @@ -webkit-user-modify: read-only; } -::content .text-prompt:empty::before { +::content .text-prompt[data-placeholder]:empty::before { content: attr(data-placeholder); color: rgb(128, 128, 128); }
diff --git a/third_party/WebKit/Source/web/WebFrameSerializer.cpp b/third_party/WebKit/Source/web/WebFrameSerializer.cpp index 38008c2..8e977263 100644 --- a/third_party/WebKit/Source/web/WebFrameSerializer.cpp +++ b/third_party/WebKit/Source/web/WebFrameSerializer.cpp
@@ -294,6 +294,11 @@ FrameSerializer serializer(resources, coreDelegate); serializer.serializeFrame(*frame); } + + // There was an error serializing the frame (e.g. of an image resource). + if (resources.isEmpty()) + return WebThreadSafeData(); + TRACE_EVENT_END1("page-serialization", "WebFrameSerializer::generateMHTMLParts serializing", "resource count", @@ -302,7 +307,6 @@ // Encode serialized resources as MHTML. RefPtr<RawData> output = RawData::create(); { - DCHECK(!resources.isEmpty()); SCOPED_BLINK_UMA_HISTOGRAM_TIMER( "PageSerialization.MhtmlGeneration.EncodingTime.SingleFrame"); // Frame is the 1st resource (see FrameSerializer::serializeFrame doc
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp index 25834de..ec409dc 100644 --- a/third_party/WebKit/Source/web/WebViewImpl.cpp +++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -1776,6 +1776,7 @@ // viewport with the browser controls shown. IntSize ICBSize = m_size; if (RuntimeEnabledFeatures::inertTopControlsEnabled() && + browserControls().permittedState() == WebBrowserControlsBoth && !browserControls().shrinkViewport()) ICBSize.expand(0, -browserControls().height()); @@ -1797,8 +1798,20 @@ void WebViewImpl::updateBrowserControlsState(WebBrowserControlsState constraint, WebBrowserControlsState current, bool animate) { + WebBrowserControlsState oldPermittedState = + browserControls().permittedState(); + browserControls().updateConstraintsAndState(constraint, current, animate); + // If the controls are going from a locked to an unlocked state, or + // vice-versa, then we need to force a recompute of the ICB size since that + // depends on the permitted browser controls state. + if (oldPermittedState != constraint && + (oldPermittedState == WebBrowserControlsBoth || + constraint == WebBrowserControlsBoth)) { + performResize(); + } + if (m_layerTreeView) m_layerTreeView->updateBrowserControlsState(constraint, current, animate); } @@ -1845,8 +1858,7 @@ return page()->frameHost().browserControls(); } -void WebViewImpl::resizeViewWhileAnchored(FrameView* view, - float browserControlsHeight, +void WebViewImpl::resizeViewWhileAnchored(float browserControlsHeight, bool browserControlsShrinkLayout) { DCHECK(mainFrameImpl()); @@ -1910,12 +1922,10 @@ if (isRotation) { RotationViewportAnchor anchor(*view, visualViewport, viewportAnchorCoords, pageScaleConstraintsSet()); - resizeViewWhileAnchored(view, browserControlsHeight, - browserControlsShrinkLayout); + resizeViewWhileAnchored(browserControlsHeight, browserControlsShrinkLayout); } else { ResizeViewportAnchor::ResizeScope resizeScope(*m_resizeViewportAnchor); - resizeViewWhileAnchored(view, browserControlsHeight, - browserControlsShrinkLayout); + resizeViewWhileAnchored(browserControlsHeight, browserControlsShrinkLayout); } sendResizeEventAndRepaint(); }
diff --git a/third_party/WebKit/Source/web/WebViewImpl.h b/third_party/WebKit/Source/web/WebViewImpl.h index b7bbfed..bcf5884 100644 --- a/third_party/WebKit/Source/web/WebViewImpl.h +++ b/third_party/WebKit/Source/web/WebViewImpl.h
@@ -519,8 +519,7 @@ IntSize contentsSize() const; void performResize(); - void resizeViewWhileAnchored(FrameView*, - float browserControlsHeight, + void resizeViewWhileAnchored(float browserControlsHeight, bool browserControlsShrinkLayout); // Overrides the compositor visibility. See the description of
diff --git a/third_party/WebKit/Source/web/tests/BrowserControlsTest.cpp b/third_party/WebKit/Source/web/tests/BrowserControlsTest.cpp index bf75054..1e81b49 100644 --- a/third_party/WebKit/Source/web/tests/BrowserControlsTest.cpp +++ b/third_party/WebKit/Source/web/tests/BrowserControlsTest.cpp
@@ -726,6 +726,86 @@ EXPECT_EQ(300, frame()->view()->layoutSize(IncludeScrollbars).height()); } +// Ensure that browser controls do not affect the layout by showing and hiding +// except for position: fixed elements. +TEST_F(BrowserControlsTest, MAYBE(AffectLayoutHeightWhenConstrained)) { + // Initialize with the browser controls showing. + WebViewImpl* webView = initialize("percent-height.html"); + webView->resizeWithBrowserControls(WebSize(400, 300), 100.f, true); + webView->updateBrowserControlsState(WebBrowserControlsBoth, + WebBrowserControlsShown, false); + webView->browserControls().setShownRatio(1); + webView->updateAllLifecyclePhases(); + + Element* absPos = getElementById(WebString::fromUTF8("abs")); + Element* fixedPos = getElementById(WebString::fromUTF8("fixed")); + + ASSERT_EQ(100.f, webView->browserControls().contentOffset()); + + // Hide the browser controls. + verticalScroll(-100.f); + webView->resizeWithBrowserControls(WebSize(400, 400), 100.f, false); + webView->updateAllLifecyclePhases(); + ASSERT_EQ(300, frame()->view()->layoutSize(IncludeScrollbars).height()); + + // Now lock the controls in a hidden state. The layout and elements should + // resize without a WebView::resize. + webView->updateBrowserControlsState(WebBrowserControlsHidden, + WebBrowserControlsBoth, false); + + EXPECT_FLOAT_EQ(200.f, absPos->getBoundingClientRect()->height()); + EXPECT_FLOAT_EQ(200.f, fixedPos->getBoundingClientRect()->height()); + + EXPECT_EQ(400, frame()->view()->layoutSize(IncludeScrollbars).height()); + + // Unlock the controls, the sizes should change even though the controls are + // still hidden. + webView->updateBrowserControlsState(WebBrowserControlsBoth, + WebBrowserControlsBoth, false); + + EXPECT_FLOAT_EQ(150.f, absPos->getBoundingClientRect()->height()); + EXPECT_FLOAT_EQ(200.f, fixedPos->getBoundingClientRect()->height()); + + EXPECT_EQ(300, frame()->view()->layoutSize(IncludeScrollbars).height()); + + // Now lock the controls in a shown state. + webView->updateBrowserControlsState(WebBrowserControlsShown, + WebBrowserControlsBoth, false); + webView->resizeWithBrowserControls(WebSize(400, 300), 100.f, true); + + EXPECT_FLOAT_EQ(150.f, absPos->getBoundingClientRect()->height()); + EXPECT_FLOAT_EQ(150.f, fixedPos->getBoundingClientRect()->height()); + + EXPECT_EQ(300, frame()->view()->layoutSize(IncludeScrollbars).height()); + + // Shown -> Hidden + webView->resizeWithBrowserControls(WebSize(400, 400), 100.f, false); + webView->updateBrowserControlsState(WebBrowserControlsHidden, + WebBrowserControlsBoth, false); + + EXPECT_FLOAT_EQ(200.f, absPos->getBoundingClientRect()->height()); + EXPECT_FLOAT_EQ(200.f, fixedPos->getBoundingClientRect()->height()); + + EXPECT_EQ(400, frame()->view()->layoutSize(IncludeScrollbars).height()); + + // Go from Unlocked and showing, to locked and hidden but issue the resize + // before the constraint update to check for race issues. + webView->updateBrowserControlsState(WebBrowserControlsBoth, + WebBrowserControlsShown, false); + webView->resizeWithBrowserControls(WebSize(400, 300), 100.f, true); + ASSERT_EQ(300, frame()->view()->layoutSize(IncludeScrollbars).height()); + webView->updateAllLifecyclePhases(); + + webView->resizeWithBrowserControls(WebSize(400, 400), 100.f, false); + webView->updateBrowserControlsState(WebBrowserControlsHidden, + WebBrowserControlsHidden, false); + + EXPECT_FLOAT_EQ(200.f, absPos->getBoundingClientRect()->height()); + EXPECT_FLOAT_EQ(200.f, fixedPos->getBoundingClientRect()->height()); + + EXPECT_EQ(400, frame()->view()->layoutSize(IncludeScrollbars).height()); +} + // Ensure that browser controls do not affect vh units. TEST_F(BrowserControlsTest, MAYBE(DontAffectVHUnits)) { // Initialize with the browser controls showing.
diff --git a/third_party/WebKit/Source/web/tests/LayoutGeometryMapTest.cpp b/third_party/WebKit/Source/web/tests/LayoutGeometryMapTest.cpp index d4d2dcff..9d6bfa83 100644 --- a/third_party/WebKit/Source/web/tests/LayoutGeometryMapTest.cpp +++ b/third_party/WebKit/Source/web/tests/LayoutGeometryMapTest.cpp
@@ -77,14 +77,19 @@ return element->layoutBox(); } - static LayoutBox* getLayoutBox(WebView* webView, - const WTF::AtomicString& elementId) { + static Element* getElement(WebView* webView, + const WTF::AtomicString& elementId) { WebViewImpl* webViewImpl = toWebViewImpl(webView); if (!webViewImpl) return nullptr; LocalFrame* frame = webViewImpl->mainFrameImpl()->frame(); Document* doc = frame->document(); - Element* element = doc->getElementById(elementId); + return doc->getElementById(elementId); + } + + static LayoutBox* getLayoutBox(WebView* webView, + const WTF::AtomicString& elementId) { + Element* element = getElement(webView, elementId); if (!element) return nullptr; return element->layoutBox(); @@ -494,4 +499,38 @@ EXPECT_EQ(3.0f, rectFromQuad(rgm.mapToAncestor(rect, nullptr)).height()); } +TEST_P(LayoutGeometryMapTest, FloatUnderInlineLayer) { + registerMockedHttpURLLoad("rgm_float_under_inline.html"); + FrameTestHelpers::WebViewHelper webViewHelper; + WebView* webView = webViewHelper.initializeAndLoad( + m_baseURL + "rgm_float_under_inline.html", true, 0, 0); + webView->resize(WebSize(1000, 1000)); + webView->updateAllLifecyclePhases(); + + LayoutGeometryMap rgm; + auto* layerUnderFloat = getLayoutBox(webView, "layer-under-float"); + auto* span = getElement(webView, "span")->layoutBoxModelObject(); + auto* floating = getLayoutBox(webView, "float"); + auto* container = getLayoutBox(webView, "container"); + FloatRect rect(3.0f, 4.0f, 10.0f, 8.0f); + + rgm.pushMappingsToAncestor(container->layer(), nullptr); + rgm.pushMappingsToAncestor(span->layer(), container->layer()); + rgm.pushMappingsToAncestor(layerUnderFloat->layer(), span->layer()); + EXPECT_EQ(rect, rectFromQuad(rgm.mapToAncestor(rect, container))); + EXPECT_EQ(FloatRect(63.0f, 54.0f, 10.0f, 8.0f), + rectFromQuad(rgm.mapToAncestor(rect, nullptr))); + + rgm.popMappingsToAncestor(span->layer()); + EXPECT_EQ(FloatRect(203.0f, 104.0f, 10.0f, 8.0f), + rectFromQuad(rgm.mapToAncestor(rect, container))); + EXPECT_EQ(FloatRect(263.0f, 154.0f, 10.0f, 8.0f), + rectFromQuad(rgm.mapToAncestor(rect, nullptr))); + + rgm.pushMappingsToAncestor(floating, span); + EXPECT_EQ(rect, rectFromQuad(rgm.mapToAncestor(rect, container))); + EXPECT_EQ(FloatRect(63.0f, 54.0f, 10.0f, 8.0f), + rectFromQuad(rgm.mapToAncestor(rect, nullptr))); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp b/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp index 626598fb..7548471 100644 --- a/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp +++ b/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp
@@ -2456,4 +2456,24 @@ RuntimeEnabledFeatures::setInertTopControlsEnabled(originalInertTopControls); } +// Make sure we don't crash when the visual viewport's height is 0. This can +// happen transiently in autoresize mode and cause a crash. This test passes if +// it doesn't crash. +TEST_P(VisualViewportTest, AutoResizeNoHeightUsesMinimumHeight) { + initializeWithDesktopSettings(); + webViewImpl()->resizeWithBrowserControls(WebSize(0, 0), 0, false); + webViewImpl()->enableAutoResizeMode(WebSize(25, 25), WebSize(100, 100)); + WebURL baseURL = URLTestHelpers::toKURL("http://example.com/"); + FrameTestHelpers::loadHTMLString(webViewImpl()->mainFrame(), + "<!DOCTYPE html>" + "<style>" + " body {" + " margin: 0px;" + " }" + " div { height:110vh; width: 110vw; }" + "</style>" + "<div></div>", + baseURL); +} + } // namespace
diff --git a/third_party/WebKit/Source/web/tests/WebFrameSerializerTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameSerializerTest.cpp index d196b2b..3379845a 100644 --- a/third_party/WebKit/Source/web/tests/WebFrameSerializerTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebFrameSerializerTest.cpp
@@ -198,10 +198,12 @@ ~WebFrameSerializerSanitizationTest() override {} - String generateMHTMLParts(const String& url, const String& fileName) { + String generateMHTMLParts(const String& url, + const String& fileName, + const String& mimeType = "text/html") { KURL parsedURL(ParsedURLString, url); URLTestHelpers::registerMockedURLLoad(parsedURL, fileName, - "frameserialization/", "text/html"); + "frameserialization/", mimeType); FrameTestHelpers::loadFrame(mainFrameImpl(), url.utf8().data()); WebThreadSafeData result = WebFrameSerializer::generateMHTMLParts( WebString("boundary"), mainFrameImpl(), &m_mhtmlDelegate); @@ -274,4 +276,12 @@ EXPECT_NE(WTF::kNotFound, mhtml.find("<div")); } +// Regression test for crbug.com/678893, where in some cases serializing an +// image document could cause code to pick an element from an empty container. +TEST_F(WebFrameSerializerSanitizationTest, FromBrokenImageDocument) { + String mhtml = generateMHTMLParts("http://www.test.com", "broken-image.png", + "image/png"); + EXPECT_TRUE(mhtml.isEmpty()); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/web/tests/data/frameserialization/broken-image.png b/third_party/WebKit/Source/web/tests/data/frameserialization/broken-image.png new file mode 100644 index 0000000..96696a17 --- /dev/null +++ b/third_party/WebKit/Source/web/tests/data/frameserialization/broken-image.png
@@ -0,0 +1 @@ +broken image / this is not a png file
diff --git a/third_party/WebKit/Source/web/tests/data/rgm_float_under_inline.html b/third_party/WebKit/Source/web/tests/data/rgm_float_under_inline.html new file mode 100644 index 0000000..519e7e2 --- /dev/null +++ b/third_party/WebKit/Source/web/tests/data/rgm_float_under_inline.html
@@ -0,0 +1,8 @@ +<!DOCTYPE html> +<div id="container" style="position: absolute; top: 50px; left: 60px"> + <span id="span" style="position: relative; top: 100px; left: 200px"> + <div id="float" style="float: left"> + <div id="layer-under-float" style="position: relative"></div> + </div> + </span> +</div>
diff --git a/third_party/closure_compiler/compiled_resources2.gyp b/third_party/closure_compiler/compiled_resources2.gyp index 7f30d1fe..12978d6 100644 --- a/third_party/closure_compiler/compiled_resources2.gyp +++ b/third_party/closure_compiler/compiled_resources2.gyp
@@ -30,6 +30,7 @@ '<(DEPTH)/chrome/browser/resources/offline_pages/compiled_resources2.gyp:*', '<(DEPTH)/chrome/browser/resources/settings/compiled_resources2.gyp:*', '<(DEPTH)/chrome/browser/resources/uber/compiled_resources2.gyp:*', + '<(DEPTH)/chrome/browser/resources/vr_shell/compiled_resources2.gyp:*', '<(DEPTH)/ui/file_manager/compiled_resources2.gyp:*', '<(DEPTH)/ui/webui/resources/cr_elements/compiled_resources2.gyp:*', '<(DEPTH)/ui/webui/resources/js/chromeos/compiled_resources2.gyp:*',
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index b6b4d92..5741715 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -44896,6 +44896,14 @@ </summary> </histogram> +<histogram name="PhysicalWeb.InitialState.IosChrome" + enum="PhysicalWebInitialStateIosChrome"> + <owner>cco3@chromium.org</owner> + <owner>mattreynolds@chromium.org</owner> + <owner>mmocny@chromium.org</owner> + <summary>Initial state of the Physical Web in Chrome for iOS.</summary> +</histogram> + <histogram name="PhysicalWeb.ReferralDelay.OptInNotification" units="ms"> <owner>cco3@chromium.org</owner> <owner>mattreynolds@chromium.org</owner> @@ -72106,6 +72114,19 @@ </summary> </histogram> +<histogram + name="WebController.StartProvisionalNavigationExitedWithEmptyNavigationManager" + enum="BooleanHit"> + <owner>eugenebut@chromium.org</owner> + <summary> + Chrome for iOS crashes in |didCommitNavigation:| if Navigation Manager is + empty. It's unclear how the app can get into this state and one assumption + is that didStartProvisionalNavigation: does not add a pending navigation. + This metric is logged when didStartProvisionalNavigation: fails to add a + pending item. + </summary> +</histogram> + <histogram name="WebCore.Animation.CSSProperties" enum="MappedCSSProperties"> <owner>ajuma@chromium.org</owner> <summary> @@ -93816,6 +93837,7 @@ <int value="-1821058653" label="enable-delay-agnostic-aec"/> <int value="-1812579951" label="ContentSuggestionsCategoryRanker:enabled"/> <int value="-1811394154" label="disable-webrtc-hw-vp8-encoding"/> + <int value="-1810294310" label="AndroidPaymentApps:enabled"/> <int value="-1804485171" label="disable-fullscreen-tab-detaching"/> <int value="-1802502753" label="enable-manual-password-generation:enabled"/> <int value="-1798337879" label="enable-md-downloads"/> @@ -94320,6 +94342,7 @@ <int value="550378029" label="reset-app-list-install-state"/> <int value="550387510" label="NTPAssetDownloadSuggestions:disabled"/> <int value="567368307" label="enable-experimental-canvas-features"/> + <int value="575394365" label="AndroidPaymentApps:disabled"/> <int value="581118445" label="enable-eol-notification"/> <int value="581355159" label="ContentSuggestionsCategoryRanker:disabled"/> <int value="584541349" label="ContextualSearchSingleActions:disabled"/> @@ -99473,6 +99496,33 @@ <int value="4" label="REFERER_DIAGNOSTICS"/> </enum> +<enum name="PhysicalWebInitialStateIosChrome" type="int"> + <int value="0" label="OPTOUT_BTOFF_LOCOFF_UNAUTH"/> + <int value="1" label="OPTOUT_BTOFF_LOCOFF_AUTH"/> + <int value="2" label="OPTOUT_BTOFF_LOCON_UNAUTH"/> + <int value="3" label="OPTOUT_BTOFF_LOCON_AUTH"/> + <int value="4" label="OPTOUT_BTON_LOCOFF_UNAUTH"/> + <int value="5" label="OPTOUT_BTON_LOCOFF_AUTH"/> + <int value="6" label="OPTOUT_BTON_LOCON_UNAUTH"/> + <int value="7" label="OPTOUT_BTON_LOCON_AUTH"/> + <int value="8" label="OPTIN_BTOFF_LOCOFF_UNAUTH"/> + <int value="9" label="OPTIN_BTOFF_LOCOFF_AUTH"/> + <int value="10" label="OPTIN_BTOFF_LOCON_UNAUTH"/> + <int value="11" label="OPTIN_BTOFF_LOCON_AUTH"/> + <int value="12" label="OPTIN_BTON_LOCOFF_UNAUTH"/> + <int value="13" label="OPTIN_BTON_LOCOFF_AUTH"/> + <int value="14" label="OPTIN_BTON_LOCON_UNAUTH"/> + <int value="15" label="OPTIN_BTON_LOCON_AUTH"/> + <int value="16" label="ONBOARDING_BTOFF_LOCOFF_UNAUTH"/> + <int value="17" label="ONBOARDING_BTOFF_LOCOFF_AUTH"/> + <int value="18" label="ONBOARDING_BTOFF_LOCON_UNAUTH"/> + <int value="19" label="ONBOARDING_BTOFF_LOCON_AUTH"/> + <int value="20" label="ONBOARDING_BTON_LOCOFF_UNAUTH"/> + <int value="21" label="ONBOARDING_BTON_LOCOFF_AUTH"/> + <int value="22" label="ONBOARDING_BTON_LOCON_UNAUTH"/> + <int value="23" label="ONBOARDING_BTON_LOCON_AUTH"/> +</enum> + <enum name="PhysicalWebPreferenceStatus" type="int"> <int value="0" label="OFF"/> <int value="1" label="ON"/> @@ -115943,6 +115993,16 @@ <affected-histogram name="Tabs.SwitchFromUserLatency"/> </histogram_suffixes> +<histogram_suffixes name="TaskSchedulerMayBlock" separator="."> + <suffix name="MayBlock" + label="Applies to tasks posted with MayBlock() or + WithBaseSyncPrimitives()."/> + <affected-histogram name="TaskScheduler.TaskLatency.BackgroundTaskPriority"/> + <affected-histogram + name="TaskScheduler.TaskLatency.UserBlockingTaskPriority"/> + <affected-histogram name="TaskScheduler.TaskLatency.UserVisibleTaskPriority"/> +</histogram_suffixes> + <histogram_suffixes name="TaskSchedulerTaskPriority" separator="."> <suffix name="BackgroundTaskPriority" label="Applies to tasks posted with a BACKGROUND priority."/> @@ -115950,10 +116010,27 @@ label="Applies to tasks posted with a USER_VISIBLE priority."/> <suffix name="UserBlockingTaskPriority" label="Applies to tasks posted with a USER_BLOCKING priority."/> - <affected-histogram name="TaskScheduler.TaskLatency.BackgroundFileIOPool"/> - <affected-histogram name="TaskScheduler.TaskLatency.BackgroundPool"/> - <affected-histogram name="TaskScheduler.TaskLatency.ForegroundFileIOPool"/> - <affected-histogram name="TaskScheduler.TaskLatency.ForegroundPool"/> + <affected-histogram name="TaskScheduler.TaskLatency"/> + <affected-histogram name="TaskScheduler.TaskLatency.BackgroundFileIOPool"> + <obsolete> + Deprecated 12/2016. Pool name removed from task latency histogram name. + </obsolete> + </affected-histogram> + <affected-histogram name="TaskScheduler.TaskLatency.BackgroundPool"> + <obsolete> + Deprecated 12/2016. Pool name removed from task latency histogram name. + </obsolete> + </affected-histogram> + <affected-histogram name="TaskScheduler.TaskLatency.ForegroundFileIOPool"> + <obsolete> + Deprecated 12/2016. Pool name removed from task latency histogram name. + </obsolete> + </affected-histogram> + <affected-histogram name="TaskScheduler.TaskLatency.ForegroundPool"> + <obsolete> + Deprecated 12/2016. Pool name removed from task latency histogram name. + </obsolete> + </affected-histogram> </histogram_suffixes> <histogram_suffixes name="TaskSchedulerWorkerPool" separator="."> @@ -115966,7 +116043,11 @@ <affected-histogram name="TaskScheduler.DetachDuration"/> <affected-histogram name="TaskScheduler.NumTasksBeforeDetach"/> <affected-histogram name="TaskScheduler.NumTasksBetweenWaits"/> - <affected-histogram name="TaskScheduler.TaskLatency"/> + <affected-histogram name="TaskScheduler.TaskLatency"> + <obsolete> + Deprecated 12/2016. Pool name removed from task latency histogram name. + </obsolete> + </affected-histogram> </histogram_suffixes> <histogram_suffixes name="ThreadWatcher" separator=".">
diff --git a/ui/events/blink/blink_features.cc b/ui/events/blink/blink_features.cc index 9c06c865..427ccf2 100644 --- a/ui/events/blink/blink_features.cc +++ b/ui/events/blink/blink_features.cc
@@ -11,4 +11,14 @@ const base::Feature kVsyncAlignedInputEvents{"VsyncAlignedInput", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kSendMouseLeaveEvents { + "SendMouseLeaveEvents", +// TODO(chaopeng) this fix only for chromeos now, should convert ET_MOUSE_EXITED +// to MouseLeave when crbug.com/450631 fixed. +#if defined(OS_CHROMEOS) + base::FEATURE_ENABLED_BY_DEFAULT +#else + base::FEATURE_DISABLED_BY_DEFAULT +#endif +}; }
diff --git a/ui/events/blink/blink_features.h b/ui/events/blink/blink_features.h index 5f1d848..3d1473d 100644 --- a/ui/events/blink/blink_features.h +++ b/ui/events/blink/blink_features.h
@@ -11,6 +11,11 @@ extern const base::Feature kVsyncAlignedInputEvents; +// This feature allows native ET_MOUSE_EXIT events to be passed +// through to blink as mouse leave events. Traditionally these events were +// converted to mouse move events due to a number of incosistencies on +// the native platforms. Enabled by default on ChromeOS. crbug.com/450631 +extern const base::Feature kSendMouseLeaveEvents; } #endif // UI_EVENTS_BLINK_BLINK_FEATURES_H_
diff --git a/ui/events/blink/web_input_event.cc b/ui/events/blink/web_input_event.cc index 10b13b5..3476f00 100644 --- a/ui/events/blink/web_input_event.cc +++ b/ui/events/blink/web_input_event.cc
@@ -6,6 +6,7 @@ #include "ui/events/base_event_utils.h" #include "ui/events/blink/blink_event_util.h" +#include "ui/events/blink/blink_features.h" #include "ui/events/event.h" #include "ui/events/event_utils.h" #include "ui/events/keycodes/dom/keycode_converter.h" @@ -385,13 +386,13 @@ type = blink::WebInputEvent::MouseUp; click_count = event.GetClickCount(); break; - case ET_MOUSE_EXITED: -// TODO(chaopeng) this fix only for chromeos now, should convert ET_MOUSE_EXITED -// to MouseLeave when crbug.com/450631 fixed. -#if defined(OS_CHROMEOS) - type = blink::WebInputEvent::MouseLeave; + case ET_MOUSE_EXITED: { + static bool s_send_leave = + base::FeatureList::IsEnabled(features::kSendMouseLeaveEvents); + type = s_send_leave ? blink::WebInputEvent::MouseLeave + : blink::WebInputEvent::MouseMove; break; -#endif + } case ET_MOUSE_ENTERED: case ET_MOUSE_MOVED: case ET_MOUSE_DRAGGED:
diff --git a/ui/gfx/canvas.cc b/ui/gfx/canvas.cc index 5f2bff97..6acf55a 100644 --- a/ui/gfx/canvas.cc +++ b/ui/gfx/canvas.cc
@@ -12,6 +12,7 @@ #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkRefCnt.h" +#include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/include/effects/SkGradientShader.h" #include "ui/gfx/font_list.h" #include "ui/gfx/geometry/insets_f.h" @@ -26,12 +27,25 @@ namespace gfx { +namespace { + +sk_sp<SkSurface> CreateSurface(const Size& size, bool is_opaque) { + // SkSurface cannot be zero-sized, but clients of Canvas sometimes request + // that (and then later resize). + int width = std::max(size.width(), 1); + int height = std::max(size.height(), 1); + SkAlphaType alpha = is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType; + SkImageInfo info = SkImageInfo::MakeN32(width, height, alpha); + return SkSurface::MakeRaster(info); +} + +} // namespace + Canvas::Canvas(const Size& size, float image_scale, bool is_opaque) : image_scale_(image_scale) { Size pixel_size = ScaleToCeiledSize(size, image_scale); - canvas_owner_ = skia::CreatePlatformCanvas(pixel_size.width(), - pixel_size.height(), is_opaque); - canvas_ = canvas_owner_.get(); + surface_ = CreateSurface(pixel_size, is_opaque); + canvas_ = surface_->getCanvas(); #if !defined(USE_CAIRO) // skia::PlatformCanvas instances are initialized to 0 by Cairo, but @@ -46,8 +60,8 @@ Canvas::Canvas() : image_scale_(1.f), - canvas_owner_(skia::CreatePlatformCanvas(0, 0, false)), - canvas_(canvas_owner_.get()) {} + surface_(CreateSurface({0, 0}, false)), + canvas_(surface_->getCanvas()) {} Canvas::Canvas(SkCanvas* canvas, float image_scale) : image_scale_(image_scale), canvas_(canvas) { @@ -62,9 +76,8 @@ bool is_opaque) { image_scale_ = image_scale; Size pixel_size = ScaleToFlooredSize(size, image_scale); - canvas_owner_ = skia::CreatePlatformCanvas(pixel_size.width(), - pixel_size.height(), is_opaque); - canvas_ = canvas_owner_.get(); + surface_ = CreateSurface(pixel_size, is_opaque); + canvas_ = surface_->getCanvas(); SkScalar scale_scalar = SkFloatToScalar(image_scale); canvas_->scale(scale_scalar, scale_scalar);
diff --git a/ui/gfx/canvas.h b/ui/gfx/canvas.h index adf1286..c81c0f25 100644 --- a/ui/gfx/canvas.h +++ b/ui/gfx/canvas.h
@@ -13,11 +13,11 @@ #include "base/macros.h" #include "base/strings/string16.h" #include "skia/ext/platform_canvas.h" -#include "third_party/skia/include/core/SkRefCnt.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkSurface.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/text_constants.h" - namespace gfx { class Rect; @@ -495,10 +495,10 @@ float image_scale_; // canvas_ is our active canvas object. Sometimes we are also the owner, - // in which case canvas_owner_ will be set. Other times we are just + // in which case surface_ will be set. Other times we are just // borrowing someone else's canvas, in which case canvas_ will point there - // but canvas_owner_ will be null. - std::unique_ptr<SkCanvas> canvas_owner_; + // but surface_ will be null. + sk_sp<SkSurface> surface_; SkCanvas* canvas_; DISALLOW_COPY_AND_ASSIGN(Canvas);
diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc index af86e79..24eaae3 100644 --- a/ui/native_theme/native_theme_win.cc +++ b/ui/native_theme/native_theme_win.cc
@@ -17,7 +17,6 @@ #include "base/win/scoped_select_object.h" #include "base/win/win_util.h" #include "base/win/windows_version.h" -#include "skia/ext/bitmap_platform_device.h" #include "skia/ext/platform_canvas.h" #include "skia/ext/skia_utils_win.h" #include "third_party/skia/include/core/SkCanvas.h"