DevTools: add auto-adjust zoom checkbox to device mode

This CL adds a checkbox to the zoom dropdown, allowing users to
turn off 'Auto-adjust zoom', which scales the device to fit upon
rotation and switching devices. It is on by default.

Screenshot: https://imgur.com/a/Sov1K

Bug: 718659
Change-Id: Ief5c3a2b84362b2125d51cd39bd5dc3e669a3e60
Reviewed-on: https://chromium-review.googlesource.com/858494
Commit-Queue: Erik Luo <luoe@chromium.org>
Reviewed-by: Dmitry Gozman <dgozman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#531127}
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/device-mode/device-mode-switching-devices-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/device-mode/device-mode-switching-devices-expected.txt
index 6e141ee..2fa69ec 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/device-mode/device-mode-switching-devices-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/device-mode/device-mode-switching-devices-expected.txt
@@ -1,12 +1,37 @@
 Test preservation of orientation and scale when that switching devices in device mode.
 
 
-Test that devices remember their scale.
-Switch to phone 0
+Test that devices automatically zoom to fit.
+Switch to phone A
+PhoneA Scale: 1
 Setting scale to 0.5
-Phone0 Scale: 0.5
-Switch to phone 1
-Phone1 Scale: 1
-Switch to phone 0
-Phone0 Scale: 0.5
+PhoneA Scale: 0.5
+Switch to phone B
+PhoneB Scale: 1
+Switch to phone large
+PhoneLarge Scale: 0.15
+Rotating...
+PhoneLarge Scale: 0.2
+Rotating back...
+PhoneLarge Scale: 0.15
+Switch to phone A
+PhoneA Scale: 1
+
+Turning off auto-zoom.
+
+Test that devices do not automatically zoom to fit.
+Switch to phone A
+PhoneA Scale: 1
+Setting scale to 0.75
+PhoneA Scale: 0.75
+Switch to phone B
+PhoneB Scale: 0.75
+Switch to phone large
+PhoneLarge Scale: 0.75
+Rotating...
+PhoneLarge Scale: 0.75
+Rotating back...
+PhoneLarge Scale: 0.75
+Switch to phone A
+PhoneA Scale: 0.75
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/device-mode/device-mode-switching-devices.js b/third_party/WebKit/LayoutTests/http/tests/devtools/device-mode/device-mode-switching-devices.js
index c06d003..730883c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/device-mode/device-mode-switching-devices.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/device-mode/device-mode-switching-devices.js
@@ -6,8 +6,15 @@
   TestRunner.addResult(`Test preservation of orientation and scale when that switching devices in device mode.\n`);
   await TestRunner.loadModule('device_mode_test_runner');
 
-  var phone0 = DeviceModeTestRunner.buildFakePhone();
-  var phone1 = DeviceModeTestRunner.buildFakePhone();
+  var phoneA = DeviceModeTestRunner.buildFakePhone();
+  var phoneB = DeviceModeTestRunner.buildFakePhone();
+  var phoneLarge = DeviceModeTestRunner.buildFakePhone({
+    'screen': {
+      'horizontal': {'width': 3840, 'height': 720},
+      'device-pixel-ratio': 2,
+      'vertical': {'width': 720, 'height': 3840}
+    }
+  });
 
   var view = new Emulation.DeviceModeView();
   var toolbar = view._toolbar;
@@ -15,18 +22,54 @@
   var viewportSize = new UI.Size(800, 600);
   model.setAvailableSize(viewportSize, viewportSize);
 
-  TestRunner.addResult('\nTest that devices remember their scale.');
-  TestRunner.addResult('Switch to phone 0');
-  toolbar._emulateDevice(phone0);
+  TestRunner.addResult('\nTest that devices automatically zoom to fit.');
+  TestRunner.addResult('Switch to phone A');
+  toolbar._emulateDevice(phoneA);
+  TestRunner.addResult('PhoneA Scale: ' + model._scaleSetting.get());
   TestRunner.addResult('Setting scale to 0.5');
   toolbar._onScaleMenuChanged(0.5);
