| // Copyright 2017 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | /** | 
 |  * @implements {Protocol.OverlayDispatcher} | 
 |  */ | 
 | export default class OverlayModel extends SDK.SDKModel { | 
 |   /** | 
 |    * @param {!SDK.Target} target | 
 |    */ | 
 |   constructor(target) { | 
 |     super(target); | 
 |     this._domModel = /** @type {!SDK.DOMModel} */ (target.model(SDK.DOMModel)); | 
 |  | 
 |     target.registerOverlayDispatcher(this); | 
 |     this._overlayAgent = target.overlayAgent(); | 
 |  | 
 |     this._debuggerModel = target.model(SDK.DebuggerModel); | 
 |     if (this._debuggerModel) { | 
 |       Common.moduleSetting('disablePausedStateOverlay').addChangeListener(this._updatePausedInDebuggerMessage, this); | 
 |       this._debuggerModel.addEventListener( | 
 |           SDK.DebuggerModel.Events.DebuggerPaused, this._updatePausedInDebuggerMessage, this); | 
 |       this._debuggerModel.addEventListener( | 
 |           SDK.DebuggerModel.Events.DebuggerResumed, this._updatePausedInDebuggerMessage, this); | 
 |       // TODO(dgozman): we should get DebuggerResumed on navigations instead of listening to GlobalObjectCleared. | 
 |       this._debuggerModel.addEventListener( | 
 |           SDK.DebuggerModel.Events.GlobalObjectCleared, this._updatePausedInDebuggerMessage, this); | 
 |     } | 
 |  | 
 |     this._inspectModeEnabled = false; | 
 |     this._hideHighlightTimeout = null; | 
 |     this._defaultHighlighter = new DefaultHighlighter(this); | 
 |     this._highlighter = this._defaultHighlighter; | 
 |  | 
 |     this._showPaintRectsSetting = Common.moduleSetting('showPaintRects'); | 
 |     this._showLayoutShiftRegionsSetting = Common.moduleSetting('showLayoutShiftRegions'); | 
 |     this._showAdHighlightsSetting = Common.moduleSetting('showAdHighlights'); | 
 |     this._showDebugBordersSetting = Common.moduleSetting('showDebugBorders'); | 
 |     this._showFPSCounterSetting = Common.moduleSetting('showFPSCounter'); | 
 |     this._showScrollBottleneckRectsSetting = Common.moduleSetting('showScrollBottleneckRects'); | 
 |     this._showHitTestBordersSetting = Common.moduleSetting('showHitTestBorders'); | 
 |  | 
 |     this._registeredListeners = []; | 
 |     this._showViewportSizeOnResize = true; | 
 |     if (!target.suspended()) { | 
 |       this._overlayAgent.enable(); | 
 |       this._wireAgentToSettings(); | 
 |     } | 
 |   } | 
 |  | 
 |   /** | 
 |    * @param {!SDK.RemoteObject} object | 
 |    */ | 
 |   static highlightObjectAsDOMNode(object) { | 
 |     const domModel = object.runtimeModel().target().model(SDK.DOMModel); | 
 |     if (domModel) { | 
 |       domModel.overlayModel().highlightInOverlay({object}); | 
 |     } | 
 |   } | 
 |  | 
 |   static hideDOMNodeHighlight() { | 
 |     for (const overlayModel of SDK.targetManager.models(OverlayModel)) { | 
 |       overlayModel._delayedHideHighlight(0); | 
 |     } | 
 |   } | 
 |  | 
 |   static async muteHighlight() { | 
 |     return Promise.all(SDK.targetManager.models(OverlayModel).map(model => model.suspendModel())); | 
 |   } | 
 |  | 
 |   static async unmuteHighlight() { | 
 |     return Promise.all(SDK.targetManager.models(OverlayModel).map(model => model.resumeModel())); | 
 |   } | 
 |  | 
 |   /** | 
 |    * @return {!Promise} | 
 |    */ | 
 |   _wireAgentToSettings() { | 
 |     this._registeredListeners = [ | 
 |       this._showPaintRectsSetting.addChangeListener( | 
 |           () => this._overlayAgent.setShowPaintRects(this._showPaintRectsSetting.get())), | 
 |       this._showLayoutShiftRegionsSetting.addChangeListener( | 
 |           () => this._overlayAgent.setShowLayoutShiftRegions(this._showLayoutShiftRegionsSetting.get())), | 
 |       this._showAdHighlightsSetting.addChangeListener( | 
 |           () => this._overlayAgent.setShowAdHighlights(this._showAdHighlightsSetting.get())), | 
 |       this._showDebugBordersSetting.addChangeListener( | 
 |           () => this._overlayAgent.setShowDebugBorders(this._showDebugBordersSetting.get())), | 
 |       this._showFPSCounterSetting.addChangeListener( | 
 |           () => this._overlayAgent.setShowFPSCounter(this._showFPSCounterSetting.get())), | 
 |       this._showScrollBottleneckRectsSetting.addChangeListener( | 
 |           () => this._overlayAgent.setShowScrollBottleneckRects(this._showScrollBottleneckRectsSetting.get())), | 
 |       this._showHitTestBordersSetting.addChangeListener( | 
 |           () => this._overlayAgent.setShowHitTestBorders(this._showHitTestBordersSetting.get())) | 
 |     ]; | 
 |  | 
 |     if (this._showPaintRectsSetting.get()) { | 
 |       this._overlayAgent.setShowPaintRects(true); | 
 |     } | 
 |     if (this._showLayoutShiftRegionsSetting.get()) { | 
 |       this._overlayAgent.setShowLayoutShiftRegions(true); | 
 |     } | 
 |     if (this._showAdHighlightsSetting.get()) { | 
 |       this._overlayAgent.setShowAdHighlights(true); | 
 |     } | 
 |     if (this._showDebugBordersSetting.get()) { | 
 |       this._overlayAgent.setShowDebugBorders(true); | 
 |     } | 
 |     if (this._showFPSCounterSetting.get()) { | 
 |       this._overlayAgent.setShowFPSCounter(true); | 
 |     } | 
 |     if (this._showScrollBottleneckRectsSetting.get()) { | 
 |       this._overlayAgent.setShowScrollBottleneckRects(true); | 
 |     } | 
 |     if (this._showHitTestBordersSetting.get()) { | 
 |       this._overlayAgent.setShowHitTestBorders(true); | 
 |     } | 
 |     if (this._debuggerModel.isPaused()) { | 
 |       this._updatePausedInDebuggerMessage(); | 
 |     } | 
 |     return this._overlayAgent.setShowViewportSizeOnResize(this._showViewportSizeOnResize); | 
 |   } | 
 |  | 
 |   /** | 
 |    * @override | 
 |    * @return {!Promise} | 
 |    */ | 
 |   suspendModel() { | 
 |     Common.EventTarget.removeEventListeners(this._registeredListeners); | 
 |     return this._overlayAgent.disable(); | 
 |   } | 
 |  | 
 |   /** | 
 |    * @override | 
 |    * @return {!Promise} | 
 |    */ | 
 |   resumeModel() { | 
 |     this._overlayAgent.enable(); | 
 |     return this._wireAgentToSettings(); | 
 |   } | 
 |  | 
 |   /** | 
 |    * @param {boolean} show | 
 |    */ | 
 |   setShowViewportSizeOnResize(show) { | 
 |     this._showViewportSizeOnResize = show; | 
 |     if (this.target().suspended()) { | 
 |       return; | 
 |     } | 
 |     this._overlayAgent.setShowViewportSizeOnResize(show); | 
 |   } | 
 |  | 
 |   /** | 
 |    * @return {!Promise} | 
 |    */ | 
 |   _updatePausedInDebuggerMessage() { | 
 |     if (this.target().suspended()) { | 
 |       return Promise.resolve(); | 
 |     } | 
 |     const message = this._debuggerModel.isPaused() && !Common.moduleSetting('disablePausedStateOverlay').get() ? | 
 |         Common.UIString('Paused in debugger') : | 
 |         undefined; | 
 |     return this._overlayAgent.setPausedInDebuggerMessage(message); | 
 |   } | 
 |  | 
 |   /** | 
 |    * @param {?Highlighter} highlighter | 
 |    */ | 
 |   setHighlighter(highlighter) { | 
 |     this._highlighter = highlighter || this._defaultHighlighter; | 
 |   } | 
 |  | 
 |   /** | 
 |    * @param {!Protocol.Overlay.InspectMode} mode | 
 |    * @param {boolean=} showStyles | 
 |    * @return {!Promise} | 
 |    */ | 
 |   async setInspectMode(mode, showStyles = true) { | 
 |     await this._domModel.requestDocument(); | 
 |     this._inspectModeEnabled = mode !== Protocol.Overlay.InspectMode.None; | 
 |     this.dispatchEventToListeners(Events.InspectModeWillBeToggled, this); | 
 |     this._highlighter.setInspectMode(mode, this._buildHighlightConfig('all', showStyles)); | 
 |   } | 
 |  | 
 |   /** | 
 |    * @return {boolean} | 
 |    */ | 
 |   inspectModeEnabled() { | 
 |     return this._inspectModeEnabled; | 
 |   } | 
 |  | 
 |   /** | 
 |    * @param {!SDK.OverlayModel.HighlightData} data | 
 |    * @param {string=} mode | 
 |    * @param {boolean=} showInfo | 
 |    */ | 
 |   highlightInOverlay(data, mode, showInfo) { | 
 |     if (this._hideHighlightTimeout) { | 
 |       clearTimeout(this._hideHighlightTimeout); | 
 |       this._hideHighlightTimeout = null; | 
 |     } | 
 |     const highlightConfig = this._buildHighlightConfig(mode); | 
 |     if (typeof showInfo !== 'undefined') { | 
 |       highlightConfig.showInfo = showInfo; | 
 |     } | 
 |     this._highlighter.highlightInOverlay(data, highlightConfig); | 
 |   } | 
 |  | 
 |   /** | 
 |    * @param {!SDK.OverlayModel.HighlightData} data | 
 |    */ | 
 |   highlightInOverlayForTwoSeconds(data) { | 
 |     this.highlightInOverlay(data); | 
 |     this._delayedHideHighlight(2000); | 
 |   } | 
 |  | 
 |   /** | 
 |    * @param {number} delay | 
 |    */ | 
 |   _delayedHideHighlight(delay) { | 
 |     if (this._hideHighlightTimeout === null) { | 
 |       this._hideHighlightTimeout = setTimeout(() => this.highlightInOverlay({}), delay); | 
 |     } | 
 |   } | 
 |  | 
 |   /** | 
 |    * @param {!Protocol.Page.FrameId} frameId | 
 |    */ | 
 |   highlightFrame(frameId) { | 
 |     if (this._hideHighlightTimeout) { | 
 |       clearTimeout(this._hideHighlightTimeout); | 
 |       this._hideHighlightTimeout = null; | 
 |     } | 
 |     this._highlighter.highlightFrame(frameId); | 
 |   } | 
 |  | 
 |   /** | 
 |    * @param {string=} mode | 
 |    * @param {boolean=} showStyles | 
 |    * @return {!Protocol.Overlay.HighlightConfig} | 
 |    */ | 
 |   _buildHighlightConfig(mode = 'all', showStyles = false) { | 
 |     const showRulers = Common.moduleSetting('showMetricsRulers').get(); | 
 |     const highlightConfig = | 
 |         {showInfo: mode === 'all', showRulers: showRulers, showStyles, showExtensionLines: showRulers}; | 
 |     if (mode === 'all' || mode === 'content') { | 
 |       highlightConfig.contentColor = Common.Color.PageHighlight.Content.toProtocolRGBA(); | 
 |     } | 
 |  | 
 |     if (mode === 'all' || mode === 'padding') { | 
 |       highlightConfig.paddingColor = Common.Color.PageHighlight.Padding.toProtocolRGBA(); | 
 |     } | 
 |  | 
 |     if (mode === 'all' || mode === 'border') { | 
 |       highlightConfig.borderColor = Common.Color.PageHighlight.Border.toProtocolRGBA(); | 
 |     } | 
 |  | 
 |     if (mode === 'all' || mode === 'margin') { | 
 |       highlightConfig.marginColor = Common.Color.PageHighlight.Margin.toProtocolRGBA(); | 
 |     } | 
 |  | 
 |     if (mode === 'all') { | 
 |       highlightConfig.eventTargetColor = Common.Color.PageHighlight.EventTarget.toProtocolRGBA(); | 
 |       highlightConfig.shapeColor = Common.Color.PageHighlight.Shape.toProtocolRGBA(); | 
 |       highlightConfig.shapeMarginColor = Common.Color.PageHighlight.ShapeMargin.toProtocolRGBA(); | 
 |     } | 
 |  | 
 |     if (mode === 'all') { | 
 |       highlightConfig.cssGridColor = Common.Color.PageHighlight.CssGrid.toProtocolRGBA(); | 
 |     } | 
 |  | 
 |     return highlightConfig; | 
 |   } | 
 |  | 
 |   /** | 
 |    * @override | 
 |    * @param {!Protocol.DOM.NodeId} nodeId | 
 |    */ | 
 |   nodeHighlightRequested(nodeId) { | 
 |     const node = this._domModel.nodeForId(nodeId); | 
 |     if (node) { | 
 |       this.dispatchEventToListeners(Events.HighlightNodeRequested, node); | 
 |     } | 
 |   } | 
 |  | 
 |   /** | 
 |    * @param {function(!SDK.DOMNode)} handler | 
 |    */ | 
 |   static setInspectNodeHandler(handler) { | 
 |     OverlayModel._inspectNodeHandler = handler; | 
 |   } | 
 |  | 
 |   /** | 
 |    * @override | 
 |    * @param {!Protocol.DOM.BackendNodeId} backendNodeId | 
 |    */ | 
 |   inspectNodeRequested(backendNodeId) { | 
 |     const deferredNode = new SDK.DeferredDOMNode(this.target(), backendNodeId); | 
 |     if (OverlayModel._inspectNodeHandler) { | 
 |       deferredNode.resolvePromise().then(node => { | 
 |         if (node) { | 
 |           OverlayModel._inspectNodeHandler(node); | 
 |         } | 
 |       }); | 
 |     } else { | 
 |       Common.Revealer.reveal(deferredNode); | 
 |     } | 
 |     this.dispatchEventToListeners(Events.ExitedInspectMode); | 
 |   } | 
 |  | 
 |   /** | 
 |    * @override | 
 |    * @param {!Protocol.Page.Viewport} viewport | 
 |    */ | 
 |   screenshotRequested(viewport) { | 
 |     this.dispatchEventToListeners(Events.ScreenshotRequested, viewport); | 
 |     this.dispatchEventToListeners(Events.ExitedInspectMode); | 
 |   } | 
 |  | 
 |   /** | 
 |    * @override | 
 |    */ | 
 |   inspectModeCanceled() { | 
 |     this.dispatchEventToListeners(Events.ExitedInspectMode); | 
 |   } | 
 | } | 
 |  | 
 | /** @enum {symbol} */ | 
 | export const Events = { | 
 |   InspectModeWillBeToggled: Symbol('InspectModeWillBeToggled'), | 
 |   ExitedInspectMode: Symbol('InspectModeExited'), | 
 |   HighlightNodeRequested: Symbol('HighlightNodeRequested'), | 
 |   ScreenshotRequested: Symbol('ScreenshotRequested'), | 
 | }; | 
 |  | 
 | /** | 
 |  * @interface | 
 |  */ | 
 | export class Highlighter { | 
 |   /** | 
 |    * @param {!SDK.OverlayModel.HighlightData} data | 
 |    * @param {!Protocol.Overlay.HighlightConfig} config | 
 |    */ | 
 |   highlightInOverlay(data, config) { | 
 |   } | 
 |  | 
 |   /** | 
 |    * @param {!Protocol.Overlay.InspectMode} mode | 
 |    * @param {!Protocol.Overlay.HighlightConfig} config | 
 |    * @return {!Promise} | 
 |    */ | 
 |   setInspectMode(mode, config) { | 
 |   } | 
 |  | 
 |   /** | 
 |    * @param {!Protocol.Page.FrameId} frameId | 
 |    */ | 
 |   highlightFrame(frameId) {} | 
 | } | 
 |  | 
 | /** | 
 |  * @implements {Highlighter} | 
 |  */ | 
 | class DefaultHighlighter { | 
 |   /** | 
 |    * @param {!OverlayModel} model | 
 |    */ | 
 |   constructor(model) { | 
 |     this._model = model; | 
 |   } | 
 |  | 
 |   /** | 
 |    * @override | 
 |    * @param {!SDK.OverlayModel.HighlightData} data | 
 |    * @param {!Protocol.Overlay.HighlightConfig} config | 
 |    */ | 
 |   highlightInOverlay(data, config) { | 
 |     const {node, deferredNode, object, selectorList} = data; | 
 |     const nodeId = node ? node.id : undefined; | 
 |     const backendNodeId = deferredNode ? deferredNode.backendNodeId() : undefined; | 
 |     const objectId = object ? object.objectId : undefined; | 
 |     if (nodeId || backendNodeId || objectId) { | 
 |       this._model._overlayAgent.highlightNode(config, nodeId, backendNodeId, objectId, selectorList); | 
 |     } else { | 
 |       this._model._overlayAgent.hideHighlight(); | 
 |     } | 
 |   } | 
 |  | 
 |   /** | 
 |    * @override | 
 |    * @param {!Protocol.Overlay.InspectMode} mode | 
 |    * @param {!Protocol.Overlay.HighlightConfig} config | 
 |    * @return {!Promise} | 
 |    */ | 
 |   setInspectMode(mode, config) { | 
 |     return this._model._overlayAgent.setInspectMode(mode, config); | 
 |   } | 
 |  | 
 |   /** | 
 |    * @override | 
 |    * @param {!Protocol.Page.FrameId} frameId | 
 |    */ | 
 |   highlightFrame(frameId) { | 
 |     this._model._overlayAgent.highlightFrame( | 
 |         frameId, Common.Color.PageHighlight.Content.toProtocolRGBA(), | 
 |         Common.Color.PageHighlight.ContentOutline.toProtocolRGBA()); | 
 |   } | 
 | } | 
 |  | 
 | /* Legacy exported object */ | 
 | self.SDK = self.SDK || {}; | 
 |  | 
 | /* Legacy exported object */ | 
 | SDK = SDK || {}; | 
 |  | 
 | /** @constructor */ | 
 | SDK.OverlayModel = OverlayModel; | 
 |  | 
 | /** @enum {symbol} */ | 
 | SDK.OverlayModel.Events = Events; | 
 |  | 
 | /** | 
 |  * @interface | 
 |  */ | 
 | SDK.OverlayModel.Highlighter = Highlighter; | 
 |  | 
 | SDK.SDKModel.register(SDK.OverlayModel, SDK.Target.Capability.DOM, true); | 
 |  | 
 | /** @typedef {{node: (!SDK.DOMNode|undefined), | 
 |   deferredNode: (!SDK.DeferredDOMNode|undefined), | 
 |   selectorList: (string|undefined), | 
 |   object:(!SDK.RemoteObject|undefined)}} */ | 
 | SDK.OverlayModel.HighlightData; |