• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
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.
17 *
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.
29 */
30
31/**
32 * @constructor
33 * @implements {WebInspector.TargetManager.Observer}
34 * @extends {WebInspector.Object}
35 * @param {boolean} responsiveDesignAvailable
36 */
37WebInspector.OverridesSupport = function(responsiveDesignAvailable)
38{
39    WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._onMainFrameNavigated.bind(this), this);
40    this._emulateViewportEnabled = false;
41    this._userAgent = "";
42    this._pageResizer = null;
43    this._initialized = false;
44    this._deviceMetricsThrottler = new WebInspector.Throttler(0);
45    this._responsiveDesignAvailable = responsiveDesignAvailable;
46    WebInspector.targetManager.observeTargets(this);
47}
48
49WebInspector.OverridesSupport.Events = {
50    OverridesWarningUpdated: "OverridesWarningUpdated",
51    EmulationStateChanged: "EmulationStateChanged"
52}
53
54/**
55 * @interface
56 * @extends {WebInspector.EventTarget}
57 */
58WebInspector.OverridesSupport.PageResizer = function()
59{
60};
61
62WebInspector.OverridesSupport.PageResizer.Events = {
63    AvailableSizeChanged: "AvailableSizeChanged",  // No data.
64    ResizeRequested: "ResizeRequested"  // Data is of type {!Size}.
65};
66
67WebInspector.OverridesSupport.PageResizer.prototype = {
68    /**
69     * Zero width and height mean default size.
70     * Scale should be applied to page-scale-dependent UI bits. Zero means no scale.
71     * @param {number} dipWidth
72     * @param {number} dipHeight
73     * @param {number} scale
74     */
75    update: function(dipWidth, dipHeight, scale) { }
76};
77
78/**
79 * @param {string} description
80 * @param {string} userAgent
81 * @constructor
82 */
83WebInspector.OverridesSupport.Device = function(description, userAgent)
84{
85    this.width = 800;
86    this.height = 600;
87    this.deviceScaleFactor = 1;
88    this.textAutosizing = true;
89    this.userAgent = userAgent;
90    this.touch = true;
91    this.viewport = true;
92
93    var splitMetrics = description.split("x");
94    if (splitMetrics.length >= 3) {
95        this.width = parseInt(splitMetrics[0], 10);
96        this.height = parseInt(splitMetrics[1], 10);
97        this.deviceScaleFactor = parseFloat(splitMetrics[2]);
98    }
99    if (splitMetrics.length >= 4)
100        this.touch = splitMetrics[3] == 1;
101    if (splitMetrics.length >= 5)
102        this.viewport = splitMetrics[4] == 1;
103}
104
105/**
106 * @constructor
107 * @param {number} latitude
108 * @param {number} longitude
109 * @param {string} error
110 */
111WebInspector.OverridesSupport.GeolocationPosition = function(latitude, longitude, error)
112{
113    this.latitude = latitude;
114    this.longitude = longitude;
115    this.error = error;
116}
117
118WebInspector.OverridesSupport.GeolocationPosition.prototype = {
119    /**
120     * @return {string}
121     */
122    toSetting: function()
123    {
124        return (typeof this.latitude === "number" && typeof this.longitude === "number" && typeof this.error === "string") ? this.latitude + "@" + this.longitude + ":" + this.error : "";
125    }
126}
127
128/**
129 * @return {!WebInspector.OverridesSupport.GeolocationPosition}
130 */
131WebInspector.OverridesSupport.GeolocationPosition.parseSetting = function(value)
132{
133    if (value) {
134        var splitError = value.split(":");
135        if (splitError.length === 2) {
136            var splitPosition = splitError[0].split("@")
137            if (splitPosition.length === 2)
138                return new WebInspector.OverridesSupport.GeolocationPosition(parseFloat(splitPosition[0]), parseFloat(splitPosition[1]), splitError[1]);
139        }
140    }
141    return new WebInspector.OverridesSupport.GeolocationPosition(0, 0, "");
142}
143
144/**
145 * @return {?WebInspector.OverridesSupport.GeolocationPosition}
146 */
147WebInspector.OverridesSupport.GeolocationPosition.parseUserInput = function(latitudeString, longitudeString, errorStatus)
148{
149    function isUserInputValid(value)
150    {
151        if (!value)
152            return true;
153        return /^[-]?[0-9]*[.]?[0-9]*$/.test(value);
154    }
155
156    if (!latitudeString ^ !latitudeString)
157        return null;
158
159    var isLatitudeValid = isUserInputValid(latitudeString);
160    var isLongitudeValid = isUserInputValid(longitudeString);
161
162    if (!isLatitudeValid && !isLongitudeValid)
163        return null;
164
165    var latitude = isLatitudeValid ? parseFloat(latitudeString) : -1;
166    var longitude = isLongitudeValid ? parseFloat(longitudeString) : -1;
167
168    return new WebInspector.OverridesSupport.GeolocationPosition(latitude, longitude, errorStatus ? "PositionUnavailable" : "");
169}
170
171WebInspector.OverridesSupport.GeolocationPosition.clearGeolocationOverride = function()
172{
173    GeolocationAgent.clearGeolocationOverride();
174}
175
176/**
177 * @constructor
178 * @param {number} alpha
179 * @param {number} beta
180 * @param {number} gamma
181 */
182WebInspector.OverridesSupport.DeviceOrientation = function(alpha, beta, gamma)
183{
184    this.alpha = alpha;
185    this.beta = beta;
186    this.gamma = gamma;
187}
188
189WebInspector.OverridesSupport.DeviceOrientation.prototype = {
190    /**
191     * @return {string}
192     */
193    toSetting: function()
194    {
195        return JSON.stringify(this);
196    }
197}
198
199/**
200 * @return {!WebInspector.OverridesSupport.DeviceOrientation}
201 */
202WebInspector.OverridesSupport.DeviceOrientation.parseSetting = function(value)
203{
204    if (value) {
205        var jsonObject = JSON.parse(value);
206        return new WebInspector.OverridesSupport.DeviceOrientation(jsonObject.alpha, jsonObject.beta, jsonObject.gamma);
207    }
208    return new WebInspector.OverridesSupport.DeviceOrientation(0, 0, 0);
209}
210
211/**
212 * @return {?WebInspector.OverridesSupport.DeviceOrientation}
213 */
214WebInspector.OverridesSupport.DeviceOrientation.parseUserInput = function(alphaString, betaString, gammaString)
215{
216    function isUserInputValid(value)
217    {
218        if (!value)
219            return true;
220        return /^[-]?[0-9]*[.]?[0-9]*$/.test(value);
221    }
222
223    if (!alphaString ^ !betaString ^ !gammaString)
224        return null;
225
226    var isAlphaValid = isUserInputValid(alphaString);
227    var isBetaValid = isUserInputValid(betaString);
228    var isGammaValid = isUserInputValid(gammaString);
229
230    if (!isAlphaValid && !isBetaValid && !isGammaValid)
231        return null;
232
233    var alpha = isAlphaValid ? parseFloat(alphaString) : -1;
234    var beta = isBetaValid ? parseFloat(betaString) : -1;
235    var gamma = isGammaValid ? parseFloat(gammaString) : -1;
236
237    return new WebInspector.OverridesSupport.DeviceOrientation(alpha, beta, gamma);
238}
239
240WebInspector.OverridesSupport.DeviceOrientation.clearDeviceOrientationOverride = function()
241{
242    PageAgent.clearDeviceOrientationOverride();
243}
244
245/**
246 * @param {string} value
247 * @return {string}
248 */
249WebInspector.OverridesSupport.deviceSizeValidator = function(value)
250{
251    if (!value || (/^[\d]+$/.test(value) && value >= 0 && value <= 10000))
252        return "";
253    return WebInspector.UIString("Value must be non-negative integer");
254}
255
256/**
257 * @param {string} value
258 * @return {string}
259 */
260WebInspector.OverridesSupport.deviceScaleFactorValidator = function(value)
261{
262    if (!value || (/^[\d]+(\.\d+)?|\.\d+$/.test(value) && value >= 0 && value <= 10))
263        return "";
264    return WebInspector.UIString("Value must be non-negative float");
265}
266
267// Second element is user agent value.
268// Third element lists device metrics separated by 'x':
269// - screen width,
270// - screen height,
271// - device scale factor,
272// - touch (true by default if not present),
273// - viewport (true by default if not present).
274WebInspector.OverridesSupport._phones = [
275    ["Apple iPhone 3GS",
276     "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5",
277     "320x480x1"],
278    ["Apple iPhone 4",
279     "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5",
280     "320x480x2"],
281    ["Apple iPhone 5",
282     "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X; en-us) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53",
283     "320x568x2"],
284    ["BlackBerry Z10",
285     "Mozilla/5.0 (BB10; Touch) AppleWebKit/537.10+ (KHTML, like Gecko) Version/10.0.9.2372 Mobile Safari/537.10+",
286     "384x640x2"],
287    ["BlackBerry Z30",
288     "Mozilla/5.0 (BB10; Touch) AppleWebKit/537.10+ (KHTML, like Gecko) Version/10.0.9.2372 Mobile Safari/537.10+",
289     "360x640x2"],
290    ["Google Nexus 4",
291     "Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 4 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19",
292     "384x640x2"],
293    ["Google Nexus 5",
294     "Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 5 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19",
295     "360x640x3"],
296    ["Google Nexus S",
297     "Mozilla/5.0 (Linux; U; Android 2.3.4; en-us; Nexus S Build/GRJ22) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
298     "320x533x1.5"],
299    ["HTC Evo, Touch HD, Desire HD, Desire",
300     "Mozilla/5.0 (Linux; U; Android 2.2; en-us; Sprint APA9292KT Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
301     "320x533x1.5"],
302    ["HTC One X, EVO LTE",
303     "Mozilla/5.0 (Linux; Android 4.0.3; HTC One X Build/IML74K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19",
304     "360x640x2"],
305    ["HTC Sensation, Evo 3D",
306     "Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; HTC Sensation Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
307     "360x640x1.5"],
308    ["LG Optimus 2X, Optimus 3D, Optimus Black",
309     "Mozilla/5.0 (Linux; U; Android 2.2; en-us; LG-P990/V08c Build/FRG83) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 MMS/LG-Android-MMS-V1.0/1.2",
310     "320x533x1.5"],
311    ["LG Optimus G",
312     "Mozilla/5.0 (Linux; Android 4.0; LG-E975 Build/IMM76L) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19",
313     "384x640x2"],
314    ["LG Optimus LTE, Optimus 4X HD",
315     "Mozilla/5.0 (Linux; U; Android 2.3; en-us; LG-P930 Build/GRJ90) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
316     "424x753x1.7"],
317    ["LG Optimus One",
318     "Mozilla/5.0 (Linux; U; Android 2.2.1; en-us; LG-MS690 Build/FRG83) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
319     "213x320x1.5"],
320    ["Motorola Defy, Droid, Droid X, Milestone",
321     "Mozilla/5.0 (Linux; U; Android 2.0; en-us; Milestone Build/ SHOLS_U2_01.03.1) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
322     "320x569x1.5"],
323    ["Motorola Droid 3, Droid 4, Droid Razr, Atrix 4G, Atrix 2",
324     "Mozilla/5.0 (Linux; U; Android 2.2; en-us; Droid Build/FRG22D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
325     "540x960x1"],
326    ["Motorola Droid Razr HD",
327     "Mozilla/5.0 (Linux; U; Android 2.3; en-us; DROID RAZR 4G Build/6.5.1-73_DHD-11_M1-29) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
328     "720x1280x1"],
329    ["Nokia C5, C6, C7, N97, N8, X7",
330     "NokiaN97/21.1.107 (SymbianOS/9.4; Series60/5.0 Mozilla/5.0; Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebkit/525 (KHTML, like Gecko) BrowserNG/7.1.4",
331     "360x640x1"],
332    ["Nokia Lumia 7X0, Lumia 8XX, Lumia 900, N800, N810, N900",
333     "Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 820)",
334     "320x533x1.5"],
335    ["Samsung Galaxy Note 3",
336     "Mozilla/5.0 (Linux; U; Android 4.3; en-us; SM-N900T Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
337     "540x960x2"],
338    ["Samsung Galaxy Note II",
339     "Mozilla/5.0 (Linux; U; Android 4.1; en-us; GT-N7100 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
340     "360x640x2"],
341    ["Samsung Galaxy Note",
342     "Mozilla/5.0 (Linux; U; Android 2.3; en-us; SAMSUNG-SGH-I717 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
343     "400x640x2"],
344    ["Samsung Galaxy S III, Galaxy Nexus",
345     "Mozilla/5.0 (Linux; U; Android 4.0; en-us; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
346     "360x640x2"],
347    ["Samsung Galaxy S, S II, W",
348     "Mozilla/5.0 (Linux; U; Android 2.1; en-us; GT-I9000 Build/ECLAIR) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2",
349     "320x533x1.5"],
350    ["Samsung Galaxy S4",
351     "Mozilla/5.0 (Linux; Android 4.2.2; GT-I9505 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36",
352     "360x640x3"],
353    ["Sony Xperia S, Ion",
354     "Mozilla/5.0 (Linux; U; Android 4.0; en-us; LT28at Build/6.1.C.1.111) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
355     "360x640x2"],
356    ["Sony Xperia Sola, U",
357     "Mozilla/5.0 (Linux; U; Android 2.3; en-us; SonyEricssonST25i Build/6.0.B.1.564) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
358     "480x854x1"],
359    ["Sony Xperia Z, Z1",
360     "Mozilla/5.0 (Linux; U; Android 4.2; en-us; SonyC6903 Build/14.1.G.1.518) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
361     "360x640x3"],
362];
363
364WebInspector.OverridesSupport._tablets = [
365    ["Amazon Kindle Fire HDX 7\u2033",
366     "Mozilla/5.0 (Linux; U; en-us; KFTHWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Safari/535.19 Silk-Accelerated=true",
367     "1920x1200x2"],
368    ["Amazon Kindle Fire HDX 8.9\u2033",
369     "Mozilla/5.0 (Linux; U; en-us; KFAPWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Safari/535.19 Silk-Accelerated=true",
370     "2560x1600x2"],
371    ["Amazon Kindle Fire (First Generation)",
372     "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us; Silk/1.0.141.16-Gen4_11004310) AppleWebkit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 Silk-Accelerated=true",
373     "1024x600x1"],
374    ["Apple iPad 1 / 2 / iPad Mini",
375     "Mozilla/5.0 (iPad; CPU OS 4_3_5 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8L1 Safari/6533.18.5",
376     "1024x768x1"],
377    ["Apple iPad 3 / 4",
378     "Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53",
379     "1024x768x2"],
380    ["BlackBerry PlayBook",
381     "Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML like Gecko) Version/7.2.1.0 Safari/536.2+",
382     "1024x600x1"],
383    ["Google Nexus 10",
384     "Mozilla/5.0 (Linux; Android 4.3; Nexus 10 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Safari/537.36",
385     "1280x800x2"],
386    ["Google Nexus 7 2",
387     "Mozilla/5.0 (Linux; Android 4.3; Nexus 7 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Safari/537.36",
388     "960x600x2"],
389    ["Google Nexus 7",
390     "Mozilla/5.0 (Linux; Android 4.3; Nexus 7 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Safari/537.36",
391     "966x604x1.325"],
392    ["Motorola Xoom, Xyboard",
393     "Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/525.10 (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2",
394     "1280x800x1"],
395    ["Samsung Galaxy Tab 7.7, 8.9, 10.1",
396     "Mozilla/5.0 (Linux; U; Android 2.2; en-us; SCH-I800 Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
397     "1280x800x1"],
398    ["Samsung Galaxy Tab",
399     "Mozilla/5.0 (Linux; U; Android 2.2; en-us; SCH-I800 Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
400     "1024x600x1"],
401];
402
403WebInspector.OverridesSupport._notebooks = [
404    ["Notebook with touch",
405     "",
406     "1280x950x1x1x0"],
407    ["Notebook with HiDPI screen",
408     "",
409     "1440x900x2x0x0"],
410    ["Generic notebook",
411     "",
412     "1280x800x1x0x0"],
413];
414
415WebInspector.OverridesSupport._networkThroughputUnlimitedValue = -1;
416WebInspector.OverridesSupport._networkThroughputPresets = [
417    ["Offline", 0],
418    ["5 Kbps", 5 * 1024 / 8],
419    ["10 Kbps (GSM)", 10 * 1024 / 8],
420    ["20 Kbps", 20 * 1024 / 8],
421    ["40 Kbps (GPRS)", 40 * 1024 / 8],
422    ["80 Kbps", 80 * 1024 / 8],
423    ["160 Kbps (EDGE)", 160 * 1024 / 8],
424    ["320 Kbps", 320 * 1024 / 8],
425    ["640 Kbps (3G)", 640 * 1024 / 8],
426    ["1 Mbps", 1024 * 1024 / 8],
427    ["2 Mbps (802.11b)", 2048 * 1024 / 8],
428    ["No throttling", WebInspector.OverridesSupport._networkThroughputUnlimitedValue]
429];
430
431WebInspector.OverridesSupport.prototype = {
432    /**
433     * @return {boolean}
434     */
435    canEmulate: function()
436    {
437        return !!this._target && !this._target.isMobile();
438    },
439
440    /**
441     * @return {boolean}
442     */
443    emulationEnabled: function()
444    {
445        return this.canEmulate() && this.settings._emulationEnabled.get();
446    },
447
448    /**
449     * @param {boolean} enabled
450     */
451    setEmulationEnabled: function(enabled)
452    {
453        if (this.canEmulate()) {
454            this.settings._emulationEnabled.set(enabled);
455            this.dispatchEventToListeners(WebInspector.OverridesSupport.Events.EmulationStateChanged);
456        }
457    },
458
459    /**
460     * @return {boolean}
461     */
462    responsiveDesignAvailable: function()
463    {
464        return this._responsiveDesignAvailable;
465    },
466
467    /**
468     * @param {?WebInspector.OverridesSupport.PageResizer} pageResizer
469     * @param {!Size} availableSize
470     */
471    setPageResizer: function(pageResizer, availableSize)
472    {
473        if (pageResizer === this._pageResizer)
474            return;
475
476        if (this._pageResizer) {
477            this._pageResizer.removeEventListener(WebInspector.OverridesSupport.PageResizer.Events.AvailableSizeChanged, this._onPageResizerAvailableSizeChanged, this);
478            this._pageResizer.removeEventListener(WebInspector.OverridesSupport.PageResizer.Events.ResizeRequested, this._onPageResizerResizeRequested, this);
479        }
480        this._pageResizer = pageResizer;
481        this._pageResizerAvailableSize = availableSize;
482        if (this._pageResizer) {
483            this._pageResizer.addEventListener(WebInspector.OverridesSupport.PageResizer.Events.AvailableSizeChanged, this._onPageResizerAvailableSizeChanged, this);
484            this._pageResizer.addEventListener(WebInspector.OverridesSupport.PageResizer.Events.ResizeRequested, this._onPageResizerResizeRequested, this);
485        }
486        if (this._initialized)
487            this._deviceMetricsChanged();
488    },
489
490    /**
491     * @param {!WebInspector.OverridesSupport.Device} device
492     */
493    emulateDevice: function(device)
494    {
495        this._deviceMetricsChangedListenerMuted = true;
496        this._userAgentChangedListenerMuted = true;
497        this.settings.userAgent.set(device.userAgent);
498        this.settings.deviceWidth.set(device.width);
499        this.settings.deviceHeight.set(device.height);
500        this.settings.deviceScaleFactor.set(device.deviceScaleFactor);
501        this.settings.deviceTextAutosizing.set(device.textAutosizing);
502        this.settings.emulateTouch.set(device.touch);
503        this.settings.emulateViewport.set(device.viewport);
504        delete this._deviceMetricsChangedListenerMuted;
505        delete this._userAgentChangedListenerMuted;
506
507        if (this._initialized) {
508            this._deviceMetricsChanged();
509            this._userAgentChanged();
510        }
511    },
512
513    reset: function()
514    {
515        this._deviceMetricsChangedListenerMuted = true;
516        this._userAgentChangedListenerMuted = true;
517        this.settings.userAgent.set("");
518        this.settings.deviceWidth.set(0);
519        this.settings.deviceHeight.set(0);
520        this.settings.deviceScaleFactor.set(0);
521        this.settings.deviceTextAutosizing.set(false);
522        this.settings.emulateTouch.set(false);
523        this.settings.emulateViewport.set(false);
524        this.settings.overrideDeviceOrientation.set(false);
525        this.settings.overrideGeolocation.set(false);
526        this.settings.overrideCSSMedia.set(false);
527        this.settings.networkConditionsThroughput.set(WebInspector.OverridesSupport._networkThroughputUnlimitedValue);
528        delete this._deviceMetricsChangedListenerMuted;
529        delete this._userAgentChangedListenerMuted;
530
531        if (this._initialized) {
532            this._deviceMetricsChanged();
533            this._userAgentChanged();
534        }
535    },
536
537    /**
538     * @param {!WebInspector.OverridesSupport.Device} device
539     * @return {boolean}
540     */
541    isEmulatingDevice: function(device)
542    {
543        return this.settings.userAgent.get() === device.userAgent
544            && this.settings.deviceWidth.get() === device.width
545            && this.settings.deviceHeight.get() === device.height
546            && this.settings.deviceScaleFactor.get() === device.deviceScaleFactor
547            && this.settings.deviceTextAutosizing.get() === device.textAutosizing
548            && this.settings.emulateTouch.get() === device.touch
549            && this.settings.emulateViewport.get() === device.viewport;
550    },
551
552    applyInitialOverrides: function()
553    {
554        if (!this._target) {
555            this._applyInitialOverridesOnTargetAdded = true;
556            return;
557        }
558
559        this._initialized = true;
560
561        this.settings._emulationEnabled.addChangeListener(this._userAgentChanged, this);
562        this.settings.userAgent.addChangeListener(this._userAgentChanged, this);
563
564        this.settings._emulationEnabled.addChangeListener(this._deviceMetricsChanged, this);
565        this.settings.deviceWidth.addChangeListener(this._deviceMetricsChanged, this);
566        this.settings.deviceHeight.addChangeListener(this._deviceMetricsChanged, this);
567        this.settings.deviceScaleFactor.addChangeListener(this._deviceMetricsChanged, this);
568        this.settings.deviceTextAutosizing.addChangeListener(this._deviceMetricsChanged, this);
569        this.settings.emulateViewport.addChangeListener(this._deviceMetricsChanged, this);
570        this.settings.deviceFitWindow.addChangeListener(this._deviceMetricsChanged, this);
571
572        this.settings._emulationEnabled.addChangeListener(this._geolocationPositionChanged, this);
573        this.settings.overrideGeolocation.addChangeListener(this._geolocationPositionChanged, this);
574        this.settings.geolocationOverride.addChangeListener(this._geolocationPositionChanged, this);
575
576        this.settings._emulationEnabled.addChangeListener(this._deviceOrientationChanged, this);
577        this.settings.overrideDeviceOrientation.addChangeListener(this._deviceOrientationChanged, this);
578        this.settings.deviceOrientationOverride.addChangeListener(this._deviceOrientationChanged, this);
579
580        this.settings._emulationEnabled.addChangeListener(this._emulateTouchEventsChanged, this);
581        this.settings.emulateTouch.addChangeListener(this._emulateTouchEventsChanged, this);
582
583        this.settings._emulationEnabled.addChangeListener(this._cssMediaChanged, this);
584        this.settings.overrideCSSMedia.addChangeListener(this._cssMediaChanged, this);
585        this.settings.emulatedCSSMedia.addChangeListener(this._cssMediaChanged, this);
586
587        if (WebInspector.experimentsSettings.networkConditions.isEnabled()) {
588            this.settings._emulationEnabled.addChangeListener(this._networkConditionsChanged, this);
589            this.settings.networkConditionsThroughput.addChangeListener(this._networkConditionsChanged, this);
590        }
591
592        WebInspector.settings.showMetricsRulers.addChangeListener(this._showRulersChanged, this);
593        this._showRulersChanged();
594
595        if (!this.emulationEnabled())
596            return;
597
598        if (this.settings.overrideDeviceOrientation.get())
599            this._deviceOrientationChanged();
600
601        if (this.settings.overrideGeolocation.get())
602            this._geolocationPositionChanged();
603
604        if (this.settings.emulateTouch.get())
605            this._emulateTouchEventsChanged();
606
607        if (this.settings.overrideCSSMedia.get())
608            this._cssMediaChanged();
609
610        this._deviceMetricsChanged();
611
612        this._userAgentChanged();
613
614        if (WebInspector.experimentsSettings.networkConditions.isEnabled() && this.networkThroughputIsLimited())
615            this._networkConditionsChanged();
616    },
617
618    _userAgentChanged: function()
619    {
620        if (this._userAgentChangedListenerMuted)
621            return;
622        var userAgent = this.emulationEnabled() ? this.settings.userAgent.get() : "";
623        NetworkAgent.setUserAgentOverride(userAgent);
624        if (this._userAgent !== userAgent)
625            this._updateUserAgentWarningMessage(WebInspector.UIString("You might need to reload the page for proper user agent spoofing and viewport rendering."));
626        this._userAgent = userAgent;
627    },
628
629    /**
630     * @param {!WebInspector.Event} event
631     */
632    _onPageResizerAvailableSizeChanged: function(event)
633    {
634        this._pageResizerAvailableSize = /** @type {!Size} */ (event.data);
635        if (this._initialized)
636            this._deviceMetricsChanged();
637    },
638
639    /**
640     * @param {!WebInspector.Event} event
641     */
642    _onPageResizerResizeRequested: function(event)
643    {
644        if (typeof event.data.width !== "undefined") {
645            var width = /** @type {number} */ (event.data.width);
646            if (width !== this.settings.deviceWidth.get())
647                this.settings.deviceWidth.set(width);
648        }
649        if (typeof event.data.height !== "undefined") {
650            var height = /** @type {number} */ (event.data.height);
651            if (height !== this.settings.deviceHeight.get())
652                this.settings.deviceHeight.set(height);
653        }
654    },
655
656    _deviceMetricsChanged: function()
657    {
658        this._showRulersChanged();
659
660        if (this._deviceMetricsChangedListenerMuted)
661            return;
662
663        if (!this.emulationEnabled()) {
664            this._deviceMetricsThrottler.schedule(clearDeviceMetricsOverride.bind(this));
665            if (this._pageResizer)
666                this._pageResizer.update(0, 0, 1);
667            return;
668        }
669
670        var dipWidth = this.settings.deviceWidth.get();
671        var dipHeight = this.settings.deviceHeight.get();
672
673        var overrideWidth = dipWidth;
674        var overrideHeight = dipHeight;
675        if (this._pageResizer) {
676            var available = this._pageResizerAvailableSize;
677            if (available.width >= dipWidth && available.height >= dipHeight) {
678                this._pageResizer.update(dipWidth, dipHeight, 0);
679                // When we have enough space, no page size override is required. This will speed things up and remove lag.
680                overrideWidth = 0;
681                overrideHeight = 0;
682            } else {
683                this._pageResizer.update(Math.min(dipWidth, available.width), Math.min(dipHeight, available.height), 0);
684            }
685        }
686
687        this._deviceMetricsThrottler.schedule(setDeviceMetricsOverride.bind(this));
688
689        /**
690         * @param {!WebInspector.Throttler.FinishCallback} finishCallback
691         * @this {WebInspector.OverridesSupport}
692         */
693        function setDeviceMetricsOverride(finishCallback)
694        {
695            PageAgent.setDeviceMetricsOverride(
696                overrideWidth, overrideHeight, this.settings.deviceScaleFactor.get(),
697                this.settings.emulateViewport.get(), this._pageResizer ? false : this.settings.deviceFitWindow.get(),
698                this.settings.deviceTextAutosizing.get(), this._fontScaleFactor(overrideWidth || dipWidth, overrideHeight || dipHeight),
699                apiCallback.bind(this, finishCallback));
700        }
701
702        /**
703         * @param {!WebInspector.Throttler.FinishCallback} finishCallback
704         * @this {WebInspector.OverridesSupport}
705         */
706        function clearDeviceMetricsOverride(finishCallback)
707        {
708            PageAgent.clearDeviceMetricsOverride(apiCallback.bind(this, finishCallback));
709        }
710
711        /**
712         * @param {!WebInspector.Throttler.FinishCallback} finishCallback
713         * @param {?Protocol.Error} error
714         * @this {WebInspector.OverridesSupport}
715         */
716        function apiCallback(finishCallback, error)
717        {
718            if (error) {
719                this._updateDeviceMetricsWarningMessage(WebInspector.UIString("Screen emulation is not available on this page."));
720                this._deviceMetricsOverrideAppliedForTest();
721                finishCallback();
722                return;
723            }
724
725            var viewportEnabled = this.emulationEnabled() && this.settings.emulateViewport.get();
726            if (this._emulateViewportEnabled !== viewportEnabled)
727                this._updateDeviceMetricsWarningMessage(WebInspector.UIString("You might need to reload the page for proper user agent spoofing and viewport rendering."));
728            this._emulateViewportEnabled = viewportEnabled;
729            this._deviceMetricsOverrideAppliedForTest();
730            finishCallback();
731        }
732    },
733
734    _deviceMetricsOverrideAppliedForTest: function()
735    {
736        // Used for sniffing in tests.
737    },
738
739    _geolocationPositionChanged: function()
740    {
741        if (!this.emulationEnabled() || !this.settings.overrideGeolocation.get()) {
742            GeolocationAgent.clearGeolocationOverride();
743            return;
744        }
745        var geolocation = WebInspector.OverridesSupport.GeolocationPosition.parseSetting(this.settings.geolocationOverride.get());
746        if (geolocation.error)
747            GeolocationAgent.setGeolocationOverride();
748        else
749            GeolocationAgent.setGeolocationOverride(geolocation.latitude, geolocation.longitude, 150);
750    },
751
752    _deviceOrientationChanged: function()
753    {
754        if (!this.emulationEnabled() || !this.settings.overrideDeviceOrientation.get()) {
755            PageAgent.clearDeviceOrientationOverride();
756            return;
757        }
758
759        var deviceOrientation = WebInspector.OverridesSupport.DeviceOrientation.parseSetting(this.settings.deviceOrientationOverride.get());
760        PageAgent.setDeviceOrientationOverride(deviceOrientation.alpha, deviceOrientation.beta, deviceOrientation.gamma);
761    },
762
763    _emulateTouchEventsChanged: function()
764    {
765        var emulateTouch = this.emulationEnabled() && this.settings.emulateTouch.get();
766        var targets = WebInspector.targetManager.targets();
767        for (var i = 0; i < targets.length; ++i)
768            targets[i].domModel.emulateTouchEventObjects(emulateTouch);
769    },
770
771    _cssMediaChanged: function()
772    {
773        var enabled = this.emulationEnabled() && this.settings.overrideCSSMedia.get();
774        PageAgent.setEmulatedMedia(enabled ? this.settings.emulatedCSSMedia.get() : "");
775        var targets = WebInspector.targetManager.targets();
776        for (var i = 0; i < targets.length; ++i)
777            targets[i].cssModel.mediaQueryResultChanged();
778    },
779
780    _networkConditionsChanged: function()
781    {
782        if (!this.emulationEnabled() || !this.networkThroughputIsLimited()) {
783            NetworkAgent.emulateNetworkConditions(false, 0, 0, 0);
784        } else {
785            var throughput = this.settings.networkConditionsThroughput.get();
786            var offline = !throughput;
787            NetworkAgent.emulateNetworkConditions(offline, 0, throughput, throughput);
788        }
789    },
790
791    /**
792     * @return {boolean}
793     */
794    showMetricsRulers: function()
795    {
796        var rulersInPageResizer = this._pageResizer && this.emulationEnabled();
797        return WebInspector.settings.showMetricsRulers.get() && !rulersInPageResizer;
798    },
799
800    _showRulersChanged: function()
801    {
802        if (WebInspector.experimentsSettings.responsiveDesign.isEnabled())
803            return;
804        PageAgent.setShowViewportSizeOnResize(true, this.showMetricsRulers());
805    },
806
807    _onMainFrameNavigated: function()
808    {
809        if (this._initialized)
810            this._deviceMetricsChanged();
811        this._updateUserAgentWarningMessage("");
812        this._updateDeviceMetricsWarningMessage("");
813    },
814
815    /**
816     * @param {string} warningMessage
817     */
818    _updateDeviceMetricsWarningMessage: function(warningMessage)
819    {
820        this._deviceMetricsWarningMessage = warningMessage;
821        this.dispatchEventToListeners(WebInspector.OverridesSupport.Events.OverridesWarningUpdated);
822    },
823
824    /**
825     * @param {string} warningMessage
826     */
827    _updateUserAgentWarningMessage: function(warningMessage)
828    {
829        this._userAgentWarningMessage = warningMessage;
830        this.dispatchEventToListeners(WebInspector.OverridesSupport.Events.OverridesWarningUpdated);
831    },
832
833    /**
834     * @return {string}
835     */
836    warningMessage: function()
837    {
838        return this._deviceMetricsWarningMessage || this._userAgentWarningMessage || "";
839    },
840
841    clearWarningMessage: function()
842    {
843        this._deviceMetricsWarningMessage = "";
844        this._userAgentWarningMessage = "";
845        this.dispatchEventToListeners(WebInspector.OverridesSupport.Events.OverridesWarningUpdated);
846    },
847
848    /**
849     * @param {!WebInspector.Target} target
850     */
851    targetAdded: function(target)
852    {
853        // FIXME: adapt this to multiple targets.
854        if (this._target)
855            return;
856        this._target = target;
857
858        this.settings = {};
859        this.settings._emulationEnabled = WebInspector.settings.createSetting("emulationEnabled", false);
860
861        this.settings.userAgent = WebInspector.settings.createSetting("userAgent", "");
862
863        this.settings.deviceWidth = WebInspector.settings.createSetting("deviceWidth", 0);
864        this.settings.deviceHeight = WebInspector.settings.createSetting("deviceHeight", 0);
865        this.settings.deviceScaleFactor = WebInspector.settings.createSetting("deviceScaleFactor", 0);
866        this.settings.deviceTextAutosizing = WebInspector.settings.createSetting("deviceTextAutosizing", true);
867        this.settings.deviceFitWindow = WebInspector.settings.createSetting("deviceFitWindow", true);
868        // FIXME: rename viewport to mobile everywhere in the code.
869        this.settings.emulateViewport = WebInspector.settings.createSetting("emulateViewport", false);
870
871        this.settings.emulateTouch = WebInspector.settings.createSetting("emulateTouch", false);
872
873        this.settings.overrideGeolocation = WebInspector.settings.createSetting("overrideGeolocation", false);
874        this.settings.geolocationOverride = WebInspector.settings.createSetting("geolocationOverride", "");
875
876        this.settings.overrideDeviceOrientation = WebInspector.settings.createSetting("overrideDeviceOrientation", false);
877        this.settings.deviceOrientationOverride = WebInspector.settings.createSetting("deviceOrientationOverride", "");
878
879        this.settings.overrideCSSMedia = WebInspector.settings.createSetting("overrideCSSMedia", false);
880        this.settings.emulatedCSSMedia = WebInspector.settings.createSetting("emulatedCSSMedia", "print");
881
882        this.settings.networkConditionsThroughput = WebInspector.settings.createSetting("networkConditionsThroughput", WebInspector.OverridesSupport._networkThroughputUnlimitedValue);
883
884        if (this._applyInitialOverridesOnTargetAdded) {
885            delete this._applyInitialOverridesOnTargetAdded;
886            this.applyInitialOverrides();
887        }
888    },
889
890    swapDimensions: function()
891    {
892        var width = WebInspector.overridesSupport.settings.deviceWidth.get();
893        var height = WebInspector.overridesSupport.settings.deviceHeight.get();
894        WebInspector.overridesSupport.settings.deviceWidth.set(height);
895        WebInspector.overridesSupport.settings.deviceHeight.set(width);
896    },
897
898    /**
899     * @param {!WebInspector.Target} target
900     */
901    targetRemoved: function(target)
902    {
903        // FIXME: adapt this to multiple targets.
904    },
905
906    /**
907     * @return {boolean}
908     */
909    hasTouchInputs: function()
910    {
911        return !!this._target && this._target.hasTouchInputs;
912    },
913
914    /**
915     * @return {boolean}
916     */
917    networkThroughputIsLimited: function()
918    {
919        return this.settings.networkConditionsThroughput.get() !== WebInspector.OverridesSupport._networkThroughputUnlimitedValue;
920    },
921
922    /**
923     * Compute the font scale factor.
924     *
925     * Chromium on Android uses a device scale adjustment for fonts used in text autosizing for
926     * improved legibility. This function computes this adjusted value for text autosizing.
927     *
928     * For a description of the Android device scale adjustment algorithm, see:
929     *     chrome/browser/chrome_content_browser_client.cc, GetFontScaleMultiplier(...)
930     *
931     * @param {number} width
932     * @param {number} height
933     * @return {number} font scale factor.
934     */
935    _fontScaleFactor: function(width, height)
936    {
937        if (!this.emulationEnabled())
938            return 1;
939        var deviceScaleFactor = this.settings.deviceScaleFactor.get();
940
941        if (!width || !height || !deviceScaleFactor)
942            return 1;
943
944        var minWidth = Math.min(width, height) / deviceScaleFactor;
945
946        var kMinFSM = 1.05;
947        var kWidthForMinFSM = 320;
948        var kMaxFSM = 1.3;
949        var kWidthForMaxFSM = 800;
950
951        if (minWidth <= kWidthForMinFSM)
952            return kMinFSM;
953        if (minWidth >= kWidthForMaxFSM)
954            return kMaxFSM;
955
956        // The font scale multiplier varies linearly between kMinFSM and kMaxFSM.
957        var ratio = (minWidth - kWidthForMinFSM) / (kWidthForMaxFSM - kWidthForMinFSM);
958        return ratio * (kMaxFSM - kMinFSM) + kMinFSM;
959    },
960
961    /**
962     * @param {!Document} document
963     * @return {!Element}
964     */
965    createDeviceSelect: function(document)
966    {
967        var deviceSelectElement = document.createElement("select");
968
969        var selectDeviceOption = new Option(WebInspector.UIString("<Select model>"), WebInspector.UIString("<Select model>"));
970        selectDeviceOption.device = new WebInspector.OverridesSupport.Device("", "");
971        deviceSelectElement.add(selectDeviceOption);
972
973        addGroup(WebInspector.UIString("Devices"), WebInspector.OverridesSupport._phones.concat(WebInspector.OverridesSupport._tablets));
974        addGroup(WebInspector.UIString("Notebooks"), WebInspector.OverridesSupport._notebooks);
975
976        /**
977         * @param {string} name
978         * @param {!Array.<!Array.<string>>} devices
979         */
980        function addGroup(name, devices)
981        {
982            devices = devices.slice();
983            devices.sort();
984            var groupElement = deviceSelectElement.createChild("optgroup");
985            groupElement.label = name;
986            for (var i = 0; i < devices.length; ++i) {
987                var device = devices[i];
988                var option = new Option(device[0], device[0]);
989                option.device = new WebInspector.OverridesSupport.Device(device[2], device[1]);
990                groupElement.appendChild(option);
991            }
992        }
993
994        deviceSelectElement.addEventListener("change", deviceSelected, false);
995
996        var emulatedSettingChangedMuted = false;
997        WebInspector.overridesSupport.settings.deviceWidth.addChangeListener(emulatedSettingChanged);
998        WebInspector.overridesSupport.settings.deviceHeight.addChangeListener(emulatedSettingChanged);
999        WebInspector.overridesSupport.settings.deviceScaleFactor.addChangeListener(emulatedSettingChanged);
1000        WebInspector.overridesSupport.settings.deviceTextAutosizing.addChangeListener(emulatedSettingChanged);
1001        WebInspector.overridesSupport.settings.emulateViewport.addChangeListener(emulatedSettingChanged);
1002        WebInspector.overridesSupport.settings.emulateTouch.addChangeListener(emulatedSettingChanged);
1003        WebInspector.overridesSupport.settings.userAgent.addChangeListener(emulatedSettingChanged);
1004        emulatedSettingChanged();
1005
1006        function deviceSelected()
1007        {
1008            if (deviceSelectElement.selectedIndex === 0)
1009                return;
1010
1011            var option = deviceSelectElement.options[deviceSelectElement.selectedIndex];
1012            emulatedSettingChangedMuted = true;
1013            WebInspector.overridesSupport.emulateDevice(option.device);
1014            emulatedSettingChangedMuted = false;
1015        }
1016
1017        function emulatedSettingChanged()
1018        {
1019            if (emulatedSettingChangedMuted)
1020                return;
1021
1022            var index = 0;
1023            for (var i = 1; i < deviceSelectElement.options.length; ++i) {
1024                var option = deviceSelectElement.options[i];
1025                if (WebInspector.overridesSupport.isEmulatingDevice(option.device)) {
1026                    index = i;
1027                    break;
1028                }
1029            }
1030            deviceSelectElement.selectedIndex = index;
1031        }
1032
1033        return deviceSelectElement;
1034    },
1035
1036    /**
1037     * @param {!Document} document
1038     * @return {!Element}
1039     */
1040    createNetworkThroughputSelect: function(document)
1041    {
1042        var throughputSetting = WebInspector.overridesSupport.settings.networkConditionsThroughput;
1043        var throughputSelectElement = document.createElement("select");
1044        var presets = WebInspector.OverridesSupport._networkThroughputPresets;
1045        for (var i = 0; i < presets.length; ++i)
1046            throughputSelectElement.add(new Option(presets[i][0], presets[i][1]));
1047
1048        settingChanged();
1049        throughputSetting.addChangeListener(settingChanged);
1050        throughputSelectElement.addEventListener("change", throughputSelected, false);
1051
1052        function throughputSelected()
1053        {
1054            var value = Number(throughputSelectElement.options[throughputSelectElement.selectedIndex].value);
1055            throughputSetting.removeChangeListener(settingChanged);
1056            throughputSetting.set(value);
1057            throughputSetting.addChangeListener(settingChanged);
1058        }
1059
1060        function settingChanged()
1061        {
1062            var value = String(throughputSetting.get());
1063            var options = throughputSelectElement.options;
1064            var selectionRestored = false;
1065            for (var i = 0; i < options.length; ++i) {
1066                if (options[i].value === value) {
1067                    throughputSelectElement.selectedIndex = i;
1068                    selectionRestored = true;
1069                    break;
1070                }
1071            }
1072            if (!selectionRestored)
1073                throughputSelectElement.selectedIndex = options.length - 1;
1074        }
1075
1076        return throughputSelectElement;
1077    },
1078
1079    reveal: function()
1080    {
1081        WebInspector.Revealer.reveal(this);
1082    },
1083
1084    __proto__: WebInspector.Object.prototype
1085}
1086
1087
1088/**
1089 * @type {!WebInspector.OverridesSupport}
1090 */
1091WebInspector.overridesSupport;
1092