Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / devtools / front_end / emulation / OverridesView.js
blob6897b1208a88c48dfcf278453fb182834df57ffe
1 /*
2 * Copyright (C) 2014 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 /**
32 * @constructor
33 * @extends {WebInspector.VBox}
35 WebInspector.OverridesView = function()
37 WebInspector.VBox.call(this);
38 this.setMinimumSize(0, 30);
39 this.registerRequiredCSS("emulation/overrides.css");
40 this.element.classList.add("overrides-view");
42 this._tabbedPane = new WebInspector.TabbedPane();
43 this._tabbedPane.setShrinkableTabs(false);
44 this._tabbedPane.setVerticalTabLayout(true);
46 new WebInspector.OverridesView.DeviceTab().appendAsTab(this._tabbedPane);
47 new WebInspector.OverridesView.MediaTab().appendAsTab(this._tabbedPane);
48 new WebInspector.OverridesView.NetworkTab().appendAsTab(this._tabbedPane);
49 new WebInspector.OverridesView.SensorsTab().appendAsTab(this._tabbedPane);
51 this._lastSelectedTabSetting = WebInspector.settings.createSetting("lastSelectedEmulateTab", "device");
52 this._tabbedPane.selectTab(this._lastSelectedTabSetting.get());
53 this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, this._tabSelected, this);
54 this._tabbedPane.show(this.element);
56 var resetButtonElement = createTextButton(WebInspector.UIString("Reset"), WebInspector.overridesSupport.reset.bind(WebInspector.overridesSupport));
57 resetButtonElement.id = "overrides-reset-button";
58 this._tabbedPane.appendAfterTabStrip(resetButtonElement);
60 var disableButtonElement = createTextButton(WebInspector.UIString("Disable"), this._toggleEmulationEnabled.bind(this), "overrides-disable-button");
61 disableButtonElement.id = "overrides-disable-button";
62 this._tabbedPane.appendAfterTabStrip(disableButtonElement);
64 this._splashScreenElement = this.element.createChild("div", "overrides-splash-screen");
65 this._splashScreenElement.appendChild(createTextButton(WebInspector.UIString("Enable emulation"), this._toggleEmulationEnabled.bind(this), "overrides-enable-button"));
67 this._unavailableSplashScreenElement = this.element.createChild("div", "overrides-splash-screen");
68 this._unavailableSplashScreenElement.createTextChild(WebInspector.UIString("Emulation is not available."));
70 this._warningFooter = this.element.createChild("div", "overrides-footer");
71 this._overridesWarningUpdated();
73 WebInspector.overridesSupport.addEventListener(WebInspector.OverridesSupport.Events.OverridesWarningUpdated, this._overridesWarningUpdated, this);
74 WebInspector.overridesSupport.addEventListener(WebInspector.OverridesSupport.Events.EmulationStateChanged, this._emulationStateChanged, this);
75 this._emulationStateChanged();
78 WebInspector.OverridesView.prototype = {
79 /**
80 * @param {!WebInspector.Event} event
82 _tabSelected: function(event)
84 this._lastSelectedTabSetting.set(this._tabbedPane.selectedTabId);
87 _overridesWarningUpdated: function()
89 var message = WebInspector.overridesSupport.warningMessage();
90 this._warningFooter.classList.toggle("hidden", !message);
91 this._warningFooter.textContent = message;
94 _toggleEmulationEnabled: function()
96 WebInspector.overridesSupport.setEmulationEnabled(!WebInspector.overridesSupport.emulationEnabled());
99 _emulationStateChanged: function()
101 this._unavailableSplashScreenElement.classList.toggle("hidden", WebInspector.overridesSupport.canEmulate());
102 this._tabbedPane.element.classList.toggle("hidden", !WebInspector.overridesSupport.emulationEnabled());
103 this._splashScreenElement.classList.toggle("hidden", WebInspector.overridesSupport.emulationEnabled() || !WebInspector.overridesSupport.canEmulate());
106 __proto__: WebInspector.VBox.prototype
110 * @constructor
111 * @extends {WebInspector.VBox}
112 * @param {string} id
113 * @param {string} name
114 * @param {!Array.<!WebInspector.Setting>} settings
115 * @param {!Array.<function():boolean>=} predicates
117 WebInspector.OverridesView.Tab = function(id, name, settings, predicates)
119 WebInspector.VBox.call(this);
120 this._id = id;
121 this._name = name;
122 this._settings = settings;
123 this._predicates = predicates || [];
124 for (var i = 0; i < settings.length; ++i)
125 settings[i].addChangeListener(this.updateActiveState, this);
128 WebInspector.OverridesView.Tab.prototype = {
130 * @param {!WebInspector.TabbedPane} tabbedPane
132 appendAsTab: function(tabbedPane)
134 this._tabbedPane = tabbedPane;
135 tabbedPane.appendTab(this._id, this._name, this);
136 this.updateActiveState();
139 updateActiveState: function()
141 if (!this._tabbedPane)
142 return;
143 var active = false;
144 for (var i = 0; !active && i < this._settings.length; ++i)
145 active = this._settings[i].get();
146 for (var i = 0; !active && i < this._predicates.length; ++i)
147 active = this._predicates[i]();
148 this._tabbedPane.toggleTabClass(this._id, "overrides-activate", active);
152 * @param {string} name
153 * @param {!WebInspector.Setting} setting
154 * @param {function(boolean)=} callback
156 _createSettingCheckbox: function(name, setting, callback)
158 var checkbox = WebInspector.SettingsUI.createSettingCheckbox(name, setting, true);
160 function changeListener(value)
162 callback(setting.get());
165 if (callback)
166 setting.addChangeListener(changeListener);
168 return checkbox;
171 __proto__: WebInspector.VBox.prototype
175 * @constructor
176 * @extends {WebInspector.OverridesView.Tab}
178 WebInspector.OverridesView.DeviceTab = function()
180 WebInspector.OverridesView.Tab.call(this, "device", WebInspector.UIString("Device"), [
181 WebInspector.overridesSupport.settings.emulateResolution,
182 WebInspector.overridesSupport.settings.deviceScaleFactor,
183 WebInspector.overridesSupport.settings.emulateMobile
185 this.element.classList.add("overrides-device");
187 this.element.appendChild(this._createDeviceElement());
189 var footnote = this.element.createChild("p", "help-footnote");
190 footnote.appendChild(WebInspector.linkifyDocumentationURLAsNode("setup/remote-debugging/remote-debugging", WebInspector.UIString("More information about screen emulation")));
193 WebInspector.OverridesView.DeviceTab.prototype = {
194 _createDeviceElement: function()
196 var fieldsetElement = createElement("fieldset");
197 fieldsetElement.id = "metrics-override-section";
199 var deviceModelElement = fieldsetElement.createChild("p", "overrides-device-model-section");
200 deviceModelElement.createChild("span").textContent = WebInspector.UIString("Model:");
202 var rotateButton = createElement("button");
203 rotateButton.textContent = " \u21C4 ";
204 var deviceSelect = new WebInspector.DeviceSelect(rotateButton, null);
205 deviceModelElement.appendChild(deviceSelect.element);
207 var emulateResolutionCheckbox = WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Emulate screen resolution"), WebInspector.overridesSupport.settings.emulateResolution, true);
208 fieldsetElement.appendChild(emulateResolutionCheckbox);
209 var resolutionFieldset = WebInspector.SettingsUI.createSettingFieldset(WebInspector.overridesSupport.settings.emulateResolution);
210 fieldsetElement.appendChild(resolutionFieldset);
212 var tableElement = resolutionFieldset.createChild("table");
213 var rowElement = tableElement.createChild("tr");
214 var cellElement = rowElement.createChild("td");
215 cellElement.createTextChild(WebInspector.UIString("Resolution:"));
216 cellElement = rowElement.createChild("td");
218 var widthOverrideInput = WebInspector.SettingsUI.createSettingInputField("", WebInspector.overridesSupport.settings.deviceWidth, true, 4, "80px", WebInspector.OverridesSupport.deviceSizeValidator, true, true, WebInspector.UIString("\u2013"));
219 cellElement.appendChild(widthOverrideInput);
220 var heightOverrideInput = WebInspector.SettingsUI.createSettingInputField("", WebInspector.overridesSupport.settings.deviceHeight, true, 4, "80px", WebInspector.OverridesSupport.deviceSizeValidator, true, true, WebInspector.UIString("\u2013"));
221 cellElement.appendChild(heightOverrideInput);
223 rowElement = tableElement.createChild("tr");
224 cellElement = rowElement.createChild("td");
225 cellElement.colSpan = 4;
227 rowElement = tableElement.createChild("tr");
228 rowElement.title = WebInspector.UIString("Ratio between a device's physical pixels and device-independent pixels");
229 rowElement.createChild("td").createTextChild(WebInspector.UIString("Device pixel ratio:"));
230 rowElement.createChild("td").appendChild(WebInspector.SettingsUI.createSettingInputField("", WebInspector.overridesSupport.settings.deviceScaleFactor, true, 4, "80px", WebInspector.OverridesSupport.deviceScaleFactorValidator, true, true, WebInspector.UIString("\u2013")));
232 var mobileCheckbox = this._createSettingCheckbox(WebInspector.UIString("Emulate mobile"), WebInspector.overridesSupport.settings.emulateMobile);
233 mobileCheckbox.title = WebInspector.UIString("Enable meta viewport, overlay scrollbars, text autosizing and default 980px body width");
234 fieldsetElement.appendChild(mobileCheckbox);
236 fieldsetElement.appendChild(this._createSettingCheckbox(WebInspector.UIString("Shrink to fit"), WebInspector.overridesSupport.settings.deviceFitWindow));
238 return fieldsetElement;
241 __proto__: WebInspector.OverridesView.Tab.prototype
246 * @constructor
247 * @extends {WebInspector.OverridesView.Tab}
249 WebInspector.OverridesView.MediaTab = function()
251 var settings = [WebInspector.overridesSupport.settings.overrideCSSMedia];
252 WebInspector.OverridesView.Tab.call(this, "media", WebInspector.UIString("Media"), settings);
253 this.element.classList.add("overrides-media");
255 this._createMediaEmulationFragment();
258 WebInspector.OverridesView.MediaTab.prototype = {
259 _createMediaEmulationFragment: function()
261 var checkbox = WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("CSS media"), WebInspector.overridesSupport.settings.overrideCSSMedia, true);
262 var fieldsetElement = WebInspector.SettingsUI.createSettingFieldset(WebInspector.overridesSupport.settings.overrideCSSMedia);
263 var mediaSelectElement = fieldsetElement.createChild("select");
264 var mediaTypes = WebInspector.CSSStyleModel.MediaTypes;
265 var defaultMedia = WebInspector.overridesSupport.settings.emulatedCSSMedia.get();
266 for (var i = 0; i < mediaTypes.length; ++i) {
267 var mediaType = mediaTypes[i];
268 if (mediaType === "all") {
269 // "all" is not a device-specific media type.
270 continue;
272 var option = createElement("option");
273 option.text = mediaType;
274 option.value = mediaType;
275 mediaSelectElement.add(option);
276 if (mediaType === defaultMedia)
277 mediaSelectElement.selectedIndex = mediaSelectElement.options.length - 1;
280 mediaSelectElement.addEventListener("change", this._emulateMediaChanged.bind(this, mediaSelectElement), false);
281 var fragment = createDocumentFragment();
282 fragment.appendChild(checkbox);
283 fragment.appendChild(fieldsetElement);
284 this.element.appendChild(fragment);
287 _emulateMediaChanged: function(select)
289 var media = select.options[select.selectedIndex].value;
290 WebInspector.overridesSupport.settings.emulatedCSSMedia.set(media);
293 __proto__: WebInspector.OverridesView.Tab.prototype
298 * @constructor
299 * @extends {WebInspector.OverridesView.Tab}
301 WebInspector.OverridesView.NetworkTab = function()
303 WebInspector.OverridesView.Tab.call(this, "network", WebInspector.UIString("Network"), [], [this._userAgentOverrideEnabled.bind(this)]);
304 this.element.classList.add("overrides-network");
305 this._createUserAgentSection();
308 WebInspector.OverridesView.NetworkTab.prototype = {
310 * @return {boolean}
312 _userAgentOverrideEnabled: function()
314 return !!WebInspector.overridesSupport.settings.userAgent.get();
317 _createUserAgentSection: function()
319 var fieldsetElement = this.element.createChild("fieldset");
320 fieldsetElement.createChild("label").textContent = WebInspector.UIString("Spoof user agent:");
321 var selectAndInput = WebInspector.OverridesUI.createUserAgentSelectAndInput();
322 fieldsetElement.appendChild(selectAndInput.select);
323 fieldsetElement.appendChild(selectAndInput.input);
325 WebInspector.overridesSupport.settings.userAgent.addChangeListener(this.updateActiveState, this);
328 __proto__: WebInspector.OverridesView.Tab.prototype
333 * @constructor
334 * @extends {WebInspector.OverridesView.Tab}
336 WebInspector.OverridesView.SensorsTab = function()
338 WebInspector.OverridesView.Tab.call(this, "sensors", WebInspector.UIString("Sensors"), [
339 WebInspector.overridesSupport.settings.overrideGeolocation,
340 WebInspector.overridesSupport.settings.overrideDeviceOrientation,
341 WebInspector.overridesSupport.settings.emulateTouch
344 this.element.classList.add("overrides-sensors");
345 this.registerRequiredCSS("emulation/accelerometer.css");
346 this.element.appendChild(this._createSettingCheckbox(WebInspector.UIString("Emulate touch screen"), WebInspector.overridesSupport.settings.emulateTouch, undefined));
347 this._appendGeolocationOverrideControl();
348 this._apendDeviceOrientationOverrideControl();
351 WebInspector.OverridesView.SensorsTab.prototype = {
352 _appendGeolocationOverrideControl: function()
354 const geolocationSetting = WebInspector.overridesSupport.settings.geolocationOverride.get();
355 var geolocation = WebInspector.OverridesSupport.GeolocationPosition.parseSetting(geolocationSetting);
356 this.element.appendChild(this._createSettingCheckbox(WebInspector.UIString("Emulate geolocation coordinates"), WebInspector.overridesSupport.settings.overrideGeolocation, this._geolocationOverrideCheckboxClicked.bind(this)));
357 this.element.appendChild(this._createGeolocationOverrideElement(geolocation));
358 this._geolocationOverrideCheckboxClicked(WebInspector.overridesSupport.settings.overrideGeolocation.get());
362 * @param {boolean} enabled
364 _geolocationOverrideCheckboxClicked: function(enabled)
366 if (enabled && !this._latitudeElement.value)
367 this._latitudeElement.focus();
370 _applyGeolocationUserInput: function()
372 this._setGeolocationPosition(WebInspector.OverridesSupport.GeolocationPosition.parseUserInput(this._latitudeElement.value.trim(), this._longitudeElement.value.trim(), this._geolocationErrorElement.checked), true);
376 * @param {?WebInspector.OverridesSupport.GeolocationPosition} geolocation
377 * @param {boolean} userInputModified
379 _setGeolocationPosition: function(geolocation, userInputModified)
381 if (!geolocation)
382 return;
384 if (!userInputModified) {
385 this._latitudeElement.value = geolocation.latitude;
386 this._longitudeElement.value = geolocation.longitude;
389 var value = geolocation.toSetting();
390 WebInspector.overridesSupport.settings.geolocationOverride.set(value);
394 * @param {!WebInspector.OverridesSupport.GeolocationPosition} geolocation
395 * @return {!Element}
397 _createGeolocationOverrideElement: function(geolocation)
399 var fieldsetElement = WebInspector.SettingsUI.createSettingFieldset(WebInspector.overridesSupport.settings.overrideGeolocation);
400 fieldsetElement.id = "geolocation-override-section";
402 var tableElement = fieldsetElement.createChild("table");
403 var rowElement = tableElement.createChild("tr");
404 var cellElement = rowElement.createChild("td");
405 cellElement = rowElement.createChild("td");
406 cellElement.createTextChild(WebInspector.UIString("Lat = "));
407 this._latitudeElement = WebInspector.SettingsUI.createInput(cellElement, "geolocation-override-latitude", String(geolocation.latitude), this._applyGeolocationUserInput.bind(this), true);
408 cellElement.createTextChild(" , ");
409 cellElement.createTextChild(WebInspector.UIString("Lon = "));
410 this._longitudeElement = WebInspector.SettingsUI.createInput(cellElement, "geolocation-override-longitude", String(geolocation.longitude), this._applyGeolocationUserInput.bind(this), true);
411 rowElement = tableElement.createChild("tr");
412 cellElement = rowElement.createChild("td");
413 cellElement.colSpan = 2;
414 var geolocationErrorLabelElement = createCheckboxLabel(WebInspector.UIString("Emulate position unavailable"), !geolocation || !!geolocation.error);
415 var geolocationErrorCheckboxElement = geolocationErrorLabelElement.checkboxElement;
416 geolocationErrorCheckboxElement.id = "geolocation-error";
417 geolocationErrorCheckboxElement.addEventListener("click", this._applyGeolocationUserInput.bind(this), false);
418 this._geolocationErrorElement = geolocationErrorCheckboxElement;
419 cellElement.appendChild(geolocationErrorLabelElement);
421 return fieldsetElement;
424 _apendDeviceOrientationOverrideControl: function()
426 const deviceOrientationSetting = WebInspector.overridesSupport.settings.deviceOrientationOverride.get();
427 var deviceOrientation = WebInspector.OverridesSupport.DeviceOrientation.parseSetting(deviceOrientationSetting);
428 this.element.appendChild(this._createSettingCheckbox(WebInspector.UIString("Accelerometer"), WebInspector.overridesSupport.settings.overrideDeviceOrientation, this._deviceOrientationOverrideCheckboxClicked.bind(this)));
429 this.element.appendChild(this._createDeviceOrientationOverrideElement(deviceOrientation));
430 this._deviceOrientationOverrideCheckboxClicked(WebInspector.overridesSupport.settings.overrideDeviceOrientation.get());
434 * @param {boolean} enabled
436 _deviceOrientationOverrideCheckboxClicked: function(enabled)
438 if (enabled && !this._alphaElement.value)
439 this._alphaElement.focus();
442 _applyDeviceOrientationUserInput: function()
444 this._setDeviceOrientation(WebInspector.OverridesSupport.DeviceOrientation.parseUserInput(this._alphaElement.value.trim(), this._betaElement.value.trim(), this._gammaElement.value.trim()), WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource.UserInput);
447 _resetDeviceOrientation: function()
449 this._setDeviceOrientation(new WebInspector.OverridesSupport.DeviceOrientation(0, 0, 0), WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource.ResetButton);
453 * @param {?WebInspector.OverridesSupport.DeviceOrientation} deviceOrientation
454 * @param {!WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource} modificationSource
456 _setDeviceOrientation: function(deviceOrientation, modificationSource)
458 if (!deviceOrientation)
459 return;
461 if (modificationSource != WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource.UserInput) {
462 this._alphaElement.value = deviceOrientation.alpha;
463 this._betaElement.value = deviceOrientation.beta;
464 this._gammaElement.value = deviceOrientation.gamma;
467 if (modificationSource != WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource.UserDrag)
468 this._setBoxOrientation(deviceOrientation);
470 var value = deviceOrientation.toSetting();
471 WebInspector.overridesSupport.settings.deviceOrientationOverride.set(value);
475 * @param {!Element} parentElement
476 * @param {string} id
477 * @param {string} label
478 * @param {string} defaultText
479 * @return {!Element}
481 _createAxisInput: function(parentElement, id, label, defaultText)
483 var div = parentElement.createChild("div", "accelerometer-axis-input-container");
484 div.createTextChild(label);
485 return WebInspector.SettingsUI.createInput(div, id, defaultText, this._applyDeviceOrientationUserInput.bind(this), true);
489 * @param {!WebInspector.OverridesSupport.DeviceOrientation} deviceOrientation
491 _createDeviceOrientationOverrideElement: function(deviceOrientation)
493 var fieldsetElement = WebInspector.SettingsUI.createSettingFieldset(WebInspector.overridesSupport.settings.overrideDeviceOrientation);
494 fieldsetElement.id = "device-orientation-override-section";
495 var tableElement = fieldsetElement.createChild("table");
496 var rowElement = tableElement.createChild("tr");
497 var cellElement = rowElement.createChild("td", "accelerometer-inputs-cell");
499 this._alphaElement = this._createAxisInput(cellElement, "device-orientation-override-alpha", "\u03B1: ", String(deviceOrientation.alpha));
500 this._betaElement = this._createAxisInput(cellElement, "device-orientation-override-beta", "\u03B2: ", String(deviceOrientation.beta));
501 this._gammaElement = this._createAxisInput(cellElement, "device-orientation-override-gamma", "\u03B3: ", String(deviceOrientation.gamma));
503 cellElement.appendChild(createTextButton(WebInspector.UIString("Reset"), this._resetDeviceOrientation.bind(this), "accelerometer-reset-button"));
505 this._stageElement = rowElement.createChild("td","accelerometer-stage");
506 this._boxElement = this._stageElement.createChild("section", "accelerometer-box");
508 this._boxElement.createChild("section", "front");
509 this._boxElement.createChild("section", "top");
510 this._boxElement.createChild("section", "back");
511 this._boxElement.createChild("section", "left");
512 this._boxElement.createChild("section", "right");
513 this._boxElement.createChild("section", "bottom");
515 WebInspector.installDragHandle(this._stageElement, this._onBoxDragStart.bind(this), this._onBoxDrag.bind(this), this._onBoxDragEnd.bind(this), "move");
516 this._setBoxOrientation(deviceOrientation);
517 return fieldsetElement;
521 * @param {!WebInspector.OverridesSupport.DeviceOrientation} deviceOrientation
523 _setBoxOrientation: function(deviceOrientation)
525 var matrix = new WebKitCSSMatrix();
526 this._boxMatrix = matrix.rotate(-deviceOrientation.beta, deviceOrientation.gamma, -deviceOrientation.alpha);
527 this._boxElement.style.webkitTransform = this._boxMatrix.toString();
531 * @param {!MouseEvent} event
532 * @return {boolean}
534 _onBoxDrag: function(event)
536 var mouseMoveVector = this._calculateRadiusVector(event.x, event.y);
537 if (!mouseMoveVector)
538 return true;
540 event.consume(true);
541 var axis = WebInspector.Geometry.crossProduct(this._mouseDownVector, mouseMoveVector);
542 axis.normalize();
543 var angle = WebInspector.Geometry.calculateAngle(this._mouseDownVector, mouseMoveVector);
544 var matrix = new WebKitCSSMatrix();
545 var rotationMatrix = matrix.rotateAxisAngle(axis.x, axis.y, axis.z, angle);
546 this._currentMatrix = rotationMatrix.multiply(this._boxMatrix);
547 this._boxElement.style.webkitTransform = this._currentMatrix;
548 var eulerAngles = WebInspector.Geometry.EulerAngles.fromRotationMatrix(this._currentMatrix);
549 var newOrientation = new WebInspector.OverridesSupport.DeviceOrientation(-eulerAngles.alpha, -eulerAngles.beta, eulerAngles.gamma);
550 this._setDeviceOrientation(newOrientation, WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource.UserDrag);
551 return false;
555 * @param {!MouseEvent} event
556 * @return {boolean}
558 _onBoxDragStart: function(event)
560 if (!WebInspector.overridesSupport.settings.overrideDeviceOrientation.get())
561 return false;
563 this._mouseDownVector = this._calculateRadiusVector(event.x, event.y);
565 if (!this._mouseDownVector)
566 return false;
568 event.consume(true);
569 return true;
572 _onBoxDragEnd: function()
574 this._boxMatrix = this._currentMatrix;
578 * @param {number} x
579 * @param {number} y
580 * @return {?WebInspector.Geometry.Vector}
582 _calculateRadiusVector: function(x, y)
584 var rect = this._stageElement.getBoundingClientRect();
585 var radius = Math.max(rect.width, rect.height) / 2;
586 var sphereX = (x - rect.left - rect.width / 2) / radius;
587 var sphereY = (y - rect.top - rect.height / 2) / radius;
588 var sqrSum = sphereX * sphereX + sphereY * sphereY;
589 if (sqrSum > 0.5)
590 return new WebInspector.Geometry.Vector(sphereX, sphereY, 0.5 / Math.sqrt(sqrSum));
592 return new WebInspector.Geometry.Vector(sphereX, sphereY, Math.sqrt(1 - sqrSum));
595 __proto__ : WebInspector.OverridesView.Tab.prototype
598 /** @enum {string} */
599 WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource = {
600 UserInput: "userInput",
601 UserDrag: "userDrag",
602 ResetButton: "resetButton"
606 * @constructor
607 * @implements {WebInspector.Revealer}
609 WebInspector.OverridesView.Revealer = function()
613 WebInspector.OverridesView.Revealer.prototype = {
615 * @override
616 * @param {!Object} overridesSupport
617 * @return {!Promise}
619 reveal: function(overridesSupport)
621 WebInspector.inspectorView.showViewInDrawer("emulation");
622 return Promise.resolve();