-  TestRunner.addResult('Phone0 Scale: ' + model._scaleSetting.get());
-  TestRunner.addResult('Switch to phone 1');
-  toolbar._emulateDevice(phone1);
-  TestRunner.addResult('Phone1 Scale: ' + model._scaleSetting.get());
-  TestRunner.addResult('Switch to phone 0');
-  toolbar._emulateDevice(phone0);
-  TestRunner.addResult('Phone0 Scale: ' + model._scaleSetting.get());
+  TestRunner.addResult('PhoneA Scale: ' + model._scaleSetting.get());
+  TestRunner.addResult('Switch to phone B');
+  toolbar._emulateDevice(phoneB);
+  TestRunner.addResult('PhoneB Scale: ' + model._scaleSetting.get());
+  TestRunner.addResult('Switch to phone large');
+  toolbar._emulateDevice(phoneLarge);
+  TestRunner.addResult('PhoneLarge Scale: ' + model._scaleSetting.get());
+  TestRunner.addResult('Rotating...');
+  toolbar._modeButton.element.click();
+  TestRunner.addResult('PhoneLarge Scale: ' + model._scaleSetting.get());
+  TestRunner.addResult('Rotating back...');
+  toolbar._modeButton.element.click();
+  TestRunner.addResult('PhoneLarge Scale: ' + model._scaleSetting.get());
+  TestRunner.addResult('Switch to phone A');
+  toolbar._emulateDevice(phoneA);
+  TestRunner.addResult('PhoneA Scale: ' + model._scaleSetting.get());
+
+  TestRunner.addResult('\nTurning off auto-zoom.');
+  toolbar._autoAdjustScaleSetting.set(false);
+
+  TestRunner.addResult('\nTest that devices do not automatically zoom to fit.');
+  TestRunner.addResult('Switch to phone A');
+  toolbar._emulateDevice(phoneA);
+  TestRunner.addResult('PhoneA Scale: ' + model._scaleSetting.get());
+  TestRunner.addResult('Setting scale to 0.75');
+  toolbar._onScaleMenuChanged(0.75);
+  TestRunner.addResult('PhoneA Scale: ' + model._scaleSetting.get());
+  TestRunner.addResult('Switch to phone B');
+  toolbar._emulateDevice(phoneB);
+  TestRunner.addResult('PhoneB Scale: ' + model._scaleSetting.get());
+  TestRunner.addResult('Switch to phone large');
+  toolbar._emulateDevice(phoneLarge);
+  TestRunner.addResult('PhoneLarge Scale: ' + model._scaleSetting.get());
+  TestRunner.addResult('Rotating...');
+  toolbar._modeButton.element.click();
+  TestRunner.addResult('PhoneLarge Scale: ' + model._scaleSetting.get());
+  TestRunner.addResult('Rotating back...');
+  toolbar._modeButton.element.click();
+  TestRunner.addResult('PhoneLarge Scale: ' + model._scaleSetting.get());
+  TestRunner.addResult('Switch to phone A');
+  toolbar._emulateDevice(phoneA);
+  TestRunner.addResult('PhoneA Scale: ' + model._scaleSetting.get());
 
   TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeToolbar.js b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeToolbar.js
index 896352e..3b0a2bce 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeToolbar.js
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeToolbar.js
@@ -22,12 +22,11 @@
     this._showUserAgentTypeSetting = Common.settings.createSetting('emulation.showUserAgentType', false);
     this._showUserAgentTypeSetting.addChangeListener(this._updateUserAgentTypeVisibility, this);
 
+    this._autoAdjustScaleSetting = Common.settings.createSetting('emulation.autoAdjustScale', true);
+
     /** @type {!Map<!Emulation.EmulatedDevice, !Emulation.EmulatedDevice.Mode>} */
     this._lastMode = new Map();
 
