diff --git a/ios/chrome/browser/ui/external_app/open_mail_handler_view_controller.h b/ios/chrome/browser/ui/external_app/open_mail_handler_view_controller.h
index 9b30541..19ed893 100644
--- a/ios/chrome/browser/ui/external_app/open_mail_handler_view_controller.h
+++ b/ios/chrome/browser/ui/external_app/open_mail_handler_view_controller.h
@@ -8,7 +8,7 @@
 #include "ios/chrome/browser/ui/collection_view/collection_view_controller.h"
 
 @class MailtoHandler;
-@class MailtoURLRewriter;
+@class MailtoHandlerManager;
 
 // Type of callback block when user selects a mailto:// handler.
 typedef void (^OpenMailtoHandlerSelectedHandler)(
@@ -18,12 +18,12 @@
 // to use to handle a tap on mailto:// URL.
 @interface OpenMailHandlerViewController : CollectionViewController
 
-// Initializes the view controller with the |rewriter| object which supplies
+// Initializes the view controller with the |manager| object which supplies
 // the list of supported apps that can handle a mailto:// URL. When the user
-// selects a mail client app, the |selectedCallback| block is called.
+// selects a mail client app, the |selectedHandler| block is called.
 - (nonnull instancetype)
-initWithRewriter:(nullable MailtoURLRewriter*)rewriter
- selectedHandler:(nullable OpenMailtoHandlerSelectedHandler)selectedHandler
+initWithManager:(nullable MailtoHandlerManager*)manager
+selectedHandler:(nullable OpenMailtoHandlerSelectedHandler)selectedHandler
     NS_DESIGNATED_INITIALIZER;
 
 - (nonnull instancetype)init NS_UNAVAILABLE;
diff --git a/ios/chrome/browser/ui/external_app/open_mail_handler_view_controller.mm b/ios/chrome/browser/ui/external_app/open_mail_handler_view_controller.mm
index da8bc032..f5014a9 100644
--- a/ios/chrome/browser/ui/external_app/open_mail_handler_view_controller.mm
+++ b/ios/chrome/browser/ui/external_app/open_mail_handler_view_controller.mm
@@ -14,7 +14,7 @@
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_cell.h"
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h"
 #import "ios/chrome/browser/web/mailto_handler.h"
-#import "ios/chrome/browser/web/mailto_url_rewriter.h"
+#import "ios/chrome/browser/web/mailto_handler_manager.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MDCPalettes.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
@@ -49,13 +49,13 @@
 }  // namespace
 
 @interface OpenMailHandlerViewController () {
-  // A rewriter object that can rewrite a mailto:// URL to one that can
+  // A manager object that can rewrite a mailto:// URL to one that can
   // launch a different mail client app.
-  MailtoURLRewriter* _rewriter;
+  MailtoHandlerManager* _manager;
   // Item with the UISwitch toggle for user to choose whether a mailto://
   // app selection should be remembered for future use.
   CollectionViewSwitchItem* _alwaysAskItem;
-  // An array of apps that can handle mailto:// URLs. The |rewriter| object
+  // An array of apps that can handle mailto:// URLs. The |_manager| object
   // lists all supported mailto:// handlers, but not all of them would be
   // installed.
   NSMutableArray<MailtoHandler*>* _availableHandlers;
@@ -71,13 +71,13 @@
 
 @implementation OpenMailHandlerViewController
 
-- (instancetype)initWithRewriter:(nullable MailtoURLRewriter*)rewriter
-                 selectedHandler:(nullable OpenMailtoHandlerSelectedHandler)
-                                     selectedHandler {
+- (instancetype)initWithManager:(nullable MailtoHandlerManager*)manager
+                selectedHandler:
+                    (nullable OpenMailtoHandlerSelectedHandler)selectedHandler {
   self = [super initWithLayout:[[MDCCollectionViewFlowLayout alloc] init]
                          style:CollectionViewControllerStyleDefault];
   if (self) {
-    _rewriter = rewriter;
+    _manager = manager;
     // This will be copied automatically by ARC.
     _selectedHandler = selectedHandler;
   }
@@ -115,7 +115,7 @@
   // Adds list of available mailto:// handler apps.
   [model addSectionWithIdentifier:SectionIdentifierApps];
   _availableHandlers = [NSMutableArray array];
-  for (MailtoHandler* handler in [_rewriter defaultHandlers]) {
+  for (MailtoHandler* handler in [_manager defaultHandlers]) {
     if ([handler isAvailable]) {
       [_availableHandlers addObject:handler];
       CollectionViewTextItem* item =
@@ -187,7 +187,7 @@
       DCHECK_LT(row, [_availableHandlers count]);
       MailtoHandler* handler = _availableHandlers[row];
       if (![_alwaysAskItem isOn])
-        [_rewriter setDefaultHandlerID:[handler appStoreID]];
+        [_manager setDefaultHandlerID:[handler appStoreID]];
       if (_selectedHandler)
         _selectedHandler(handler);
       [self.presentingViewController dismissViewControllerAnimated:YES
diff --git a/ios/chrome/browser/ui/external_app/open_mail_handler_view_controller_unittest.mm b/ios/chrome/browser/ui/external_app/open_mail_handler_view_controller_unittest.mm
index c985f0d..d9c2f1c 100644
--- a/ios/chrome/browser/ui/external_app/open_mail_handler_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/external_app/open_mail_handler_view_controller_unittest.mm
@@ -8,7 +8,7 @@
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item.h"
 #import "ios/chrome/browser/ui/collection_view/collection_view_controller_test.h"
 #import "ios/chrome/browser/web/mailto_handler.h"
-#import "ios/chrome/browser/web/mailto_url_rewriter.h"
+#import "ios/chrome/browser/web/mailto_handler_manager.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "testing/gtest_mac.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
@@ -22,8 +22,8 @@
  protected:
   CollectionViewController* InstantiateController() override {
     return [[OpenMailHandlerViewController alloc]
-        initWithRewriter:rewriter_
-         selectedHandler:selected_handler_];
+        initWithManager:manager_
+        selectedHandler:selected_handler_];
   }
 
   // Returns an OCMock object representing a MailtoHandler object with name
@@ -38,20 +38,20 @@
     return mail_app;
   }
 
-  MailtoURLRewriter* rewriter_;
+  MailtoHandlerManager* manager_;
   OpenMailtoHandlerSelectedHandler selected_handler_;
 };
 
 // Verifies the basic structure of the model.
 TEST_F(OpenMailHandlerViewControllerTest, TestModel) {
-  // Mock rewriter_ must be created before the controller.
-  id rewriter_mock = OCMClassMock([MailtoURLRewriter class]);
+  // Mock manager_ must be created before the controller.
+  id manager_mock = OCMClassMock([MailtoHandlerManager class]);
   NSArray* mail_apps = @[
     CreateMockApp(@"app1", @"111", YES), CreateMockApp(@"app2", @"222", NO),
     CreateMockApp(@"app3", @"333", YES)
   ];
-  OCMStub([rewriter_mock defaultHandlers]).andReturn(mail_apps);
-  rewriter_ = base::mac::ObjCCastStrict<MailtoURLRewriter>(rewriter_mock);
+  OCMStub([manager_mock defaultHandlers]).andReturn(mail_apps);
+  manager_ = base::mac::ObjCCastStrict<MailtoHandlerManager>(manager_mock);
   CreateController();
   CheckController();
 
@@ -70,13 +70,13 @@
 // Verifies that when the second row is selected, the callback is called with
 // the second mailto:// handler.
 TEST_F(OpenMailHandlerViewControllerTest, TestSelectionCallback) {
-  // Mock rewriter_ and callback block must be created before the controller.
-  id rewriter_mock = OCMClassMock([MailtoURLRewriter class]);
+  // Mock manager_ and callback block must be created before the controller.
+  id manager_mock = OCMClassMock([MailtoHandlerManager class]);
   NSArray* mailApps = @[
     CreateMockApp(@"app1", @"111", YES), CreateMockApp(@"app2", @"222", YES)
   ];
-  OCMStub([rewriter_mock defaultHandlers]).andReturn(mailApps);
-  rewriter_ = base::mac::ObjCCastStrict<MailtoURLRewriter>(rewriter_mock);
+  OCMStub([manager_mock defaultHandlers]).andReturn(mailApps);
+  manager_ = base::mac::ObjCCastStrict<MailtoHandlerManager>(manager_mock);
   __block BOOL handler_called = NO;
   selected_handler_ = ^(MailtoHandler* handler) {
     EXPECT_NSEQ(@"222", [handler appStoreID]);
@@ -97,17 +97,17 @@
 
 // Verifies that if the "always ask" toggle is turned OFF and a certain row
 // in the view controller is selected, the corresponding mailto:// handler
-// app is set as the default in |rewriter_|.
+// app is set as the default in |manager_|.
 TEST_F(OpenMailHandlerViewControllerTest, TestAlwaysAskToggle) {
-  // Mock rewriter_ must be created before the controller.
-  id rewriter_mock = OCMClassMock([MailtoURLRewriter class]);
+  // Mock manager_ must be created before the controller.
+  id manager_mock = OCMClassMock([MailtoHandlerManager class]);
   NSArray* mail_apps = @[
     CreateMockApp(@"app1", @"111", YES), CreateMockApp(@"app2", @"222", YES)
   ];
-  OCMStub([rewriter_mock defaultHandlers]).andReturn(mail_apps);
+  OCMStub([manager_mock defaultHandlers]).andReturn(mail_apps);
   // The second app will be selected for this test.
-  OCMExpect([rewriter_mock setDefaultHandlerID:@"222"]);
-  rewriter_ = base::mac::ObjCCastStrict<MailtoURLRewriter>(rewriter_mock);
+  OCMExpect([manager_mock setDefaultHandlerID:@"222"]);
+  manager_ = base::mac::ObjCCastStrict<MailtoHandlerManager>(manager_mock);
   CreateController();
 
   // Finds the UISwitch cell and toggle the switch to OFF.
@@ -127,5 +127,5 @@
       [NSIndexPath indexPathForRow:1 inSection:1];
   [test_view_controller collectionView:[test_view_controller collectionView]
               didSelectItemAtIndexPath:selected_index_path];
-  EXPECT_OCMOCK_VERIFY(rewriter_mock);
+  EXPECT_OCMOCK_VERIFY(manager_mock);
 }
diff --git a/ios/chrome/browser/ui/settings/compose_email_handler_collection_view_controller.h b/ios/chrome/browser/ui/settings/compose_email_handler_collection_view_controller.h
index 4fda87cf..e954962 100644
--- a/ios/chrome/browser/ui/settings/compose_email_handler_collection_view_controller.h
+++ b/ios/chrome/browser/ui/settings/compose_email_handler_collection_view_controller.h
@@ -7,7 +7,7 @@
 
 #import "ios/chrome/browser/ui/settings/settings_root_collection_view_controller.h"
 
-@class MailtoURLRewriter;
+@class MailtoHandlerManager;
 
 // UI for Compose Email settings to specify which installed Mail client app to
 // use for handling mailto: URLs. There must be at least 2 Mail client apps
@@ -16,7 +16,7 @@
 @interface ComposeEmailHandlerCollectionViewController
     : SettingsRootCollectionViewController
 
-- (instancetype)initWithRewriter:(MailtoURLRewriter*)rewriter
+- (instancetype)initWithManager:(MailtoHandlerManager*)manager
     NS_DESIGNATED_INITIALIZER;
 
 - (instancetype)initWithLayout:(UICollectionViewLayout*)layout
diff --git a/ios/chrome/browser/ui/settings/compose_email_handler_collection_view_controller.mm b/ios/chrome/browser/ui/settings/compose_email_handler_collection_view_controller.mm
index 57962364..24304bdb 100644
--- a/ios/chrome/browser/ui/settings/compose_email_handler_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/compose_email_handler_collection_view_controller.mm
@@ -8,7 +8,7 @@
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item.h"
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h"
 #import "ios/chrome/browser/web/mailto_handler.h"
-#import "ios/chrome/browser/web/mailto_url_rewriter.h"
+#import "ios/chrome/browser/web/mailto_handler_manager.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MDCPalettes.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -33,7 +33,9 @@
 }  // namespace
 
 @interface ComposeEmailHandlerCollectionViewController () {
-  MailtoURLRewriter* _rewriter;
+  // Object that manages a set of MailtoHandler objects which can handle
+  // mailto:// URLs.
+  MailtoHandlerManager* _manager;
   // When this switch is ON, the user wants to be prompted for which Mail
   // client app to use, so the list of available Mail client apps should be
   // disabled (grayed out).
@@ -57,12 +59,12 @@
 
 @implementation ComposeEmailHandlerCollectionViewController
 
-- (instancetype)initWithRewriter:(MailtoURLRewriter*)rewriter {
+- (instancetype)initWithManager:(MailtoHandlerManager*)manager {
   UICollectionViewLayout* layout = [[MDCCollectionViewFlowLayout alloc] init];
   self =
       [super initWithLayout:layout style:CollectionViewControllerStyleAppBar];
   if (self) {
-    _rewriter = rewriter;
+    _manager = manager;
   }
   return self;
 }
@@ -86,8 +88,8 @@
   [model addSectionWithIdentifier:SectionIdentifierMailtoHandlers];
 
   // Finds the default Mail client app.
-  NSArray<MailtoHandler*>* handlers = [_rewriter defaultHandlers];
-  NSString* currentHandlerID = [_rewriter defaultHandlerID];
+  NSArray<MailtoHandler*>* handlers = [_manager defaultHandlers];
+  NSString* currentHandlerID = [_manager defaultHandlerID];
 
   // Populates the toggle "Always Ask" toggle switch row first because the
   // state of of the Mail client apps selection list is dependent on the value
@@ -164,7 +166,7 @@
   // Sets the Mail client app that will handle mailto:// URLs.
   MailtoHandler* handler = [self handlerAtIndexPath:indexPath];
   DCHECK([handler isAvailable]);
-  [_rewriter setDefaultHandlerID:[handler appStoreID]];
+  [_manager setDefaultHandlerID:[handler appStoreID]];
 
   [self reconfigureCellsForItems:modifiedItems];
 }
@@ -202,14 +204,14 @@
 - (void)didToggleAlwaysAskSwitch:(id)sender {
   BOOL isOn = [sender isOn];
   [_alwaysAskItem setOn:isOn];
-  [_rewriter setDefaultHandlerID:nil];
+  [_manager setDefaultHandlerID:nil];
 
   // Clear all sections by iterating through the rows. Text color of each
   // row is changed to reflect whether selection is enabled.
   NSMutableArray* modifiedItems = [NSMutableArray array];
   NSArray<CollectionViewItem*>* itemsInSection = [self.collectionViewModel
       itemsInSectionWithIdentifier:SectionIdentifierMailtoHandlers];
-  NSArray<MailtoHandler*>* handlers = [_rewriter defaultHandlers];
+  NSArray<MailtoHandler*>* handlers = [_manager defaultHandlers];
   for (NSUInteger index = 0; index < [itemsInSection count]; ++index) {
     CollectionViewTextItem* textItem =
         base::mac::ObjCCastStrict<CollectionViewTextItem>(
@@ -242,7 +244,7 @@
   if (itemType != ItemTypeMailtoHandlers)
     return nil;
   NSUInteger handlerIndex = [model indexInItemTypeForIndexPath:indexPath];
-  return [[_rewriter defaultHandlers] objectAtIndex:handlerIndex];
+  return [[_manager defaultHandlers] objectAtIndex:handlerIndex];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/settings/compose_email_handler_collection_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/compose_email_handler_collection_view_controller_unittest.mm
index e1ec1c3..142942c 100644
--- a/ios/chrome/browser/ui/settings/compose_email_handler_collection_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/compose_email_handler_collection_view_controller_unittest.mm
@@ -9,8 +9,8 @@
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h"
 #import "ios/chrome/browser/ui/collection_view/collection_view_controller_test.h"
 #import "ios/chrome/browser/web/fake_mailto_handler_helpers.h"
+#import "ios/chrome/browser/web/mailto_handler_manager.h"
 #import "ios/chrome/browser/web/mailto_handler_system_mail.h"
-#import "ios/chrome/browser/web/nullable_mailto_url_rewriter.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MDCPalettes.h"
 #include "testing/gtest_mac.h"
@@ -19,8 +19,6 @@
 #error "This file requires ARC support."
 #endif
 
-#pragma mark - MailtoURLRewriter private interface for testing.
-
 #pragma mark - ComposeEmailHandlerCollectionViewControllerTest
 
 class ComposeEmailHandlerCollectionViewControllerTest
@@ -28,26 +26,25 @@
  protected:
   // Before CreateController() is called, set |handers_| and optionally
   // |default_handler_id_| ivars. They will be used to seed the construction of
-  // a MailtoURLRewriter which in turn used for the construction of the
+  // a MailtoHandlerManager which in turn used for the construction of the
   // CollectionViewController.
   CollectionViewController* InstantiateController() override {
-    rewriter_ =
-        [NullableMailtoURLRewriter mailtoURLRewriterWithStandardHandlers];
+    manager_ = [MailtoHandlerManager mailtoHandlerManagerWithStandardHandlers];
     // Clears the state so unit tests start from a known state.
     [[NSUserDefaults standardUserDefaults]
-        removeObjectForKey:[[rewriter_ class] userDefaultsKey]];
-    [rewriter_ setDefaultHandlers:handlers_];
+        removeObjectForKey:kMailtoHandlerManagerUserDefaultsKey];
+    [manager_ setDefaultHandlers:handlers_];
     if (default_handler_id_)
-      [rewriter_ setDefaultHandlerID:default_handler_id_];
+      [manager_ setDefaultHandlerID:default_handler_id_];
     return [[ComposeEmailHandlerCollectionViewController alloc]
-        initWithRewriter:rewriter_];
+        initWithManager:manager_];
   }
 
   // |handlers_| and |default_handler_id_| must be set before first call to
   // CreateController().
   NSArray<MailtoHandler*>* handlers_;
   NSString* default_handler_id_;
-  MailtoURLRewriter* rewriter_;
+  MailtoHandlerManager* manager_;
 };
 
 TEST_F(ComposeEmailHandlerCollectionViewControllerTest, TestConstructor) {
@@ -65,7 +62,7 @@
   ASSERT_EQ(2, NumberOfSections());
   // Array returned by -defaultHandlers is sorted by the name of the Mail app
   // and may not be in the same order as |handlers_|.
-  NSArray<MailtoHandler*>* handlers = [rewriter_ defaultHandlers];
+  NSArray<MailtoHandler*>* handlers = [manager_ defaultHandlers];
   int number_of_handlers = [handlers count];
   EXPECT_EQ(number_of_handlers, NumberOfItemsInSection(0));
   for (int index = 0; index < number_of_handlers; ++index) {
@@ -77,7 +74,7 @@
     // The enable/disable state of each Mail client app depends on the state
     // of the "Always Ask" toggle. All rows should be disabled if user has
     // not selected a default Mail client app.
-    BOOL is_enabled = [rewriter_ defaultHandlerID] != nil;
+    BOOL is_enabled = [manager_ defaultHandlerID] != nil;
     // Checks that text cells are displayed differently depending on the
     // availability of the handlers.
     UIColor* darkest_tint = [[MDCPalette greyPalette] tint900];
@@ -89,9 +86,9 @@
       EXPECT_EQ(UIAccessibilityTraitNotEnabled, item.accessibilityTraits);
     }
   }
-    bool is_on = [rewriter_ defaultHandlerID] == nil;
-    CheckSwitchCellStateAndTitleWithId(is_on, IDS_IOS_CHOOSE_EMAIL_ASK_TOGGLE,
-                                       1, 0);
+  bool is_on = [manager_ defaultHandlerID] == nil;
+  CheckSwitchCellStateAndTitleWithId(is_on, IDS_IOS_CHOOSE_EMAIL_ASK_TOGGLE, 1,
+                                     0);
 }
 
 TEST_F(ComposeEmailHandlerCollectionViewControllerTest, TestSelection) {
@@ -107,16 +104,16 @@
 
   // Have an observer to make sure that selecting in the UI causes the
   // observer to be called.
-  CountingMailtoURLRewriterObserver* observer =
-      [[CountingMailtoURLRewriterObserver alloc] init];
-  [rewriter_ setObserver:observer];
+  CountingMailtoHandlerManagerObserver* observer =
+      [[CountingMailtoHandlerManagerObserver alloc] init];
+  [manager_ setObserver:observer];
 
   // The array of |handlers| here is sorted for display and may not be in the
   // same order as |handlers_|. Finds another entry in the |handlers| that is
   // not currently selected and use that as the new selection. This test
   // must set up at least two handlers in |handlers_| which guarantees that
   // a new |selection| must be found, thus the DCHECK_GE.
-  NSArray<MailtoHandler*>* handlers = [rewriter_ defaultHandlers];
+  NSArray<MailtoHandler*>* handlers = [manager_ defaultHandlers];
   int selection = -1;
   int number_of_handlers = [handlers count];
   for (int index = 0; index < number_of_handlers; ++index) {
@@ -132,7 +129,7 @@
                                                   inSection:0]];
   // Verify that the observer has been called and new selection has been set.
   EXPECT_EQ(1, [observer changeCount]);
-  EXPECT_NSEQ([handlers[selection] appStoreID], [rewriter_ defaultHandlerID]);
+  EXPECT_NSEQ([handlers[selection] appStoreID], [manager_ defaultHandlerID]);
 }
 
 // Tests the state of the mailto:// handler apps and as the "Always ask"
@@ -167,7 +164,7 @@
   [switch_cell.switchView
       sendActionsForControlEvents:UIControlEventValueChanged];
   EXPECT_FALSE(switch_cell.switchView.on);
-  NSArray<MailtoHandler*>* handlers = [rewriter_ defaultHandlers];
+  NSArray<MailtoHandler*>* handlers = [manager_ defaultHandlers];
   UIColor* darkest_tint = [[MDCPalette greyPalette] tint900];
   for (NSUInteger index = 0U; index < [handlers count]; ++index) {
     CollectionViewTextItem* item = GetCollectionViewItem(0, index);
@@ -185,7 +182,7 @@
   [switch_cell.switchView
       sendActionsForControlEvents:UIControlEventValueChanged];
   EXPECT_TRUE(switch_cell.switchView.on);
-  handlers = [rewriter_ defaultHandlers];
+  handlers = [manager_ defaultHandlers];
   for (NSUInteger index = 0U; index < [handlers count]; ++index) {
     CollectionViewTextItem* item = GetCollectionViewItem(0, index);
     EXPECT_EQ(MDCCollectionViewCellAccessoryNone, item.accessoryType);
diff --git a/ios/chrome/browser/ui/settings/content_settings_collection_view_controller.h b/ios/chrome/browser/ui/settings/content_settings_collection_view_controller.h
index 26d96f5..636e3294 100644
--- a/ios/chrome/browser/ui/settings/content_settings_collection_view_controller.h
+++ b/ios/chrome/browser/ui/settings/content_settings_collection_view_controller.h
@@ -6,7 +6,7 @@
 #define IOS_CHROME_BROWSER_UI_SETTINGS_CONTENT_SETTINGS_COLLECTION_VIEW_CONTROLLER_H_
 
 #import "ios/chrome/browser/ui/settings/settings_root_collection_view_controller.h"
-#import "ios/chrome/browser/web/mailto_url_rewriter.h"
+#import "ios/chrome/browser/web/mailto_handler_manager.h"
 
 namespace ios {
 class ChromeBrowserState;
@@ -15,7 +15,7 @@
 // Controller for the UI that allows the user to change content settings like
 // blocking popups.
 @interface ContentSettingsCollectionViewController
-    : SettingsRootCollectionViewController<MailtoURLRewriterObserver>
+    : SettingsRootCollectionViewController<MailtoHandlerManagerObserver>
 
 // The designated initializer. |browserState| must not be nil.
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
diff --git a/ios/chrome/browser/ui/settings/content_settings_collection_view_controller.mm b/ios/chrome/browser/ui/settings/content_settings_collection_view_controller.mm
index e6195b4..fa734f5 100644
--- a/ios/chrome/browser/ui/settings/content_settings_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/content_settings_collection_view_controller.mm
@@ -23,7 +23,7 @@
 #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h"
 #import "ios/chrome/browser/ui/settings/translate_collection_view_controller.h"
 #import "ios/chrome/browser/ui/settings/utils/content_setting_backed_boolean.h"
-#import "ios/chrome/browser/web/nullable_mailto_url_rewriter.h"
+#import "ios/chrome/browser/web/mailto_handler_manager.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
@@ -60,7 +60,7 @@
 
   // This object contains the list of available Mail client apps that can
   // handle mailto: URLs.
-  MailtoURLRewriter* _mailtoURLRewriter;
+  MailtoHandlerManager* _mailtoHandlerManager;
 
   // Updatable Items
   CollectionViewDetailItem* _blockPopupsDetailItem;
@@ -106,9 +106,9 @@
                               inverted:YES];
     [_disablePopupsSetting setObserver:self];
 
-    _mailtoURLRewriter =
-        [NullableMailtoURLRewriter mailtoURLRewriterWithStandardHandlers];
-    [_mailtoURLRewriter setObserver:self];
+    _mailtoHandlerManager =
+        [MailtoHandlerManager mailtoHandlerManagerWithStandardHandlers];
+    [_mailtoHandlerManager setObserver:self];
 
     // TODO(crbug.com/764578): -loadModel should not be called from
     // initializer. A possible fix is to move this call to -viewDidLoad.
@@ -173,7 +173,8 @@
       initWithType:ItemTypeSettingsComposeEmail];
   _composeEmailDetailItem.text =
       l10n_util::GetNSString(IDS_IOS_COMPOSE_EMAIL_SETTING);
-  _composeEmailDetailItem.detailText = [_mailtoURLRewriter defaultHandlerName];
+  _composeEmailDetailItem.detailText =
+      [_mailtoHandlerManager defaultHandlerName];
   _composeEmailDetailItem.accessoryType =
       MDCCollectionViewCellAccessoryDisclosureIndicator;
   _composeEmailDetailItem.accessibilityTraits |= UIAccessibilityTraitButton;
@@ -212,7 +213,7 @@
     case ItemTypeSettingsComposeEmail: {
       UIViewController* controller =
           [[ComposeEmailHandlerCollectionViewController alloc]
-              initWithRewriter:_mailtoURLRewriter];
+              initWithManager:_mailtoHandlerManager];
       [self.navigationController pushViewController:controller animated:YES];
       break;
     }
@@ -246,12 +247,12 @@
   [self reconfigureCellsForItems:@[ _blockPopupsDetailItem ]];
 }
 
-#pragma mark - MailtoURLRewriterObserver
+#pragma mark - MailtoHandlerManagerObserver
 
-- (void)rewriterDidChange:(MailtoURLRewriter*)rewriter {
-  if (rewriter != _mailtoURLRewriter)
+- (void)handlerDidChangeForMailtoHandlerManager:(MailtoHandlerManager*)manager {
+  if (manager != _mailtoHandlerManager)
     return;
-  _composeEmailDetailItem.detailText = [rewriter defaultHandlerName];
+  _composeEmailDetailItem.detailText = [manager defaultHandlerName];
   [self reconfigureCellsForItems:@[ _composeEmailDetailItem ]];
 }
 
diff --git a/ios/chrome/browser/web/BUILD.gn b/ios/chrome/browser/web/BUILD.gn
index f71a8ec..8737fa5 100644
--- a/ios/chrome/browser/web/BUILD.gn
+++ b/ios/chrome/browser/web/BUILD.gn
@@ -17,16 +17,14 @@
     "mailto_handler_gmail.mm",
     "mailto_handler_inbox.h",
     "mailto_handler_inbox.mm",
+    "mailto_handler_manager.h",
+    "mailto_handler_manager.mm",
     "mailto_handler_system_mail.h",
     "mailto_handler_system_mail.mm",
-    "mailto_url_rewriter.h",
-    "mailto_url_rewriter.mm",
     "navigation_manager_util.h",
     "navigation_manager_util.mm",
     "network_activity_indicator_tab_helper.h",
     "network_activity_indicator_tab_helper.mm",
-    "nullable_mailto_url_rewriter.h",
-    "nullable_mailto_url_rewriter.mm",
     "page_placeholder_tab_helper.h",
     "page_placeholder_tab_helper.mm",
     "repost_form_tab_helper.h",
@@ -67,11 +65,11 @@
     "load_timing_tab_helper_unittest.mm",
     "mailto_handler_gmail_unittest.mm",
     "mailto_handler_inbox_unittest.mm",
+    "mailto_handler_manager_unittest.mm",
     "mailto_handler_system_mail_unittest.mm",
     "mailto_handler_unittest.mm",
     "navigation_manager_util_unittest.mm",
     "network_activity_indicator_tab_helper_unittest.mm",
-    "nullable_mailto_url_rewriter_unittest.mm",
     "page_placeholder_tab_helper_unittest.mm",
     "repost_form_tab_helper_unittest.mm",
     "sad_tab_tab_helper_unittest.mm",
diff --git a/ios/chrome/browser/web/external_app_launcher.mm b/ios/chrome/browser/web/external_app_launcher.mm
index 4407c53c..52f5964 100644
--- a/ios/chrome/browser/web/external_app_launcher.mm
+++ b/ios/chrome/browser/web/external_app_launcher.mm
@@ -15,8 +15,7 @@
 #import "ios/chrome/browser/ui/external_app/open_mail_handler_view_controller.h"
 #import "ios/chrome/browser/web/external_apps_launch_policy_decider.h"
 #import "ios/chrome/browser/web/mailto_handler.h"
-#import "ios/chrome/browser/web/mailto_url_rewriter.h"
-#import "ios/chrome/browser/web/nullable_mailto_url_rewriter.h"
+#import "ios/chrome/browser/web/mailto_handler_manager.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ios/third_party/material_components_ios/src/components/BottomSheet/src/MDCBottomSheetController.h"
 #import "net/base/mac/url_conversions.h"
@@ -99,7 +98,7 @@
 // Shows a prompt in Material Design for the user to choose which mail client
 // app to use to handle a mailto:// URL.
 - (void)promptForMailClientWithURL:(const GURL&)URL
-                       URLRewriter:(MailtoURLRewriter*)rewriter;
+              mailtoHandlerManager:(MailtoHandlerManager*)manager;
 // Presents an alert controller with |prompt| and |openLabel| as button label
 // on the root view controller before launching an external app identified by
 // |URL|.
@@ -151,14 +150,14 @@
 }
 
 - (void)promptForMailClientWithURL:(const GURL&)URL
-                       URLRewriter:(MailtoURLRewriter*)rewriter {
+              mailtoHandlerManager:(MailtoHandlerManager*)manager {
   GURL copiedURLToOpen = URL;
   OpenMailHandlerViewController* mailHandlerChooser =
       [[OpenMailHandlerViewController alloc]
-          initWithRewriter:rewriter
-           selectedHandler:^(MailtoHandler* _Nonnull handler) {
-             LaunchMailClientApp(copiedURLToOpen, handler);
-           }];
+          initWithManager:manager
+          selectedHandler:^(MailtoHandler* _Nonnull handler) {
+            LaunchMailClientApp(copiedURLToOpen, handler);
+          }];
   MDCBottomSheetController* bottomSheet = [[MDCBottomSheetController alloc]
       initWithContentViewController:mailHandlerChooser];
   [[[[UIApplication sharedApplication] keyWindow] rootViewController]
@@ -319,14 +318,14 @@
 
   // Replaces |URL| with a rewritten URL if it is of mailto: scheme.
   if (gURL.SchemeIs(url::kMailToScheme)) {
-    MailtoURLRewriter* rewriter =
-        [NullableMailtoURLRewriter mailtoURLRewriterWithStandardHandlers];
-    NSString* handlerID = [rewriter defaultHandlerID];
+    MailtoHandlerManager* manager =
+        [MailtoHandlerManager mailtoHandlerManagerWithStandardHandlers];
+    NSString* handlerID = [manager defaultHandlerID];
     if (!handlerID) {
-      [self promptForMailClientWithURL:gURL URLRewriter:rewriter];
+      [self promptForMailClientWithURL:gURL mailtoHandlerManager:manager];
       return YES;
     }
-    MailtoHandler* handler = [rewriter defaultHandlerByID:handlerID];
+    MailtoHandler* handler = [manager defaultHandlerByID:handlerID];
     LaunchMailClientApp(gURL, handler);
     return YES;
   }
diff --git a/ios/chrome/browser/web/fake_mailto_handler_helpers.h b/ios/chrome/browser/web/fake_mailto_handler_helpers.h
index 5816751e1..8f30cfe 100644
--- a/ios/chrome/browser/web/fake_mailto_handler_helpers.h
+++ b/ios/chrome/browser/web/fake_mailto_handler_helpers.h
@@ -7,7 +7,7 @@
 
 #import "ios/chrome/browser/web/mailto_handler.h"
 #import "ios/chrome/browser/web/mailto_handler_gmail.h"
-#import "ios/chrome/browser/web/mailto_url_rewriter.h"
+#import "ios/chrome/browser/web/mailto_handler_manager.h"
 
 // Test fixtures for faking MailtoHandlerGmail objects that reports whether
 // Gmail app as installed or not.
@@ -25,9 +25,9 @@
 @end
 
 // An observer object that counts and reports the number of times it has been
-// called by the MailtoURLRewriter object.
-@interface CountingMailtoURLRewriterObserver
-    : NSObject<MailtoURLRewriterObserver>
+// called by the MailtoHandlerManager object.
+@interface CountingMailtoHandlerManagerObserver
+    : NSObject<MailtoHandlerManagerObserver>
 // Returns the number of times that observer has been called.
 @property(nonatomic, readonly) int changeCount;
 @end
diff --git a/ios/chrome/browser/web/fake_mailto_handler_helpers.mm b/ios/chrome/browser/web/fake_mailto_handler_helpers.mm
index c87eee89..8c41695 100644
--- a/ios/chrome/browser/web/fake_mailto_handler_helpers.mm
+++ b/ios/chrome/browser/web/fake_mailto_handler_helpers.mm
@@ -32,9 +32,9 @@
 }
 @end
 
-@implementation CountingMailtoURLRewriterObserver
+@implementation CountingMailtoHandlerManagerObserver
 @synthesize changeCount = _changeCount;
-- (void)rewriterDidChange:(MailtoURLRewriter*)rewriter {
+- (void)handlerDidChangeForMailtoHandlerManager:(MailtoHandlerManager*)manager {
   ++_changeCount;
 }
 @end
diff --git a/ios/chrome/browser/web/mailto_handler.h b/ios/chrome/browser/web/mailto_handler.h
index cff1479..ada6dee 100644
--- a/ios/chrome/browser/web/mailto_handler.h
+++ b/ios/chrome/browser/web/mailto_handler.h
@@ -11,7 +11,7 @@
 
 // MailtoHandler is the base class for Mail client apps that can handle
 // mailto: URLs via custom URL schemes. To add support for Mail clients,
-// subclass from this and add it to MailtoURLRewriter class.
+// subclass from this and add it to MailtoHandlerManager class.
 @interface MailtoHandler : NSObject
 
 // Name of Mail client. This is a name that a user can recognize, e.g. @"Gmail".
diff --git a/ios/chrome/browser/web/mailto_handler_manager.h b/ios/chrome/browser/web/mailto_handler_manager.h
new file mode 100644
index 0000000..82089ff8
--- /dev/null
+++ b/ios/chrome/browser/web/mailto_handler_manager.h
@@ -0,0 +1,64 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_WEB_MAILTO_HANDLER_MANAGER_H_
+#define IOS_CHROME_BROWSER_WEB_MAILTO_HANDLER_MANAGER_H_
+
+#import <Foundation/Foundation.h>
+
+@class MailtoHandler;
+@class MailtoHandlerManager;
+class GURL;
+
+// Key to store selected mailto:// URL handler in NSUserDefaults. The value for
+// this key in NSUserDefaults is the default handler ID.
+extern NSString* const kMailtoHandlerManagerUserDefaultsKey;
+
+// Protocol that must be implemented by observers of MailtoHandlerManager
+// object.
+@protocol MailtoHandlerManagerObserver<NSObject>
+// The default mailto: handler has changed.
+- (void)handlerDidChangeForMailtoHandlerManager:(MailtoHandlerManager*)manager;
+@end
+
+// An object that manages the available Mail client apps. The currently selected
+// Mail client to handle mailto: URL is stored in a key in NSUserDefaults. If a
+// default has not been set in NSUserDefaults, nil may be returned from some of
+// the public APIs of MailtoHandlerManager.
+@interface MailtoHandlerManager : NSObject
+
+// The unique ID of the Mail client app that handles mailto: URL scheme.
+// This has a value of nil if default has not been set.
+@property(nonatomic, copy) NSString* defaultHandlerID;
+
+// Array of all the currently supported Mail client apps that claim to handle
+// mailto: URL scheme through their own custom defined URL schemes.
+@property(nonatomic, strong) NSArray<MailtoHandler*>* defaultHandlers;
+
+// Observer object that will be called when |defaultHandlerID| is changed.
+@property(nonatomic, weak) id<MailtoHandlerManagerObserver> observer;
+
+// Returns the ID as a string for the system-provided Mail client app.
++ (NSString*)systemMailApp;
+
+// Convenience method to return a new instance of this class initialized with
+// a standard set of MailtoHandlers.
++ (instancetype)mailtoHandlerManagerWithStandardHandlers;
+
+// Returns the name of the application that handles mailto: URLs. Returns nil
+// if a default has not been set.
+- (NSString*)defaultHandlerName;
+
+// Returns the mailto:// handler app corresponding to |handlerID|. Returns nil
+// if there is no handler corresponding to |handlerID|.
+- (MailtoHandler*)defaultHandlerByID:(NSString*)handlerID;
+
+// Rewrites |URL| into a new URL that can be "opened" to launch the Mail
+// client app. May return nil if |URL| is not a mailto: URL, a mail client
+// app has not been selected, or there are no Mail client app available.
+- (NSString*)rewriteMailtoURL:(const GURL&)URL;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_WEB_MAILTO_HANDLER_MANAGER_H_
diff --git a/ios/chrome/browser/web/nullable_mailto_url_rewriter.mm b/ios/chrome/browser/web/mailto_handler_manager.mm
similarity index 74%
rename from ios/chrome/browser/web/nullable_mailto_url_rewriter.mm
rename to ios/chrome/browser/web/mailto_handler_manager.mm
index a12bb6b..aa881bb 100644
--- a/ios/chrome/browser/web/nullable_mailto_url_rewriter.mm
+++ b/ios/chrome/browser/web/mailto_handler_manager.mm
@@ -2,11 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/chrome/browser/web/nullable_mailto_url_rewriter.h"
+#import "ios/chrome/browser/web/mailto_handler_manager.h"
 
 #import <UIKit/UIKit.h>
 
-#import "base/logging.h"
 #import "ios/chrome/browser/web/mailto_handler.h"
 #import "ios/chrome/browser/web/mailto_handler_gmail.h"
 #import "ios/chrome/browser/web/mailto_handler_inbox.h"
@@ -16,7 +15,10 @@
 #error "This file requires ARC support."
 #endif
 
-@interface NullableMailtoURLRewriter ()
+NSString* const kMailtoHandlerManagerUserDefaultsKey =
+    @"UserChosenDefaultMailApp";
+
+@interface MailtoHandlerManager ()
 
 // Dictionary keyed by the unique ID of the Mail client. The value is
 // the MailtoHandler object that can rewrite a mailto: URL.
@@ -25,23 +27,10 @@
 
 @end
 
-@implementation NullableMailtoURLRewriter
+@implementation MailtoHandlerManager
+@synthesize observer = _observer;
 @synthesize handlers = _handlers;
 
-+ (NSString*)userDefaultsKey {
-  // This key in NSUserDefaults stores the default handler ID stored.
-  return @"UserChosenDefaultMailApp";
-}
-
-+ (instancetype)mailtoURLRewriterWithStandardHandlers {
-  id result = [[NullableMailtoURLRewriter alloc] init];
-  [result setDefaultHandlers:@[
-    [[MailtoHandlerSystemMail alloc] init], [[MailtoHandlerGmail alloc] init],
-    [[MailtoHandlerInbox alloc] init]
-  ]];
-  return result;
-}
-
 - (instancetype)init {
   self = [super init];
   if (self) {
@@ -50,6 +39,21 @@
   return self;
 }
 
++ (NSString*)systemMailApp {
+  // This is the App Store ID for Apple Mail app.
+  // See https://itunes.apple.com/us/app/mail/id1108187098?mt=8
+  return @"1108187098";
+}
+
++ (instancetype)mailtoHandlerManagerWithStandardHandlers {
+  id result = [[MailtoHandlerManager alloc] init];
+  [result setDefaultHandlers:@[
+    [[MailtoHandlerSystemMail alloc] init], [[MailtoHandlerGmail alloc] init],
+    [[MailtoHandlerInbox alloc] init]
+  ]];
+  return result;
+}
+
 - (NSArray<MailtoHandler*>*)defaultHandlers {
   return [[_handlers allValues]
       sortedArrayUsingComparator:^NSComparisonResult(
@@ -66,7 +70,7 @@
 
 - (NSString*)defaultHandlerID {
   NSString* value = [[NSUserDefaults standardUserDefaults]
-      stringForKey:[[self class] userDefaultsKey]];
+      stringForKey:kMailtoHandlerManagerUserDefaultsKey];
   if (value) {
     if ([_handlers[value] isAvailable])
       return value;
@@ -85,15 +89,16 @@
 
 - (void)setDefaultHandlerID:(NSString*)appStoreID {
   NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
-  NSString* defaultsKey = [[self class] userDefaultsKey];
   if (appStoreID) {
-    if ([appStoreID isEqual:[defaults objectForKey:defaultsKey]])
+    NSString* handlerID =
+        [defaults objectForKey:kMailtoHandlerManagerUserDefaultsKey];
+    if ([appStoreID isEqual:handlerID])
       return;
-    [defaults setObject:appStoreID forKey:defaultsKey];
+    [defaults setObject:appStoreID forKey:kMailtoHandlerManagerUserDefaultsKey];
   } else {
-    [defaults removeObjectForKey:defaultsKey];
+    [defaults removeObjectForKey:kMailtoHandlerManagerUserDefaultsKey];
   }
-  [self.observer rewriterDidChange:self];
+  [self.observer handlerDidChangeForMailtoHandlerManager:self];
 }
 
 - (NSString*)defaultHandlerName {
diff --git a/ios/chrome/browser/web/mailto_handler_manager_unittest.mm b/ios/chrome/browser/web/mailto_handler_manager_unittest.mm
new file mode 100644
index 0000000..c832604
--- /dev/null
+++ b/ios/chrome/browser/web/mailto_handler_manager_unittest.mm
@@ -0,0 +1,124 @@
+// 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.
+
+#import "ios/chrome/browser/web/mailto_handler_manager.h"
+
+#import "ios/chrome/browser/web/fake_mailto_handler_helpers.h"
+#import "ios/chrome/browser/web/mailto_handler_system_mail.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+class MailtoHandlerManagerTest : public PlatformTest {
+ public:
+  MailtoHandlerManagerTest() {
+    [[NSUserDefaults standardUserDefaults]
+        removeObjectForKey:kMailtoHandlerManagerUserDefaultsKey];
+  }
+};
+
+// Tests that a new instance has expected properties and behaviors.
+TEST_F(MailtoHandlerManagerTest, TestStandardInstance) {
+  MailtoHandlerManager* manager =
+      [MailtoHandlerManager mailtoHandlerManagerWithStandardHandlers];
+  EXPECT_TRUE(manager);
+
+  NSArray<MailtoHandler*>* handlers = [manager defaultHandlers];
+  EXPECT_GE([handlers count], 1U);
+  for (MailtoHandler* handler in handlers) {
+    ASSERT_TRUE(handler);
+    NSString* appStoreID = [handler appStoreID];
+    NSString* expectedDefaultAppID = [handler isAvailable]
+                                         ? appStoreID
+                                         : [MailtoHandlerManager systemMailApp];
+    [manager setDefaultHandlerID:appStoreID];
+    EXPECT_NSEQ(expectedDefaultAppID, [manager defaultHandlerID]);
+    MailtoHandler* foundHandler = [manager defaultHandlerByID:appStoreID];
+    EXPECT_NSEQ(handler, foundHandler);
+  }
+}
+
+// If Gmail is not installed, rewriter defaults to system Mail app.
+TEST_F(MailtoHandlerManagerTest, TestNoGmailInstalled) {
+  MailtoHandlerManager* manager = [[MailtoHandlerManager alloc] init];
+  [manager setDefaultHandlers:@[
+    [[MailtoHandlerSystemMail alloc] init],
+    [[FakeMailtoHandlerGmailNotInstalled alloc] init]
+  ]];
+  EXPECT_NSEQ([MailtoHandlerManager systemMailApp], [manager defaultHandlerID]);
+}
+
+// If Gmail is installed but user has not made a choice, there is no default
+// mail app.
+TEST_F(MailtoHandlerManagerTest, TestWithGmailChoiceNotMade) {
+  MailtoHandlerManager* manager = [[MailtoHandlerManager alloc] init];
+  [manager setDefaultHandlers:@[
+    [[MailtoHandlerSystemMail alloc] init],
+    [[FakeMailtoHandlerGmailInstalled alloc] init]
+  ]];
+  EXPECT_FALSE([manager defaultHandlerID]);
+}
+
+// Tests that it is possible to unset the default handler.
+TEST_F(MailtoHandlerManagerTest, TestUnsetDefaultHandler) {
+  MailtoHandlerManager* manager = [[MailtoHandlerManager alloc] init];
+  MailtoHandler* gmailInstalled =
+      [[FakeMailtoHandlerGmailInstalled alloc] init];
+  MailtoHandler* systemMail = [[MailtoHandlerSystemMail alloc] init];
+  [manager setDefaultHandlers:@[ systemMail, gmailInstalled ]];
+  [manager setDefaultHandlerID:[systemMail appStoreID]];
+  EXPECT_NSEQ([systemMail appStoreID], [manager defaultHandlerID]);
+  [manager setDefaultHandlerID:nil];
+  EXPECT_FALSE([manager defaultHandlerID]);
+}
+
+// If Gmail was installed and user has made a choice, then Gmail is uninstalled.
+// The default returns to system Mail app.
+TEST_F(MailtoHandlerManagerTest, TestWithGmailUninstalled) {
+  MailtoHandlerManager* manager = [[MailtoHandlerManager alloc] init];
+  MailtoHandler* systemMailHandler = [[MailtoHandlerSystemMail alloc] init];
+  MailtoHandler* fakeGmailHandler =
+      [[FakeMailtoHandlerGmailInstalled alloc] init];
+  [manager setDefaultHandlers:@[ systemMailHandler, fakeGmailHandler ]];
+  [manager setDefaultHandlerID:[fakeGmailHandler appStoreID]];
+  EXPECT_NSEQ([fakeGmailHandler appStoreID], [manager defaultHandlerID]);
+
+  manager = [[MailtoHandlerManager alloc] init];
+  fakeGmailHandler = [[FakeMailtoHandlerGmailNotInstalled alloc] init];
+  [manager setDefaultHandlers:@[ systemMailHandler, fakeGmailHandler ]];
+  EXPECT_NSEQ([MailtoHandlerManager systemMailApp], [manager defaultHandlerID]);
+}
+
+// If Gmail is installed but system Mail app has been chosen by user as the
+// default mail handler app. Then Gmail is uninstalled. User's choice of system
+// Mail app remains unchanged and will persist through a re-installation of
+// Gmail.
+TEST_F(MailtoHandlerManagerTest, TestSystemMailAppChosenSurviveGmailUninstall) {
+  // Initial state of system Mail app explicitly chosen.
+  MailtoHandlerManager* manager = [[MailtoHandlerManager alloc] init];
+  MailtoHandler* systemMailHandler = [[MailtoHandlerSystemMail alloc] init];
+  [manager setDefaultHandlers:@[
+    systemMailHandler, [[FakeMailtoHandlerGmailInstalled alloc] init]
+  ]];
+  [manager setDefaultHandlerID:[systemMailHandler appStoreID]];
+  EXPECT_NSEQ([systemMailHandler appStoreID], [manager defaultHandlerID]);
+
+  // Gmail is installed.
+  manager = [[MailtoHandlerManager alloc] init];
+  [manager setDefaultHandlers:@[
+    systemMailHandler, [[FakeMailtoHandlerGmailNotInstalled alloc] init]
+  ]];
+  EXPECT_NSEQ([systemMailHandler appStoreID], [manager defaultHandlerID]);
+
+  // Gmail is installed again.
+  manager = [[MailtoHandlerManager alloc] init];
+  [manager setDefaultHandlers:@[
+    systemMailHandler, [[FakeMailtoHandlerGmailInstalled alloc] init]
+  ]];
+  EXPECT_NSEQ([systemMailHandler appStoreID], [manager defaultHandlerID]);
+}
diff --git a/ios/chrome/browser/web/mailto_handler_system_mail.mm b/ios/chrome/browser/web/mailto_handler_system_mail.mm
index 43b9f91..53098d0 100644
--- a/ios/chrome/browser/web/mailto_handler_system_mail.mm
+++ b/ios/chrome/browser/web/mailto_handler_system_mail.mm
@@ -5,7 +5,7 @@
 #import "ios/chrome/browser/web/mailto_handler_system_mail.h"
 
 #include "base/strings/sys_string_conversions.h"
-#import "ios/chrome/browser/web/mailto_url_rewriter.h"
+#import "ios/chrome/browser/web/mailto_handler_manager.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
@@ -18,7 +18,8 @@
 
 - (instancetype)init {
   NSString* name = l10n_util::GetNSString(IDS_IOS_SYSTEM_MAIL_APP);
-  self = [super initWithName:name appStoreID:[MailtoURLRewriter systemMailApp]];
+  self =
+      [super initWithName:name appStoreID:[MailtoHandlerManager systemMailApp]];
   return self;
 }
 
diff --git a/ios/chrome/browser/web/mailto_url_rewriter.h b/ios/chrome/browser/web/mailto_url_rewriter.h
deleted file mode 100644
index df2e903..0000000
--- a/ios/chrome/browser/web/mailto_url_rewriter.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_WEB_MAILTO_URL_REWRITER_H_
-#define IOS_CHROME_BROWSER_WEB_MAILTO_URL_REWRITER_H_
-
-#import <Foundation/Foundation.h>
-
-@class MailtoHandler;
-@class MailtoURLRewriter;
-class GURL;
-
-// Protocol that must be implemented by observers of MailtoURLRewriter object.
-@protocol MailtoURLRewriterObserver<NSObject>
-// The default mailto: handler has been changed.
-- (void)rewriterDidChange:(MailtoURLRewriter*)rewriter;
-@end
-
-// An abstract base class for objects that manage the available Mail client
-// apps. The currently selected Mail client to handle mailto: URL is available
-// through -defaultHandlerID property. If the corresponding app is no longer
-// installed, the system-provided Mail client app will be used.
-@interface MailtoURLRewriter : NSObject
-
-// The unique ID of the Mail client app that handles mailto: URL scheme.
-// This has a value of nil if default has not been set.
-@property(nonatomic, copy) NSString* defaultHandlerID;
-
-// Array of all the currently supported Mail client apps that claim to handle
-// mailto: URL scheme through their own custom defined URL schemes.
-@property(nonatomic, strong) NSArray<MailtoHandler*>* defaultHandlers;
-
-// Observer object that will be called when |defaultHandlerID| is changed.
-@property(nonatomic, weak) id<MailtoURLRewriterObserver> observer;
-
-// Returns the NSString* key to store state in NSUserDefaults.
-+ (NSString*)userDefaultsKey;
-
-// Returns the ID as a string for the system-provided Mail client app.
-+ (NSString*)systemMailApp;
-
-// Convenience method to return a new instance of this class initialized with
-// a standard set of MailtoHandlers.
-+ (instancetype)mailtoURLRewriterWithStandardHandlers;
-
-// Returns the name of the application that handles mailto: URLs. Returns nil
-// if a default has not been set.
-- (NSString*)defaultHandlerName;
-
-// Returns the mailto:// handler app corresponding to |handlerID|. Returns nil
-// if there is no handler corresponding to |handlerID|.
-- (MailtoHandler*)defaultHandlerByID:(NSString*)handlerID;
-
-// Rewrites |URL| into a new URL that can be "opened" to launch the Mail
-// client app. May return nil if |URL| is not a mailto: URL, a mail client
-// app has not been selected, or there are no Mail client app available.
-- (NSString*)rewriteMailtoURL:(const GURL&)URL;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_WEB_MAILTO_URL_REWRITER_H_
diff --git a/ios/chrome/browser/web/mailto_url_rewriter.mm b/ios/chrome/browser/web/mailto_url_rewriter.mm
deleted file mode 100644
index 523ab53..0000000
--- a/ios/chrome/browser/web/mailto_url_rewriter.mm
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/web/mailto_url_rewriter.h"
-
-#import "base/logging.h"
-#import "ios/chrome/browser/web/mailto_handler.h"
-#import "ios/chrome/browser/web/mailto_handler_gmail.h"
-#import "ios/chrome/browser/web/mailto_handler_system_mail.h"
-
-#import <UIKit/UIKit.h>
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@implementation MailtoURLRewriter
-@synthesize observer = _observer;
-@dynamic defaultHandlers;
-
-- (NSString*)defaultHandlerID {
-  NOTREACHED();
-  return nil;
-}
-
-- (void)setDefaultHandlerID:(NSString*)defaultHandlerID {
-  NOTREACHED();
-}
-
-+ (NSString*)userDefaultsKey {
-  return nil;
-}
-
-+ (NSString*)systemMailApp {
-  // This is the App Store ID for Apple Mail app.
-  // See https://itunes.apple.com/us/app/mail/id1108187098?mt=8
-  return @"1108187098";
-}
-
-+ (instancetype)mailtoURLRewriterWithStandardHandlers {
-  NOTREACHED();
-  return nil;
-}
-
-- (void)setDefaultHandlers:(NSArray<MailtoHandler*>*)defaultHandlers {
-  NOTREACHED();
-}
-
-- (NSArray<MailtoHandler*>*)defaultHandlers {
-  NOTREACHED();
-  return nil;
-}
-
-- (NSString*)defaultHandlerName {
-  NOTREACHED();
-  return nil;
-}
-
-- (MailtoHandler*)defaultHandlerByID:(NSString*)handlerID {
-  NOTREACHED();
-  return nil;
-}
-
-- (NSString*)rewriteMailtoURL:(const GURL&)gURL {
-  NOTREACHED();
-  return nil;
-}
-
-@end
diff --git a/ios/chrome/browser/web/nullable_mailto_url_rewriter.h b/ios/chrome/browser/web/nullable_mailto_url_rewriter.h
deleted file mode 100644
index 9f15241..0000000
--- a/ios/chrome/browser/web/nullable_mailto_url_rewriter.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_WEB_NULLABLE_MAILTO_URL_REWRITER_H_
-#define IOS_CHROME_BROWSER_WEB_NULLABLE_MAILTO_URL_REWRITER_H_
-
-#import "ios/chrome/browser/web/mailto_url_rewriter.h"
-
-// An object that manages the available Mail client apps. The currently selected
-// Mail client to handle mailto: URL is stored in a key in NSUserDefaults. If a
-// default has not been set in NSUserDefaults, nil may be returned from some of
-// the public APIs of MailtoURLRewriter.
-@interface NullableMailtoURLRewriter : MailtoURLRewriter
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_WEB_NULLABLE_MAILTO_URL_REWRITER_H_
diff --git a/ios/chrome/browser/web/nullable_mailto_url_rewriter_unittest.mm b/ios/chrome/browser/web/nullable_mailto_url_rewriter_unittest.mm
deleted file mode 100644
index 5ac83a3..0000000
--- a/ios/chrome/browser/web/nullable_mailto_url_rewriter_unittest.mm
+++ /dev/null
@@ -1,129 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/web/nullable_mailto_url_rewriter.h"
-
-#import "ios/chrome/browser/web/fake_mailto_handler_helpers.h"
-#import "ios/chrome/browser/web/mailto_handler_system_mail.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-class NullableMailtoURLRewriterTest : public PlatformTest {
- public:
-  NullableMailtoURLRewriterTest() {
-    [[NSUserDefaults standardUserDefaults]
-        removeObjectForKey:[NullableMailtoURLRewriter userDefaultsKey]];
-  }
-};
-
-// Tests that a new instance has expected properties and behaviors.
-TEST_F(NullableMailtoURLRewriterTest, TestStandardInstance) {
-  NullableMailtoURLRewriter* rewriter =
-      [NullableMailtoURLRewriter mailtoURLRewriterWithStandardHandlers];
-  EXPECT_TRUE(rewriter);
-
-  NSArray<MailtoHandler*>* handlers = [rewriter defaultHandlers];
-  EXPECT_GE([handlers count], 1U);
-  for (MailtoHandler* handler in handlers) {
-    ASSERT_TRUE(handler);
-    NSString* appStoreID = [handler appStoreID];
-    NSString* expectedDefaultAppID =
-        [handler isAvailable] ? appStoreID : [MailtoURLRewriter systemMailApp];
-    [rewriter setDefaultHandlerID:appStoreID];
-    EXPECT_NSEQ(expectedDefaultAppID, [rewriter defaultHandlerID]);
-    MailtoHandler* foundHandler = [rewriter defaultHandlerByID:appStoreID];
-    EXPECT_NSEQ(handler, foundHandler);
-  }
-}
-
-// If Gmail is not installed, rewriter defaults to system Mail app.
-TEST_F(NullableMailtoURLRewriterTest, TestNoGmailInstalled) {
-  NullableMailtoURLRewriter* rewriter =
-      [[NullableMailtoURLRewriter alloc] init];
-  [rewriter setDefaultHandlers:@[
-    [[MailtoHandlerSystemMail alloc] init],
-    [[FakeMailtoHandlerGmailNotInstalled alloc] init]
-  ]];
-  EXPECT_NSEQ([MailtoURLRewriter systemMailApp], [rewriter defaultHandlerID]);
-}
-
-// If Gmail is installed but user has not made a choice, there is no default
-// mail app.
-TEST_F(NullableMailtoURLRewriterTest, TestWithGmailChoiceNotMade) {
-  NullableMailtoURLRewriter* rewriter =
-      [[NullableMailtoURLRewriter alloc] init];
-  [rewriter setDefaultHandlers:@[
-    [[MailtoHandlerSystemMail alloc] init],
-    [[FakeMailtoHandlerGmailInstalled alloc] init]
-  ]];
-  EXPECT_FALSE([rewriter defaultHandlerID]);
-}
-
-// Tests that it is possible to unset the default handler.
-TEST_F(NullableMailtoURLRewriterTest, TestUnsetDefaultHandler) {
-  NullableMailtoURLRewriter* rewriter =
-      [[NullableMailtoURLRewriter alloc] init];
-  MailtoHandler* gmailInstalled =
-      [[FakeMailtoHandlerGmailInstalled alloc] init];
-  MailtoHandler* systemMail = [[MailtoHandlerSystemMail alloc] init];
-  [rewriter setDefaultHandlers:@[ systemMail, gmailInstalled ]];
-  [rewriter setDefaultHandlerID:[systemMail appStoreID]];
-  EXPECT_NSEQ([systemMail appStoreID], [rewriter defaultHandlerID]);
-  [rewriter setDefaultHandlerID:nil];
-  EXPECT_FALSE([rewriter defaultHandlerID]);
-}
-
-// If Gmail was installed and user has made a choice, then Gmail is uninstalled.
-// The default returns to system Mail app.
-TEST_F(NullableMailtoURLRewriterTest, TestWithGmailUninstalled) {
-  NullableMailtoURLRewriter* rewriter =
-      [[NullableMailtoURLRewriter alloc] init];
-  MailtoHandler* systemMailHandler = [[MailtoHandlerSystemMail alloc] init];
-  MailtoHandler* fakeGmailHandler =
-      [[FakeMailtoHandlerGmailInstalled alloc] init];
-  [rewriter setDefaultHandlers:@[ systemMailHandler, fakeGmailHandler ]];
-  [rewriter setDefaultHandlerID:[fakeGmailHandler appStoreID]];
-  EXPECT_NSEQ([fakeGmailHandler appStoreID], [rewriter defaultHandlerID]);
-
-  rewriter = [[NullableMailtoURLRewriter alloc] init];
-  fakeGmailHandler = [[FakeMailtoHandlerGmailNotInstalled alloc] init];
-  [rewriter setDefaultHandlers:@[ systemMailHandler, fakeGmailHandler ]];
-  EXPECT_NSEQ([MailtoURLRewriter systemMailApp], [rewriter defaultHandlerID]);
-}
-
-// If Gmail is installed but system Mail app has been chosen by user as the
-// default mail handler app. Then Gmail is uninstalled. User's choice of system
-// Mail app remains unchanged and will persist through a re-installation of
-// Gmail.
-TEST_F(NullableMailtoURLRewriterTest,
-       TestSystemMailAppChosenSurviveGmailUninstall) {
-  // Initial state of system Mail app explicitly chosen.
-  NullableMailtoURLRewriter* rewriter =
-      [[NullableMailtoURLRewriter alloc] init];
-  MailtoHandler* systemMailHandler = [[MailtoHandlerSystemMail alloc] init];
-  [rewriter setDefaultHandlers:@[
-    systemMailHandler, [[FakeMailtoHandlerGmailInstalled alloc] init]
-  ]];
-  [rewriter setDefaultHandlerID:[systemMailHandler appStoreID]];
-  EXPECT_NSEQ([systemMailHandler appStoreID], [rewriter defaultHandlerID]);
-
-  // Gmail is installed.
-  rewriter = [[NullableMailtoURLRewriter alloc] init];
-  [rewriter setDefaultHandlers:@[
-    systemMailHandler, [[FakeMailtoHandlerGmailNotInstalled alloc] init]
-  ]];
-  EXPECT_NSEQ([systemMailHandler appStoreID], [rewriter defaultHandlerID]);
-
-  // Gmail is installed again.
-  rewriter = [[NullableMailtoURLRewriter alloc] init];
-  [rewriter setDefaultHandlers:@[
-    systemMailHandler, [[FakeMailtoHandlerGmailInstalled alloc] init]
-  ]];
-  EXPECT_NSEQ([systemMailHandler appStoreID], [rewriter defaultHandlerID]);
-}
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index 498c19a..677fd441 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -496,90 +496,36 @@
   "Android Cronet Builder Asan": {
     "gtest_tests": [
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "cronet_sample_test_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "cronet_sample_test_apk"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "cronet_smoketests_missing_native_library_instrumentation_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "cronet_smoketests_missing_native_library_instrumentation_apk"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "cronet_smoketests_platform_only_instrumentation_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "cronet_smoketests_platform_only_instrumentation_apk"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "cronet_test_instrumentation_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "cronet_test_instrumentation_apk"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "cronet_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "cronet_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "net_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
@@ -845,30 +791,12 @@
   "Android Tests (trial)(dbg)": {
     "gtest_tests": [
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "blink_heap_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "blink_heap_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "blink_platform_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
@@ -903,326 +831,164 @@
   "Jelly Bean Tester": {
     "gtest_tests": [
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "android_webview_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "android_webview_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "base_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "base_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "breakpad_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "breakpad_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "capture_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "capture_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "cc_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "cc_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "components_browsertests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "components_browsertests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "components_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "components_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "content_browsertests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "content_browsertests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "content_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "content_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "device_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "device_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "events_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "events_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gfx_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "gfx_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gl_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "gl_tests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gl_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "gl_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gpu_ipc_service_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "gpu_ipc_service_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gpu_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "gpu_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ipc_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "ipc_tests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "latency_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "latency_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "media_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "media_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "net_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "net_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "sandbox_linux_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "sandbox_linux_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "sql_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "sql_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "storage_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "storage_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ui_android_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "ui_android_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ui_base_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "ui_base_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ui_touch_selection_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "ui_touch_selection_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "unit_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "unit_tests"
       }
@@ -1242,326 +1008,164 @@
   "Lollipop Consumer Tester": {
     "gtest_tests": [
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "android_webview_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "android_webview_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "base_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "base_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "breakpad_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "breakpad_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "capture_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "capture_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "cc_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "cc_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "components_browsertests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "components_browsertests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "components_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "components_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "content_browsertests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "content_browsertests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "content_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "content_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "device_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "device_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "events_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "events_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gfx_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "gfx_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gl_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "gl_tests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gl_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "gl_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gpu_ipc_service_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "gpu_ipc_service_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gpu_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "gpu_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ipc_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "ipc_tests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "latency_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "latency_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "media_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "media_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "net_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "net_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "sandbox_linux_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "sandbox_linux_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "sql_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "sql_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "storage_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "storage_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ui_android_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "ui_android_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ui_base_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "ui_base_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ui_touch_selection_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "ui_touch_selection_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "unit_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        "swarming": {
+          "can_use_on_swarming_builders": false
         },
         "test": "unit_tests"
       }
@@ -3621,6 +3225,16 @@
               "device_type": "marlin"
             }
           ],
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
           "shards": 5
         },
         "test": "chrome_public_test_apk"
@@ -3670,105 +3284,42 @@
   "Unswarmed N5 Tests Dummy Builder": {
     "gtest_tests": [
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "android_webview_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "android_webview_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "base_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "base_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "breakpad_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "breakpad_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "capture_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "capture_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "cc_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "cc_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "components_browsertests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "components_browsertests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "components_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
@@ -3779,135 +3330,54 @@
           "--shard-timeout",
           "600"
         ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "content_browsertests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "content_browsertests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "content_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "content_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "device_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "device_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "events_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "events_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gfx_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "gfx_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gl_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "gl_tests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gl_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "gl_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gpu_ipc_service_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "gpu_ipc_service_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gpu_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
@@ -3918,150 +3388,60 @@
           "--shard-timeout",
           "600"
         ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ipc_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "ipc_tests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "media_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "media_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "net_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "net_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "sandbox_linux_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "sandbox_linux_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "sql_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "sql_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "storage_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "storage_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ui_android_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "ui_android_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ui_base_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "ui_base_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ui_touch_selection_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "ui_touch_selection_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "unit_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
@@ -4092,105 +3472,42 @@
   "Unswarmed N5X Tests Dummy Builder": {
     "gtest_tests": [
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "android_webview_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "android_webview_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "base_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "base_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "breakpad_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "breakpad_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "capture_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "capture_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "cc_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "cc_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "components_browsertests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "components_browsertests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "components_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
@@ -4201,135 +3518,54 @@
           "--shard-timeout",
           "600"
         ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "content_browsertests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "content_browsertests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "content_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "content_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "device_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "device_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "events_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "events_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gfx_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "gfx_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gl_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "gl_tests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gl_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "gl_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gpu_ipc_service_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "gpu_ipc_service_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gpu_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
@@ -4340,150 +3576,60 @@
           "--shard-timeout",
           "600"
         ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ipc_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "ipc_tests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "media_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "media_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "net_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "net_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "sandbox_linux_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "sandbox_linux_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "sql_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "sql_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "storage_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "storage_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ui_android_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "ui_android_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ui_base_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "ui_base_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ui_touch_selection_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
         "test": "ui_touch_selection_unittests"
       },
       {
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "unit_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
         "swarming": {
           "can_use_on_swarming_builders": false
         },
@@ -6184,8 +5330,7 @@
               "device_type": "gce_x86"
             }
           ],
-          "hard_timeout": 960,
-          "shards": 1
+          "hard_timeout": 960
         }
       }
     ]
diff --git a/third_party/WebKit/Source/bindings/modules/v8/generated.gni b/third_party/WebKit/Source/bindings/modules/v8/generated.gni
index 356d873e8..358ce4f 100644
--- a/third_party/WebKit/Source/bindings/modules/v8/generated.gni
+++ b/third_party/WebKit/Source/bindings/modules/v8/generated.gni
@@ -79,18 +79,22 @@
 ]
 
 generated_modules_callback_function_files = [
+  "$bindings_modules_v8_output_dir/v8_database_callback.cc",
+  "$bindings_modules_v8_output_dir/v8_database_callback.h",
   "$bindings_modules_v8_output_dir/v8_decode_error_callback.cc",
   "$bindings_modules_v8_output_dir/v8_decode_error_callback.h",
   "$bindings_modules_v8_output_dir/v8_decode_success_callback.cc",
   "$bindings_modules_v8_output_dir/v8_decode_success_callback.h",
-  "$bindings_modules_v8_output_dir/v8_database_callback.cc",
-  "$bindings_modules_v8_output_dir/v8_database_callback.h",
   "$bindings_modules_v8_output_dir/v8_idb_observer_callback.cc",
   "$bindings_modules_v8_output_dir/v8_idb_observer_callback.h",
   "$bindings_modules_v8_output_dir/v8_lock_granted_callback.cc",
   "$bindings_modules_v8_output_dir/v8_lock_granted_callback.h",
   "$bindings_modules_v8_output_dir/v8_media_session_action_handler.cc",
   "$bindings_modules_v8_output_dir/v8_media_session_action_handler.h",
+  "$bindings_modules_v8_output_dir/v8_navigator_user_media_error_callback.cc",
+  "$bindings_modules_v8_output_dir/v8_navigator_user_media_error_callback.h",
+  "$bindings_modules_v8_output_dir/v8_navigator_user_media_success_callback.cc",
+  "$bindings_modules_v8_output_dir/v8_navigator_user_media_success_callback.h",
   "$bindings_modules_v8_output_dir/v8_position_callback.cc",
   "$bindings_modules_v8_output_dir/v8_position_callback.h",
   "$bindings_modules_v8_output_dir/v8_position_error_callback.cc",
diff --git a/third_party/WebKit/Source/bindings/scripts/code_generator_v8.py b/third_party/WebKit/Source/bindings/scripts/code_generator_v8.py
index c971aa9..0f3a7d5 100644
--- a/third_party/WebKit/Source/bindings/scripts/code_generator_v8.py
+++ b/third_party/WebKit/Source/bindings/scripts/code_generator_v8.py
@@ -383,6 +383,14 @@
             template_context['exported'] = self.info_provider.specifier_for_export
             template_context['header_includes'].append(
                 self.info_provider.include_path_for_export)
+
+        # TODO(bashi): Dependency resolution shouldn't happen here.
+        # Move this into includes_for_type() families.
+        for argument in callback_function.arguments:
+            if argument.idl_type.is_union_type:
+                template_context['header_includes'].append(
+                    self.info_provider.include_path_for_union_types(argument.idl_type))
+
         template_context['header_includes'] = normalize_and_sort_includes(
             template_context['header_includes'], self.snake_case_generated_files)
         template_context['cpp_includes'] = normalize_and_sort_includes(
diff --git a/third_party/WebKit/Source/core/dom/DocumentTest.cpp b/third_party/WebKit/Source/core/dom/DocumentTest.cpp
index de222472..590b602 100644
--- a/third_party/WebKit/Source/core/dom/DocumentTest.cpp
+++ b/third_party/WebKit/Source/core/dom/DocumentTest.cpp
@@ -513,16 +513,14 @@
 }
 
 TEST_F(DocumentTest, OutgoingReferrer) {
-  GetDocument().SetURL(
-      KURL(NullURL(), "https://www.example.com/hoge#fuga?piyo"));
+  GetDocument().SetURL(KURL("https://www.example.com/hoge#fuga?piyo"));
   GetDocument().SetSecurityOrigin(
-      SecurityOrigin::Create(KURL(NullURL(), "https://www.example.com/")));
+      SecurityOrigin::Create(KURL("https://www.example.com/")));
   EXPECT_EQ("https://www.example.com/hoge", GetDocument().OutgoingReferrer());
 }
 
 TEST_F(DocumentTest, OutgoingReferrerWithUniqueOrigin) {
-  GetDocument().SetURL(
-      KURL(NullURL(), "https://www.example.com/hoge#fuga?piyo"));
+  GetDocument().SetURL(KURL("https://www.example.com/hoge#fuga?piyo"));
   GetDocument().SetSecurityOrigin(SecurityOrigin::CreateUnique());
   EXPECT_EQ(String(), GetDocument().OutgoingReferrer());
 }
@@ -831,13 +829,13 @@
   GetDocument().SetSecurityOrigin(origin);
   SandboxFlags mask = kSandboxOrigin;
   GetDocument().EnforceSandboxFlags(mask);
-  GetDocument().SetURL(KURL(NullURL(), "https://test.com/foobar/document"));
+  GetDocument().SetURL(KURL("https://test.com/foobar/document"));
 
   ApplicationCacheHost* appcache_host =
       GetDocument().Loader()->GetApplicationCacheHost();
   appcache_host->host_ = std::make_unique<MockWebApplicationCacheHost>();
   appcache_host->SelectCacheWithManifest(
-      KURL(NullURL(), "https://test.com/foobar/manifest"));
+      KURL("https://test.com/foobar/manifest"));
   MockWebApplicationCacheHost* mock_web_host =
       static_cast<MockWebApplicationCacheHost*>(appcache_host->host_.get());
   EXPECT_FALSE(mock_web_host->with_manifest_was_called_);
@@ -852,13 +850,13 @@
   suborigin.SetName("foobar");
   origin->AddSuborigin(suborigin);
   GetDocument().SetSecurityOrigin(origin);
-  GetDocument().SetURL(KURL(NullURL(), "https://test.com/foobar/document"));
+  GetDocument().SetURL(KURL("https://test.com/foobar/document"));
 
   ApplicationCacheHost* appcache_host =
       GetDocument().Loader()->GetApplicationCacheHost();
   appcache_host->host_ = std::make_unique<MockWebApplicationCacheHost>();
   appcache_host->SelectCacheWithManifest(
-      KURL(NullURL(), "https://test.com/foobar/manifest"));
+      KURL("https://test.com/foobar/manifest"));
   MockWebApplicationCacheHost* mock_web_host =
       static_cast<MockWebApplicationCacheHost*>(appcache_host->host_.get());
   EXPECT_FALSE(mock_web_host->with_manifest_was_called_);
diff --git a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
index c357881..44bbfc8 100644
--- a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
@@ -1649,6 +1649,7 @@
   visitor->TraceWrappers(modulator_);
   visitor->TraceWrappers(navigator_);
   DOMWindow::TraceWrappers(visitor);
+  Supplementable<LocalDOMWindow>::TraceWrappers(visitor);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/PerformanceMonitorTest.cpp b/third_party/WebKit/Source/core/frame/PerformanceMonitorTest.cpp
index bab39ab..0e43a53 100644
--- a/third_party/WebKit/Source/core/frame/PerformanceMonitorTest.cpp
+++ b/third_party/WebKit/Source/core/frame/PerformanceMonitorTest.cpp
@@ -69,14 +69,12 @@
 
 void PerformanceMonitorTest::SetUp() {
   page_holder_ = DummyPageHolder::Create(IntSize(800, 600));
-  page_holder_->GetDocument().SetURL(
-      KURL(NullURL(), "https://example.com/foo"));
+  page_holder_->GetDocument().SetURL(KURL("https://example.com/foo"));
   monitor_ = new PerformanceMonitor(GetFrame());
 
   // Create another dummy page holder and pretend this is the iframe.
   another_page_holder_ = DummyPageHolder::Create(IntSize(400, 300));
-  another_page_holder_->GetDocument().SetURL(
-      KURL(NullURL(), "https://iframed.com/bar"));
+  another_page_holder_->GetDocument().SetURL(KURL("https://iframed.com/bar"));
 }
 
 void PerformanceMonitorTest::TearDown() {
diff --git a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveListTest.cpp b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveListTest.cpp
index 054a7b7..be4e6b24 100644
--- a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveListTest.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveListTest.cpp
@@ -161,7 +161,7 @@
   for (const auto& test : cases) {
     SCOPED_TRACE(::testing::Message()
                  << "List: `" << test.list << "`, URL: `" << test.url << "`");
-    KURL script_src = KURL(NullURL(), test.url);
+    const KURL script_src(test.url);
 
     // Report-only
     Member<CSPDirectiveList> directive_list =
@@ -217,7 +217,7 @@
   for (const auto& test : cases) {
     SCOPED_TRACE(::testing::Message()
                  << "List: `" << test.list << "`, URL: `" << test.url << "`");
-    KURL resource = KURL(NullURL(), test.url);
+    const KURL resource(test.url);
 
     // Report-only 'script-src'
     Member<CSPDirectiveList> directive_list =
@@ -355,7 +355,7 @@
     SCOPED_TRACE(::testing::Message()
                  << "List: `" << test.list << "`, URL: `" << test.url
                  << "`, Integrity: `" << test.integrity << "`");
-    KURL resource = KURL(NullURL(), test.url);
+    const KURL resource(test.url);
 
     IntegrityMetadataSet integrity_metadata;
     ASSERT_EQ(SubresourceIntegrity::kIntegrityParseValidResult,
@@ -487,7 +487,7 @@
   };
 
   for (const auto& test : cases) {
-    KURL resource = KURL(NullURL(), test.url);
+    const KURL resource(test.url);
     // Report-only
     Member<CSPDirectiveList> directive_list =
         CreateList(test.list, kContentSecurityPolicyHeaderTypeReport);
@@ -542,7 +542,7 @@
 
   for (const auto& test : cases) {
     SCOPED_TRACE(test.list);
-    KURL resource = KURL(NullURL(), "https://example.test/worker.js");
+    const KURL resource("https://example.test/worker.js");
     Member<CSPDirectiveList> directive_list =
         CreateList(test.list, kContentSecurityPolicyHeaderTypeEnforce);
     EXPECT_EQ(test.allowed,
@@ -587,7 +587,7 @@
 
   for (const auto& test : cases) {
     SCOPED_TRACE(test.list);
-    KURL resource = KURL(NullURL(), "https://example.test/worker.js");
+    const KURL resource("https://example.test/worker.js");
     Member<CSPDirectiveList> directive_list =
         CreateList(test.list, kContentSecurityPolicyHeaderTypeEnforce);
     EXPECT_EQ(test.allowed,
diff --git a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicyTest.cpp b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicyTest.cpp
index 2c32d2cf..b2db626 100644
--- a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicyTest.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicyTest.cpp
@@ -129,8 +129,8 @@
                         kContentSecurityPolicyHeaderTypeReport,
                         kContentSecurityPolicyHeaderSourceHTTP);
 
-  KURL example_url(NullURL(), "http://example.com");
-  KURL not_example_url(NullURL(), "http://not-example.com");
+  const KURL example_url("http://example.com");
+  const KURL not_example_url("http://not-example.com");
 
   ContentSecurityPolicy* csp2 = ContentSecurityPolicy::Create();
   csp2->CopyStateFrom(csp.Get());
@@ -163,8 +163,8 @@
                         kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceHTTP);
 
-  KURL example_url(NullURL(), "http://example.com");
-  KURL not_example_url(NullURL(), "http://not-example.com");
+  const KURL example_url("http://example.com");
+  const KURL not_example_url("http://not-example.com");
 
   ContentSecurityPolicy* csp2 = ContentSecurityPolicy::Create();
   csp2->CopyPluginTypesFrom(csp.Get());
@@ -251,7 +251,7 @@
 // plugin, but not to subresource requests that the plugin itself
 // makes. https://crbug.com/603952
 TEST_F(ContentSecurityPolicyTest, ObjectSrc) {
-  KURL url(NullURL(), "https://example.test");
+  const KURL url("https://example.test");
   csp->BindToExecutionContext(execution_context.Get());
   csp->DidReceiveHeader("object-src 'none';",
                         kContentSecurityPolicyHeaderTypeEnforce,
@@ -274,7 +274,7 @@
 }
 
 TEST_F(ContentSecurityPolicyTest, ConnectSrc) {
-  KURL url(NullURL(), "https://example.test");
+  const KURL url("https://example.test");
   csp->BindToExecutionContext(execution_context.Get());
   csp->DidReceiveHeader("connect-src 'none';",
                         kContentSecurityPolicyHeaderTypeEnforce,
@@ -308,7 +308,7 @@
 // Tests that requests for scripts and styles are blocked
 // if `require-sri-for` delivered in HTTP header requires integrity be present
 TEST_F(ContentSecurityPolicyTest, RequireSRIForInHeaderMissingIntegrity) {
-  KURL url(NullURL(), "https://example.test");
+  const KURL url("https://example.test");
   // Enforce
   Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
   policy->BindToExecutionContext(execution_context.Get());
@@ -396,7 +396,7 @@
 // Tests that requests for scripts and styles are allowed
 // if `require-sri-for` delivered in HTTP header requires integrity be present
 TEST_F(ContentSecurityPolicyTest, RequireSRIForInHeaderPresentIntegrity) {
-  KURL url(NullURL(), "https://example.test");
+  const KURL url("https://example.test");
   IntegrityMetadataSet integrity_metadata;
   integrity_metadata.insert(
       IntegrityMetadata("1234", IntegrityAlgorithm::kSha384).ToPair());
@@ -479,7 +479,7 @@
 // Tests that requests for scripts and styles are blocked
 // if `require-sri-for` delivered in meta tag requires integrity be present
 TEST_F(ContentSecurityPolicyTest, RequireSRIForInMetaMissingIntegrity) {
-  KURL url(NullURL(), "https://example.test");
+  const KURL url("https://example.test");
   // Enforce
   Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
   policy->BindToExecutionContext(execution_context.Get());
@@ -568,7 +568,7 @@
 // Tests that requests for scripts and styles are allowed
 // if `require-sri-for` delivered meta tag requires integrity be present
 TEST_F(ContentSecurityPolicyTest, RequireSRIForInMetaPresentIntegrity) {
-  KURL url(NullURL(), "https://example.test");
+  const KURL url("https://example.test");
   IntegrityMetadataSet integrity_metadata;
   integrity_metadata.insert(
       IntegrityMetadata("1234", IntegrityAlgorithm::kSha384).ToPair());
@@ -669,7 +669,7 @@
     SCOPED_TRACE(::testing::Message()
                  << "Policy: `" << test.policy << "`, URL: `" << test.url
                  << "`, Nonce: `" << test.nonce << "`");
-    KURL resource = KURL(NullURL(), test.url);
+    const KURL resource(test.url);
 
     unsigned expected_reports = test.allowed ? 0u : 1u;
 
@@ -832,7 +832,7 @@
     SCOPED_TRACE(::testing::Message() << "Policy: `" << test.policy1 << "`/`"
                                       << test.policy2 << "`, URL: `" << test.url
                                       << "`, Nonce: `" << test.nonce << "`");
-    KURL resource = KURL(NullURL(), test.url);
+    const KURL resource(test.url);
 
     unsigned expected_reports =
         test.allowed1 != test.allowed2 ? 1u : (test.allowed1 ? 0u : 2u);
@@ -1050,7 +1050,7 @@
 }
 
 TEST_F(ContentSecurityPolicyTest, RequestsAllowedWhenBypassingCSP) {
-  KURL base;
+  const KURL base;
   execution_context = CreateExecutionContext();
   execution_context->SetSecurityOrigin(secure_origin);  // https://example.com
   execution_context->SetURL(secure_url);                // https://example.com
@@ -1090,7 +1090,7 @@
       "https");
 }
 TEST_F(ContentSecurityPolicyTest, FilesystemAllowedWhenBypassingCSP) {
-  KURL base;
+  const KURL base;
   execution_context = CreateExecutionContext();
   execution_context->SetSecurityOrigin(secure_origin);  // https://example.com
   execution_context->SetURL(secure_url);                // https://example.com
@@ -1135,7 +1135,7 @@
 }
 
 TEST_F(ContentSecurityPolicyTest, BlobAllowedWhenBypassingCSP) {
-  KURL base;
+  const KURL base;
   execution_context = CreateExecutionContext();
   execution_context->SetSecurityOrigin(secure_origin);  // https://example.com
   execution_context->SetURL(secure_url);                // https://example.com
diff --git a/third_party/WebKit/Source/core/html/HTMLFrameElementTest.cpp b/third_party/WebKit/Source/core/html/HTMLFrameElementTest.cpp
index 837052ca..65f459f 100644
--- a/third_party/WebKit/Source/core/html/HTMLFrameElementTest.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLFrameElementTest.cpp
@@ -16,7 +16,7 @@
 // fullscreen feature should be unconditionally disabled.
 TEST_F(HTMLFrameElementTest, DefaultContainerPolicy) {
   Document* document = Document::CreateForTest();
-  KURL document_url = KURL(NullURL(), "http://example.com");
+  const KURL document_url("http://example.com");
   document->SetURL(document_url);
   document->UpdateSecurityOrigin(SecurityOrigin::Create(document_url));
 
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElementTest.cpp b/third_party/WebKit/Source/core/html/HTMLIFrameElementTest.cpp
index 152b0b5d..920708b 100644
--- a/third_party/WebKit/Source/core/html/HTMLIFrameElementTest.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLIFrameElementTest.cpp
@@ -23,7 +23,7 @@
 // and that frames which should inherit their parent document's origin do so.
 TEST_F(HTMLIFrameElementTest, FramesUseCorrectOrigin) {
   Document* document = Document::CreateForTest();
-  KURL document_url = KURL(NullURL(), "http://example.com");
+  const KURL document_url("http://example.com");
   document->SetURL(document_url);
   document->UpdateSecurityOrigin(SecurityOrigin::Create(document_url));
 
@@ -53,7 +53,7 @@
 // sandboxed iframe.
 TEST_F(HTMLIFrameElementTest, SandboxFramesUseCorrectOrigin) {
   Document* document = Document::CreateForTest();
-  KURL document_url = KURL(NullURL(), "http://example.com");
+  const KURL document_url("http://example.com");
   document->SetURL(document_url);
   document->UpdateSecurityOrigin(SecurityOrigin::Create(document_url));
 
@@ -78,7 +78,7 @@
 // parent document's origin for the container policy.
 TEST_F(HTMLIFrameElementTest, SameOriginSandboxFramesUseCorrectOrigin) {
   Document* document = Document::CreateForTest();
-  KURL document_url = KURL(NullURL(), "http://example.com");
+  const KURL document_url("http://example.com");
   document->SetURL(document_url);
   document->UpdateSecurityOrigin(SecurityOrigin::Create(document_url));
 
@@ -97,7 +97,7 @@
 // container policy in a srcdoc iframe.
 TEST_F(HTMLIFrameElementTest, SrcdocFramesUseCorrectOrigin) {
   Document* document = Document::CreateForTest();
-  KURL document_url = KURL(NullURL(), "http://example.com");
+  const KURL document_url("http://example.com");
   document->SetURL(document_url);
   document->UpdateSecurityOrigin(SecurityOrigin::Create(document_url));
 
@@ -114,7 +114,7 @@
 // sandboxed iframe with a srcdoc.
 TEST_F(HTMLIFrameElementTest, SandboxedSrcdocFramesUseCorrectOrigin) {
   Document* document = Document::CreateForTest();
-  KURL document_url = KURL(NullURL(), "http://example.com");
+  const KURL document_url("http://example.com");
   document->SetURL(document_url);
   document->UpdateSecurityOrigin(SecurityOrigin::Create(document_url));
 
@@ -133,7 +133,7 @@
 // relative to the parent document.
 TEST_F(HTMLIFrameElementTest, RelativeURLsUseCorrectOrigin) {
   Document* document = Document::CreateForTest();
-  KURL document_url = KURL(NullURL(), "http://example.com");
+  const KURL document_url("http://example.com");
   document->SetURL(document_url);
   document->UpdateSecurityOrigin(SecurityOrigin::Create(document_url));
 
@@ -159,7 +159,7 @@
 // Test that the correct container policy is constructed on an iframe element.
 TEST_F(HTMLIFrameElementTest, DefaultContainerPolicy) {
   Document* document = Document::CreateForTest();
-  KURL document_url = KURL(NullURL(), "http://example.com");
+  const KURL document_url("http://example.com");
   document->SetURL(document_url);
   document->UpdateSecurityOrigin(SecurityOrigin::Create(document_url));
 
@@ -177,7 +177,7 @@
 // restricted to the domain in the src attribute.
 TEST_F(HTMLIFrameElementTest, AllowAttributeContainerPolicy) {
   Document* document = Document::CreateForTest();
-  KURL document_url = KURL(NullURL(), "http://example.com");
+  const KURL document_url("http://example.com");
   document->SetURL(document_url);
   document->UpdateSecurityOrigin(SecurityOrigin::Create(document_url));
 
@@ -238,7 +238,7 @@
 // policy which is restricted to a unique origin.
 TEST_F(HTMLIFrameElementTest, SandboxAttributeContainerPolicy) {
   Document* document = Document::CreateForTest();
-  KURL document_url = KURL(NullURL(), "http://example.com");
+  const KURL document_url("http://example.com");
   document->SetURL(document_url);
   document->UpdateSecurityOrigin(SecurityOrigin::Create(document_url));
 
@@ -264,7 +264,7 @@
 // containing document.
 TEST_F(HTMLIFrameElementTest, SameOriginSandboxAttributeContainerPolicy) {
   Document* document = Document::CreateForTest();
-  KURL document_url = KURL(NullURL(), "http://example.com");
+  const KURL document_url("http://example.com");
   document->SetURL(document_url);
   document->UpdateSecurityOrigin(SecurityOrigin::Create(document_url));
 
@@ -290,7 +290,7 @@
 // iframe element.
 TEST_F(HTMLIFrameElementTest, ConstructEmptyContainerPolicy) {
   Document* document = Document::CreateForTest();
-  KURL document_url = KURL(NullURL(), "http://example.com");
+  const KURL document_url("http://example.com");
   document->SetURL(document_url);
   document->UpdateSecurityOrigin(SecurityOrigin::Create(document_url));
 
@@ -305,7 +305,7 @@
 // to enable features in the frame.
 TEST_F(HTMLIFrameElementTest, ConstructContainerPolicy) {
   Document* document = Document::CreateForTest();
-  KURL document_url = KURL(NullURL(), "http://example.com");
+  const KURL document_url("http://example.com");
   document->SetURL(document_url);
   document->UpdateSecurityOrigin(SecurityOrigin::Create(document_url));
 
@@ -330,7 +330,7 @@
 // is used to enable fullscreen in the frame.
 TEST_F(HTMLIFrameElementTest, ConstructContainerPolicyWithAllowFullscreen) {
   Document* document = Document::CreateForTest();
-  KURL document_url = KURL(NullURL(), "http://example.com");
+  const KURL document_url("http://example.com");
   document->SetURL(document_url);
   document->UpdateSecurityOrigin(SecurityOrigin::Create(document_url));
 
@@ -348,7 +348,7 @@
 // attribute is used to enable the paymentrequest API in the frame.
 TEST_F(HTMLIFrameElementTest, ConstructContainerPolicyWithAllowPaymentRequest) {
   Document* document = Document::CreateForTest();
-  KURL document_url = KURL(NullURL(), "http://example.com");
+  const KURL document_url("http://example.com");
   document->SetURL(document_url);
   document->UpdateSecurityOrigin(SecurityOrigin::Create(document_url));
 
@@ -376,7 +376,7 @@
 // allowpaymentrequest,) while fullscreen should be enabled for all origins.
 TEST_F(HTMLIFrameElementTest, ConstructContainerPolicyWithAllowAttributes) {
   Document* document = Document::CreateForTest();
-  KURL document_url = KURL(NullURL(), "http://example.com");
+  const KURL document_url("http://example.com");
   document->SetURL(document_url);
   document->UpdateSecurityOrigin(SecurityOrigin::Create(document_url));
 
diff --git a/third_party/WebKit/Source/core/html/forms/PasswordInputTypeTest.cpp b/third_party/WebKit/Source/core/html/forms/PasswordInputTypeTest.cpp
index e56a166..ff87f654 100644
--- a/third_party/WebKit/Source/core/html/forms/PasswordInputTypeTest.cpp
+++ b/third_party/WebKit/Source/core/html/forms/PasswordInputTypeTest.cpp
@@ -83,9 +83,9 @@
   std::unique_ptr<DummyPageHolder> page_holder =
       DummyPageHolder::Create(IntSize(2000, 2000), nullptr, nullptr, nullptr);
   MockInsecureInputService mock_service(page_holder->GetFrame());
-  page_holder->GetDocument().SetURL(KURL(NullURL(), "https://example.test"));
+  page_holder->GetDocument().SetURL(KURL("https://example.test"));
   page_holder->GetDocument().SetSecurityOrigin(
-      SecurityOrigin::Create(KURL(NullURL(), "https://example.test")));
+      SecurityOrigin::Create(KURL("https://example.test")));
   page_holder->GetDocument().SetSecureContextStateForTesting(
       SecureContextState::kSecure);
   page_holder->GetDocument().body()->SetInnerHTMLFromString(
@@ -335,9 +335,9 @@
   std::unique_ptr<DummyPageHolder> page_holder =
       DummyPageHolder::Create(IntSize(2000, 2000), nullptr, nullptr, nullptr);
   MockInsecureInputService mock_service(page_holder->GetFrame());
-  page_holder->GetDocument().SetURL(KURL(NullURL(), "https://example.test"));
+  page_holder->GetDocument().SetURL(KURL("https://example.test"));
   page_holder->GetDocument().SetSecurityOrigin(
-      SecurityOrigin::Create(KURL(NullURL(), "https://example.test")));
+      SecurityOrigin::Create(KURL("https://example.test")));
   page_holder->GetDocument().SetSecureContextStateForTesting(
       SecureContextState::kSecure);
   page_holder->GetDocument().body()->SetInnerHTMLFromString(
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLDocumentParserTest.cpp b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParserTest.cpp
index fb630732..a7c9014 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLDocumentParserTest.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParserTest.cpp
@@ -31,8 +31,7 @@
 class HTMLDocumentParserTest : public ::testing::Test {
  protected:
   HTMLDocumentParserTest() : dummy_page_holder_(DummyPageHolder::Create()) {
-    dummy_page_holder_->GetDocument().SetURL(
-        KURL(NullURL(), "https://example.test"));
+    dummy_page_holder_->GetDocument().SetURL(KURL("https://example.test"));
   }
 
   HTMLDocumentParser* CreateParser(HTMLDocument& document) {
diff --git a/third_party/WebKit/Source/core/loader/AllowedByNosniffTest.cpp b/third_party/WebKit/Source/core/loader/AllowedByNosniffTest.cpp
index ed78475..6b4b8cc9 100644
--- a/third_party/WebKit/Source/core/loader/AllowedByNosniffTest.cpp
+++ b/third_party/WebKit/Source/core/loader/AllowedByNosniffTest.cpp
@@ -86,7 +86,7 @@
                  << "\n  mime type: " << testcase.mimetype
                  << "\n  allowed: " << (testcase.allowed ? "true" : "false"));
 
-    KURL url(NullURL(), "https://bla.com/");
+    const KURL url("https://bla.com/");
     doc()->SetSecurityOrigin(SecurityOrigin::Create(url));
     ResourceResponse response;
     response.SetURL(url);
@@ -134,10 +134,9 @@
                  << "\n  url: " << testcase.url << "\n  origin: "
                  << testcase.origin << "\n  mime type: " << testcase.mimetype
                  << "\n  webfeature: " << testcase.expected);
-    doc()->SetSecurityOrigin(
-        SecurityOrigin::Create(KURL(NullURL(), testcase.origin)));
+    doc()->SetSecurityOrigin(SecurityOrigin::Create(KURL(testcase.origin)));
     ResourceResponse response;
-    response.SetURL(KURL(NullURL(), testcase.url));
+    response.SetURL(KURL(testcase.url));
     response.SetHTTPHeaderField("Content-Type", testcase.mimetype);
 
     AllowedByNosniff::MimeTypeAsScript(doc(), response);
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp
index 9291d76f..19cc3f6 100644
--- a/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameFetchContextTest.cpp
@@ -201,7 +201,7 @@
  private:
   ResourceRequestBlockedReason CanRequestInternal(
       SecurityViolationReportingPolicy reporting_policy) {
-    KURL input_url("http://example.com/");
+    const KURL input_url("http://example.com/");
     ResourceRequest resource_request(input_url);
     resource_request.SetFetchCredentialsMode(
         network::mojom::FetchCredentialsMode::kOmit);
@@ -220,9 +220,9 @@
     : public FrameFetchContextTest {
  protected:
   void SetUp() override {
-    url = KURL(NullURL(), "https://example.test/foo");
-    http_url = KURL(NullURL(), "http://example.test/foo");
-    main_resource_url = KURL(NullURL(), "https://www.example.test");
+    url = KURL("https://example.test/foo");
+    http_url = KURL("http://example.test/foo");
+    main_resource_url = KURL("https://www.example.test");
     client = new ::testing::NiceMock<FrameFetchContextMockLocalFrameClient>();
     dummy_page_holder =
         DummyPageHolder::Create(IntSize(500, 500), nullptr, client);
@@ -259,8 +259,8 @@
                      WebURLRequest::RequestContext request_context,
                      WebURLRequest::FrameType frame_type,
                      const char* expected) {
-    KURL input_url(input);
-    KURL expected_url(expected);
+    const KURL input_url(input);
+    const KURL expected_url(expected);
 
     ResourceRequest resource_request(input_url);
     resource_request.SetRequestContext(request_context);
@@ -279,7 +279,7 @@
   void ExpectUpgradeInsecureRequestHeader(const char* input,
                                           WebURLRequest::FrameType frame_type,
                                           bool should_prefer) {
-    KURL input_url(input);
+    const KURL input_url(input);
 
     ResourceRequest resource_request(input_url);
     resource_request.SetRequestContext(WebURLRequest::kRequestContextScript);
@@ -304,7 +304,7 @@
       const char* input,
       WebURLRequest::FrameType frame_type,
       const AtomicString& expected_required_csp) {
-    KURL input_url(input);
+    const KURL input_url(input);
     ResourceRequest resource_request(input_url);
     resource_request.SetRequestContext(WebURLRequest::kRequestContextScript);
     resource_request.SetFrameType(frame_type);
@@ -510,7 +510,7 @@
       resource_width.is_set = true;
     }
 
-    KURL input_url(input);
+    const KURL input_url(input);
     ResourceRequest resource_request(input_url);
 
     fetch_context->AddClientHintsIfNecessary(hints_preferences, resource_width,
@@ -1040,13 +1040,13 @@
 }
 
 TEST_F(FrameFetchContextTest, AddAdditionalRequestHeadersWhenDetached) {
-  const KURL document_url(NullURL(), "https://www2.example.com/fuga/hoge.html");
+  const KURL document_url("https://www2.example.com/fuga/hoge.html");
   const String origin = "https://www2.example.com";
-  ResourceRequest request(KURL(NullURL(), "https://localhost/"));
+  ResourceRequest request(KURL("https://localhost/"));
   request.SetHTTPMethod("PUT");
 
   GetNetworkStateNotifier().SetSaveDataEnabledOverride(true);
-  document->SetSecurityOrigin(SecurityOrigin::Create(KURL(NullURL(), origin)));
+  document->SetSecurityOrigin(SecurityOrigin::Create(KURL(origin)));
   document->SetURL(document_url);
   document->SetReferrerPolicy(kReferrerPolicyOrigin);
   document->SetAddressSpace(kWebAddressSpacePublic);
@@ -1061,7 +1061,7 @@
 }
 
 TEST_F(FrameFetchContextTest, ResourceRequestCachePolicyWhenDetached) {
-  ResourceRequest request(KURL(NullURL(), "https://localhost/"));
+  ResourceRequest request(KURL("https://localhost/"));
 
   dummy_page_holder = nullptr;
 
@@ -1090,7 +1090,7 @@
   dummy_page_holder = nullptr;
   checkpoint.Call(2);
 
-  ResourceRequest request(KURL(NullURL(), "https://localhost/"));
+  ResourceRequest request(KURL("https://localhost/"));
   fetch_context->PrepareRequest(request,
                                 FetchContext::RedirectType::kNotForRedirect);
 
@@ -1098,7 +1098,7 @@
 }
 
 TEST_F(FrameFetchContextTest, DispatchWillSendRequestWhenDetached) {
-  ResourceRequest request(KURL(NullURL(), "https://www.example.com/"));
+  ResourceRequest request(KURL("https://www.example.com/"));
   ResourceResponse response;
   FetchInitiatorInfo initiator_info;
 
@@ -1111,7 +1111,7 @@
 
 TEST_F(FrameFetchContextTest,
        DispatchDidLoadResourceFromMemoryCacheWhenDetached) {
-  ResourceRequest request(KURL(NullURL(), "https://www.example.com/"));
+  ResourceRequest request(KURL("https://www.example.com/"));
   ResourceResponse response;
   FetchInitiatorInfo initiator_info;
 
@@ -1122,7 +1122,7 @@
 }
 
 TEST_F(FrameFetchContextTest, DispatchDidReceiveResponseWhenDetached) {
-  ResourceRequest request(KURL(NullURL(), "https://www.example.com/"));
+  ResourceRequest request(KURL("https://www.example.com/"));
   request.SetFetchCredentialsMode(network::mojom::FetchCredentialsMode::kOmit);
   Resource* resource = MockResource::Create(request);
   ResourceResponse response;
@@ -1182,7 +1182,7 @@
 }
 
 TEST_F(FrameFetchContextTest, RecordLoadingActivityWhenDetached) {
-  ResourceRequest request(KURL(NullURL(), "https://www.example.com/"));
+  ResourceRequest request(KURL("https://www.example.com/"));
 
   dummy_page_holder = nullptr;
 
@@ -1196,7 +1196,7 @@
 }
 
 TEST_F(FrameFetchContextTest, DidLoadResourceWhenDetached) {
-  ResourceRequest request(KURL(NullURL(), "https://www.example.com/"));
+  ResourceRequest request(KURL("https://www.example.com/"));
   request.SetFetchCredentialsMode(network::mojom::FetchCredentialsMode::kOmit);
   Resource* resource = MockResource::Create(request);
 
@@ -1217,7 +1217,7 @@
 }
 
 TEST_F(FrameFetchContextTest, AllowImageWhenDetached) {
-  KURL url(NullURL(), "https://www.example.com/");
+  const KURL url("https://www.example.com/");
 
   dummy_page_holder = nullptr;
 
@@ -1281,7 +1281,7 @@
 }
 
 TEST_F(FrameFetchContextTest, SendImagePingWhenDetached) {
-  KURL url(NullURL(), "https://www.example.com/");
+  const KURL url("https://www.example.com/");
 
   dummy_page_holder = nullptr;
 
@@ -1298,7 +1298,7 @@
 
 TEST_F(FrameFetchContextTest, GetSecurityOriginWhenDetached) {
   scoped_refptr<SecurityOrigin> origin =
-      SecurityOrigin::Create(KURL(NullURL(), "https://www.example.com"));
+      SecurityOrigin::Create(KURL("https://www.example.com"));
   document->SetSecurityOrigin(origin);
 
   dummy_page_holder = nullptr;
@@ -1306,7 +1306,7 @@
 }
 
 TEST_F(FrameFetchContextTest, PopulateResourceRequestWhenDetached) {
-  KURL url(NullURL(), "https://www.example.com/");
+  const KURL url("https://www.example.com/");
   ResourceRequest request(url);
   request.SetFetchCredentialsMode(network::mojom::FetchCredentialsMode::kOmit);
 
@@ -1341,9 +1341,9 @@
 
 TEST_F(FrameFetchContextTest,
        SetFirstPartyCookieAndRequestorOriginWhenDetached) {
-  KURL url(NullURL(), "https://www.example.com/hoge/fuga");
+  const KURL url("https://www.example.com/hoge/fuga");
   ResourceRequest request(url);
-  KURL document_url(NullURL(), "https://www2.example.com/foo/bar");
+  const KURL document_url("https://www2.example.com/foo/bar");
   scoped_refptr<SecurityOrigin> origin = SecurityOrigin::Create(document_url);
 
   document->SetSecurityOrigin(origin);
diff --git a/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp b/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp
index 0c8ced0..17929aa 100644
--- a/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp
+++ b/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp
@@ -88,16 +88,16 @@
 }
 
 KURL SuccessURL() {
-  return KURL(NullURL(), "http://example.com/success");
+  return KURL("http://example.com/success");
 }
 KURL ErrorURL() {
-  return KURL(NullURL(), "http://example.com/error");
+  return KURL("http://example.com/error");
 }
 KURL RedirectURL() {
-  return KURL(NullURL(), "http://example.com/redirect");
+  return KURL("http://example.com/redirect");
 }
 KURL RedirectLoopURL() {
-  return KURL(NullURL(), "http://example.com/loop");
+  return KURL("http://example.com/loop");
 }
 
 enum ThreadableLoaderToTest {
@@ -826,8 +826,7 @@
   // test is not saying that didFailAccessControlCheck should be dispatched
   // synchronously, but is saying that even when a response is served
   // synchronously it should not lead to a crash.
-  StartLoader(KURL(NullURL(), "about:blank"),
-              network::mojom::FetchRequestMode::kCORS);
+  StartLoader(KURL("about:blank"), network::mojom::FetchRequestMode::kCORS);
   CallCheckpoint(2);
 }
 
diff --git a/third_party/WebKit/Source/core/loader/resource/CSSStyleSheetResourceTest.cpp b/third_party/WebKit/Source/core/loader/resource/CSSStyleSheetResourceTest.cpp
index 6786a780..80c3d590 100644
--- a/third_party/WebKit/Source/core/loader/resource/CSSStyleSheetResourceTest.cpp
+++ b/third_party/WebKit/Source/core/loader/resource/CSSStyleSheetResourceTest.cpp
@@ -56,12 +56,12 @@
 
   void SetUp() override {
     PageTestBase::SetUp(IntSize());
-    GetDocument().SetURL(KURL(NullURL(), "https://localhost/"));
+    GetDocument().SetURL(KURL("https://localhost/"));
   }
 
   CSSStyleSheetResource* CreateAndSaveTestStyleSheetResource() {
     const char kUrl[] = "https://localhost/style.css";
-    KURL css_url(NullURL(), kUrl);
+    const KURL css_url(kUrl);
 
     CSSStyleSheetResource* css_resource =
         CSSStyleSheetResource::CreateForTest(css_url, UTF8Encoding());
@@ -77,8 +77,8 @@
 
 TEST_F(CSSStyleSheetResourceTest, DuplicateResourceNotCached) {
   const char kUrl[] = "https://localhost/style.css";
-  KURL image_url(NullURL(), kUrl);
-  KURL css_url(NullURL(), kUrl);
+  const KURL image_url(kUrl);
+  const KURL css_url(kUrl);
 
   // Emulate using <img> to do async stylesheet preloads.
 
diff --git a/third_party/WebKit/Source/core/timing/DOMWindowPerformance.cpp b/third_party/WebKit/Source/core/timing/DOMWindowPerformance.cpp
index 6c17fcad..b0dfbf8e 100644
--- a/third_party/WebKit/Source/core/timing/DOMWindowPerformance.cpp
+++ b/third_party/WebKit/Source/core/timing/DOMWindowPerformance.cpp
@@ -18,6 +18,12 @@
   Supplement<LocalDOMWindow>::Trace(visitor);
 }
 
+void DOMWindowPerformance::TraceWrappers(
+    const ScriptWrappableVisitor* visitor) const {
+  visitor->TraceWrappers(performance_);
+  Supplement<LocalDOMWindow>::TraceWrappers(visitor);
+}
+
 // static
 const char* DOMWindowPerformance::SupplementName() {
   return "DOMWindowPerformance";
diff --git a/third_party/WebKit/Source/core/timing/DOMWindowPerformance.h b/third_party/WebKit/Source/core/timing/DOMWindowPerformance.h
index 53a2bb14..abeb02a 100644
--- a/third_party/WebKit/Source/core/timing/DOMWindowPerformance.h
+++ b/third_party/WebKit/Source/core/timing/DOMWindowPerformance.h
@@ -25,6 +25,7 @@
   static Performance* performance(LocalDOMWindow&);
 
   void Trace(blink::Visitor*);
+  void TraceWrappers(const ScriptWrappableVisitor*) const override;
 
  private:
   explicit DOMWindowPerformance(LocalDOMWindow&);
@@ -32,7 +33,7 @@
 
   Performance* performance();
 
-  Member<Performance> performance_;
+  TraceWrapperMember<Performance> performance_;
   DISALLOW_COPY_AND_ASSIGN(DOMWindowPerformance);
 };
 
diff --git a/third_party/WebKit/Source/core/timing/Performance.h b/third_party/WebKit/Source/core/timing/Performance.h
index 4930d2dc..73efe12 100644
--- a/third_party/WebKit/Source/core/timing/Performance.h
+++ b/third_party/WebKit/Source/core/timing/Performance.h
@@ -68,7 +68,8 @@
 
   ScriptValue toJSONForBinding(ScriptState*) const;
 
-  virtual void Trace(blink::Visitor*);
+  void Trace(blink::Visitor*) override;
+  using PerformanceBase::TraceWrappers;
 
  private:
   explicit Performance(LocalDOMWindow*);
diff --git a/third_party/WebKit/Source/core/timing/PerformanceBase.cpp b/third_party/WebKit/Source/core/timing/PerformanceBase.cpp
index 6c22d34..5ed113b 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceBase.cpp
+++ b/third_party/WebKit/Source/core/timing/PerformanceBase.cpp
@@ -568,7 +568,7 @@
 }
 
 void PerformanceBase::DeliverObservationsTimerFired(TimerBase*) {
-  PerformanceObservers observers;
+  decltype(active_observers_) observers;
   active_observers_.Swap(observers);
   for (const auto& observer : observers) {
     if (observer->ShouldBeSuspended())
@@ -623,4 +623,11 @@
   EventTargetWithInlineData::Trace(visitor);
 }
 
+void PerformanceBase::TraceWrappers(
+    const ScriptWrappableVisitor* visitor) const {
+  for (const auto& observer : observers_)
+    visitor->TraceWrappers(observer);
+  EventTargetWithInlineData::TraceWrappers(visitor);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/timing/PerformanceBase.h b/third_party/WebKit/Source/core/timing/PerformanceBase.h
index d70d320a..77425a616 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceBase.h
+++ b/third_party/WebKit/Source/core/timing/PerformanceBase.h
@@ -59,7 +59,6 @@
 class SubTaskAttribution;
 
 using PerformanceEntryVector = HeapVector<Member<PerformanceEntry>>;
-using PerformanceObservers = HeapLinkedHashSet<Member<PerformanceObserver>>;
 
 class CORE_EXPORT PerformanceBase : public EventTargetWithInlineData {
 
@@ -188,7 +187,8 @@
                                    const SecurityOrigin&,
                                    ExecutionContext*);
 
-  virtual void Trace(blink::Visitor*);
+  void Trace(blink::Visitor*) override;
+  void TraceWrappers(const ScriptWrappableVisitor*) const override;
 
  private:
   static bool PassesTimingAllowCheck(const ResourceResponse&,
@@ -199,7 +199,7 @@
   void AddPaintTiming(PerformancePaintTiming::PaintType, double start_time);
 
  protected:
-  explicit PerformanceBase(double time_origin, scoped_refptr<WebTaskRunner>);
+  PerformanceBase(double time_origin, scoped_refptr<WebTaskRunner>);
 
   // Expect Performance to override this method,
   // WorkerPerformance doesn't have to override this.
@@ -228,9 +228,9 @@
   double time_origin_;
 
   PerformanceEntryTypeMask observer_filter_options_;
-  PerformanceObservers observers_;
-  PerformanceObservers active_observers_;
-  PerformanceObservers suspended_observers_;
+  HeapLinkedHashSet<TraceWrapperMember<PerformanceObserver>> observers_;
+  HeapLinkedHashSet<Member<PerformanceObserver>> active_observers_;
+  HeapLinkedHashSet<Member<PerformanceObserver>> suspended_observers_;
   TaskRunnerTimer<PerformanceBase> deliver_observations_timer_;
 };
 
diff --git a/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp b/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp
index bca9b16f..dbb65d61 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp
+++ b/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp
@@ -113,6 +113,9 @@
 void PerformanceObserver::Deliver() {
   DCHECK(!ShouldBeSuspended());
 
+  if (!GetExecutionContext())
+    return;
+
   if (performance_entries_.IsEmpty())
     return;
 
diff --git a/third_party/WebKit/Source/core/timing/PerformanceTest.cpp b/third_party/WebKit/Source/core/timing/PerformanceTest.cpp
index dbc4004..aea5c93 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceTest.cpp
+++ b/third_party/WebKit/Source/core/timing/PerformanceTest.cpp
@@ -51,14 +51,13 @@
  protected:
   void SetUp() override {
     page_holder_ = DummyPageHolder::Create(IntSize(800, 600));
-    page_holder_->GetDocument().SetURL(KURL(NullURL(), "https://example.com"));
+    page_holder_->GetDocument().SetURL(KURL("https://example.com"));
     performance_ = Performance::Create(page_holder_->GetDocument().domWindow());
     performance_->time_origin_ = kTimeOrigin;
 
     // Create another dummy page holder and pretend this is the iframe.
     another_page_holder_ = DummyPageHolder::Create(IntSize(400, 300));
-    another_page_holder_->GetDocument().SetURL(
-        KURL(NullURL(), "https://iframed.com/bar"));
+    another_page_holder_->GetDocument().SetURL(KURL("https://iframed.com/bar"));
   }
 
   bool ObservingLongTasks() {
diff --git a/third_party/WebKit/Source/core/timing/WorkerGlobalScopePerformance.cpp b/third_party/WebKit/Source/core/timing/WorkerGlobalScopePerformance.cpp
index 90aa629..1f498eb 100644
--- a/third_party/WebKit/Source/core/timing/WorkerGlobalScopePerformance.cpp
+++ b/third_party/WebKit/Source/core/timing/WorkerGlobalScopePerformance.cpp
@@ -73,4 +73,10 @@
   Supplement<WorkerGlobalScope>::Trace(visitor);
 }
 
+void WorkerGlobalScopePerformance::TraceWrappers(
+    const ScriptWrappableVisitor* visitor) const {
+  visitor->TraceWrappers(performance_);
+  Supplement<WorkerGlobalScope>::TraceWrappers(visitor);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/timing/WorkerGlobalScopePerformance.h b/third_party/WebKit/Source/core/timing/WorkerGlobalScopePerformance.h
index 8a28a60..c4a0e550 100644
--- a/third_party/WebKit/Source/core/timing/WorkerGlobalScopePerformance.h
+++ b/third_party/WebKit/Source/core/timing/WorkerGlobalScopePerformance.h
@@ -51,7 +51,8 @@
 
   static WorkerPerformance* performance(WorkerGlobalScope&);
 
-  virtual void Trace(blink::Visitor*);
+  void Trace(blink::Visitor*);
+  void TraceWrappers(const ScriptWrappableVisitor*) const override;
 
  private:
   explicit WorkerGlobalScopePerformance(WorkerGlobalScope&);
@@ -59,7 +60,7 @@
   WorkerPerformance* performance(WorkerGlobalScope*);
   static const char* SupplementName();
 
-  Member<WorkerPerformance> performance_;
+  TraceWrapperMember<WorkerPerformance> performance_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBRequestTest.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBRequestTest.cpp
index 01b85c3..2aac369 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBRequestTest.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBRequestTest.cpp
@@ -65,7 +65,7 @@
   void SetUp() override {
     url_loader_mock_factory_ = platform_->GetURLLoaderMockFactory();
     WebURLResponse response;
-    response.SetURL(KURL(NullURL(), "blob:"));
+    response.SetURL(KURL("blob:"));
     url_loader_mock_factory_->RegisterURLProtocol(WebString("blob"), response,
                                                   "");
   }
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBTransactionTest.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBTransactionTest.cpp
index 4ecad5b2..e2f9c69c 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBTransactionTest.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBTransactionTest.cpp
@@ -82,7 +82,7 @@
   void SetUp() override {
     url_loader_mock_factory_ = platform_->GetURLLoaderMockFactory();
     WebURLResponse response;
-    response.SetURL(KURL(NullURL(), "blob:"));
+    response.SetURL(KURL("blob:"));
     url_loader_mock_factory_->RegisterURLProtocol(WebString("blob"), response,
                                                   "");
   }
diff --git a/third_party/WebKit/Source/modules/mediastream/BUILD.gn b/third_party/WebKit/Source/modules/mediastream/BUILD.gn
index 94890c6..7508e90 100644
--- a/third_party/WebKit/Source/modules/mediastream/BUILD.gn
+++ b/third_party/WebKit/Source/modules/mediastream/BUILD.gn
@@ -32,8 +32,6 @@
     "NavigatorMediaStream.h",
     "NavigatorUserMedia.cpp",
     "NavigatorUserMedia.h",
-    "NavigatorUserMediaErrorCallback.h",
-    "NavigatorUserMediaSuccessCallback.h",
     "OverconstrainedError.cpp",
     "OverconstrainedError.h",
     "URLMediaStream.cpp",
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaDevices.cpp b/third_party/WebKit/Source/modules/mediastream/MediaDevices.cpp
index e504f2a1..2aaa72d 100644
--- a/third_party/WebKit/Source/modules/mediastream/MediaDevices.cpp
+++ b/third_party/WebKit/Source/modules/mediastream/MediaDevices.cpp
@@ -16,8 +16,6 @@
 #include "modules/mediastream/MediaStream.h"
 #include "modules/mediastream/MediaStreamConstraints.h"
 #include "modules/mediastream/NavigatorMediaStream.h"
-#include "modules/mediastream/NavigatorUserMediaErrorCallback.h"
-#include "modules/mediastream/NavigatorUserMediaSuccessCallback.h"
 #include "modules/mediastream/UserMediaController.h"
 #include "modules/mediastream/UserMediaRequest.h"
 #include "platform/bindings/ScriptState.h"
@@ -30,41 +28,32 @@
 
 namespace {
 
-class PromiseSuccessCallback final : public NavigatorUserMediaSuccessCallback {
+class PromiseResolverCallbacks final : public UserMediaRequest::Callbacks {
  public:
-  explicit PromiseSuccessCallback(ScriptPromiseResolver* resolver)
-      : resolver_(resolver) {}
-
-  ~PromiseSuccessCallback() {}
-
-  void handleEvent(MediaStream* stream) { resolver_->Resolve(stream); }
-
-  virtual void Trace(blink::Visitor* visitor) {
-    visitor->Trace(resolver_);
-    NavigatorUserMediaSuccessCallback::Trace(visitor);
+  static PromiseResolverCallbacks* Create(ScriptPromiseResolver* resolver) {
+    return new PromiseResolverCallbacks(resolver);
   }
 
- private:
-  Member<ScriptPromiseResolver> resolver_;
-};
+  ~PromiseResolverCallbacks() override = default;
 
-class PromiseErrorCallback final : public NavigatorUserMediaErrorCallback {
- public:
-  explicit PromiseErrorCallback(ScriptPromiseResolver* resolver)
-      : resolver_(resolver) {}
-
-  ~PromiseErrorCallback() {}
-
-  void handleEvent(DOMExceptionOrOverconstrainedError error) {
+  void OnSuccess(ScriptWrappable* callback_this_value,
+                 MediaStream* stream) override {
+    resolver_->Resolve(stream);
+  }
+  void OnError(ScriptWrappable* callback_this_value,
+               DOMExceptionOrOverconstrainedError error) override {
     resolver_->Reject(error);
   }
 
-  virtual void Trace(blink::Visitor* visitor) {
+  void Trace(blink::Visitor* visitor) override {
     visitor->Trace(resolver_);
-    NavigatorUserMediaErrorCallback::Trace(visitor);
+    UserMediaRequest::Callbacks::Trace(visitor);
   }
 
  private:
+  explicit PromiseResolverCallbacks(ScriptPromiseResolver* resolver)
+      : resolver_(resolver) {}
+
   Member<ScriptPromiseResolver> resolver_;
 };
 
@@ -110,11 +99,8 @@
                                          const MediaStreamConstraints& options,
                                          ExceptionState& exception_state) {
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
-
-  NavigatorUserMediaSuccessCallback* success_callback =
-      new PromiseSuccessCallback(resolver);
-  NavigatorUserMediaErrorCallback* error_callback =
-      new PromiseErrorCallback(resolver);
+  PromiseResolverCallbacks* callbacks =
+      PromiseResolverCallbacks::Create(resolver);
 
   Document* document = ToDocument(ExecutionContext::From(script_state));
   UserMediaController* user_media =
@@ -127,9 +113,8 @@
                              "detached window?"));
 
   MediaErrorState error_state;
-  UserMediaRequest* request =
-      UserMediaRequest::Create(document, user_media, options, success_callback,
-                               error_callback, error_state);
+  UserMediaRequest* request = UserMediaRequest::Create(
+      document, user_media, options, callbacks, error_state);
   if (!request) {
     DCHECK(error_state.HadException());
     if (error_state.CanGenerateException()) {
diff --git a/third_party/WebKit/Source/modules/mediastream/NavigatorMediaStream.cpp b/third_party/WebKit/Source/modules/mediastream/NavigatorMediaStream.cpp
index 25a2d3c..42ddf2f 100644
--- a/third_party/WebKit/Source/modules/mediastream/NavigatorMediaStream.cpp
+++ b/third_party/WebKit/Source/modules/mediastream/NavigatorMediaStream.cpp
@@ -25,6 +25,8 @@
 
 #include "bindings/core/v8/Dictionary.h"
 #include "bindings/core/v8/ExceptionState.h"
+#include "bindings/modules/v8/v8_navigator_user_media_error_callback.h"
+#include "bindings/modules/v8/v8_navigator_user_media_success_callback.h"
 #include "core/dom/Document.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/frame/LocalFrame.h"
@@ -33,8 +35,6 @@
 #include "core/page/Page.h"
 #include "modules/mediastream/MediaErrorState.h"
 #include "modules/mediastream/MediaStreamConstraints.h"
-#include "modules/mediastream/NavigatorUserMediaErrorCallback.h"
-#include "modules/mediastream/NavigatorUserMediaSuccessCallback.h"
 #include "modules/mediastream/UserMediaController.h"
 #include "modules/mediastream/UserMediaRequest.h"
 
@@ -43,11 +43,11 @@
 void NavigatorMediaStream::getUserMedia(
     Navigator& navigator,
     const MediaStreamConstraints& options,
-    NavigatorUserMediaSuccessCallback* success_callback,
-    NavigatorUserMediaErrorCallback* error_callback,
+    V8NavigatorUserMediaSuccessCallback* success_callback,
+    V8NavigatorUserMediaErrorCallback* error_callback,
     ExceptionState& exception_state) {
-  if (!success_callback)
-    return;
+  DCHECK(success_callback);
+  DCHECK(error_callback);
 
   UserMediaController* user_media =
       UserMediaController::From(navigator.GetFrame());
@@ -67,7 +67,8 @@
     if (error_state.CanGenerateException()) {
       error_state.RaiseException(exception_state);
     } else {
-      error_callback->handleEvent(error_state.CreateError());
+      error_callback->InvokeAndReportException(nullptr,
+                                               error_state.CreateError());
     }
     return;
   }
diff --git a/third_party/WebKit/Source/modules/mediastream/NavigatorMediaStream.h b/third_party/WebKit/Source/modules/mediastream/NavigatorMediaStream.h
index a07d7e20..f70ec2f 100644
--- a/third_party/WebKit/Source/modules/mediastream/NavigatorMediaStream.h
+++ b/third_party/WebKit/Source/modules/mediastream/NavigatorMediaStream.h
@@ -30,8 +30,8 @@
 class ExceptionState;
 class MediaStreamConstraints;
 class Navigator;
-class NavigatorUserMediaErrorCallback;
-class NavigatorUserMediaSuccessCallback;
+class V8NavigatorUserMediaErrorCallback;
+class V8NavigatorUserMediaSuccessCallback;
 
 class NavigatorMediaStream {
   STATIC_ONLY(NavigatorMediaStream);
@@ -39,8 +39,8 @@
  public:
   static void getUserMedia(Navigator&,
                            const MediaStreamConstraints&,
-                           NavigatorUserMediaSuccessCallback*,
-                           NavigatorUserMediaErrorCallback*,
+                           V8NavigatorUserMediaSuccessCallback*,
+                           V8NavigatorUserMediaErrorCallback*,
                            ExceptionState&);
 };
 
diff --git a/third_party/WebKit/Source/modules/mediastream/NavigatorMediaStream.idl b/third_party/WebKit/Source/modules/mediastream/NavigatorMediaStream.idl
index 85c3e5f..5c8401a 100644
--- a/third_party/WebKit/Source/modules/mediastream/NavigatorMediaStream.idl
+++ b/third_party/WebKit/Source/modules/mediastream/NavigatorMediaStream.idl
@@ -18,7 +18,6 @@
  */
 
 // https://w3c.github.io/mediacapture-main/#navigatorusermedia-interface-extensions
-
 [
     ImplementedAs=NavigatorMediaStream
 ] partial interface Navigator {
@@ -36,3 +35,15 @@
                               NavigatorUserMediaSuccessCallback successCallback,
                               NavigatorUserMediaErrorCallback errorCallback);
 };
+
+// https://w3c.github.io/mediacapture-main/#navigatorusermediasuccesscallback
+callback NavigatorUserMediaSuccessCallback = void (MediaStream stream);
+
+// https://w3c.github.io/mediacapture-main/#navigatorusermediaerrorcallback
+callback NavigatorUserMediaErrorCallback = void (MediaStreamError error);
+
+// TODO(orphis): The only valid types for MediaStreamError are DOMException and
+// OverconstrainedError. The spec defines MediaStreamError as object because
+// neither DOMException nor OverconstrainedError is an IDL type in the spec.
+// Bug: http://crbug.com/737497 http://crbug.com/769726
+typedef (DOMException or OverconstrainedError) MediaStreamError;
diff --git a/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaErrorCallback.h b/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaErrorCallback.h
deleted file mode 100644
index e85805c..0000000
--- a/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaErrorCallback.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef NavigatorUserMediaErrorCallback_h
-#define NavigatorUserMediaErrorCallback_h
-
-#include "bindings/modules/v8/dom_exception_or_overconstrained_error.h"
-#include "modules/mediastream/OverconstrainedError.h"
-#include "platform/heap/Handle.h"
-
-namespace blink {
-
-class NavigatorUserMediaErrorCallback
-    : public GarbageCollectedFinalized<NavigatorUserMediaErrorCallback> {
- public:
-  virtual ~NavigatorUserMediaErrorCallback() {}
-  virtual void Trace(blink::Visitor* visitor) {}
-  virtual void handleEvent(DOMExceptionOrOverconstrainedError) = 0;
-};
-
-}  // namespace blink
-
-#endif  // NavigatorUserMediaErrorCallback_h
diff --git a/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaErrorCallback.idl b/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaErrorCallback.idl
deleted file mode 100644
index 7501936c..0000000
--- a/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaErrorCallback.idl
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- */
-
-// https://w3c.github.io/mediacapture-main/#navigatorusermediaerrorcallback
-
-// TODO(orphis): The only valid types for MediaStreamError are DOMException and
-// OverconstrainedError. The spec defines MediaStreamError as object because
-// neither DOMException nor OverconstrainedError is an IDL type in the spec.
-// Bug: http://crbug.com/737497 http://crbug.com/769726
-typedef (DOMException or OverconstrainedError) MediaStreamError;
-
-// TODO(foolip): This should be a callback function, not a callback interface.
-// https://crbug.com/569301
-callback interface NavigatorUserMediaErrorCallback {
-    void handleEvent(MediaStreamError error);
-};
diff --git a/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaSuccessCallback.h b/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaSuccessCallback.h
deleted file mode 100644
index ecb71dea..0000000
--- a/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaSuccessCallback.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef NavigatorUserMediaSuccessCallback_h
-#define NavigatorUserMediaSuccessCallback_h
-
-#include "platform/heap/Handle.h"
-
-namespace blink {
-
-class MediaStream;
-
-class NavigatorUserMediaSuccessCallback
-    : public GarbageCollectedFinalized<NavigatorUserMediaSuccessCallback> {
- public:
-  virtual ~NavigatorUserMediaSuccessCallback() {}
-  virtual void Trace(blink::Visitor* visitor) {}
-  virtual void handleEvent(MediaStream*) = 0;
-};
-
-}  // namespace blink
-
-#endif  // NavigatorUserMediaSuccessCallback_h
diff --git a/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaSuccessCallback.idl b/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaSuccessCallback.idl
deleted file mode 100644
index 02db88b0..0000000
--- a/third_party/WebKit/Source/modules/mediastream/NavigatorUserMediaSuccessCallback.idl
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- */
-
-// https://w3c.github.io/mediacapture-main/#navigatorusermediasuccesscallback
-
-// TODO(foolip): This should be a callback function, not a callback interface.
-// https://crbug.com/569301
-callback interface NavigatorUserMediaSuccessCallback {
-    void handleEvent(MediaStream stream);
-};
diff --git a/third_party/WebKit/Source/modules/mediastream/UserMediaRequest.cpp b/third_party/WebKit/Source/modules/mediastream/UserMediaRequest.cpp
index d0b244b0..d77010d3d 100644
--- a/third_party/WebKit/Source/modules/mediastream/UserMediaRequest.cpp
+++ b/third_party/WebKit/Source/modules/mediastream/UserMediaRequest.cpp
@@ -47,6 +47,7 @@
 #include "modules/mediastream/MediaStream.h"
 #include "modules/mediastream/MediaStreamConstraints.h"
 #include "modules/mediastream/MediaTrackConstraints.h"
+#include "modules/mediastream/OverconstrainedError.h"
 #include "modules/mediastream/UserMediaController.h"
 #include "platform/mediastream/MediaStreamCenter.h"
 #include "platform/mediastream/MediaStreamDescriptor.h"
@@ -309,7 +310,6 @@
                                  MediaErrorState& error_state) {
   WebMediaConstraints constraints;
 
-  Dictionary constraints_dictionary;
   if (options.IsNull()) {
     // Do nothing.
   } else if (options.IsMediaTrackConstraints()) {
@@ -327,12 +327,48 @@
 
 }  // namespace
 
+class UserMediaRequest::V8Callbacks final : public UserMediaRequest::Callbacks {
+ public:
+  static V8Callbacks* Create(
+      V8NavigatorUserMediaSuccessCallback* success_callback,
+      V8NavigatorUserMediaErrorCallback* error_callback) {
+    return new V8Callbacks(success_callback, error_callback);
+  }
+
+  ~V8Callbacks() override = default;
+
+  void OnSuccess(ScriptWrappable* callback_this_value,
+                 MediaStream* stream) override {
+    success_callback_->InvokeAndReportException(callback_this_value, stream);
+  }
+  void OnError(ScriptWrappable* callback_this_value,
+               DOMExceptionOrOverconstrainedError error) override {
+    error_callback_->InvokeAndReportException(callback_this_value, error);
+  }
+
+ private:
+  V8Callbacks(V8NavigatorUserMediaSuccessCallback* success_callback,
+              V8NavigatorUserMediaErrorCallback* error_callback)
+      : success_callback_(success_callback), error_callback_(error_callback) {}
+
+  // As Blink does not hold a UserMediaRequest and lets content/ hold it,
+  // we cannot use wrapper-tracing to keep the underlying callback functions.
+  // Plus, it's guaranteed that the callbacks are one-shot type (not repeated
+  // type) and the owner UserMediaRequest will be discarded in a limited
+  // timeframe. Thus these persistent handles are okay.
+  V8NavigatorUserMediaSuccessCallback::Persistent<
+      V8NavigatorUserMediaSuccessCallback>
+      success_callback_;
+  V8NavigatorUserMediaErrorCallback::Persistent<
+      V8NavigatorUserMediaErrorCallback>
+      error_callback_;
+};
+
 UserMediaRequest* UserMediaRequest::Create(
     ExecutionContext* context,
     UserMediaController* controller,
     const MediaStreamConstraints& options,
-    NavigatorUserMediaSuccessCallback* success_callback,
-    NavigatorUserMediaErrorCallback* error_callback,
+    Callbacks* callbacks,
     MediaErrorState& error_state) {
   WebMediaConstraints audio =
       ParseOptions(context, options.audio(), error_state);
@@ -355,31 +391,39 @@
   if (!video.IsNull())
     CountVideoConstraintUses(context, video);
 
-  return new UserMediaRequest(context, controller, audio, video,
-                              success_callback, error_callback);
+  return new UserMediaRequest(context, controller, audio, video, callbacks);
+}
+
+UserMediaRequest* UserMediaRequest::Create(
+    ExecutionContext* context,
+    UserMediaController* controller,
+    const MediaStreamConstraints& options,
+    V8NavigatorUserMediaSuccessCallback* success_callback,
+    V8NavigatorUserMediaErrorCallback* error_callback,
+    MediaErrorState& error_state) {
+  return Create(context, controller, options,
+                V8Callbacks::Create(success_callback, error_callback),
+                error_state);
 }
 
 UserMediaRequest* UserMediaRequest::CreateForTesting(
     const WebMediaConstraints& audio,
     const WebMediaConstraints& video) {
-  return new UserMediaRequest(nullptr, nullptr, audio, video, nullptr, nullptr);
+  return new UserMediaRequest(nullptr, nullptr, audio, video, nullptr);
 }
 
-UserMediaRequest::UserMediaRequest(
-    ExecutionContext* context,
-    UserMediaController* controller,
-    WebMediaConstraints audio,
-    WebMediaConstraints video,
-    NavigatorUserMediaSuccessCallback* success_callback,
-    NavigatorUserMediaErrorCallback* error_callback)
+UserMediaRequest::UserMediaRequest(ExecutionContext* context,
+                                   UserMediaController* controller,
+                                   WebMediaConstraints audio,
+                                   WebMediaConstraints video,
+                                   Callbacks* callbacks)
     : ContextLifecycleObserver(context),
       audio_(audio),
       video_(video),
       should_disable_hardware_noise_suppression_(
           OriginTrials::disableHardwareNoiseSuppressionEnabled(context)),
       controller_(controller),
-      success_callback_(success_callback),
-      error_callback_(error_callback) {
+      callbacks_(callbacks) {
   if (should_disable_hardware_noise_suppression_) {
     UseCounter::Count(context,
                       WebFeature::kUserMediaDisableHardwareNoiseSuppression);
@@ -493,7 +537,7 @@
     (*iter)->SetConstraints(video_);
   }
 
-  success_callback_->handleEvent(stream);
+  callbacks_->OnSuccess(nullptr, stream);
 }
 
 void UserMediaRequest::FailConstraint(const String& constraint_name,
@@ -501,9 +545,9 @@
   DCHECK(!constraint_name.IsEmpty());
   if (!GetExecutionContext())
     return;
-  error_callback_->handleEvent(
-      DOMExceptionOrOverconstrainedError::FromOverconstrainedError(
-          OverconstrainedError::Create(constraint_name, message)));
+  callbacks_->OnError(
+      nullptr, DOMExceptionOrOverconstrainedError::FromOverconstrainedError(
+                   OverconstrainedError::Create(constraint_name, message)));
 }
 
 void UserMediaRequest::Fail(WebUserMediaRequest::Error name,
@@ -540,9 +584,9 @@
     default:
       NOTREACHED();
   }
-  error_callback_->handleEvent(
-      DOMExceptionOrOverconstrainedError::FromDOMException(
-          DOMException::Create(ec, message)));
+  callbacks_->OnError(nullptr,
+                      DOMExceptionOrOverconstrainedError::FromDOMException(
+                          DOMException::Create(ec, message)));
 }
 
 void UserMediaRequest::ContextDestroyed(ExecutionContext*) {
@@ -554,8 +598,7 @@
 
 void UserMediaRequest::Trace(blink::Visitor* visitor) {
   visitor->Trace(controller_);
-  visitor->Trace(success_callback_);
-  visitor->Trace(error_callback_);
+  visitor->Trace(callbacks_);
   ContextLifecycleObserver::Trace(visitor);
 }
 
diff --git a/third_party/WebKit/Source/modules/mediastream/UserMediaRequest.h b/third_party/WebKit/Source/modules/mediastream/UserMediaRequest.h
index 88ede19..48de138 100644
--- a/third_party/WebKit/Source/modules/mediastream/UserMediaRequest.h
+++ b/third_party/WebKit/Source/modules/mediastream/UserMediaRequest.h
@@ -31,10 +31,10 @@
 #ifndef UserMediaRequest_h
 #define UserMediaRequest_h
 
+#include "bindings/modules/v8/v8_navigator_user_media_error_callback.h"
+#include "bindings/modules/v8/v8_navigator_user_media_success_callback.h"
 #include "core/dom/PausableObject.h"
 #include "modules/ModulesExport.h"
-#include "modules/mediastream/NavigatorUserMediaErrorCallback.h"
-#include "modules/mediastream/NavigatorUserMediaSuccessCallback.h"
 #include "platform/mediastream/MediaStreamSource.h"
 #include "platform/wtf/Forward.h"
 #include "public/platform/WebMediaConstraints.h"
@@ -54,22 +54,38 @@
   USING_GARBAGE_COLLECTED_MIXIN(UserMediaRequest);
 
  public:
+  class Callbacks : public GarbageCollectedFinalized<Callbacks> {
+   public:
+    virtual ~Callbacks() = default;
+
+    virtual void OnSuccess(ScriptWrappable* callback_this_value,
+                           MediaStream*) = 0;
+    virtual void OnError(ScriptWrappable* callback_this_value,
+                         DOMExceptionOrOverconstrainedError) = 0;
+
+    virtual void Trace(blink::Visitor*) {}
+
+   protected:
+    Callbacks() = default;
+  };
+
+  class V8Callbacks;
+
   static UserMediaRequest* Create(ExecutionContext*,
                                   UserMediaController*,
                                   const MediaStreamConstraints& options,
-                                  NavigatorUserMediaSuccessCallback*,
-                                  NavigatorUserMediaErrorCallback*,
+                                  Callbacks*,
+                                  MediaErrorState&);
+  static UserMediaRequest* Create(ExecutionContext*,
+                                  UserMediaController*,
+                                  const MediaStreamConstraints& options,
+                                  V8NavigatorUserMediaSuccessCallback*,
+                                  V8NavigatorUserMediaErrorCallback*,
                                   MediaErrorState&);
   static UserMediaRequest* CreateForTesting(const WebMediaConstraints& audio,
                                             const WebMediaConstraints& video);
   virtual ~UserMediaRequest();
 
-  NavigatorUserMediaSuccessCallback* SuccessCallback() const {
-    return success_callback_.Get();
-  }
-  NavigatorUserMediaErrorCallback* ErrorCallback() const {
-    return error_callback_.Get();
-  }
   Document* OwnerDocument();
 
   void Start();
@@ -101,8 +117,7 @@
                    UserMediaController*,
                    WebMediaConstraints audio,
                    WebMediaConstraints video,
-                   NavigatorUserMediaSuccessCallback*,
-                   NavigatorUserMediaErrorCallback*);
+                   Callbacks*);
 
   WebMediaConstraints audio_;
   WebMediaConstraints video_;
@@ -110,8 +125,7 @@
 
   Member<UserMediaController> controller_;
 
-  Member<NavigatorUserMediaSuccessCallback> success_callback_;
-  Member<NavigatorUserMediaErrorCallback> error_callback_;
+  Member<Callbacks> callbacks_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/modules_idl_files.gni b/third_party/WebKit/Source/modules/modules_idl_files.gni
index 0ddd413..eeede38 100644
--- a/third_party/WebKit/Source/modules/modules_idl_files.gni
+++ b/third_party/WebKit/Source/modules/modules_idl_files.gni
@@ -190,8 +190,6 @@
           "mediastream/MediaStreamEvent.idl",
           "mediastream/MediaStreamTrack.idl",
           "mediastream/MediaStreamTrackEvent.idl",
-          "mediastream/NavigatorUserMediaErrorCallback.idl",
-          "mediastream/NavigatorUserMediaSuccessCallback.idl",
           "mediastream/OverconstrainedError.idl",
           "netinfo/NetworkInformation.idl",
           "nfc/MessageCallback.idl",
diff --git a/third_party/WebKit/Source/modules/payments/PaymentRequestDetailsTest.cpp b/third_party/WebKit/Source/modules/payments/PaymentRequestDetailsTest.cpp
index d0b0c18..dcbc1a60 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentRequestDetailsTest.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentRequestDetailsTest.cpp
@@ -128,7 +128,7 @@
 TEST_P(PaymentRequestDetailsTest, ValidatesDetails) {
   V8TestingScope scope;
   scope.GetDocument().SetSecurityOrigin(
-      SecurityOrigin::Create(KURL(NullURL(), "https://www.example.com/")));
+      SecurityOrigin::Create(KURL("https://www.example.com/")));
   scope.GetDocument().SetSecureContextStateForTesting(
       SecureContextState::kSecure);
   PaymentOptions options;
diff --git a/third_party/WebKit/Source/modules/payments/PaymentRequestTest.cpp b/third_party/WebKit/Source/modules/payments/PaymentRequestTest.cpp
index 2b533d34..7448464 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentRequestTest.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentRequestTest.cpp
@@ -17,7 +17,7 @@
 TEST(PaymentRequestTest, SecureContextRequired) {
   V8TestingScope scope;
   scope.GetDocument().SetSecurityOrigin(
-      SecurityOrigin::Create(KURL(NullURL(), "http://www.example.com/")));
+      SecurityOrigin::Create(KURL("http://www.example.com/")));
 
   PaymentRequest::Create(
       scope.GetExecutionContext(), BuildPaymentMethodDataForTest(),
diff --git a/third_party/WebKit/Source/modules/payments/PaymentTestHelper.cpp b/third_party/WebKit/Source/modules/payments/PaymentTestHelper.cpp
index ee10cd8..90b8e954 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentTestHelper.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentTestHelper.cpp
@@ -207,7 +207,7 @@
 
 void MakePaymentRequestOriginSecure(Document& document) {
   document.SetSecurityOrigin(
-      SecurityOrigin::Create(KURL(NullURL(), "https://www.example.com/")));
+      SecurityOrigin::Create(KURL("https://www.example.com/")));
   document.SetSecureContextStateForTesting(SecureContextState::kSecure);
 }
 
diff --git a/third_party/WebKit/Source/modules/presentation/PresentationReceiverTest.cpp b/third_party/WebKit/Source/modules/presentation/PresentationReceiverTest.cpp
index 0ac7af6d..91d2f2170 100644
--- a/third_party/WebKit/Source/modules/presentation/PresentationReceiverTest.cpp
+++ b/third_party/WebKit/Source/modules/presentation/PresentationReceiverTest.cpp
@@ -37,7 +37,7 @@
 class PresentationReceiverTest : public ::testing::Test {
  public:
   PresentationReceiverTest()
-      : connection_info_(KURL(NullURL(), "http://example.com"), "id") {}
+      : connection_info_(KURL("http://example.com"), "id") {}
   void AddConnectionavailableEventListener(EventListener*,
                                            const PresentationReceiver*);
   void VerifyConnectionListPropertyState(ScriptPromisePropertyBase::State,
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainerTest.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainerTest.cpp
index 07f3089a0..6a6024de7 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainerTest.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainerTest.cpp
@@ -367,9 +367,9 @@
                                      options);
 
     EXPECT_EQ(1ul, stub_provider.RegisterCallCount());
-    EXPECT_EQ(WebURL(KURL(NullURL(), "http://localhost/x/y/")),
+    EXPECT_EQ(WebURL(KURL("http://localhost/x/y/")),
               stub_provider.RegisterScope());
-    EXPECT_EQ(WebURL(KURL(NullURL(), "http://localhost/x/y/worker.js")),
+    EXPECT_EQ(WebURL(KURL("http://localhost/x/y/worker.js")),
               stub_provider.RegisterScriptURL());
     EXPECT_EQ(mojom::ServiceWorkerUpdateViaCache::kImports,
               stub_provider.UpdateViaCache());
@@ -390,7 +390,7 @@
     ScriptState::Scope script_scope(GetScriptState());
     container->getRegistration(GetScriptState(), "");
     EXPECT_EQ(1ul, stub_provider.GetRegistrationCallCount());
-    EXPECT_EQ(WebURL(KURL(NullURL(), "http://localhost/x/index.html")),
+    EXPECT_EQ(WebURL(KURL("http://localhost/x/index.html")),
               stub_provider.GetRegistrationURL());
     EXPECT_EQ(mojom::ServiceWorkerUpdateViaCache::kImports,
               stub_provider.UpdateViaCache());
diff --git a/third_party/WebKit/Source/modules/websockets/DOMWebSocketTest.cpp b/third_party/WebKit/Source/modules/websockets/DOMWebSocketTest.cpp
index e477a535..23522f9 100644
--- a/third_party/WebKit/Source/modules/websockets/DOMWebSocketTest.cpp
+++ b/third_party/WebKit/Source/modules/websockets/DOMWebSocketTest.cpp
@@ -209,9 +209,8 @@
   DOMWebSocketTestScope web_socket_scope(scope.GetExecutionContext());
   {
     InSequence s;
-    EXPECT_CALL(
-        web_socket_scope.Channel(),
-        Connect(KURL(NullURL(), "wss://example.com/endpoint"), String()))
+    EXPECT_CALL(web_socket_scope.Channel(),
+                Connect(KURL("wss://example.com/endpoint"), String()))
         .WillOnce(Return(true));
   }
 
@@ -221,7 +220,7 @@
 
   EXPECT_FALSE(scope.GetExceptionState().HadException());
   EXPECT_EQ(DOMWebSocket::kConnecting, web_socket_scope.Socket().readyState());
-  EXPECT_EQ(KURL(NullURL(), "wss://example.com/endpoint"),
+  EXPECT_EQ(KURL("wss://example.com/endpoint"),
             web_socket_scope.Socket().url());
 }
 
@@ -231,7 +230,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/endpoint"), String()))
+                Connect(KURL("ws://example.com/endpoint"), String()))
         .WillOnce(Return(true));
   }
 
@@ -241,8 +240,7 @@
 
   EXPECT_FALSE(scope.GetExceptionState().HadException());
   EXPECT_EQ(DOMWebSocket::kConnecting, web_socket_scope.Socket().readyState());
-  EXPECT_EQ(KURL(NullURL(), "ws://example.com/endpoint"),
-            web_socket_scope.Socket().url());
+  EXPECT_EQ(KURL("ws://example.com/endpoint"), web_socket_scope.Socket().url());
 }
 
 TEST(DOMWebSocketTest, channelConnectSuccess) {
@@ -254,9 +252,8 @@
 
   {
     InSequence s;
-    EXPECT_CALL(
-        web_socket_scope.Channel(),
-        Connect(KURL(NullURL(), "ws://example.com/hoge"), String("aa, bb")))
+    EXPECT_CALL(web_socket_scope.Channel(),
+                Connect(KURL("ws://example.com/hoge"), String("aa, bb")))
         .WillOnce(Return(true));
   }
 
@@ -266,8 +263,7 @@
 
   EXPECT_FALSE(scope.GetExceptionState().HadException());
   EXPECT_EQ(DOMWebSocket::kConnecting, web_socket_scope.Socket().readyState());
-  EXPECT_EQ(KURL(NullURL(), "ws://example.com/hoge"),
-            web_socket_scope.Socket().url());
+  EXPECT_EQ(KURL("ws://example.com/hoge"), web_socket_scope.Socket().url());
 }
 
 TEST(DOMWebSocketTest, channelConnectFail) {
@@ -280,7 +276,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/"), String("aa, bb")))
+                Connect(KURL("ws://example.com/"), String("aa, bb")))
         .WillOnce(Return(false));
     EXPECT_CALL(web_socket_scope.Channel(), Disconnect());
   }
@@ -333,7 +329,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/"), String("aa, bb")))
+                Connect(KURL("ws://example.com/"), String("aa, bb")))
         .WillOnce(Return(true));
   }
   web_socket_scope.Socket().Connect("ws://example.com/", subprotocols,
@@ -355,7 +351,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/"), String()))
+                Connect(KURL("ws://example.com/"), String()))
         .WillOnce(Return(true));
     EXPECT_CALL(web_socket_scope.Channel(), Disconnect());
   }
@@ -377,7 +373,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/"), String()))
+                Connect(KURL("ws://example.com/"), String()))
         .WillOnce(Return(true));
     EXPECT_CALL(web_socket_scope.Channel(), FailMock(_, _, _));
   }
@@ -403,7 +399,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/"), String()))
+                Connect(KURL("ws://example.com/"), String()))
         .WillOnce(Return(true));
   }
   StringBuilder reason;
@@ -431,7 +427,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/"), String()))
+                Connect(KURL("ws://example.com/"), String()))
         .WillOnce(Return(true));
     EXPECT_CALL(
         web_socket_scope.Channel(),
@@ -457,7 +453,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/"), String()))
+                Connect(KURL("ws://example.com/"), String()))
         .WillOnce(Return(true));
     EXPECT_CALL(web_socket_scope.Channel(), Close(3005, String("bye")));
   }
@@ -481,7 +477,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/"), String()))
+                Connect(KURL("ws://example.com/"), String()))
         .WillOnce(Return(true));
     EXPECT_CALL(web_socket_scope.Channel(), Close(3005, String()));
   }
@@ -505,7 +501,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/"), String()))
+                Connect(KURL("ws://example.com/"), String()))
         .WillOnce(Return(true));
     EXPECT_CALL(web_socket_scope.Channel(), Close(-1, String()));
   }
@@ -529,7 +525,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/"), String()))
+                Connect(KURL("ws://example.com/"), String()))
         .WillOnce(Return(true));
     EXPECT_CALL(web_socket_scope.Channel(), Close(-1, String()));
   }
@@ -557,7 +553,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/"), String()))
+                Connect(KURL("ws://example.com/"), String()))
         .WillOnce(Return(true));
     EXPECT_CALL(web_socket_scope.Channel(), Close(-1, String()));
     EXPECT_CALL(web_socket_scope.Channel(), Disconnect());
@@ -589,7 +585,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/"), String()))
+                Connect(KURL("ws://example.com/"), String()))
         .WillOnce(Return(true));
   }
   web_socket_scope.Socket().Connect("ws://example.com/", Vector<String>(),
@@ -612,7 +608,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/"), String()))
+                Connect(KURL("ws://example.com/"), String()))
         .WillOnce(Return(true));
     EXPECT_CALL(web_socket_scope.Channel(), FailMock(_, _, _));
   }
@@ -637,7 +633,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/"), String()))
+                Connect(KURL("ws://example.com/"), String()))
         .WillOnce(Return(true));
     EXPECT_CALL(web_socket_scope.Channel(), Disconnect());
     EXPECT_CALL(checkpoint, Call(1));
@@ -663,7 +659,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/"), String()))
+                Connect(KURL("ws://example.com/"), String()))
         .WillOnce(Return(true));
     EXPECT_CALL(web_socket_scope.Channel(), Send(CString("hello")));
   }
@@ -685,7 +681,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/"), String()))
+                Connect(KURL("ws://example.com/"), String()))
         .WillOnce(Return(true));
     EXPECT_CALL(web_socket_scope.Channel(),
                 Send(CString("\xe7\x8b\x90\xe0\xa4\x94")));
@@ -710,7 +706,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/"), String()))
+                Connect(KURL("ws://example.com/"), String()))
         .WillOnce(Return(true));
   }
   web_socket_scope.Socket().Connect("ws://example.com/", Vector<String>(),
@@ -733,7 +729,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/"), String()))
+                Connect(KURL("ws://example.com/"), String()))
         .WillOnce(Return(true));
     EXPECT_CALL(web_socket_scope.Channel(), FailMock(_, _, _));
   }
@@ -759,7 +755,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/"), String()))
+                Connect(KURL("ws://example.com/"), String()))
         .WillOnce(Return(true));
     EXPECT_CALL(web_socket_scope.Channel(), Disconnect());
     EXPECT_CALL(checkpoint, Call(1));
@@ -786,7 +782,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/"), String()))
+                Connect(KURL("ws://example.com/"), String()))
         .WillOnce(Return(true));
     EXPECT_CALL(web_socket_scope.Channel(), Send(Ref(*view->buffer()), 0, 8));
   }
@@ -834,7 +830,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/"), String()))
+                Connect(KURL("ws://example.com/"), String()))
         .WillOnce(Return(true));
     EXPECT_CALL(web_socket_scope.Channel(), FailMock(_, _, _));
   }
@@ -863,7 +859,7 @@
   {
     InSequence s;
     EXPECT_CALL(web_socket_scope.Channel(),
-                Connect(KURL(NullURL(), "ws://example.com/"), String()))
+                Connect(KURL("ws://example.com/"), String()))
         .WillOnce(Return(true));
   }
   web_socket_scope.Socket().Connect("ws://example.com/", Vector<String>(),
diff --git a/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannelTest.cpp b/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannelTest.cpp
index d5a31f1..76c875b 100644
--- a/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannelTest.cpp
+++ b/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannelTest.cpp
@@ -164,12 +164,12 @@
     {
       InSequence s;
       EXPECT_CALL(*Handle(), DoInitialize(_));
-      EXPECT_CALL(*Handle(), Connect(KURL(NullURL(), "ws://localhost/"), _, _,
-                                     _, _, HandleClient(), _));
+      EXPECT_CALL(*Handle(), Connect(KURL("ws://localhost/"), _, _, _, _,
+                                     HandleClient(), _));
       EXPECT_CALL(*Handle(), FlowControl(65536));
       EXPECT_CALL(*ChannelClient(), DidConnect(String("a"), String("b")));
     }
-    EXPECT_TRUE(Channel()->Connect(KURL(NullURL(), "ws://localhost/"), "x"));
+    EXPECT_TRUE(Channel()->Connect(KURL("ws://localhost/"), "x"));
     HandleClient()->DidConnect(Handle(), String("a"), String("b"));
     ::testing::Mock::VerifyAndClearExpectations(this);
   }
@@ -200,7 +200,7 @@
           std::string(negation ? "doesn't equal" : "equals") + " to \"" +
               url_string +
               "\"") {
-  KURL url(NullURL(), url_string);
+  const KURL url(NullURL(), url_string);
   *result_listener << "where the url is \"" << arg.GetString().Utf8().data()
                    << "\"";
   return arg == url;
@@ -223,7 +223,7 @@
     EXPECT_CALL(*ChannelClient(), DidConnect(String("a"), String("b")));
   }
 
-  KURL page_url(NullURL(), "http://example.com/");
+  const KURL page_url("http://example.com/");
   page_holder_->GetFrame().GetSecurityContext()->SetSecurityOrigin(
       SecurityOrigin::Create(page_url));
   Document& document = page_holder_->GetDocument();
@@ -232,7 +232,7 @@
   EXPECT_STREQ("http://example.com/",
                document.SiteForCookies().GetString().Utf8().data());
 
-  EXPECT_TRUE(Channel()->Connect(KURL(NullURL(), "ws://localhost/"), "x"));
+  EXPECT_TRUE(Channel()->Connect(KURL("ws://localhost/"), "x"));
 
   EXPECT_EQ(1U, protocols.size());
   EXPECT_STREQ("x", protocols[0].Utf8().data());
@@ -830,7 +830,7 @@
     EXPECT_CALL(*handshake_throttle_, ThrottleHandshake(_, _, _));
   }
 
-  static KURL url() { return KURL(NullURL(), "ws://localhost/"); }
+  static KURL url() { return KURL("ws://localhost/"); }
 };
 
 TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, ThrottleArguments) {
diff --git a/third_party/WebKit/Source/platform/weborigin/KURLTest.cpp b/third_party/WebKit/Source/platform/weborigin/KURLTest.cpp
index ddaa12f..bac33234 100644
--- a/third_party/WebKit/Source/platform/weborigin/KURLTest.cpp
+++ b/third_party/WebKit/Source/platform/weborigin/KURLTest.cpp
@@ -433,8 +433,8 @@
 
   for (const auto& test : cases) {
     SCOPED_TRACE(::testing::Message() << test.input << ", " << test.expected);
-    const KURL input(NullURL(), test.input);
-    const KURL expected(NullURL(), test.expected);
+    const KURL input(test.input);
+    const KURL expected(test.expected);
     EXPECT_EQ(input, expected) << input.GetString() << expected.GetString();
     EXPECT_EQ(test.potentially_dangling_markup,
               input.PotentiallyDanglingMarkup());
@@ -443,7 +443,7 @@
 }
 
 TEST(KURLTest, ResolveEmpty) {
-  KURL empty_base;
+  const KURL empty_base;
 
   // WebKit likes to be able to resolve absolute input agains empty base URLs,
   // which would normally be invalid since the base URL is invalid.
@@ -529,59 +529,59 @@
   EXPECT_TRUE(kurl.ProtocolIs("ftp"));
   EXPECT_TRUE(kurl.IsValid());
 
-  kurl = KURL(NullURL(), "http://");
+  kurl = KURL("http://");
   EXPECT_FALSE(kurl.ProtocolIs("http"));
 
-  kurl = KURL(NullURL(), "http://wide#鸡");
+  kurl = KURL("http://wide#鸡");
   EXPECT_TRUE(kurl.ProtocolIs("http"));
   EXPECT_EQ(kurl.Protocol(), "http");
 
-  kurl = KURL(NullURL(), "http-so://foo");
+  kurl = KURL("http-so://foo");
   EXPECT_TRUE(kurl.ProtocolIs("http-so"));
 
-  kurl = KURL(NullURL(), "https://foo");
+  kurl = KURL("https://foo");
   EXPECT_TRUE(kurl.ProtocolIs("https"));
 
-  kurl = KURL(NullURL(), "https-so://foo");
+  kurl = KURL("https-so://foo");
   EXPECT_TRUE(kurl.ProtocolIs("https-so"));
 
-  kurl = KURL(NullURL(), "ftp://foo");
+  kurl = KURL("ftp://foo");
   EXPECT_TRUE(kurl.ProtocolIs("ftp"));
 
-  kurl = KURL(NullURL(), "http://host/");
+  kurl = KURL("http://host/");
   EXPECT_TRUE(kurl.IsValid());
   kurl.SetHost("");
   EXPECT_FALSE(kurl.IsValid());
 
-  kurl = KURL(NullURL(), "http-so://host/");
+  kurl = KURL("http-so://host/");
   EXPECT_TRUE(kurl.IsValid());
   kurl.SetHost("");
   EXPECT_FALSE(kurl.IsValid());
 
-  kurl = KURL(NullURL(), "https://host/");
+  kurl = KURL("https://host/");
   EXPECT_TRUE(kurl.IsValid());
   kurl.SetHost("");
   EXPECT_FALSE(kurl.IsValid());
 
-  kurl = KURL(NullURL(), "https-so://host/");
+  kurl = KURL("https-so://host/");
   EXPECT_TRUE(kurl.IsValid());
   kurl.SetHost("");
   EXPECT_FALSE(kurl.IsValid());
 
-  kurl = KURL(NullURL(), "ftp://host/");
+  kurl = KURL("ftp://host/");
   EXPECT_TRUE(kurl.IsValid());
   kurl.SetHost("");
   EXPECT_FALSE(kurl.IsValid());
 
-  kurl = KURL(NullURL(), "http:///noodles/pho.php");
+  kurl = KURL("http:///noodles/pho.php");
   EXPECT_STREQ("http://noodles/pho.php", kurl.GetString().Utf8().data());
   EXPECT_STREQ("noodles", kurl.Host().Utf8().data());
   EXPECT_TRUE(kurl.IsValid());
 
-  kurl = KURL(NullURL(), "https://username:password@/");
+  kurl = KURL("https://username:password@/");
   EXPECT_FALSE(kurl.IsValid());
 
-  kurl = KURL(NullURL(), "https://username:password@host/");
+  kurl = KURL("https://username:password@host/");
   EXPECT_TRUE(kurl.IsValid());
 }
 
@@ -629,7 +629,7 @@
 }
 
 TEST(KURLTest, Ref) {
-  KURL kurl("http://foo/bar#baz");
+  const KURL kurl("http://foo/bar#baz");
 
   // Basic ref setting.
   KURL cur("http://foo/bar");
@@ -657,7 +657,7 @@
 }
 
 TEST(KURLTest, Empty) {
-  KURL kurl;
+  const KURL kurl;
 
   // First test that regular empty URLs are the same.
   EXPECT_TRUE(kurl.IsEmpty());
@@ -667,7 +667,7 @@
   EXPECT_TRUE(kurl.GetString().IsEmpty());
 
   // Test resolving a null URL on an empty string.
-  KURL kurl2(kurl, "");
+  const KURL kurl2(kurl, "");
   EXPECT_FALSE(kurl2.IsNull());
   EXPECT_TRUE(kurl2.IsEmpty());
   EXPECT_FALSE(kurl2.IsValid());
@@ -677,7 +677,7 @@
   EXPECT_TRUE(kurl2.GetString().IsEmpty());
 
   // Resolve the null URL on a null string.
-  KURL kurl22(kurl, String());
+  const KURL kurl22(kurl, String());
   EXPECT_FALSE(kurl22.IsNull());
   EXPECT_TRUE(kurl22.IsEmpty());
   EXPECT_FALSE(kurl22.IsValid());
@@ -689,20 +689,20 @@
   // Test non-hierarchical schemes resolving. The actual URLs will be different.
   // WebKit's one will set the string to "something.gif" and we'll set it to an
   // empty string. I think either is OK, so we just check our behavior.
-  KURL kurl3(KURL("data:foo"), "something.gif");
+  const KURL kurl3(KURL("data:foo"), "something.gif");
   EXPECT_TRUE(kurl3.IsEmpty());
   EXPECT_FALSE(kurl3.IsValid());
 
   // Test for weird isNull string input,
   // see: http://bugs.webkit.org/show_bug.cgi?id=16487
-  KURL kurl4(kurl.GetString());
+  const KURL kurl4(kurl.GetString());
   EXPECT_TRUE(kurl4.IsEmpty());
   EXPECT_FALSE(kurl4.IsValid());
   EXPECT_TRUE(kurl4.GetString().IsNull());
   EXPECT_TRUE(kurl4.GetString().IsEmpty());
 
   // Resolving an empty URL on an invalid string.
-  KURL kurl5(NullURL(), "foo.js");
+  const KURL kurl5("foo.js");
   // We'll be empty in this case, but KURL won't be. Should be OK.
   // EXPECT_EQ(kurl5.isEmpty(), kurl5.isEmpty());
   // EXPECT_EQ(kurl5.getString().isEmpty(), kurl5.getString().isEmpty());
@@ -710,14 +710,14 @@
   EXPECT_FALSE(kurl5.GetString().IsNull());
 
   // Empty string as input
-  KURL kurl6("");
+  const KURL kurl6("");
   EXPECT_TRUE(kurl6.IsEmpty());
   EXPECT_FALSE(kurl6.IsValid());
   EXPECT_FALSE(kurl6.GetString().IsNull());
   EXPECT_TRUE(kurl6.GetString().IsEmpty());
 
   // Non-empty but invalid C string as input.
-  KURL kurl7("foo.js");
+  const KURL kurl7("foo.js");
   // WebKit will actually say this URL has the string "foo.js" but is invalid.
   // We don't do that.
   // EXPECT_EQ(kurl7.isEmpty(), kurl7.isEmpty());
@@ -745,7 +745,7 @@
 
 TEST(KURLTest, Offsets) {
   const char* src1 = "http://user:pass@google.com/foo/bar.html?baz=query#ref";
-  KURL kurl1(src1);
+  const KURL kurl1(src1);
 
   EXPECT_EQ(17u, kurl1.HostStart());
   EXPECT_EQ(27u, kurl1.HostEnd());
@@ -754,7 +754,7 @@
   EXPECT_EQ(32u, kurl1.PathAfterLastSlash());
 
   const char* src2 = "http://google.com/foo/";
-  KURL kurl2(src2);
+  const KURL kurl2(src2);
 
   EXPECT_EQ(7u, kurl2.HostStart());
   EXPECT_EQ(17u, kurl2.HostEnd());
@@ -763,7 +763,7 @@
   EXPECT_EQ(22u, kurl2.PathAfterLastSlash());
 
   const char* src3 = "javascript:foobar";
-  KURL kurl3(src3);
+  const KURL kurl3(src3);
 
   EXPECT_EQ(11u, kurl3.HostStart());
   EXPECT_EQ(11u, kurl3.HostEnd());
@@ -774,10 +774,10 @@
 
 TEST(KURLTest, DeepCopy) {
   const char kUrl[] = "http://www.google.com/";
-  KURL src(kUrl);
+  const KURL src(kUrl);
   EXPECT_TRUE(src.GetString() ==
               kUrl);  // This really just initializes the cache.
-  KURL dest = src.Copy();
+  const KURL dest = src.Copy();
   EXPECT_TRUE(dest.GetString() ==
               kUrl);  // This really just initializes the cache.
 
@@ -788,27 +788,27 @@
 TEST(KURLTest, DeepCopyInnerURL) {
   const char kUrl[] = "filesystem:http://www.google.com/temporary/test.txt";
   const char kInnerURL[] = "http://www.google.com/temporary";
-  KURL src(kUrl);
+  const KURL src(kUrl);
   EXPECT_TRUE(src.GetString() == kUrl);
   EXPECT_TRUE(src.InnerURL()->GetString() == kInnerURL);
-  KURL dest = src.Copy();
+  const KURL dest = src.Copy();
   EXPECT_TRUE(dest.GetString() == kUrl);
   EXPECT_TRUE(dest.InnerURL()->GetString() == kInnerURL);
 }
 
 TEST(KURLTest, LastPathComponent) {
-  KURL url1("http://host/path/to/file.txt");
+  const KURL url1("http://host/path/to/file.txt");
   EXPECT_EQ("file.txt", url1.LastPathComponent());
 
-  KURL invalid_utf8("http://a@9%aa%:/path/to/file.txt");
+  const KURL invalid_utf8("http://a@9%aa%:/path/to/file.txt");
   EXPECT_EQ(String(), invalid_utf8.LastPathComponent());
 }
 
 TEST(KURLTest, IsHierarchical) {
-  KURL url1("http://host/path/to/file.txt");
+  const KURL url1("http://host/path/to/file.txt");
   EXPECT_TRUE(url1.IsHierarchical());
 
-  KURL invalid_utf8("http://a@9%aa%:/path/to/file.txt");
+  const KURL invalid_utf8("http://a@9%aa%:/path/to/file.txt");
   EXPECT_FALSE(invalid_utf8.IsHierarchical());
 }
 
@@ -821,26 +821,26 @@
 }
 
 TEST(KURLTest, ProtocolIsInHTTPFamily) {
-  KURL url1("http://host/path/to/file.txt");
+  const KURL url1("http://host/path/to/file.txt");
   EXPECT_TRUE(url1.ProtocolIsInHTTPFamily());
 
-  KURL invalid_utf8("http://a@9%aa%:/path/to/file.txt");
+  const KURL invalid_utf8("http://a@9%aa%:/path/to/file.txt");
   EXPECT_FALSE(invalid_utf8.ProtocolIsInHTTPFamily());
 }
 
 TEST(KURLTest, ProtocolIs) {
-  KURL url1("foo://bar");
+  const KURL url1("foo://bar");
   EXPECT_TRUE(url1.ProtocolIs("foo"));
   EXPECT_FALSE(url1.ProtocolIs("foo-bar"));
 
-  KURL url2("foo-bar:");
+  const KURL url2("foo-bar:");
   EXPECT_TRUE(url2.ProtocolIs("foo-bar"));
   EXPECT_FALSE(url2.ProtocolIs("foo"));
 
-  KURL invalid_utf8("http://a@9%aa%:");
+  const KURL invalid_utf8("http://a@9%aa%:");
   EXPECT_FALSE(invalid_utf8.ProtocolIs("http"));
 
-  KURL capital(NullURL(), "HTTP://www.example.text");
+  const KURL capital("HTTP://www.example.text");
   EXPECT_TRUE(capital.ProtocolIs("http"));
   EXPECT_EQ(capital.Protocol(), "http");
 }
@@ -864,7 +864,7 @@
   };
 
   for (size_t i = 0; i < WTF_ARRAY_LENGTH(referrer_cases); i++) {
-    KURL kurl(referrer_cases[i].input);
+    const KURL kurl(referrer_cases[i].input);
     String referrer = kurl.StrippedForUseAsReferrer();
     EXPECT_STREQ(referrer_cases[i].output, referrer.Utf8().data());
   }
diff --git a/third_party/WebKit/Source/platform/weborigin/SecurityPolicyTest.cpp b/third_party/WebKit/Source/platform/weborigin/SecurityPolicyTest.cpp
index 38310704..4c74e07 100644
--- a/third_party/WebKit/Source/platform/weborigin/SecurityPolicyTest.cpp
+++ b/third_party/WebKit/Source/platform/weborigin/SecurityPolicyTest.cpp
@@ -62,7 +62,7 @@
 
 TEST(SecurityPolicyTest, ShouldHideReferrerRespectsReferrerSchemesRegistry) {
   const KURL example_http_url = KURL("http://example.com/");
-  const KURL foobar_url = KURL(NullURL(), "foobar://somepage/");
+  const KURL foobar_url = KURL("foobar://somepage/");
   const String foobar_scheme = String::FromUTF8("foobar");
 
   EXPECT_TRUE(SecurityPolicy::ShouldHideReferrer(example_http_url, foobar_url));