mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-23 10:15:41 +00:00
Bug 1572651 - (Part 1) Add highlighter renderer base class r=jdescottes,pbro,bgrins
**Update October 8** To use the new box model highlighter, flip this pref to true: `devtools.inspector.use-new-box-model-highlighter` --- Adding Julian as reviewer to check the sanity of the communication system and Patrick for the overall highlighter behavior. --- This patch adds a base class for the renderer part of highlighters which is set up on the parent process in the browser window. This is used by the `BoxModelHighlighterRender` introduced by D47092 `HighlighterRenderer.init()` will create an HTML iframe and inject it to the appropriate position in the browser window in order to serve as a rendering surface for highlighters of the inspected page content (content toolbox) or the browser UI (browser toolbox). A host iframe is used until [Bug 1492582](https://bugzilla.mozilla.org/show_bug.cgi?id=1492582) is fixed because the browser window is XUL and does not support the anonymous canvas frame used by existing highlighters. The primary use case of `HighlighterRenderer` is as a base class for renderers which live in a separate process than the observers. This happens with highlighters for the content toolbox. Therefore, it provides methods to setup a communication system (via MessageManager for now) whereby the observer can send messages to the renderer and vice-versa: `setMessageManager()`, `postMessage()` and `onMessage()`. I used the existing code from [`AccessibilityParent`](https://searchfox.org/mozilla-central/source/devtools/server/actors/accessibility/accessibility-parent.js) as a reference for this. Classes that extend HighlighterRenderer must implement: - a typeName representing the highlighter type; used to differentiate between other types of messages when the Message Manager is used; - a _buildMarkup() method to generate the highlighter markup; - a `render()` method to update the highlighter markup when given new information about the observed node. NOTE: A temporary pink outline is set on the highlighter surface as a quick visual check to show its extent depending on context: browser toolbox or content toolbox. This will be removed before landing. Differential Revision: https://phabricator.services.mozilla.com/D47091 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
ba43684bbe
commit
c34e4a24a6
@ -1347,3 +1347,24 @@ toolbarpaletteitem > toolbaritem {
|
||||
toolbar[keyNav=true]:not([collapsed=true]):not([customizing=true]) toolbartabstop {
|
||||
-moz-user-focus: normal;
|
||||
}
|
||||
|
||||
/* Frame used for rendering the DevTools inspector highlighters */
|
||||
iframe.devtools-highlighter-renderer {
|
||||
border: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Highlighter for the Browser Toolbox */
|
||||
:root > iframe.devtools-highlighter-renderer {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* Highlighter for web content */
|
||||
.browserStack > iframe.devtools-highlighter-renderer {
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
202
devtools/server/actors/highlighters/highlighter-renderer.js
Normal file
202
devtools/server/actors/highlighters/highlighter-renderer.js
Normal file
@ -0,0 +1,202 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const Services = require("Services");
|
||||
|
||||
const {
|
||||
HighlighterEnvironment,
|
||||
} = require("devtools/server/actors/highlighters");
|
||||
|
||||
const {
|
||||
CanvasFrameAnonymousContentHelper,
|
||||
} = require("devtools/server/actors/highlighters/utils/markup");
|
||||
|
||||
/**
|
||||
* HighlighterRenderer is the base class that implements the rendering surface for a
|
||||
* highlighter in the parent process.
|
||||
*
|
||||
* It injects an iframe in the browser window which hosts the anonymous canvas
|
||||
* frame where the highlighter's markup is generated and manipulated.
|
||||
*
|
||||
* This is the renderer part of a highlighter. It has a counterpart: the observer part of
|
||||
* a highlighter which lives in the content process so it can observe changes to a node's
|
||||
* position and attributes over time. The observer communicates any changes either through
|
||||
* messages (via message manager) or directly to the renderer which updates the
|
||||
* highlighter markup.
|
||||
*
|
||||
* NOTE: When the highlighter is used in the context of the browser toolbox, for example,
|
||||
* when inspecting the browser UI, both observer and renderer live in the parent process
|
||||
* and communication is done by direct reference, not using messages.
|
||||
*
|
||||
* Classes that extend HighlighterRenderer must implement:
|
||||
* - a `typeName` string to identify the highighter type
|
||||
* - a `_buildMarkup()` method to generate the highlighter markup;
|
||||
* - a `render()` method to update the highlighter markup when given new information
|
||||
* about the observed node.
|
||||
*/
|
||||
class HighlighterRenderer {
|
||||
constructor() {
|
||||
// The highlighter's type name. To be implemented by sub classes.
|
||||
this.typeName = "";
|
||||
this.onMessage = this.onMessage.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an HTML iframe in order to use the anonymous canvas frame within it
|
||||
* for hosting and manipulating the highlighter's markup.
|
||||
*
|
||||
* @param {Boolean} isBrowserToolboxHighlighter
|
||||
* Whether the highlighter is used in the context of the
|
||||
* browser toolbox (as opposed to the content toolbox).
|
||||
* When set to true, this will influence where the
|
||||
* iframe is appended so that it overlaps the browser UI
|
||||
* (as opposed to overlapping just the page content).
|
||||
*/
|
||||
init(isBrowserToolboxHighlighter) {
|
||||
// Get a reference to the parent process window.
|
||||
this.win = Services.wm.getMostRecentBrowserWindow();
|
||||
|
||||
const { gBrowser } = this.win;
|
||||
// Get a reference to the selected <browser> element.
|
||||
const browser = gBrowser.selectedBrowser;
|
||||
const browserContainer = gBrowser.getBrowserContainer(browser);
|
||||
|
||||
// The parent node of the iframe depends on the highlighter context:
|
||||
// - browser toolbox: top-level browser window
|
||||
// - content toolbox: host node of the <browser> element for the selected tab
|
||||
const parent = isBrowserToolboxHighlighter
|
||||
? this.win.document.documentElement
|
||||
: browserContainer.querySelector(".browserStack");
|
||||
|
||||
// Grab the host iframe if it was previously created by another highlighter.
|
||||
const iframe = parent.querySelector(
|
||||
`:scope > .devtools-highlighter-renderer`
|
||||
);
|
||||
|
||||
if (iframe) {
|
||||
this.iframe = iframe;
|
||||
this.setupMarkup();
|
||||
} else {
|
||||
this.iframe = this.win.document.createElement("iframe");
|
||||
this.iframe.classList.add("devtools-highlighter-renderer");
|
||||
|
||||
if (isBrowserToolboxHighlighter) {
|
||||
parent.append(this.iframe);
|
||||
} else {
|
||||
// Ensure highlighters are drawn underneath alerts and dialog boxes.
|
||||
parent.querySelector("browser").after(this.iframe);
|
||||
}
|
||||
|
||||
this.iframe.contentWindow.addEventListener(
|
||||
"DOMContentLoaded",
|
||||
this.setupMarkup.bind(this)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the highlighter markup and insert it into the anoymous canvas frame.
|
||||
*/
|
||||
setupMarkup() {
|
||||
if (!this.iframe || !this.iframe.contentWindow) {
|
||||
throw Error(
|
||||
"The highlighter renderer's host iframe is missing or not yet ready"
|
||||
);
|
||||
}
|
||||
|
||||
this.highlighterEnv = new HighlighterEnvironment();
|
||||
this.highlighterEnv.initFromWindow(this.iframe.contentWindow);
|
||||
|
||||
this.markup = new CanvasFrameAnonymousContentHelper(
|
||||
this.highlighterEnv,
|
||||
this._buildMarkup.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up message manager listener to listen for messages
|
||||
* coming from the from the child process.
|
||||
*
|
||||
* @param {Object} mm
|
||||
* Message manager that corresponds to the current content tab.
|
||||
* @param {String} prefix
|
||||
* Cross-process connection prefix.
|
||||
*/
|
||||
setMessageManager(mm, prefix) {
|
||||
if (this.messageManager === mm) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Message name used to distinguish between messages over the message manager.
|
||||
this._msgName = `debug:${prefix}${this.typeName}`;
|
||||
|
||||
if (this.messageManager) {
|
||||
// If the browser was swapped we need to reset the message manager.
|
||||
const oldMM = this.messageManager;
|
||||
oldMM.removeMessageListener(this._msgName, this.onMessage);
|
||||
}
|
||||
|
||||
this.messageManager = mm;
|
||||
if (mm) {
|
||||
mm.addMessageListener(this._msgName, this.onMessage);
|
||||
}
|
||||
}
|
||||
|
||||
postMessage(topic, data = {}) {
|
||||
this.messageManager.sendAsyncMessage(`${this._msgName}:event`, {
|
||||
topic,
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for messages coming from the content process.
|
||||
*
|
||||
* @param {Object} msg
|
||||
* Data payload associated with the message.
|
||||
*/
|
||||
onMessage(msg) {
|
||||
const { topic, data } = msg.json;
|
||||
switch (topic) {
|
||||
case "render":
|
||||
this.render(data);
|
||||
break;
|
||||
|
||||
case "destroy":
|
||||
this.destroy();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
// When called, sub classes should update the highlighter.
|
||||
// To be implemented by sub classes.
|
||||
throw new Error(
|
||||
"Highlighter renderer class had to implement render method"
|
||||
);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this.highlighterEnv) {
|
||||
this.highlighterEnv.destroy();
|
||||
this.highlighterEnv = null;
|
||||
}
|
||||
|
||||
if (this.markup) {
|
||||
this.markup.destroy();
|
||||
this.markup = null;
|
||||
}
|
||||
|
||||
if (this.iframe) {
|
||||
this.iframe.remove();
|
||||
this.iframe = null;
|
||||
}
|
||||
|
||||
this.win = null;
|
||||
this.setMessageManager(null);
|
||||
}
|
||||
}
|
||||
exports.HighlighterRenderer = HighlighterRenderer;
|
@ -18,6 +18,7 @@ DevToolsModules(
|
||||
'flexbox.js',
|
||||
'fonts.js',
|
||||
'geometry-editor.js',
|
||||
'highlighter-renderer.js',
|
||||
'measuring-tool.js',
|
||||
'paused-debugger.js',
|
||||
'rulers.js',
|
||||
|
Loading…
Reference in New Issue
Block a user