-    /** @type {!Map<!Emulation.EmulatedDevice, number>} */
-    this._lastScale = new Map();
-
     this._element = createElementWithClass('div', 'device-mode-toolbar');
 
     var leftContainer = this._element.createChild('div', 'device-mode-toolbar-spacer');
@@ -203,10 +202,12 @@
    */
   _appendScaleMenuItems(contextMenu) {
     if (this._model.type() === Emulation.DeviceModeModel.Type.Device) {
-      contextMenu.headerSection().appendItem(
+      contextMenu.footerSection().appendItem(
           Common.UIString('Fit to window (%.0f%%)', this._model.fitScale() * 100),
           this._onScaleMenuChanged.bind(this, this._model.fitScale()), false);
     }
+    contextMenu.footerSection().appendCheckboxItem(
+        ls`Auto-adjust zoom`, this._onAutoAdjustScaleChanged.bind(this), this._autoAdjustScaleSetting.get());
     var boundAppendScaleItem = appendScaleItem.bind(this);
     boundAppendScaleItem(Common.UIString('50%'), 0.5);
     boundAppendScaleItem(Common.UIString('75%'), 0.75);
@@ -229,12 +230,13 @@
    * @param {number} value
    */
   _onScaleMenuChanged(value) {
-    var device = this._model.device();
-    if (device)
-      this._lastScale.set(device, value);
     this._model.scaleSetting().set(value);
   }
 
+  _onAutoAdjustScaleChanged() {
+    this._autoAdjustScaleSetting.set(!this._autoAdjustScaleSetting.get());
+  }
+
   /**
    * @param {!UI.ContextMenu} contextMenu
    */
@@ -342,9 +344,9 @@
    * @param {!Emulation.EmulatedDevice} device
    */
   _emulateDevice(device) {
+    var scale = this._autoAdjustScaleSetting.get() ? undefined : this._model.scaleSetting().get();
     this._model.emulate(
-        Emulation.DeviceModeModel.Type.Device, device, this._lastMode.get(device) || device.modes[0],
-        this._lastScale.get(device));
+        Emulation.DeviceModeModel.Type.Device, device, this._lastMode.get(device) || device.modes[0], scale);
   }
 
   _switchToResponsive() {
@@ -443,15 +445,23 @@
   _modeMenuClicked(event) {
     var device = this._model.device();
     var model = this._model;
+    var autoAdjustScaleSetting = this._autoAdjustScaleSetting;
 
     if (model.type() === Emulation.DeviceModeModel.Type.Responsive) {
       var appliedSize = model.appliedDeviceSize();
-      model.setSizeAndScaleToFit(appliedSize.height, appliedSize.width);
+      if (autoAdjustScaleSetting.get()) {
+        model.setSizeAndScaleToFit(appliedSize.height, appliedSize.width);
+      } else {
+        model.setWidth(appliedSize.height);
+        model.setHeight(appliedSize.width);
+      }
       return;
     }
 
     if (device.modes.length === 2 && device.modes[0].orientation !== device.modes[1].orientation) {
-      model.emulate(model.type(), model.device(), model.mode() === device.modes[0] ? device.modes[1] : device.modes[0]);
+      var scale = autoAdjustScaleSetting.get() ? undefined : model.scaleSetting().get();
+      model.emulate(
+          model.type(), model.device(), model.mode() === device.modes[0] ? device.modes[1] : device.modes[0], scale);
       return;
     }
 
@@ -490,7 +500,8 @@
      * @param {!Emulation.EmulatedDevice.Mode} mode
      */
     function applyMode(mode) {
-      model.emulate(model.type(), model.device(), mode);
+      var scale = autoAdjustScaleSetting.get() ? undefined : model.scaleSetting().get();
+      model.emulate(model.type(), model.device(), mode, scale);
     }
   }