Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / toolbox / ResponsiveDesignView.js
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 /**
6  * @constructor
7  * @extends {WebInspector.VBox}
8  * @implements {WebInspector.OverridesSupport.PageResizer}
9  * @implements {WebInspector.TargetManager.Observer}
10  * @param {!WebInspector.InspectedPagePlaceholder} inspectedPagePlaceholder
11  */
12 WebInspector.ResponsiveDesignView = function(inspectedPagePlaceholder)
13 {
14     WebInspector.VBox.call(this);
15     this.setMinimumSize(150, 150);
16     this.element.classList.add("overflow-hidden");
17
18     this._responsiveDesignContainer = new WebInspector.VBox();
19     this._responsiveDesignContainer.registerRequiredCSS("toolbox/responsiveDesignView.css");
20
21     this._createToolbar();
22
23     this._canvasContainer = new WebInspector.View();
24     this._canvasContainer.element.classList.add("responsive-design");
25     this._canvasContainer.show(this._responsiveDesignContainer.element);
26
27     this._canvas = this._canvasContainer.element.createChild("canvas", "fill responsive-design-canvas");
28
29     this._mediaInspectorContainer = this._canvasContainer.element.createChild("div", "responsive-design-media-container");
30     this._mediaInspector = new WebInspector.MediaQueryInspector();
31     this._updateMediaQueryInspector();
32
33     this._warningMessage = this._canvasContainer.element.createChild("div", "responsive-design-warning hidden");
34     this._warningMessage.createChild("div", "warning-icon-small");
35     this._warningMessage.createChild("span");
36     var warningDisableButton = this._warningMessage.createChild("div", "disable-warning");
37     warningDisableButton.textContent = WebInspector.UIString("Never show");
38     warningDisableButton.addEventListener("click", this._disableOverridesWarnings.bind(this), false);
39     var warningCloseButton = this._warningMessage.createChild("div", "close-button");
40     warningCloseButton.addEventListener("click", WebInspector.overridesSupport.clearWarningMessage.bind(WebInspector.overridesSupport), false);
41     WebInspector.overridesSupport.addEventListener(WebInspector.OverridesSupport.Events.OverridesWarningUpdated, this._overridesWarningUpdated, this);
42     WebInspector.settings.disableOverridesWarning.addChangeListener(this._overridesWarningUpdated, this);
43
44     this._slidersContainer = this._canvasContainer.element.createChild("div", "vbox responsive-design-sliders-container");
45     var genericDeviceOutline = this._slidersContainer.createChild("div", "responsive-design-generic-outline-container");
46     genericDeviceOutline.createChild("div", "responsive-design-generic-outline");
47     var widthSlider = this._slidersContainer.createChild("div", "responsive-design-slider-width");
48     widthSlider.createChild("div", "responsive-design-thumb-handle");
49     this._createResizer(widthSlider, false);
50     var heightSlider = this._slidersContainer.createChild("div", "responsive-design-slider-height");
51     heightSlider.createChild("div", "responsive-design-thumb-handle");
52     this._createResizer(heightSlider, true);
53     this._pageContainer = this._slidersContainer.createChild("div", "vbox flex-auto");
54
55     // Page scale controls.
56     this._pageScaleContainer = this._canvasContainer.element.createChild("div", "hbox responsive-design-page-scale-container");
57     this._decreasePageScaleButton = new WebInspector.StatusBarButton(WebInspector.UIString(""), "responsive-design-page-scale-button responsive-design-page-scale-decrease");
58     this._decreasePageScaleButton.element.tabIndex = -1;
59     this._decreasePageScaleButton.addEventListener("click", this._pageScaleButtonClicked.bind(this, false), this);
60     this._pageScaleContainer.appendChild(this._decreasePageScaleButton.element);
61
62     this._pageScaleLabel = this._pageScaleContainer.createChild("label", "responsive-design-page-scale-label");
63     this._pageScaleLabel.title = WebInspector.UIString("For a simpler way to change the current page scale, hold down Shift and drag with your mouse.");
64     this._pageScaleLabel.addEventListener("dblclick", this._resetPageScale.bind(this), false);
65
66     this._increasePageScaleButton = new WebInspector.StatusBarButton(WebInspector.UIString(""), "responsive-design-page-scale-button responsive-design-page-scale-increase");
67     this._increasePageScaleButton.element.tabIndex = -1;
68     this._increasePageScaleButton.addEventListener("click", this._pageScaleButtonClicked.bind(this, true), this);
69     this._pageScaleContainer.appendChild(this._increasePageScaleButton.element);
70
71     this._inspectedPagePlaceholder = inspectedPagePlaceholder;
72     inspectedPagePlaceholder.show(this.element);
73
74     this._enabled = false;
75     this._viewport = { scrollX: 0, scrollY: 0, contentsWidth: 0, contentsHeight: 0, pageScaleFactor: 1, minimumPageScaleFactor: 1, maximumPageScaleFactor: 1 };
76     this._drawContentsSize = true;
77     this._viewportChangedThrottler = new WebInspector.Throttler(0);
78     this._pageScaleFactorThrottler = new WebInspector.Throttler(50);
79
80     WebInspector.zoomManager.addEventListener(WebInspector.ZoomManager.Events.ZoomChanged, this._onZoomChanged, this);
81     WebInspector.overridesSupport.addEventListener(WebInspector.OverridesSupport.Events.EmulationStateChanged, this._emulationEnabledChanged, this);
82     this._mediaInspector.addEventListener(WebInspector.MediaQueryInspector.Events.CountUpdated, this._updateMediaQueryInspectorButton, this);
83     this._mediaInspector.addEventListener(WebInspector.MediaQueryInspector.Events.HeightUpdated, this.onResize, this);
84     WebInspector.targetManager.observeTargets(this);
85
86     this._emulationEnabledChanged();
87     this._overridesWarningUpdated();
88 };
89
90 // Measured in DIP.
91 WebInspector.ResponsiveDesignView.RulerWidth = 34;
92 WebInspector.ResponsiveDesignView.RulerHeight = 22;
93 WebInspector.ResponsiveDesignView.RulerTopHeight = 11;
94 WebInspector.ResponsiveDesignView.RulerBottomHeight = 9;
95
96 WebInspector.ResponsiveDesignView.prototype = {
97
98     /**
99      * @param {!WebInspector.Target} target
100      */
101     targetAdded: function(target)
102     {
103         // FIXME: adapt this to multiple targets.
104         if (this._target)
105             return;
106         this._target = target;
107         target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.ViewportChanged, this._viewportChanged, this);
108     },
109
110     /**
111      * @param {!WebInspector.Target} target
112      */
113     targetRemoved: function(target)
114     {
115         if (target !== this._target)
116             return;
117         target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.ViewportChanged, this._viewportChanged, this);
118     },
119
120     _invalidateCache: function()
121     {
122         delete this._cachedScale;
123         delete this._cachedCssCanvasWidth;
124         delete this._cachedCssCanvasHeight;
125         delete this._cachedCssHeight;
126         delete this._cachedCssWidth;
127         delete this._cachedZoomFactor;
128         delete this._cachedViewport;
129         delete this._cachedDrawContentsSize;
130         delete this._cachedMediaInspectorHeight;
131         delete this._availableSize;
132     },
133
134     _emulationEnabledChanged: function()
135     {
136         var enabled = WebInspector.overridesSupport.emulationEnabled();
137         this._mediaInspector.setEnabled(enabled);
138         if (enabled && !this._enabled) {
139             this._invalidateCache();
140             this._ignoreResize = true;
141             this._enabled = true;
142             this._inspectedPagePlaceholder.clearMinimumSizeAndMargins();
143             this._inspectedPagePlaceholder.show(this._pageContainer);
144             this._responsiveDesignContainer.show(this.element);
145             delete this._ignoreResize;
146             this.onResize();
147         } else if (!enabled && this._enabled) {
148             this._invalidateCache();
149             this._ignoreResize = true;
150             this._enabled = false;
151             this._scale = 1;
152             this._inspectedPagePlaceholder.restoreMinimumSizeAndMargins();
153             this._responsiveDesignContainer.detach();
154             this._inspectedPagePlaceholder.show(this.element);
155             delete this._ignoreResize;
156             this.onResize();
157         }
158     },
159
160     /**
161      * WebInspector.OverridesSupport.PageResizer override.
162      * @param {number} dipWidth
163      * @param {number} dipHeight
164      * @param {number} scale
165      */
166     update: function(dipWidth, dipHeight, scale)
167     {
168         this._scale = scale;
169         this._dipWidth = dipWidth ? Math.max(dipWidth, 1) : 0;
170         this._dipHeight = dipHeight ? Math.max(dipHeight, 1) : 0;
171         this._updateUI();
172     },
173
174     updatePageResizer: function()
175     {
176         WebInspector.overridesSupport.setPageResizer(this, this._availableDipSize());
177     },
178
179     /**
180      * @return {!Size}
181      */
182     _availableDipSize: function()
183     {
184         if (typeof this._availableSize === "undefined") {
185             var zoomFactor = WebInspector.zoomManager.zoomFactor();
186             var rect = this._canvasContainer.element.getBoundingClientRect();
187             var rulerTotalHeight = this._rulerTotalHeightDIP();
188             this._availableSize = new Size(Math.max(rect.width * zoomFactor - WebInspector.ResponsiveDesignView.RulerWidth, 1),
189                                            Math.max(rect.height * zoomFactor - rulerTotalHeight, 1));
190         }
191         return this._availableSize;
192     },
193
194     /**
195      * @param {!Element} element
196      * @param {boolean} vertical
197      * @return {!WebInspector.ResizerWidget}
198      */
199     _createResizer: function(element, vertical)
200     {
201         var resizer = new WebInspector.ResizerWidget();
202         resizer.addElement(element);
203         resizer.setVertical(vertical);
204         resizer.addEventListener(WebInspector.ResizerWidget.Events.ResizeStart, this._onResizeStart, this);
205         resizer.addEventListener(WebInspector.ResizerWidget.Events.ResizeUpdate, this._onResizeUpdate, this);
206         resizer.addEventListener(WebInspector.ResizerWidget.Events.ResizeEnd, this._onResizeEnd, this);
207         return resizer;
208     },
209
210     /**
211      * @param {!WebInspector.Event} event
212      */
213     _onResizeStart: function(event)
214     {
215         this._drawContentsSize = false;
216         var available = this._availableDipSize();
217         this._slowPositionStart = null;
218         this._resizeStartSize = event.target.isVertical() ? (this._dipHeight || available.height) : (this._dipWidth || available.width);
219         this.dispatchEventToListeners(WebInspector.OverridesSupport.PageResizer.Events.FixedScaleRequested, true);
220         this._updateUI();
221     },
222
223     /**
224      * @param {!WebInspector.Event} event
225      */
226     _onResizeUpdate: function(event)
227     {
228         if (event.data.shiftKey !== !!this._slowPositionStart)
229             this._slowPositionStart = event.data.shiftKey ? event.data.currentPosition : null;
230         var cssOffset = this._slowPositionStart ? (event.data.currentPosition - this._slowPositionStart) / 10 + this._slowPositionStart - event.data.startPosition : event.data.currentPosition - event.data.startPosition;
231         var dipOffset = Math.round(cssOffset * WebInspector.zoomManager.zoomFactor());
232         var newSize = this._resizeStartSize + dipOffset;
233         newSize = Math.round(newSize / (this._scale || 1));
234         newSize = Math.max(Math.min(newSize, WebInspector.OverridesSupport.MaxDeviceSize), 1);
235         var requested = {};
236         if (event.target.isVertical())
237             requested.height = newSize;
238         else
239             requested.width = newSize;
240         this.dispatchEventToListeners(WebInspector.OverridesSupport.PageResizer.Events.ResizeRequested, requested);
241     },
242
243     /**
244      * @param {!WebInspector.Event} event
245      */
246     _onResizeEnd: function(event)
247     {
248         this._drawContentsSize = true;
249         this.dispatchEventToListeners(WebInspector.OverridesSupport.PageResizer.Events.FixedScaleRequested, false);
250         delete this._resizeStartSize;
251         this._updateUI();
252     },
253
254     /**
255      * Draws canvas of the specified css size in DevTools page space.
256      * Canvas contains grid and rulers.
257      * @param {number} cssCanvasWidth
258      * @param {number} cssCanvasHeight
259      * @param {number} rulerHeight
260      */
261     _drawCanvas: function(cssCanvasWidth, cssCanvasHeight, rulerHeight)
262     {
263         if (!this._enabled)
264             return;
265
266         var canvas = this._canvas;
267         var context = canvas.getContext("2d");
268         canvas.style.width = cssCanvasWidth + "px";
269         canvas.style.height = cssCanvasHeight + "px";
270
271         var zoomFactor = WebInspector.zoomManager.zoomFactor();
272         var dipCanvasWidth = cssCanvasWidth * zoomFactor;
273         var dipCanvasHeight = cssCanvasHeight * zoomFactor;
274
275         var deviceScaleFactor = window.devicePixelRatio;
276         canvas.width = deviceScaleFactor * cssCanvasWidth;
277         canvas.height = deviceScaleFactor * cssCanvasHeight;
278         context.scale(canvas.width / dipCanvasWidth, canvas.height / dipCanvasHeight);
279         context.font = "11px " + WebInspector.fontFamily();
280
281         const backgroundColor = "rgb(102, 102, 102)";
282         const lightLineColor = "rgb(132, 132, 132)";
283         const darkLineColor = "rgb(114, 114, 114)";
284         const rulerColor = "rgb(125, 125, 125)";
285         const textColor = "rgb(186, 186, 186)";
286         const contentsSizeColor = "rgba(0, 0, 0, 0.3)";
287
288         var scale = (this._scale || 1) * this._viewport.pageScaleFactor;
289         var rulerScale = 0.5;
290         while (Math.abs(rulerScale * scale - 1) > Math.abs((rulerScale + 0.5) * scale - 1))
291             rulerScale += 0.5;
292
293         var gridStep = 50 * scale * rulerScale;
294         var gridSubStep = 10 * scale * rulerScale;
295
296         var rulerSubStep = 5 * scale * rulerScale;
297         var rulerStepCount = 20;
298
299         var rulerWidth = WebInspector.ResponsiveDesignView.RulerWidth;
300
301         var dipGridWidth = dipCanvasWidth - rulerWidth;
302         var dipGridHeight = dipCanvasHeight - rulerHeight;
303         var dipScrollX = this._viewport.scrollX * scale;
304         var dipScrollY = this._viewport.scrollY * scale;
305         context.translate(rulerWidth, rulerHeight);
306
307         context.fillStyle = backgroundColor;
308         context.fillRect(0, 0, dipGridWidth, dipGridHeight);
309
310         context.translate(0.5, 0.5);
311         context.strokeStyle = rulerColor;
312         context.fillStyle = textColor;
313         context.lineWidth = 1;
314
315         // Draw horizontal ruler.
316         context.save();
317
318         var minXIndex = Math.ceil(dipScrollX / rulerSubStep);
319         var maxXIndex = Math.floor((dipScrollX + dipGridWidth) / rulerSubStep);
320         if (minXIndex) {
321             context.beginPath();
322             context.moveTo(0, -rulerHeight);
323             context.lineTo(0, 0);
324             context.stroke();
325         }
326
327         context.translate(-dipScrollX, 0);
328         for (var index = minXIndex; index <= maxXIndex; index++) {
329             var x = index * rulerSubStep;
330             var height = WebInspector.ResponsiveDesignView.RulerHeight * 0.25;
331
332             if (!(index % (rulerStepCount / 4)))
333                 height = WebInspector.ResponsiveDesignView.RulerHeight * 0.5;
334
335             if (!(index % (rulerStepCount / 2)))
336                 height = rulerHeight;
337
338             if (!(index % rulerStepCount)) {
339                 context.save();
340                 context.translate(x, 0);
341                 context.fillText(Math.round(x / scale), 2, -rulerHeight + 10);
342                 context.restore();
343                 height = rulerHeight;
344             }
345
346             context.beginPath();
347             context.moveTo(x, - height);
348             context.lineTo(x, 0);
349             context.stroke();
350         }
351         context.restore();
352
353         // Draw vertical ruler.
354         context.save();
355         var minYIndex = Math.ceil(dipScrollY / rulerSubStep);
356         var maxYIndex = Math.floor((dipScrollY + dipGridHeight) / rulerSubStep);
357         context.translate(0, -dipScrollY);
358         for (var index = minYIndex; index <= maxYIndex; index++) {
359             var y = index * rulerSubStep;
360             var x = -rulerWidth * 0.25;
361             if (!(index % (rulerStepCount / 4)))
362                 x = -rulerWidth * 0.5;
363             if (!(index % (rulerStepCount / 2)))
364                 x = -rulerWidth * 0.75;
365
366             if (!(index % rulerStepCount)) {
367                 context.save();
368                 context.translate(0, y);
369                 context.rotate(-Math.PI / 2);
370                 context.fillText(Math.round(y / scale), 2, -rulerWidth + 10);
371                 context.restore();
372                 x = -rulerWidth;
373             }
374
375             context.beginPath();
376             context.moveTo(x, y);
377             context.lineTo(0, y);
378             context.stroke();
379         }
380         context.restore();
381
382         // Draw grid.
383         drawGrid(dipScrollX, dipScrollY, darkLineColor, gridSubStep);
384         drawGrid(dipScrollX, dipScrollY, lightLineColor, gridStep);
385
386         /**
387          * @param {number} scrollX
388          * @param {number} scrollY
389          * @param {string} color
390          * @param {number} step
391          */
392         function drawGrid(scrollX, scrollY, color, step)
393         {
394             context.strokeStyle = color;
395             var minX = Math.ceil(scrollX / step) * step;
396             var maxX = Math.floor((scrollX + dipGridWidth) / step) * step - minX;
397             var minY = Math.ceil(scrollY / step) * step;
398             var maxY = Math.floor((scrollY + dipGridHeight) / step) * step - minY;
399
400             context.save();
401             context.translate(minX - scrollX, 0);
402             for (var x = 0; x <= maxX; x += step) {
403                 context.beginPath();
404                 context.moveTo(x, 0);
405                 context.lineTo(x, dipGridHeight);
406                 context.stroke();
407             }
408             context.restore();
409
410             context.save();
411             context.translate(0, minY - scrollY);
412             for (var y = 0; y <= maxY; y += step) {
413                 context.beginPath();
414                 context.moveTo(0, y);
415                 context.lineTo(dipGridWidth, y);
416                 context.stroke();
417             }
418             context.restore();
419         }
420
421         context.translate(-0.5, -0.5);
422
423         // Draw contents size.
424         var pageScaleAvailable = WebInspector.overridesSupport.settings.emulateMobile.get() || WebInspector.overridesSupport.settings.emulateTouch.get();
425         if (this._drawContentsSize && pageScaleAvailable) {
426             context.fillStyle = contentsSizeColor;
427             var visibleContentsWidth = Math.max(0, Math.min(dipGridWidth, this._viewport.contentsWidth * scale - dipScrollX));
428             var visibleContentsHeight = Math.max(0, Math.min(dipGridHeight, this._viewport.contentsHeight * scale - dipScrollY));
429             context.fillRect(0, 0, visibleContentsWidth, visibleContentsHeight);
430         }
431     },
432
433     /**
434      * @return {number}
435      */
436     _rulerTotalHeightDIP: function()
437     {
438         var mediaInspectorHeight = this._mediaInspector.isShowing() ? this._mediaInspector.element.offsetHeight : 0;
439         if (!mediaInspectorHeight)
440             return WebInspector.ResponsiveDesignView.RulerHeight;
441         return WebInspector.ResponsiveDesignView.RulerTopHeight + WebInspector.ResponsiveDesignView.RulerBottomHeight + mediaInspectorHeight * WebInspector.zoomManager.zoomFactor();
442     },
443
444     _updateUI: function()
445     {
446         if (!this._enabled || !this.isShowing())
447             return;
448
449         var zoomFactor = WebInspector.zoomManager.zoomFactor();
450         var rect = this._canvas.parentElement.getBoundingClientRect();
451         var availableDip = this._availableDipSize();
452         var cssCanvasWidth = rect.width;
453         var cssCanvasHeight = rect.height;
454         var mediaInspectorHeight = this._mediaInspector.isShowing() ? this._mediaInspector.element.offsetHeight : 0;
455         var rulerTotalHeight = this._rulerTotalHeightDIP();
456
457         this._mediaInspector.setAxisTransform(this._viewport.scrollX, this._scale * this._viewport.pageScaleFactor);
458
459         if (this._cachedZoomFactor !== zoomFactor || this._cachedMediaInspectorHeight !== mediaInspectorHeight) {
460             var cssRulerWidth = WebInspector.ResponsiveDesignView.RulerWidth / zoomFactor + "px";
461             var cssRulerHeight = (mediaInspectorHeight ? WebInspector.ResponsiveDesignView.RulerTopHeight : WebInspector.ResponsiveDesignView.RulerHeight) / zoomFactor + "px";
462             var cssCanvasOffset = rulerTotalHeight / zoomFactor + "px";
463             this._slidersContainer.style.left = cssRulerWidth;
464             this._slidersContainer.style.top = cssCanvasOffset;
465             this._warningMessage.style.height = cssCanvasOffset;
466             this._pageScaleContainer.style.top = cssCanvasOffset;
467             this._mediaInspectorContainer.style.left = cssRulerWidth;
468             this._mediaInspectorContainer.style.marginTop = cssRulerHeight;
469         }
470
471         var cssWidth = (this._dipWidth ? this._dipWidth : availableDip.width) / zoomFactor;
472         var cssHeight = (this._dipHeight ? this._dipHeight : availableDip.height) / zoomFactor;
473         if (this._cachedCssWidth !== cssWidth || this._cachedCssHeight !== cssHeight) {
474             this._slidersContainer.style.width = cssWidth + "px";
475             this._slidersContainer.style.height = cssHeight + "px";
476             this._inspectedPagePlaceholder.onResize();
477         }
478
479         var pageScaleVisible = cssWidth + this._pageScaleContainerWidth + WebInspector.ResponsiveDesignView.RulerWidth / zoomFactor <= rect.width;
480         this._pageScaleContainer.classList.toggle("hidden", !pageScaleVisible);
481
482         var viewportChanged = !this._cachedViewport
483             || this._cachedViewport.scrollX !== this._viewport.scrollX || this._cachedViewport.scrollY !== this._viewport.scrollY
484             || this._cachedViewport.contentsWidth !== this._viewport.contentsWidth || this._cachedViewport.contentsHeight !== this._viewport.contentsHeight
485             || this._cachedViewport.pageScaleFactor !== this._viewport.pageScaleFactor
486             || this._cachedViewport.minimumPageScaleFactor !== this._viewport.minimumPageScaleFactor
487             || this._cachedViewport.maximumPageScaleFactor !== this._viewport.maximumPageScaleFactor;
488
489         var canvasInvalidated = viewportChanged || this._drawContentsSize !== this._cachedDrawContentsSize || this._cachedScale !== this._scale ||
490             this._cachedCssCanvasWidth !== cssCanvasWidth || this._cachedCssCanvasHeight !== cssCanvasHeight || this._cachedZoomFactor !== zoomFactor ||
491             this._cachedMediaInspectorHeight !== mediaInspectorHeight;
492
493         if (canvasInvalidated)
494             this._drawCanvas(cssCanvasWidth, cssCanvasHeight, rulerTotalHeight);
495
496         if (viewportChanged) {
497             this._pageScaleLabel.textContent = WebInspector.UIString("%.1f", this._viewport.pageScaleFactor);
498             this._decreasePageScaleButton.title = WebInspector.UIString("Scale down (minimum %.1f)", this._viewport.minimumPageScaleFactor);
499             this._decreasePageScaleButton.setEnabled(this._viewport.pageScaleFactor > this._viewport.minimumPageScaleFactor);
500             this._increasePageScaleButton.title = WebInspector.UIString("Scale up (maximum %.1f)", this._viewport.maximumPageScaleFactor);
501             this._increasePageScaleButton.setEnabled(this._viewport.pageScaleFactor < this._viewport.maximumPageScaleFactor);
502         }
503
504         this._cachedScale = this._scale;
505         this._cachedCssCanvasWidth = cssCanvasWidth;
506         this._cachedCssCanvasHeight = cssCanvasHeight;
507         this._cachedCssHeight = cssHeight;
508         this._cachedCssWidth = cssWidth;
509         this._cachedZoomFactor = zoomFactor;
510         this._cachedViewport = this._viewport;
511         this._cachedDrawContentsSize = this._drawContentsSize;
512         this._cachedMediaInspectorHeight = mediaInspectorHeight;
513     },
514
515     onResize: function()
516     {
517         if (!this._enabled || this._ignoreResize)
518             return;
519         var oldSize = this._availableSize;
520
521         this._pageScaleContainer.classList.remove("hidden");
522         this._pageScaleContainerWidth = this._pageScaleContainer.offsetWidth;
523
524         delete this._availableSize;
525         var newSize = this._availableDipSize();
526         if (!newSize.isEqual(oldSize))
527             this.dispatchEventToListeners(WebInspector.OverridesSupport.PageResizer.Events.AvailableSizeChanged, newSize);
528         this._updateUI();
529         this._inspectedPagePlaceholder.onResize();
530     },
531
532     _onZoomChanged: function()
533     {
534         this._updateUI();
535     },
536
537     _createToolbar: function()
538     {
539         this._toolbarElement = this._responsiveDesignContainer.element.createChild("div", "responsive-design-toolbar");
540         this._createButtonsSection();
541         this._createDeviceSection();
542         this._toolbarElement.createChild("div", "responsive-design-separator");
543         this._createNetworkSection();
544         this._toolbarElement.createChild("div", "responsive-design-separator");
545
546         var moreButtonContainer = this._toolbarElement.createChild("div", "responsive-design-more-button-container");
547         var moreButton = moreButtonContainer.createChild("button", "responsive-design-more-button");
548         moreButton.title = WebInspector.UIString("More overrides");
549         moreButton.addEventListener("click", this._showEmulationInDrawer.bind(this), false);
550         moreButton.textContent = "\u2026";
551     },
552
553     _createButtonsSection: function()
554     {
555         var buttonsSection = this._toolbarElement.createChild("div", "responsive-design-section responsive-design-section-buttons");
556
557         var resetButton = new WebInspector.StatusBarButton(WebInspector.UIString("Reset all overrides."), "clear-status-bar-item");
558         buttonsSection.appendChild(resetButton.element);
559         resetButton.addEventListener("click", WebInspector.overridesSupport.reset, WebInspector.overridesSupport);
560
561         // Media Query Inspector.
562         this._toggleMediaInspectorButton = new WebInspector.StatusBarButton(WebInspector.UIString("Media queries not found"), "responsive-design-toggle-media-inspector");
563         this._toggleMediaInspectorButton.toggled = WebInspector.settings.showMediaQueryInspector.get();
564         this._toggleMediaInspectorButton.setEnabled(false);
565         this._toggleMediaInspectorButton.addEventListener("click", this._onToggleMediaInspectorButtonClick, this);
566         WebInspector.settings.showMediaQueryInspector.addChangeListener(this._updateMediaQueryInspector, this);
567         buttonsSection.appendChild(this._toggleMediaInspectorButton.element);
568     },
569
570     _createDeviceSection: function()
571     {
572         var deviceSection = this._toolbarElement.createChild("div", "responsive-design-section responsive-design-section-device");
573
574         var separator = deviceSection.createChild("div", "responsive-design-section-decorator");
575
576         // Device.
577         var deviceElement = deviceSection.createChild("div", "responsive-design-suite responsive-design-suite-top").createChild("div");
578
579         var fieldsetElement = deviceElement.createChild("fieldset");
580         fieldsetElement.createChild("label").textContent = WebInspector.UIString("Device");
581         var deviceSelectElement = WebInspector.OverridesUI.createDeviceSelect();
582         fieldsetElement.appendChild(deviceSelectElement);
583         deviceSelectElement.classList.add("responsive-design-device-select");
584
585         var detailsElement = deviceSection.createChild("div", "responsive-design-suite");
586
587         // Dimensions.
588         var screenElement = detailsElement.createChild("div", "");
589         fieldsetElement = screenElement.createChild("fieldset");
590
591         var emulateResolutionCheckbox = WebInspector.SettingsUI.createSettingCheckbox("", WebInspector.overridesSupport.settings.emulateResolution, true, undefined, WebInspector.UIString("Emulate screen resolution"));
592         fieldsetElement.appendChild(emulateResolutionCheckbox);
593
594         var resolutionButton = new WebInspector.StatusBarButton(WebInspector.UIString("Screen resolution"), "responsive-design-icon responsive-design-icon-resolution");
595         resolutionButton.setEnabled(false);
596         fieldsetElement.appendChild(resolutionButton.element);
597         var resolutionFieldset = WebInspector.SettingsUI.createSettingFieldset(WebInspector.overridesSupport.settings.emulateResolution);
598         fieldsetElement.appendChild(resolutionFieldset);
599
600         resolutionFieldset.appendChild(WebInspector.SettingsUI.createSettingInputField("", WebInspector.overridesSupport.settings.deviceWidth, true, 4, "3em", WebInspector.OverridesSupport.deviceSizeValidator, true, true, WebInspector.UIString("\u2013")));
601         resolutionFieldset.createTextChild("\u00D7");
602         resolutionFieldset.appendChild(WebInspector.SettingsUI.createSettingInputField("", WebInspector.overridesSupport.settings.deviceHeight, true, 4, "3em", WebInspector.OverridesSupport.deviceSizeValidator, true, true, WebInspector.UIString("\u2013")));
603
604         var swapButton = new WebInspector.StatusBarButton(WebInspector.UIString("Swap dimensions"), "responsive-design-icon responsive-design-icon-swap");
605         swapButton.element.tabIndex = -1;
606         swapButton.addEventListener("click", WebInspector.overridesSupport.swapDimensions, WebInspector.overridesSupport);
607         resolutionFieldset.appendChild(swapButton.element);
608
609         // Device pixel ratio.
610         detailsElement.createChild("div", "responsive-design-suite-separator");
611
612         var dprElement = detailsElement.createChild("div", "");
613         var resolutionFieldset2 = WebInspector.SettingsUI.createSettingFieldset(WebInspector.overridesSupport.settings.emulateResolution);
614         dprElement.appendChild(resolutionFieldset2);
615         var dprButton = new WebInspector.StatusBarButton(WebInspector.UIString("Device pixel ratio"), "responsive-design-icon responsive-design-icon-dpr");
616         dprButton.setEnabled(false);
617         resolutionFieldset2.appendChild(dprButton.element);
618         resolutionFieldset2.appendChild(WebInspector.SettingsUI.createSettingInputField("", WebInspector.overridesSupport.settings.deviceScaleFactor, true, 4, "1.9em", WebInspector.OverridesSupport.deviceScaleFactorValidator, true, true, WebInspector.UIString("\u2013")));
619
620         // Fit to window.
621         detailsElement.createChild("div", "responsive-design-suite-separator");
622         var fitToWindowElement = detailsElement.createChild("div", "");
623         fieldsetElement = fitToWindowElement.createChild("fieldset");
624         fieldsetElement.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Fit"), WebInspector.overridesSupport.settings.deviceFitWindow, true, undefined, WebInspector.UIString("Zoom to fit available space")));
625     },
626
627     _createNetworkSection: function()
628     {
629         var networkSection = this._toolbarElement.createChild("div", "responsive-design-section responsive-design-section-network");
630
631         var separator = networkSection.createChild("div", "responsive-design-section-decorator");
632
633         // Bandwidth.
634         var bandwidthElement = networkSection.createChild("div", "responsive-design-suite responsive-design-suite-top").createChild("div");
635         var fieldsetElement = bandwidthElement.createChild("fieldset");
636         var networkCheckbox = fieldsetElement.createChild("label");
637         networkCheckbox.textContent = WebInspector.UIString("Network");
638         fieldsetElement.appendChild(WebInspector.OverridesUI.createNetworkConditionsSelect());
639
640         // User agent.
641         var userAgentElement = networkSection.createChild("div", "responsive-design-suite").createChild("div");
642         fieldsetElement = userAgentElement.createChild("fieldset");
643         fieldsetElement.appendChild(WebInspector.SettingsUI.createSettingInputField("UA", WebInspector.overridesSupport.settings.userAgent, false, 0, "", undefined, false, false, WebInspector.UIString("No override")));
644     },
645
646     _onToggleMediaInspectorButtonClick: function()
647     {
648         WebInspector.settings.showMediaQueryInspector.set(!this._toggleMediaInspectorButton.toggled);
649     },
650
651     _updateMediaQueryInspector: function()
652     {
653         this._toggleMediaInspectorButton.toggled = WebInspector.settings.showMediaQueryInspector.get();
654         if (this._mediaInspector.isShowing() === WebInspector.settings.showMediaQueryInspector.get())
655             return;
656         if (this._mediaInspector.isShowing())
657             this._mediaInspector.detach();
658         else
659             this._mediaInspector.show(this._mediaInspectorContainer);
660         this.onResize();
661     },
662
663     /**
664      * @param {!WebInspector.Event} event
665      */
666     _updateMediaQueryInspectorButton: function(event)
667     {
668         var count = /** @type {number} */ (event.data);
669         this._toggleMediaInspectorButton.setEnabled(!!count);
670         this._toggleMediaInspectorButton.title = !count ? WebInspector.UIString("Media queries not found") :
671             WebInspector.UIString((count === 1 ? "%d media query found" : "%d media queries found"), count);
672     },
673
674     _overridesWarningUpdated: function()
675     {
676         var message = WebInspector.settings.disableOverridesWarning.get() ? "" : WebInspector.overridesSupport.warningMessage();
677         if (this._warning === message)
678             return;
679         this._warning = message;
680         this._warningMessage.classList.toggle("hidden", !message);
681         this._warningMessage.querySelector("span").textContent = message;
682         this._invalidateCache();
683         this.onResize();
684     },
685
686     _disableOverridesWarnings: function()
687     {
688         WebInspector.settings.disableOverridesWarning.set(true);
689     },
690
691     _showEmulationInDrawer: function()
692     {
693         WebInspector.Revealer.reveal(WebInspector.overridesSupport);
694     },
695
696     /**
697      * @param {!WebInspector.Event} event
698      */
699     _viewportChanged: function(event)
700     {
701         var viewport = /** @type {?PageAgent.Viewport} */ (event.data);
702         if (viewport) {
703             this._viewport = viewport;
704             this._viewport.minimumPageScaleFactor = Math.max(0.1, this._viewport.minimumPageScaleFactor);
705             this._viewport.minimumPageScaleFactor = Math.min(this._viewport.minimumPageScaleFactor, this._viewport.pageScaleFactor);
706             this._viewport.maximumPageScaleFactor = Math.min(10, this._viewport.maximumPageScaleFactor);
707             this._viewport.maximumPageScaleFactor = Math.max(this._viewport.maximumPageScaleFactor, this._viewport.pageScaleFactor);
708             this._viewportChangedThrottler.schedule(this._updateUIThrottled.bind(this));
709         }
710     },
711
712     /**
713      * @param {!WebInspector.Throttler.FinishCallback} finishCallback
714      */
715     _updateUIThrottled: function(finishCallback)
716     {
717         this._updateUI();
718         finishCallback();
719     },
720
721     /**
722      * @param {boolean} increase
723      * @param {!WebInspector.Event} event
724      */
725     _pageScaleButtonClicked: function(increase, event)
726     {
727         this._pageScaleFactorThrottler.schedule(updatePageScaleFactor.bind(this));
728
729         /**
730          * @param {!WebInspector.Throttler.FinishCallback} finishCallback
731          * @this {WebInspector.ResponsiveDesignView}
732          */
733         function updatePageScaleFactor(finishCallback)
734         {
735             if (this._target && this._viewport) {
736                 var value = this._viewport.pageScaleFactor;
737                 value = increase ? value * 1.1 : value / 1.1;
738                 value = Math.min(this._viewport.maximumPageScaleFactor, value);
739                 value = Math.max(this._viewport.minimumPageScaleFactor, value)
740                 this._target.pageAgent().setPageScaleFactor(value);
741             }
742             finishCallback();
743         }
744     },
745
746     _resetPageScale: function()
747     {
748         this._pageScaleFactorThrottler.schedule(updatePageScaleFactor.bind(this));
749
750         /**
751          * @param {!WebInspector.Throttler.FinishCallback} finishCallback
752          * @this {WebInspector.ResponsiveDesignView}
753          */
754         function updatePageScaleFactor(finishCallback)
755         {
756             if (this._target && this._viewport && this._viewport.minimumPageScaleFactor <= 1 && this._viewport.maximumPageScaleFactor >= 1)
757                 this._target.pageAgent().setPageScaleFactor(1);
758             finishCallback();
759         }
760     },
761
762     __proto__: WebInspector.VBox.prototype
763 };