mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-14 05:45:37 +00:00
Merge autoland to mozilla-central. a=merge
This commit is contained in:
commit
d068047dfa
@ -9,6 +9,8 @@
|
||||
%charsetDTD;
|
||||
<!ENTITY % textcontextDTD SYSTEM "chrome://global/locale/textcontext.dtd" >
|
||||
%textcontextDTD;
|
||||
<!ENTITY % downloadsDTD SYSTEM "chrome://browser/locale/downloads/downloads.dtd">
|
||||
%downloadsDTD;
|
||||
<!ENTITY % placesDTD SYSTEM "chrome://browser/locale/places/places.dtd">
|
||||
%placesDTD;
|
||||
<!ENTITY % safebrowsingDTD SYSTEM "chrome://browser/locale/safebrowsing/phishing-afterload-warning-message.dtd">
|
||||
|
@ -7,10 +7,12 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
<?xml-stylesheet href="chrome://browser/content/browser.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/downloads/downloads.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/places/places.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/usercontext/usercontext.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/controlcenter/panel.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/customizableui/panelUI.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/downloads/downloads.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
|
||||
|
||||
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
|
||||
@ -496,6 +498,7 @@
|
||||
|
||||
#include ../../components/customizableui/content/panelUI.inc.xul
|
||||
#include ../../components/controlcenter/content/panel.inc.xul
|
||||
#include ../../components/downloads/content/downloadsPanel.inc.xul
|
||||
|
||||
<hbox id="downloads-animation-container" mousethrough="always">
|
||||
<vbox id="downloads-notification-anchor" hidden="true">
|
||||
@ -925,7 +928,20 @@
|
||||
overflows="false"
|
||||
cui-areatype="toolbar"
|
||||
hidden="true"
|
||||
tooltip="dynamic-shortcut-tooltip"/>
|
||||
tooltip="dynamic-shortcut-tooltip"
|
||||
indicator="true">
|
||||
<!-- The panel's anchor area is smaller than the outer button, but must
|
||||
always be visible and must not move or resize when the indicator
|
||||
state changes, otherwise the panel could change its position or lose
|
||||
its arrow unexpectedly. -->
|
||||
<stack id="downloads-indicator-anchor"
|
||||
consumeanchor="downloads-button">
|
||||
<box id="downloads-indicator-icon"/>
|
||||
<stack id="downloads-indicator-progress-outer">
|
||||
<box id="downloads-indicator-progress-inner"/>
|
||||
</stack>
|
||||
</stack>
|
||||
</toolbarbutton>
|
||||
|
||||
<toolbarbutton id="library-button" class="toolbarbutton-1 chromeclass-toolbar-additional subviewbutton-nav"
|
||||
removable="true"
|
||||
|
@ -195,27 +195,15 @@ class DownloadsSubview extends DownloadsViewUI.BaseView {
|
||||
|
||||
// ----- Static methods. -----
|
||||
|
||||
/**
|
||||
* Perform all tasks necessary to be able to show a Downloads Subview.
|
||||
*
|
||||
* @param {DOMWindow} window Global window object.
|
||||
* @return {Promise} Will resolve when all tasks are done.
|
||||
*/
|
||||
static init(window) {
|
||||
return new Promise(resolve =>
|
||||
window.DownloadsOverlayLoader.ensureOverlayLoaded(window.DownloadsPanel.kDownloadsOverlay, resolve));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the Downloads subview panel and listen for events that will trigger
|
||||
* building the dynamic part of the view.
|
||||
*
|
||||
* @param {DOMNode} anchor The button that was commanded to trigger this function.
|
||||
*/
|
||||
static async show(anchor) {
|
||||
static show(anchor) {
|
||||
let document = anchor.ownerDocument;
|
||||
let window = anchor.ownerGlobal;
|
||||
await DownloadsSubview.init(window);
|
||||
|
||||
let panelview = document.getElementById("PanelUI-downloads");
|
||||
anchor.setAttribute("closemenu", "none");
|
||||
|
@ -13,10 +13,6 @@
|
||||
* DownloadsPanel
|
||||
* Main entry point for the downloads panel interface.
|
||||
*
|
||||
* DownloadsOverlayLoader
|
||||
* Allows loading the downloads panel and the status indicator interfaces on
|
||||
* demand, to improve startup performance.
|
||||
*
|
||||
* DownloadsView
|
||||
* Builds and updates the downloads list widget, responding to changes in the
|
||||
* download state and real-time data. In addition, handles part of the user
|
||||
@ -103,36 +99,19 @@ var DownloadsPanel = {
|
||||
get kStateWaitingData() {
|
||||
return 2;
|
||||
},
|
||||
/** The panel is almost shown - we're just waiting to get a handle on the
|
||||
anchor. */
|
||||
get kStateWaitingAnchor() {
|
||||
return 3;
|
||||
},
|
||||
/** The panel is open. */
|
||||
get kStateShown() {
|
||||
return 4;
|
||||
},
|
||||
|
||||
/**
|
||||
* Location of the panel overlay.
|
||||
*/
|
||||
get kDownloadsOverlay() {
|
||||
return "chrome://browser/content/downloads/downloadsOverlay.xul";
|
||||
return 3;
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts loading the download data in background, without opening the panel.
|
||||
* Use showPanel instead to load the data and open the panel at the same time.
|
||||
*
|
||||
* @param aCallback
|
||||
* Called when initialization is complete.
|
||||
*/
|
||||
initialize(aCallback) {
|
||||
initialize() {
|
||||
DownloadsCommon.log("Attempting to initialize DownloadsPanel for a window.");
|
||||
if (this._state != this.kStateUninitialized) {
|
||||
DownloadsCommon.log("DownloadsPanel is already initialized.");
|
||||
DownloadsOverlayLoader.ensureOverlayLoaded(this.kDownloadsOverlay,
|
||||
aCallback);
|
||||
return;
|
||||
}
|
||||
this._state = this.kStateHidden;
|
||||
@ -145,19 +124,17 @@ var DownloadsPanel = {
|
||||
|
||||
// Now that data loading has eventually started, load the required XUL
|
||||
// elements and initialize our views.
|
||||
DownloadsCommon.log("Ensuring DownloadsPanel overlay loaded.");
|
||||
DownloadsOverlayLoader.ensureOverlayLoaded(this.kDownloadsOverlay, () => {
|
||||
DownloadsViewController.initialize();
|
||||
DownloadsCommon.log("Attaching DownloadsView...");
|
||||
DownloadsCommon.getData(window).addView(DownloadsView);
|
||||
DownloadsCommon.getSummary(window, DownloadsView.kItemCountLimit)
|
||||
.addView(DownloadsSummary);
|
||||
DownloadsCommon.log("DownloadsView attached - the panel for this window",
|
||||
"should now see download items come in.");
|
||||
DownloadsPanel._attachEventListeners();
|
||||
DownloadsCommon.log("DownloadsPanel initialized.");
|
||||
aCallback();
|
||||
});
|
||||
|
||||
this.panel.hidden = false;
|
||||
DownloadsViewController.initialize();
|
||||
DownloadsCommon.log("Attaching DownloadsView...");
|
||||
DownloadsCommon.getData(window).addView(DownloadsView);
|
||||
DownloadsCommon.getSummary(window, DownloadsView.kItemCountLimit)
|
||||
.addView(DownloadsSummary);
|
||||
DownloadsCommon.log("DownloadsView attached - the panel for this window",
|
||||
"should now see download items come in.");
|
||||
DownloadsPanel._attachEventListeners();
|
||||
DownloadsCommon.log("DownloadsPanel initialized.");
|
||||
},
|
||||
|
||||
/**
|
||||
@ -192,18 +169,11 @@ var DownloadsPanel = {
|
||||
// Panel interface
|
||||
|
||||
/**
|
||||
* Main panel element in the browser window, or null if the panel overlay
|
||||
* hasn't been loaded yet.
|
||||
* Main panel element in the browser window.
|
||||
*/
|
||||
get panel() {
|
||||
// If the downloads panel overlay hasn't loaded yet, just return null
|
||||
// without resetting this.panel.
|
||||
let downloadsPanel = document.getElementById("downloadsPanel");
|
||||
if (!downloadsPanel)
|
||||
return null;
|
||||
|
||||
delete this.panel;
|
||||
return this.panel = downloadsPanel;
|
||||
return this.panel = document.getElementById("downloadsPanel");
|
||||
},
|
||||
|
||||
/**
|
||||
@ -224,13 +194,12 @@ var DownloadsPanel = {
|
||||
// As a belt-and-suspenders check, ensure the button is not hidden.
|
||||
DownloadsButton.unhide();
|
||||
|
||||
this.initialize(() => {
|
||||
// Delay displaying the panel because this function will sometimes be
|
||||
// called while another window is closing (like the window for selecting
|
||||
// whether to save or open the file), and that would cause the panel to
|
||||
// close immediately.
|
||||
setTimeout(() => this._openPopupIfDataReady(), 0);
|
||||
});
|
||||
this.initialize();
|
||||
// Delay displaying the panel because this function will sometimes be
|
||||
// called while another window is closing (like the window for selecting
|
||||
// whether to save or open the file), and that would cause the panel to
|
||||
// close immediately.
|
||||
setTimeout(() => this._openPopupIfDataReady(), 0);
|
||||
|
||||
DownloadsCommon.log("Waiting for the downloads panel to appear.");
|
||||
this._state = this.kStateWaitingData;
|
||||
@ -262,7 +231,6 @@ var DownloadsPanel = {
|
||||
*/
|
||||
get isPanelShowing() {
|
||||
return this._state == this.kStateWaitingData ||
|
||||
this._state == this.kStateWaitingAnchor ||
|
||||
this._state == this.kStateShown;
|
||||
},
|
||||
|
||||
@ -530,131 +498,43 @@ var DownloadsPanel = {
|
||||
return;
|
||||
}
|
||||
|
||||
this._state = this.kStateWaitingAnchor;
|
||||
// At this point, if the window is minimized, opening the panel could fail
|
||||
// without any notification, and there would be no way to either open or
|
||||
// close the panel any more. To prevent this, check if the window is
|
||||
// minimized and in that case force the panel to the closed state.
|
||||
if (window.windowState == window.STATE_MINIMIZED) {
|
||||
this._state = this.kStateHidden;
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure the anchor is visible. If that is not possible, show the panel
|
||||
// anchored to the top area of the window, near the default anchor position.
|
||||
DownloadsButton.getAnchor(anchor => {
|
||||
// If somehow we've switched states already (by getting a panel hiding
|
||||
// event before an overlay is loaded, for example), bail out.
|
||||
if (this._state != this.kStateWaitingAnchor) {
|
||||
return;
|
||||
}
|
||||
let anchor = DownloadsButton.getAnchor();
|
||||
|
||||
// At this point, if the window is minimized, opening the panel could fail
|
||||
// without any notification, and there would be no way to either open or
|
||||
// close the panel any more. To prevent this, check if the window is
|
||||
// minimized and in that case force the panel to the closed state.
|
||||
if (window.windowState == window.STATE_MINIMIZED) {
|
||||
DownloadsButton.releaseAnchor();
|
||||
this._state = this.kStateHidden;
|
||||
return;
|
||||
}
|
||||
if (!anchor) {
|
||||
DownloadsCommon.error("Downloads button cannot be found.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!anchor) {
|
||||
DownloadsCommon.error("Downloads button cannot be found.");
|
||||
return;
|
||||
}
|
||||
let onBookmarksToolbar = !!anchor.closest("#PersonalToolbar");
|
||||
this.panel.classList.toggle("bookmarks-toolbar", onBookmarksToolbar);
|
||||
|
||||
let onBookmarksToolbar = !!anchor.closest("#PersonalToolbar");
|
||||
this.panel.classList.toggle("bookmarks-toolbar", onBookmarksToolbar);
|
||||
// When the panel is opened, we check if the target files of visible items
|
||||
// still exist, and update the allowed items interactions accordingly. We
|
||||
// do these checks on a background thread, and don't prevent the panel to
|
||||
// be displayed while these checks are being performed.
|
||||
for (let viewItem of DownloadsView._visibleViewItems.values()) {
|
||||
viewItem.download.refresh().catch(Cu.reportError);
|
||||
}
|
||||
|
||||
// When the panel is opened, we check if the target files of visible items
|
||||
// still exist, and update the allowed items interactions accordingly. We
|
||||
// do these checks on a background thread, and don't prevent the panel to
|
||||
// be displayed while these checks are being performed.
|
||||
for (let viewItem of DownloadsView._visibleViewItems.values()) {
|
||||
viewItem.download.refresh().catch(Cu.reportError);
|
||||
}
|
||||
|
||||
DownloadsCommon.log("Opening downloads panel popup.");
|
||||
PanelMultiView.openPopup(this.panel, anchor, "bottomcenter topright",
|
||||
0, 0, false, null).catch(Cu.reportError);
|
||||
});
|
||||
DownloadsCommon.log("Opening downloads panel popup.");
|
||||
PanelMultiView.openPopup(this.panel, anchor, "bottomcenter topright",
|
||||
0, 0, false, null).catch(Cu.reportError);
|
||||
},
|
||||
};
|
||||
|
||||
XPCOMUtils.defineConstant(this, "DownloadsPanel", DownloadsPanel);
|
||||
|
||||
// DownloadsOverlayLoader
|
||||
|
||||
/**
|
||||
* Allows loading the downloads panel and the status indicator interfaces on
|
||||
* demand, to improve startup performance.
|
||||
*/
|
||||
var DownloadsOverlayLoader = {
|
||||
/**
|
||||
* We cannot load two overlays at the same time, thus we use a queue of
|
||||
* pending load requests.
|
||||
*/
|
||||
_loadRequests: [],
|
||||
|
||||
/**
|
||||
* True while we are waiting for an overlay to be loaded.
|
||||
*/
|
||||
_overlayLoading: false,
|
||||
|
||||
/**
|
||||
* This object has a key for each overlay URI that is already loaded.
|
||||
*/
|
||||
_loadedOverlays: {},
|
||||
|
||||
/**
|
||||
* Loads the specified overlay and invokes the given callback when finished.
|
||||
*
|
||||
* @param aOverlay
|
||||
* String containing the URI of the overlay to load in the current
|
||||
* window. If this overlay has already been loaded using this
|
||||
* function, then the overlay is not loaded again.
|
||||
* @param aCallback
|
||||
* Invoked when loading is completed. If the overlay is already
|
||||
* loaded, the function is called immediately.
|
||||
*/
|
||||
ensureOverlayLoaded(aOverlay, aCallback) {
|
||||
// The overlay is already loaded, invoke the callback immediately.
|
||||
if (aOverlay in this._loadedOverlays) {
|
||||
aCallback();
|
||||
return;
|
||||
}
|
||||
|
||||
// The callback will be invoked when loading is finished.
|
||||
this._loadRequests.push({ overlay: aOverlay, callback: aCallback });
|
||||
if (this._overlayLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._overlayLoading = true;
|
||||
DownloadsCommon.log("Loading overlay ", aOverlay);
|
||||
document.loadOverlay(aOverlay, () => {
|
||||
this._overlayLoading = false;
|
||||
this._loadedOverlays[aOverlay] = true;
|
||||
|
||||
this.processPendingRequests();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Re-processes all the currently pending requests, invoking the callbacks
|
||||
* and/or loading more overlays as needed. In most cases, there will be a
|
||||
* single request for one overlay, that will be processed immediately.
|
||||
*/
|
||||
processPendingRequests() {
|
||||
// Re-process all the currently pending requests, yet allow more requests
|
||||
// to be appended at the end of the array if we're not ready for them.
|
||||
let currentLength = this._loadRequests.length;
|
||||
for (let i = 0; i < currentLength; i++) {
|
||||
let request = this._loadRequests.shift();
|
||||
|
||||
// We must call ensureOverlayLoaded again for each request, to check if
|
||||
// the associated callback can be invoked now, or if we must still wait
|
||||
// for the associated overlay to load.
|
||||
this.ensureOverlayLoaded(request.overlay, request.callback);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
XPCOMUtils.defineConstant(this, "DownloadsOverlayLoader", DownloadsOverlayLoader);
|
||||
|
||||
// DownloadsView
|
||||
|
||||
/**
|
||||
|
@ -1,214 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
# -*- Mode: HTML; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
# vim: set ts=2 et sw=2 tw=80:
|
||||
# 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/.
|
||||
|
||||
<?xml-stylesheet href="chrome://browser/content/downloads/downloads.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/downloads/downloads.css"?>
|
||||
|
||||
<!DOCTYPE overlay SYSTEM "chrome://browser/locale/downloads/downloads.dtd">
|
||||
|
||||
<overlay xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
id="downloadsOverlay">
|
||||
|
||||
<commandset>
|
||||
<command id="downloadsCmd_doDefault"
|
||||
oncommand="goDoCommand('downloadsCmd_doDefault')"/>
|
||||
<command id="downloadsCmd_pauseResume"
|
||||
oncommand="goDoCommand('downloadsCmd_pauseResume')"/>
|
||||
<command id="downloadsCmd_cancel"
|
||||
oncommand="goDoCommand('downloadsCmd_cancel')"/>
|
||||
<command id="downloadsCmd_unblock"
|
||||
oncommand="goDoCommand('downloadsCmd_unblock')"/>
|
||||
<command id="downloadsCmd_chooseUnblock"
|
||||
oncommand="goDoCommand('downloadsCmd_chooseUnblock')"/>
|
||||
<command id="downloadsCmd_unblockAndOpen"
|
||||
oncommand="goDoCommand('downloadsCmd_unblockAndOpen')"/>
|
||||
<command id="downloadsCmd_confirmBlock"
|
||||
oncommand="goDoCommand('downloadsCmd_confirmBlock')"/>
|
||||
<command id="downloadsCmd_open"
|
||||
oncommand="goDoCommand('downloadsCmd_open')"/>
|
||||
<command id="downloadsCmd_show"
|
||||
oncommand="goDoCommand('downloadsCmd_show')"/>
|
||||
<command id="downloadsCmd_retry"
|
||||
oncommand="goDoCommand('downloadsCmd_retry')"/>
|
||||
<command id="downloadsCmd_openReferrer"
|
||||
oncommand="goDoCommand('downloadsCmd_openReferrer')"/>
|
||||
<command id="downloadsCmd_copyLocation"
|
||||
oncommand="goDoCommand('downloadsCmd_copyLocation')"/>
|
||||
<command id="downloadsCmd_clearList"
|
||||
oncommand="goDoCommand('downloadsCmd_clearList')"/>
|
||||
</commandset>
|
||||
|
||||
<popupset id="mainPopupSet">
|
||||
<!-- The panel has level="top" to ensure that it is never hidden by the
|
||||
taskbar on Windows. See bug 672365. For accessibility to screen
|
||||
readers, we use a label on the panel instead of the anchor because the
|
||||
panel can also be displayed without an anchor. -->
|
||||
<panel id="downloadsPanel"
|
||||
aria-label="&downloads.title;"
|
||||
role="group"
|
||||
type="arrow"
|
||||
orient="vertical"
|
||||
level="top"
|
||||
onpopupshown="DownloadsPanel.onPopupShown(event);"
|
||||
onpopuphidden="DownloadsPanel.onPopupHidden(event);">
|
||||
<!-- The following popup menu should be a child of the panel element,
|
||||
otherwise flickering may occur when the cursor is moved over the area
|
||||
of a disabled menu item that overlaps the panel. See bug 492960. -->
|
||||
<menupopup id="downloadsContextMenu"
|
||||
onpopupshown="DownloadsView.onContextPopupShown(event);"
|
||||
onpopuphidden="DownloadsView.onContextPopupHidden(event);"
|
||||
class="download-state">
|
||||
<menuitem command="downloadsCmd_pauseResume"
|
||||
class="downloadPauseMenuItem"
|
||||
label="&cmd.pause.label;"
|
||||
accesskey="&cmd.pause.accesskey;"/>
|
||||
<menuitem command="downloadsCmd_pauseResume"
|
||||
class="downloadResumeMenuItem"
|
||||
label="&cmd.resume.label;"
|
||||
accesskey="&cmd.resume.accesskey;"/>
|
||||
<menuitem command="downloadsCmd_unblock"
|
||||
class="downloadUnblockMenuItem"
|
||||
label="&cmd.unblock2.label;"
|
||||
accesskey="&cmd.unblock2.accesskey;"/>
|
||||
<menuitem command="downloadsCmd_show"
|
||||
class="downloadShowMenuItem"
|
||||
#ifdef XP_MACOSX
|
||||
label="&cmd.showMac.label;"
|
||||
accesskey="&cmd.showMac.accesskey;"
|
||||
#else
|
||||
label="&cmd.show.label;"
|
||||
accesskey="&cmd.show.accesskey;"
|
||||
#endif
|
||||
/>
|
||||
|
||||
<menuseparator class="downloadCommandsSeparator"/>
|
||||
|
||||
<menuitem command="downloadsCmd_openReferrer"
|
||||
label="&cmd.goToDownloadPage.label;"
|
||||
accesskey="&cmd.goToDownloadPage.accesskey;"/>
|
||||
<menuitem command="downloadsCmd_copyLocation"
|
||||
label="&cmd.copyDownloadLink.label;"
|
||||
accesskey="&cmd.copyDownloadLink.accesskey;"/>
|
||||
|
||||
<menuseparator/>
|
||||
|
||||
<menuitem command="cmd_delete"
|
||||
class="downloadRemoveFromHistoryMenuItem"
|
||||
label="&cmd.removeFromHistory.label;"
|
||||
accesskey="&cmd.removeFromHistory.accesskey;"/>
|
||||
<menuitem command="downloadsCmd_clearList"
|
||||
label="&cmd.clearList2.label;"
|
||||
accesskey="&cmd.clearList2.accesskey;"/>
|
||||
<menuitem command="downloadsCmd_clearDownloads"
|
||||
hidden="true"
|
||||
label="&cmd.clearDownloads.label;"/>
|
||||
</menupopup>
|
||||
|
||||
<panelmultiview id="downloadsPanel-multiView"
|
||||
mainViewId="downloadsPanel-mainView">
|
||||
|
||||
<panelview id="downloadsPanel-mainView">
|
||||
<vbox class="panel-view-body-unscrollable">
|
||||
<richlistbox id="downloadsListBox"
|
||||
context="downloadsContextMenu"
|
||||
onmouseover="DownloadsView.onDownloadMouseOver(event);"
|
||||
onmouseout="DownloadsView.onDownloadMouseOut(event);"
|
||||
oncontextmenu="DownloadsView.onDownloadContextMenu(event);"
|
||||
ondragstart="DownloadsView.onDownloadDragStart(event);"/>
|
||||
<description id="emptyDownloads"
|
||||
mousethrough="always"
|
||||
value="&downloadsPanelEmpty.label;"/>
|
||||
</vbox>
|
||||
<vbox id="downloadsFooter"
|
||||
class="downloadsPanelFooter">
|
||||
<stack>
|
||||
<hbox id="downloadsSummary"
|
||||
align="center"
|
||||
orient="horizontal"
|
||||
onkeydown="DownloadsSummary.onKeyDown(event);"
|
||||
onclick="DownloadsSummary.onClick(event);">
|
||||
<image class="downloadTypeIcon" />
|
||||
<vbox pack="center"
|
||||
class="downloadContainer"
|
||||
style="width: &downloadDetails.width;">
|
||||
<description id="downloadsSummaryDescription"
|
||||
style="min-width: &downloadsSummary.minWidth2;"/>
|
||||
<progressmeter id="downloadsSummaryProgress"
|
||||
class="downloadProgress"
|
||||
min="0"
|
||||
max="100"
|
||||
mode="normal" />
|
||||
<description id="downloadsSummaryDetails"
|
||||
crop="end"/>
|
||||
</vbox>
|
||||
</hbox>
|
||||
<hbox id="downloadsFooterButtons">
|
||||
<button id="downloadsHistory"
|
||||
class="downloadsPanelFooterButton"
|
||||
label="&downloadsHistory.label;"
|
||||
accesskey="&downloadsHistory.accesskey;"
|
||||
flex="1"
|
||||
oncommand="DownloadsPanel.showDownloadsHistory();"
|
||||
pack="start"/>
|
||||
</hbox>
|
||||
</stack>
|
||||
</vbox>
|
||||
</panelview>
|
||||
|
||||
<panelview id="downloadsPanel-blockedSubview"
|
||||
descriptionheightworkaround="true"
|
||||
class="PanelUI-subView"
|
||||
title="&downloadDetails.label;">
|
||||
<vbox class="panel-view-body-unscrollable">
|
||||
<description id="downloadsPanel-blockedSubview-title"/>
|
||||
<description id="downloadsPanel-blockedSubview-details1"/>
|
||||
<description id="downloadsPanel-blockedSubview-details2"/>
|
||||
</vbox>
|
||||
<hbox id="downloadsPanel-blockedSubview-buttons"
|
||||
class="downloadsPanelFooter"
|
||||
align="stretch">
|
||||
<button id="downloadsPanel-blockedSubview-openButton"
|
||||
class="downloadsPanelFooterButton"
|
||||
command="downloadsCmd_unblockAndOpen"
|
||||
flex="1"/>
|
||||
<toolbarseparator/>
|
||||
<button id="downloadsPanel-blockedSubview-deleteButton"
|
||||
class="downloadsPanelFooterButton"
|
||||
oncommand="DownloadsBlockedSubview.confirmBlock();"
|
||||
default="true"
|
||||
flex="1"/>
|
||||
</hbox>
|
||||
</panelview>
|
||||
|
||||
<panelview id="PanelUI-downloads" class="PanelUI-subView">
|
||||
<vbox class="panel-subview-body">
|
||||
<toolbarbutton id="appMenu-library-downloads-show-button"
|
||||
class="subviewbutton subviewbutton-iconic"
|
||||
label="&cmd.showDownloads.label;"
|
||||
closemenu="none"
|
||||
oncommand="DownloadsSubview.onShowDownloads(this);"/>
|
||||
<toolbarseparator/>
|
||||
<toolbaritem id="panelMenu_downloadsMenu"
|
||||
orient="vertical"
|
||||
smoothscroll="false"
|
||||
flatList="true"
|
||||
tooltip="bhTooltip">
|
||||
<!-- downloads menu items will go here -->
|
||||
</toolbaritem>
|
||||
</vbox>
|
||||
<toolbarbutton id="PanelUI-downloadsMore"
|
||||
class="panel-subview-footer subviewbutton"
|
||||
label="&downloadsHistory.label;"
|
||||
oncommand="BrowserDownloadsUI(); CustomizableUI.hidePanelForNode(this);"/>
|
||||
</panelview>
|
||||
|
||||
</panelmultiview>
|
||||
|
||||
</panel>
|
||||
</popupset>
|
||||
</overlay>
|
200
browser/components/downloads/content/downloadsPanel.inc.xul
Normal file
200
browser/components/downloads/content/downloadsPanel.inc.xul
Normal file
@ -0,0 +1,200 @@
|
||||
<!-- 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/. -->
|
||||
|
||||
<commandset>
|
||||
<command id="downloadsCmd_doDefault"
|
||||
oncommand="goDoCommand('downloadsCmd_doDefault')"/>
|
||||
<command id="downloadsCmd_pauseResume"
|
||||
oncommand="goDoCommand('downloadsCmd_pauseResume')"/>
|
||||
<command id="downloadsCmd_cancel"
|
||||
oncommand="goDoCommand('downloadsCmd_cancel')"/>
|
||||
<command id="downloadsCmd_unblock"
|
||||
oncommand="goDoCommand('downloadsCmd_unblock')"/>
|
||||
<command id="downloadsCmd_chooseUnblock"
|
||||
oncommand="goDoCommand('downloadsCmd_chooseUnblock')"/>
|
||||
<command id="downloadsCmd_unblockAndOpen"
|
||||
oncommand="goDoCommand('downloadsCmd_unblockAndOpen')"/>
|
||||
<command id="downloadsCmd_confirmBlock"
|
||||
oncommand="goDoCommand('downloadsCmd_confirmBlock')"/>
|
||||
<command id="downloadsCmd_open"
|
||||
oncommand="goDoCommand('downloadsCmd_open')"/>
|
||||
<command id="downloadsCmd_show"
|
||||
oncommand="goDoCommand('downloadsCmd_show')"/>
|
||||
<command id="downloadsCmd_retry"
|
||||
oncommand="goDoCommand('downloadsCmd_retry')"/>
|
||||
<command id="downloadsCmd_openReferrer"
|
||||
oncommand="goDoCommand('downloadsCmd_openReferrer')"/>
|
||||
<command id="downloadsCmd_copyLocation"
|
||||
oncommand="goDoCommand('downloadsCmd_copyLocation')"/>
|
||||
<command id="downloadsCmd_clearList"
|
||||
oncommand="goDoCommand('downloadsCmd_clearList')"/>
|
||||
</commandset>
|
||||
|
||||
<!-- The panel has level="top" to ensure that it is never hidden by the
|
||||
taskbar on Windows. See bug 672365. For accessibility to screen
|
||||
readers, we use a label on the panel instead of the anchor because the
|
||||
panel can also be displayed without an anchor. -->
|
||||
<panel id="downloadsPanel"
|
||||
aria-label="&downloads.title;"
|
||||
role="group"
|
||||
type="arrow"
|
||||
orient="vertical"
|
||||
level="top"
|
||||
onpopupshown="DownloadsPanel.onPopupShown(event);"
|
||||
onpopuphidden="DownloadsPanel.onPopupHidden(event);"
|
||||
hidden="true">
|
||||
<!-- The following popup menu should be a child of the panel element,
|
||||
otherwise flickering may occur when the cursor is moved over the area
|
||||
of a disabled menu item that overlaps the panel. See bug 492960. -->
|
||||
<menupopup id="downloadsContextMenu"
|
||||
onpopupshown="DownloadsView.onContextPopupShown(event);"
|
||||
onpopuphidden="DownloadsView.onContextPopupHidden(event);"
|
||||
class="download-state">
|
||||
<menuitem command="downloadsCmd_pauseResume"
|
||||
class="downloadPauseMenuItem"
|
||||
label="&cmd.pause.label;"
|
||||
accesskey="&cmd.pause.accesskey;"/>
|
||||
<menuitem command="downloadsCmd_pauseResume"
|
||||
class="downloadResumeMenuItem"
|
||||
label="&cmd.resume.label;"
|
||||
accesskey="&cmd.resume.accesskey;"/>
|
||||
<menuitem command="downloadsCmd_unblock"
|
||||
class="downloadUnblockMenuItem"
|
||||
label="&cmd.unblock2.label;"
|
||||
accesskey="&cmd.unblock2.accesskey;"/>
|
||||
<menuitem command="downloadsCmd_show"
|
||||
class="downloadShowMenuItem"
|
||||
#ifdef XP_MACOSX
|
||||
label="&cmd.showMac.label;"
|
||||
accesskey="&cmd.showMac.accesskey;"
|
||||
#else
|
||||
label="&cmd.show.label;"
|
||||
accesskey="&cmd.show.accesskey;"
|
||||
#endif
|
||||
/>
|
||||
|
||||
<menuseparator class="downloadCommandsSeparator"/>
|
||||
|
||||
<menuitem command="downloadsCmd_openReferrer"
|
||||
label="&cmd.goToDownloadPage.label;"
|
||||
accesskey="&cmd.goToDownloadPage.accesskey;"/>
|
||||
<menuitem command="downloadsCmd_copyLocation"
|
||||
label="&cmd.copyDownloadLink.label;"
|
||||
accesskey="&cmd.copyDownloadLink.accesskey;"/>
|
||||
|
||||
<menuseparator/>
|
||||
|
||||
<menuitem command="cmd_delete"
|
||||
class="downloadRemoveFromHistoryMenuItem"
|
||||
label="&cmd.removeFromHistory.label;"
|
||||
accesskey="&cmd.removeFromHistory.accesskey;"/>
|
||||
<menuitem command="downloadsCmd_clearList"
|
||||
label="&cmd.clearList2.label;"
|
||||
accesskey="&cmd.clearList2.accesskey;"/>
|
||||
<menuitem command="downloadsCmd_clearDownloads"
|
||||
hidden="true"
|
||||
label="&cmd.clearDownloads.label;"/>
|
||||
</menupopup>
|
||||
|
||||
<panelmultiview id="downloadsPanel-multiView"
|
||||
mainViewId="downloadsPanel-mainView">
|
||||
|
||||
<panelview id="downloadsPanel-mainView">
|
||||
<vbox class="panel-view-body-unscrollable">
|
||||
<richlistbox id="downloadsListBox"
|
||||
context="downloadsContextMenu"
|
||||
onmouseover="DownloadsView.onDownloadMouseOver(event);"
|
||||
onmouseout="DownloadsView.onDownloadMouseOut(event);"
|
||||
oncontextmenu="DownloadsView.onDownloadContextMenu(event);"
|
||||
ondragstart="DownloadsView.onDownloadDragStart(event);"/>
|
||||
<description id="emptyDownloads"
|
||||
mousethrough="always"
|
||||
value="&downloadsPanelEmpty.label;"/>
|
||||
</vbox>
|
||||
<vbox id="downloadsFooter"
|
||||
class="downloadsPanelFooter">
|
||||
<stack>
|
||||
<hbox id="downloadsSummary"
|
||||
align="center"
|
||||
orient="horizontal"
|
||||
onkeydown="DownloadsSummary.onKeyDown(event);"
|
||||
onclick="DownloadsSummary.onClick(event);">
|
||||
<image class="downloadTypeIcon" />
|
||||
<vbox pack="center"
|
||||
class="downloadContainer"
|
||||
style="width: &downloadDetails.width;">
|
||||
<description id="downloadsSummaryDescription"
|
||||
style="min-width: &downloadsSummary.minWidth2;"/>
|
||||
<progressmeter id="downloadsSummaryProgress"
|
||||
class="downloadProgress"
|
||||
min="0"
|
||||
max="100"
|
||||
mode="normal" />
|
||||
<description id="downloadsSummaryDetails"
|
||||
crop="end"/>
|
||||
</vbox>
|
||||
</hbox>
|
||||
<hbox id="downloadsFooterButtons">
|
||||
<button id="downloadsHistory"
|
||||
class="downloadsPanelFooterButton"
|
||||
label="&downloadsHistory.label;"
|
||||
accesskey="&downloadsHistory.accesskey;"
|
||||
flex="1"
|
||||
oncommand="DownloadsPanel.showDownloadsHistory();"
|
||||
pack="start"/>
|
||||
</hbox>
|
||||
</stack>
|
||||
</vbox>
|
||||
</panelview>
|
||||
|
||||
<panelview id="downloadsPanel-blockedSubview"
|
||||
descriptionheightworkaround="true"
|
||||
class="PanelUI-subView"
|
||||
title="&downloadDetails.label;">
|
||||
<vbox class="panel-view-body-unscrollable">
|
||||
<description id="downloadsPanel-blockedSubview-title"/>
|
||||
<description id="downloadsPanel-blockedSubview-details1"/>
|
||||
<description id="downloadsPanel-blockedSubview-details2"/>
|
||||
</vbox>
|
||||
<hbox id="downloadsPanel-blockedSubview-buttons"
|
||||
class="downloadsPanelFooter"
|
||||
align="stretch">
|
||||
<button id="downloadsPanel-blockedSubview-openButton"
|
||||
class="downloadsPanelFooterButton"
|
||||
command="downloadsCmd_unblockAndOpen"
|
||||
flex="1"/>
|
||||
<toolbarseparator/>
|
||||
<button id="downloadsPanel-blockedSubview-deleteButton"
|
||||
class="downloadsPanelFooterButton"
|
||||
oncommand="DownloadsBlockedSubview.confirmBlock();"
|
||||
default="true"
|
||||
flex="1"/>
|
||||
</hbox>
|
||||
</panelview>
|
||||
|
||||
<panelview id="PanelUI-downloads" class="PanelUI-subView">
|
||||
<vbox class="panel-subview-body">
|
||||
<toolbarbutton id="appMenu-library-downloads-show-button"
|
||||
class="subviewbutton subviewbutton-iconic"
|
||||
label="&cmd.showDownloads.label;"
|
||||
closemenu="none"
|
||||
oncommand="DownloadsSubview.onShowDownloads(this);"/>
|
||||
<toolbarseparator/>
|
||||
<toolbaritem id="panelMenu_downloadsMenu"
|
||||
orient="vertical"
|
||||
smoothscroll="false"
|
||||
flatList="true"
|
||||
tooltip="bhTooltip">
|
||||
<!-- downloads menu items will go here -->
|
||||
</toolbaritem>
|
||||
</vbox>
|
||||
<toolbarbutton id="PanelUI-downloadsMore"
|
||||
class="panel-subview-footer subviewbutton"
|
||||
label="&downloadsHistory.label;"
|
||||
oncommand="BrowserDownloadsUI(); CustomizableUI.hidePanelForNode(this);"/>
|
||||
</panelview>
|
||||
|
||||
</panelmultiview>
|
||||
|
||||
</panel>
|
@ -39,13 +39,6 @@ ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
* downloads panel.
|
||||
*/
|
||||
const DownloadsButton = {
|
||||
/**
|
||||
* Location of the indicator overlay.
|
||||
*/
|
||||
get kIndicatorOverlay() {
|
||||
return "chrome://browser/content/downloads/indicatorOverlay.xul";
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a reference to the downloads button position placeholder, or null
|
||||
* if not available because it has been removed from the toolbars.
|
||||
@ -78,8 +71,7 @@ const DownloadsButton = {
|
||||
_getAnchorInternal() {
|
||||
let indicator = DownloadsIndicatorView.indicator;
|
||||
if (!indicator) {
|
||||
// Exit now if the indicator overlay isn't loaded yet, or if the button
|
||||
// is not in the document.
|
||||
// Exit now if the button is not in the document.
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -104,22 +96,18 @@ const DownloadsButton = {
|
||||
/**
|
||||
* Ensures that there is an anchor available for the panel.
|
||||
*
|
||||
* @param aCallback
|
||||
* Called when the anchor is available, passing the element where the
|
||||
* panel should be anchored, or null if an anchor is not available (for
|
||||
* example because both the tab bar and the navigation bar are hidden).
|
||||
* @return Anchor element where the panel should be anchored, or null if an
|
||||
* anchor is not available (for example because both the tab bar and
|
||||
* the navigation bar are hidden).
|
||||
*/
|
||||
getAnchor(aCallback) {
|
||||
getAnchor() {
|
||||
// Do not allow anchoring the panel to the element while customizing.
|
||||
if (this._customizing) {
|
||||
aCallback(null);
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
DownloadsOverlayLoader.ensureOverlayLoaded(this.kIndicatorOverlay, () => {
|
||||
this._anchorRequested = true;
|
||||
aCallback(this._getAnchorInternal());
|
||||
});
|
||||
this._anchorRequested = true;
|
||||
return this._getAnchorInternal();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -300,39 +288,26 @@ const DownloadsIndicatorView = {
|
||||
|
||||
/**
|
||||
* Ensures that the user interface elements required to display the indicator
|
||||
* are loaded, then invokes the given callback.
|
||||
* are loaded.
|
||||
*/
|
||||
_ensureOperational(aCallback) {
|
||||
_ensureOperational() {
|
||||
if (this._operational) {
|
||||
if (aCallback) {
|
||||
aCallback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If we don't have a _placeholder, there's no chance that the overlay
|
||||
// If we don't have a _placeholder, there's no chance that everything
|
||||
// will load correctly: bail (and don't set _operational to true!)
|
||||
if (!DownloadsButton._placeholder) {
|
||||
return;
|
||||
}
|
||||
|
||||
DownloadsOverlayLoader.ensureOverlayLoaded(
|
||||
DownloadsButton.kIndicatorOverlay,
|
||||
() => {
|
||||
this._operational = true;
|
||||
this._operational = true;
|
||||
|
||||
// If the view is initialized, we need to update the elements now that
|
||||
// they are finally available in the document.
|
||||
// We need to re-check for the placeholder because it might have
|
||||
// disappeared since then.
|
||||
if (this._initialized && DownloadsButton._placeholder) {
|
||||
DownloadsCommon.getIndicatorData(window).refreshView(this);
|
||||
}
|
||||
|
||||
if (aCallback) {
|
||||
aCallback();
|
||||
}
|
||||
});
|
||||
// If the view is initialized, we need to update the elements now that
|
||||
// they are finally available in the document.
|
||||
if (this._initialized) {
|
||||
DownloadsCommon.getIndicatorData(window).refreshView(this);
|
||||
}
|
||||
},
|
||||
|
||||
// Direct control functions
|
||||
|
@ -1,34 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- -*- Mode: HTML; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- -->
|
||||
<!-- vim: set ts=2 et sw=2 tw=80: -->
|
||||
|
||||
<!-- 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/. -->
|
||||
|
||||
<!DOCTYPE overlay [
|
||||
<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd" >
|
||||
%browserDTD;
|
||||
]>
|
||||
|
||||
<overlay xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
id="indicatorOverlay">
|
||||
|
||||
<!-- We dynamically add the stack with the progress meter and notification icon,
|
||||
originally loaded lazily because of performance reasons, to the existing
|
||||
downloads-button. -->
|
||||
<toolbarbutton id="downloads-button" indicator="true">
|
||||
<!-- The panel's anchor area is smaller than the outer button, but must
|
||||
always be visible and must not move or resize when the indicator
|
||||
state changes, otherwise the panel could change its position or lose
|
||||
its arrow unexpectedly. -->
|
||||
<stack id="downloads-indicator-anchor"
|
||||
consumeanchor="downloads-button">
|
||||
<box id="downloads-indicator-icon"/>
|
||||
<stack id="downloads-indicator-progress-outer">
|
||||
<box id="downloads-indicator-progress-inner"/>
|
||||
</stack>
|
||||
</stack>
|
||||
</toolbarbutton>
|
||||
</overlay>
|
@ -6,9 +6,7 @@ browser.jar:
|
||||
* content/browser/downloads/download.xml (content/download.xml)
|
||||
content/browser/downloads/downloads.css (content/downloads.css)
|
||||
content/browser/downloads/downloads.js (content/downloads.js)
|
||||
* content/browser/downloads/downloadsOverlay.xul (content/downloadsOverlay.xul)
|
||||
content/browser/downloads/indicator.js (content/indicator.js)
|
||||
content/browser/downloads/indicatorOverlay.xul (content/indicatorOverlay.xul)
|
||||
* content/browser/downloads/allDownloadsViewOverlay.xul (content/allDownloadsViewOverlay.xul)
|
||||
content/browser/downloads/allDownloadsViewOverlay.js (content/allDownloadsViewOverlay.js)
|
||||
* content/browser/downloads/contentAreaDownloadsView.xul (content/contentAreaDownloadsView.xul)
|
||||
|
@ -138,3 +138,24 @@ responsive.deviceDetails=Size: %1$S x %2$S\nDPR: %3$S\nUA: %4$S\nTouch: %5$S
|
||||
# LOCALIZATION NOTE (responsive.devicePixelRatioOption): UI option in a menu to configure
|
||||
# the device pixel ratio. %1$S is the devicePixelRatio value of the device.
|
||||
responsive.devicePixelRatioOption=DPR: %1$S
|
||||
|
||||
# LOCALIZATION NOTE (responsive.reloadConditions.label): Label on button to open a menu
|
||||
# used to choose whether to reload the page automatically when certain actions occur.
|
||||
responsive.reloadConditions.label=Reload when…
|
||||
|
||||
# LOCALIZATION NOTE (responsive.reloadConditions.title): Title on button to open a menu
|
||||
# used to choose whether to reload the page automatically when certain actions occur.
|
||||
responsive.reloadConditions.title=Choose whether to reload the page automatically when certain actions occur
|
||||
|
||||
# LOCALIZATION NOTE (responsive.reloadConditions.touchSimulation): Label on checkbox used
|
||||
# to select whether to reload when touch simulation is toggled.
|
||||
responsive.reloadConditions.touchSimulation=Reload when touch simulation is toggled
|
||||
|
||||
# LOCALIZATION NOTE (responsive.reloadConditions.userAgent): Label on checkbox used
|
||||
# to select whether to reload when user agent is changed.
|
||||
responsive.reloadConditions.userAgent=Reload when user agent is changed
|
||||
|
||||
# LOCALIZATION NOTE (responsive.reloadNotification.description): Text in notification bar
|
||||
# shown on first open to clarify that some features need a reload to apply. %1$S is the
|
||||
# label on the reload conditions menu (responsive.reloadConditions.label).
|
||||
responsive.reloadNotification.description=Device simulation changes require a reload to fully apply. Automatic reloads are disabled by default to avoid losing any changes in DevTools. You can enable reloading via the “%1$S” menu.
|
||||
|
@ -357,3 +357,10 @@ pref("devtools.editor.autocomplete", true);
|
||||
// opened developer tool. This allows us to ping telemetry just once per browser
|
||||
// version for each user.
|
||||
pref("devtools.telemetry.tools.opened.version", "{}");
|
||||
|
||||
// Whether to reload when touch simulation is toggled
|
||||
pref("devtools.responsive.reloadConditions.touchSimulation", false);
|
||||
// Whether to reload when user agent is changed
|
||||
pref("devtools.responsive.reloadConditions.userAgent", false);
|
||||
// Whether to show the notification about reloading to apply emulation
|
||||
pref("devtools.responsive.reloadNotification.enabled", true);
|
||||
|
@ -41,18 +41,24 @@ createEnum([
|
||||
// selected from the device pixel ratio dropdown.
|
||||
"CHANGE_PIXEL_RATIO",
|
||||
|
||||
// Change one of the reload conditions.
|
||||
"CHANGE_RELOAD_CONDITION",
|
||||
|
||||
// Change the touch simulation state.
|
||||
"CHANGE_TOUCH_SIMULATION",
|
||||
|
||||
// Indicates that the device list is being loaded
|
||||
// Indicates that the device list is being loaded.
|
||||
"LOAD_DEVICE_LIST_START",
|
||||
|
||||
// Indicates that the device list loading action threw an error
|
||||
// Indicates that the device list loading action threw an error.
|
||||
"LOAD_DEVICE_LIST_ERROR",
|
||||
|
||||
// Indicates that the device list has been loaded successfully
|
||||
// Indicates that the device list has been loaded successfully.
|
||||
"LOAD_DEVICE_LIST_END",
|
||||
|
||||
// Indicates that the reload conditions have been loaded successfully.
|
||||
"LOAD_RELOAD_CONDITIONS_END",
|
||||
|
||||
// Remove a device.
|
||||
"REMOVE_DEVICE",
|
||||
|
||||
|
@ -10,6 +10,7 @@ DevToolsModules(
|
||||
'index.js',
|
||||
'location.js',
|
||||
'network-throttling.js',
|
||||
'reload-conditions.js',
|
||||
'screenshot.js',
|
||||
'touch-simulation.js',
|
||||
'viewports.js',
|
||||
|
52
devtools/client/responsive.html/actions/reload-conditions.js
Normal file
52
devtools/client/responsive.html/actions/reload-conditions.js
Normal file
@ -0,0 +1,52 @@
|
||||
/* 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 {
|
||||
CHANGE_RELOAD_CONDITION,
|
||||
LOAD_RELOAD_CONDITIONS_END,
|
||||
} = require("./index");
|
||||
|
||||
const Types = require("../types");
|
||||
const Services = require("Services");
|
||||
|
||||
const PREF_PREFIX = "devtools.responsive.reloadConditions.";
|
||||
|
||||
module.exports = {
|
||||
|
||||
changeReloadCondition(id, value) {
|
||||
return dispatch => {
|
||||
let pref = PREF_PREFIX + id;
|
||||
Services.prefs.setBoolPref(pref, value);
|
||||
dispatch({
|
||||
type: CHANGE_RELOAD_CONDITION,
|
||||
id,
|
||||
value,
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
loadReloadConditions() {
|
||||
return dispatch => {
|
||||
// Loop over the conditions and load their values from prefs.
|
||||
for (let id in Types.reloadConditions) {
|
||||
// Skip over the loading state of the list.
|
||||
if (id == "state") {
|
||||
return;
|
||||
}
|
||||
let pref = PREF_PREFIX + id;
|
||||
let value = Services.prefs.getBoolPref(pref, false);
|
||||
dispatch({
|
||||
type: CHANGE_RELOAD_CONDITION,
|
||||
id,
|
||||
value,
|
||||
});
|
||||
}
|
||||
|
||||
dispatch({ type: LOAD_RELOAD_CONDITIONS_END });
|
||||
};
|
||||
},
|
||||
|
||||
};
|
@ -19,6 +19,7 @@ const {
|
||||
updatePreferredDevices,
|
||||
} = require("./actions/devices");
|
||||
const { changeNetworkThrottling } = require("./actions/network-throttling");
|
||||
const { changeReloadCondition } = require("./actions/reload-conditions");
|
||||
const { takeScreenshot } = require("./actions/screenshot");
|
||||
const { changeTouchSimulation } = require("./actions/touch-simulation");
|
||||
const {
|
||||
@ -40,6 +41,7 @@ class App extends Component {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
displayPixelRatio: Types.pixelRatio.value.isRequired,
|
||||
networkThrottling: PropTypes.shape(Types.networkThrottling).isRequired,
|
||||
reloadConditions: PropTypes.shape(Types.reloadConditions).isRequired,
|
||||
screenshot: PropTypes.shape(Types.screenshot).isRequired,
|
||||
touchSimulation: PropTypes.shape(Types.touchSimulation).isRequired,
|
||||
viewports: PropTypes.arrayOf(PropTypes.shape(Types.viewport)).isRequired,
|
||||
@ -53,6 +55,7 @@ class App extends Component {
|
||||
this.onChangeDevice = this.onChangeDevice.bind(this);
|
||||
this.onChangeNetworkThrottling = this.onChangeNetworkThrottling.bind(this);
|
||||
this.onChangePixelRatio = this.onChangePixelRatio.bind(this);
|
||||
this.onChangeReloadCondition = this.onChangeReloadCondition.bind(this);
|
||||
this.onChangeTouchSimulation = this.onChangeTouchSimulation.bind(this);
|
||||
this.onContentResize = this.onContentResize.bind(this);
|
||||
this.onDeviceListUpdate = this.onDeviceListUpdate.bind(this);
|
||||
@ -104,6 +107,10 @@ class App extends Component {
|
||||
this.props.dispatch(changePixelRatio(0, pixelRatio));
|
||||
}
|
||||
|
||||
onChangeReloadCondition(id, value) {
|
||||
this.props.dispatch(changeReloadCondition(id, value));
|
||||
}
|
||||
|
||||
onChangeTouchSimulation(enabled) {
|
||||
window.postMessage({
|
||||
type: "change-touch-simulation",
|
||||
@ -165,6 +172,7 @@ class App extends Component {
|
||||
devices,
|
||||
displayPixelRatio,
|
||||
networkThrottling,
|
||||
reloadConditions,
|
||||
screenshot,
|
||||
touchSimulation,
|
||||
viewports,
|
||||
@ -176,6 +184,7 @@ class App extends Component {
|
||||
onChangeDevice,
|
||||
onChangeNetworkThrottling,
|
||||
onChangePixelRatio,
|
||||
onChangeReloadCondition,
|
||||
onChangeTouchSimulation,
|
||||
onContentResize,
|
||||
onDeviceListUpdate,
|
||||
@ -210,12 +219,14 @@ class App extends Component {
|
||||
devices,
|
||||
displayPixelRatio,
|
||||
networkThrottling,
|
||||
reloadConditions,
|
||||
screenshot,
|
||||
selectedDevice,
|
||||
selectedPixelRatio,
|
||||
touchSimulation,
|
||||
onChangeNetworkThrottling,
|
||||
onChangePixelRatio,
|
||||
onChangeReloadCondition,
|
||||
onChangeTouchSimulation,
|
||||
onExit,
|
||||
onScreenshot,
|
||||
|
@ -92,8 +92,8 @@ class DevicePixelRatioSelector extends PureComponent {
|
||||
}
|
||||
|
||||
let state = devices.listState;
|
||||
let isDisabled = (state !== Types.deviceListState.LOADED) || (selectedDevice !== "");
|
||||
let selectorClass = "";
|
||||
let isDisabled = (state !== Types.loadableState.LOADED) || (selectedDevice !== "");
|
||||
let selectorClass = "toolbar-dropdown";
|
||||
let title;
|
||||
|
||||
if (isDisabled) {
|
||||
@ -113,7 +113,7 @@ class DevicePixelRatioSelector extends PureComponent {
|
||||
|
||||
let listContent = PIXEL_RATIO_PRESET.map(createVisibleOption);
|
||||
|
||||
if (state == Types.deviceListState.LOADED) {
|
||||
if (state == Types.loadableState.LOADED) {
|
||||
listContent = listContent.concat(hiddenOptions.map(createHiddenOption));
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ class DeviceSelector extends PureComponent {
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
|
||||
let selectClass = "viewport-device-selector";
|
||||
let selectClass = "viewport-device-selector toolbar-dropdown";
|
||||
if (selectedDevice) {
|
||||
selectClass += " selected";
|
||||
}
|
||||
@ -80,7 +80,7 @@ class DeviceSelector extends PureComponent {
|
||||
let state = devices.listState;
|
||||
let listContent;
|
||||
|
||||
if (state == Types.deviceListState.LOADED) {
|
||||
if (state == Types.loadableState.LOADED) {
|
||||
listContent = [
|
||||
dom.option({
|
||||
value: "",
|
||||
@ -100,14 +100,14 @@ class DeviceSelector extends PureComponent {
|
||||
value: OPEN_DEVICE_MODAL_VALUE,
|
||||
title: "",
|
||||
}, getStr("responsive.editDeviceList"))];
|
||||
} else if (state == Types.deviceListState.LOADING
|
||||
|| state == Types.deviceListState.INITIALIZED) {
|
||||
} else if (state == Types.loadableState.LOADING
|
||||
|| state == Types.loadableState.INITIALIZED) {
|
||||
listContent = [dom.option({
|
||||
value: "",
|
||||
title: "",
|
||||
disabled: true,
|
||||
}, getStr("responsive.deviceListLoading"))];
|
||||
} else if (state == Types.deviceListState.ERROR) {
|
||||
} else if (state == Types.loadableState.ERROR) {
|
||||
listContent = [dom.option({
|
||||
value: "",
|
||||
title: "",
|
||||
@ -121,7 +121,7 @@ class DeviceSelector extends PureComponent {
|
||||
value: selectedDevice,
|
||||
title: selectedDevice,
|
||||
onChange: this.onSelectChange,
|
||||
disabled: (state !== Types.deviceListState.LOADED),
|
||||
disabled: (state !== Types.loadableState.LOADED),
|
||||
},
|
||||
...listContent
|
||||
);
|
||||
|
@ -12,6 +12,7 @@ const { getStr } = require("../utils/l10n");
|
||||
const Types = require("../types");
|
||||
const DevicePixelRatioSelector = createFactory(require("./DevicePixelRatioSelector"));
|
||||
const NetworkThrottlingSelector = createFactory(require("./NetworkThrottlingSelector"));
|
||||
const ReloadConditions = createFactory(require("./ReloadConditions"));
|
||||
|
||||
class GlobalToolbar extends PureComponent {
|
||||
static get propTypes() {
|
||||
@ -19,12 +20,14 @@ class GlobalToolbar extends PureComponent {
|
||||
devices: PropTypes.shape(Types.devices).isRequired,
|
||||
displayPixelRatio: Types.pixelRatio.value.isRequired,
|
||||
networkThrottling: PropTypes.shape(Types.networkThrottling).isRequired,
|
||||
reloadConditions: PropTypes.shape(Types.reloadConditions).isRequired,
|
||||
screenshot: PropTypes.shape(Types.screenshot).isRequired,
|
||||
selectedDevice: PropTypes.string.isRequired,
|
||||
selectedPixelRatio: PropTypes.shape(Types.pixelRatio).isRequired,
|
||||
touchSimulation: PropTypes.shape(Types.touchSimulation).isRequired,
|
||||
onChangeNetworkThrottling: PropTypes.func.isRequired,
|
||||
onChangePixelRatio: PropTypes.func.isRequired,
|
||||
onChangeReloadCondition: PropTypes.func.isRequired,
|
||||
onChangeTouchSimulation: PropTypes.func.isRequired,
|
||||
onExit: PropTypes.func.isRequired,
|
||||
onScreenshot: PropTypes.func.isRequired,
|
||||
@ -36,12 +39,14 @@ class GlobalToolbar extends PureComponent {
|
||||
devices,
|
||||
displayPixelRatio,
|
||||
networkThrottling,
|
||||
reloadConditions,
|
||||
screenshot,
|
||||
selectedDevice,
|
||||
selectedPixelRatio,
|
||||
touchSimulation,
|
||||
onChangeNetworkThrottling,
|
||||
onChangePixelRatio,
|
||||
onChangeReloadCondition,
|
||||
onChangeTouchSimulation,
|
||||
onExit,
|
||||
onScreenshot,
|
||||
@ -74,6 +79,10 @@ class GlobalToolbar extends PureComponent {
|
||||
selectedPixelRatio,
|
||||
onChangePixelRatio,
|
||||
}),
|
||||
ReloadConditions({
|
||||
reloadConditions,
|
||||
onChangeReloadCondition,
|
||||
}),
|
||||
dom.button({
|
||||
id: "global-touch-simulation-button",
|
||||
className: touchButtonClass,
|
||||
|
@ -48,7 +48,7 @@ class NetworkThrottlingSelector extends PureComponent {
|
||||
networkThrottling,
|
||||
} = this.props;
|
||||
|
||||
let selectClass = "";
|
||||
let selectClass = "toolbar-dropdown";
|
||||
let selectedProfile;
|
||||
if (networkThrottling.enabled) {
|
||||
selectClass += " selected";
|
||||
|
@ -0,0 +1,49 @@
|
||||
/* 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 { PureComponent, createFactory } = require("devtools/client/shared/vendor/react");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
|
||||
const Types = require("../types");
|
||||
const { getStr } = require("../utils/l10n");
|
||||
const ToggleMenu = createFactory(require("./ToggleMenu"));
|
||||
|
||||
class ReloadConditions extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
reloadConditions: PropTypes.shape(Types.reloadConditions).isRequired,
|
||||
onChangeReloadCondition: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
let {
|
||||
reloadConditions,
|
||||
onChangeReloadCondition,
|
||||
} = this.props;
|
||||
|
||||
return ToggleMenu({
|
||||
id: "global-reload-conditions-menu",
|
||||
items: [
|
||||
{
|
||||
id: "touchSimulation",
|
||||
label: getStr("responsive.reloadConditions.touchSimulation"),
|
||||
checked: reloadConditions.touchSimulation,
|
||||
},
|
||||
{
|
||||
id: "userAgent",
|
||||
label: getStr("responsive.reloadConditions.userAgent"),
|
||||
checked: reloadConditions.userAgent,
|
||||
},
|
||||
],
|
||||
label: getStr("responsive.reloadConditions.label"),
|
||||
title: getStr("responsive.reloadConditions.title"),
|
||||
onChange: onChangeReloadCondition,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ReloadConditions;
|
129
devtools/client/responsive.html/components/ToggleMenu.js
Normal file
129
devtools/client/responsive.html/components/ToggleMenu.js
Normal file
@ -0,0 +1,129 @@
|
||||
/* 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 { PureComponent } = require("devtools/client/shared/vendor/react");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
|
||||
let MenuItem = {
|
||||
id: PropTypes.string.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
checked: PropTypes.bool,
|
||||
};
|
||||
|
||||
class ToggleMenu extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
id: PropTypes.string,
|
||||
items: PropTypes.arrayOf(PropTypes.shape(MenuItem)).isRequired,
|
||||
label: PropTypes.string,
|
||||
title: PropTypes.string,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
isOpen: false,
|
||||
};
|
||||
|
||||
this.onItemChange = this.onItemChange.bind(this);
|
||||
this.onToggleOpen = this.onToggleOpen.bind(this);
|
||||
}
|
||||
|
||||
onItemChange({ target }) {
|
||||
let {
|
||||
onChange,
|
||||
} = this.props;
|
||||
|
||||
// Close menu after changing an item
|
||||
this.setState({
|
||||
isOpen: false,
|
||||
});
|
||||
|
||||
let id = target.name;
|
||||
onChange(id, target.checked);
|
||||
}
|
||||
|
||||
onToggleOpen() {
|
||||
let {
|
||||
isOpen,
|
||||
} = this.state;
|
||||
|
||||
this.setState({
|
||||
isOpen: !isOpen,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
let {
|
||||
id: menuID,
|
||||
items,
|
||||
label: toggleLabel,
|
||||
title,
|
||||
} = this.props;
|
||||
|
||||
let {
|
||||
isOpen,
|
||||
} = this.state;
|
||||
|
||||
let {
|
||||
onItemChange,
|
||||
onToggleOpen,
|
||||
} = this;
|
||||
|
||||
let menuItems = items.map(({ id, label, checked }) => {
|
||||
let inputID = `devtools-menu-item-${id}`;
|
||||
|
||||
return dom.div(
|
||||
{
|
||||
className: "devtools-menu-item",
|
||||
},
|
||||
dom.input({
|
||||
type: "checkbox",
|
||||
id: inputID,
|
||||
name: id,
|
||||
checked,
|
||||
onChange: onItemChange,
|
||||
}),
|
||||
dom.label({
|
||||
htmlFor: inputID,
|
||||
}, label)
|
||||
);
|
||||
});
|
||||
|
||||
let menuClass = "devtools-menu";
|
||||
if (isOpen) {
|
||||
menuClass += " opened";
|
||||
}
|
||||
let menu = dom.div(
|
||||
{
|
||||
className: menuClass,
|
||||
},
|
||||
menuItems
|
||||
);
|
||||
|
||||
let buttonClass = "devtools-toggle-menu";
|
||||
buttonClass += " toolbar-dropdown toolbar-button devtools-button";
|
||||
if (isOpen || items.some(({ checked }) => checked)) {
|
||||
buttonClass += " selected";
|
||||
}
|
||||
return dom.div(
|
||||
{
|
||||
id: menuID,
|
||||
className: buttonClass,
|
||||
title,
|
||||
onClick: onToggleOpen,
|
||||
},
|
||||
toggleLabel,
|
||||
menu
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ToggleMenu;
|
@ -12,7 +12,9 @@ DevToolsModules(
|
||||
'DeviceSelector.js',
|
||||
'GlobalToolbar.js',
|
||||
'NetworkThrottlingSelector.js',
|
||||
'ReloadConditions.js',
|
||||
'ResizableViewport.js',
|
||||
'ToggleMenu.js',
|
||||
'Viewport.js',
|
||||
'ViewportDimension.js',
|
||||
'Viewports.js',
|
||||
|
@ -67,10 +67,13 @@ body,
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
color: var(--viewport-color);
|
||||
}
|
||||
|
||||
.toolbar-button:empty:hover:not(:disabled),
|
||||
.toolbar-button:empty:-moz-any(:hover:active, .checked):not(:disabled) {
|
||||
.toolbar-button:empty:-moz-any(:hover:active, .checked):not(:disabled),
|
||||
.toolbar-button:not(:empty),
|
||||
.toolbar-button:hover:not(:empty):not(:disabled):not(.checked) {
|
||||
/* Reset background from .devtools-button */
|
||||
background: none;
|
||||
}
|
||||
@ -79,16 +82,17 @@ body,
|
||||
filter: var(--theme-icon-checked-filter);
|
||||
}
|
||||
|
||||
.toolbar-button.selected {
|
||||
color: var(--viewport-active-color);
|
||||
}
|
||||
|
||||
.toolbar-button:not(:disabled):hover {
|
||||
color: var(--viewport-hover-color);
|
||||
}
|
||||
|
||||
select {
|
||||
-moz-appearance: none;
|
||||
background-color: var(--theme-toolbar-background);
|
||||
background-image: var(--viewport-selection-arrow);
|
||||
-moz-context-properties: fill;
|
||||
fill: currentColor;
|
||||
color: var(--viewport-color);
|
||||
background-position: 100% 50%;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 7px;
|
||||
border: none;
|
||||
height: 100%;
|
||||
padding: 0 8px;
|
||||
@ -129,6 +133,52 @@ select > option.divider {
|
||||
font-size: 0px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle Menu
|
||||
*/
|
||||
|
||||
.devtools-toggle-menu {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.devtools-toggle-menu .devtools-menu {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
align-items: start;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 100%;
|
||||
z-index: 1;
|
||||
padding: 5px;
|
||||
border-radius: 2px;
|
||||
background-color: var(--theme-toolbar-background);
|
||||
box-shadow: var(--rdm-box-shadow);
|
||||
}
|
||||
|
||||
.devtools-toggle-menu .devtools-menu.opened {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.devtools-toggle-menu .devtools-menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/**
|
||||
* Common background for dropdowns like select and toggle menu
|
||||
*/
|
||||
.toolbar-dropdown,
|
||||
.toolbar-dropdown.devtools-button,
|
||||
.toolbar-dropdown.devtools-button:hover:not(:empty):not(:disabled):not(.checked) {
|
||||
background-color: var(--theme-toolbar-background);
|
||||
background-image: var(--viewport-selection-arrow);
|
||||
background-position: 100% 50%;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 7px;
|
||||
-moz-context-properties: fill;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Global Toolbar
|
||||
*/
|
||||
@ -140,6 +190,7 @@ select > option.divider {
|
||||
margin: 0 0 15px 0;
|
||||
padding: 4px 5px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
@ -157,6 +208,13 @@ select > option.divider {
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
#global-toolbar .toolbar-dropdown {
|
||||
background-position-x: right 5px;
|
||||
border-right: 1px solid var(--theme-splitter-color);
|
||||
padding-right: 15px;
|
||||
/* padding-left: 0; */
|
||||
}
|
||||
|
||||
#global-touch-simulation-button::before {
|
||||
background-image: url("./images/touch-events.svg");
|
||||
}
|
||||
|
@ -23,10 +23,11 @@ const { Provider } = require("devtools/client/shared/vendor/react-redux");
|
||||
const message = require("./utils/message");
|
||||
const App = createFactory(require("./app"));
|
||||
const Store = require("./store");
|
||||
const { changeLocation } = require("./actions/location");
|
||||
const { changeDisplayPixelRatio } = require("./actions/display-pixel-ratio");
|
||||
const { addViewport, resizeViewport } = require("./actions/viewports");
|
||||
const { loadDevices } = require("./actions/devices");
|
||||
const { changeDisplayPixelRatio } = require("./actions/display-pixel-ratio");
|
||||
const { changeLocation } = require("./actions/location");
|
||||
const { loadReloadConditions } = require("./actions/reload-conditions");
|
||||
const { addViewport, resizeViewport } = require("./actions/viewports");
|
||||
|
||||
// Exposed for use by tests
|
||||
window.require = require;
|
||||
@ -79,7 +80,10 @@ message.wait(window, "init").then(() => bootstrap.init());
|
||||
|
||||
// manager.js sends a message to signal init is done, which can be used for delayed
|
||||
// startup work that shouldn't block initial load
|
||||
message.wait(window, "post-init").then(() => bootstrap.dispatch(loadDevices()));
|
||||
message.wait(window, "post-init").then(() => {
|
||||
bootstrap.dispatch(loadDevices());
|
||||
bootstrap.dispatch(loadReloadConditions());
|
||||
});
|
||||
|
||||
window.addEventListener("unload", function () {
|
||||
bootstrap.destroy();
|
||||
|
@ -6,26 +6,24 @@
|
||||
|
||||
const { Ci } = require("chrome");
|
||||
const promise = require("promise");
|
||||
const Services = require("Services");
|
||||
const EventEmitter = require("devtools/shared/old-event-emitter");
|
||||
|
||||
const TOOL_URL = "chrome://devtools/content/responsive.html/index.xhtml";
|
||||
|
||||
loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/debugger-client", true);
|
||||
loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
|
||||
loader.lazyRequireGetter(this, "TargetFactory", "devtools/client/framework/target", true);
|
||||
loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
|
||||
loader.lazyRequireGetter(this, "throttlingProfiles",
|
||||
"devtools/client/shared/network-throttling-profiles");
|
||||
loader.lazyRequireGetter(this, "swapToInnerBrowser",
|
||||
"devtools/client/responsive.html/browser/swap", true);
|
||||
loader.lazyRequireGetter(this, "startup",
|
||||
"devtools/client/responsive.html/utils/window", true);
|
||||
loader.lazyRequireGetter(this, "message",
|
||||
"devtools/client/responsive.html/utils/message");
|
||||
loader.lazyRequireGetter(this, "getStr",
|
||||
"devtools/client/responsive.html/utils/l10n", true);
|
||||
loader.lazyRequireGetter(this, "EmulationFront",
|
||||
"devtools/shared/fronts/emulation", true);
|
||||
loader.lazyRequireGetter(this, "throttlingProfiles", "devtools/client/shared/network-throttling-profiles");
|
||||
loader.lazyRequireGetter(this, "swapToInnerBrowser", "devtools/client/responsive.html/browser/swap", true);
|
||||
loader.lazyRequireGetter(this, "startup", "devtools/client/responsive.html/utils/window", true);
|
||||
loader.lazyRequireGetter(this, "message", "devtools/client/responsive.html/utils/message");
|
||||
loader.lazyRequireGetter(this, "showNotification", "devtools/client/responsive.html/utils/notification", true);
|
||||
loader.lazyRequireGetter(this, "l10n", "devtools/client/responsive.html/utils/l10n");
|
||||
loader.lazyRequireGetter(this, "EmulationFront", "devtools/shared/fronts/emulation", true);
|
||||
loader.lazyRequireGetter(this, "PriorityLevels", "devtools/client/shared/components/NotificationBox", true);
|
||||
|
||||
const RELOAD_CONDITION_PREF_PREFIX = "devtools.responsive.reloadConditions.";
|
||||
const RELOAD_NOTIFICATION_PREF = "devtools.responsive.reloadNotification.enabled";
|
||||
|
||||
function debug(msg) {
|
||||
// console.log(`RDM manager: ${msg}`);
|
||||
@ -221,42 +219,20 @@ const ResponsiveUIManager = exports.ResponsiveUIManager = {
|
||||
}
|
||||
},
|
||||
|
||||
showRemoteOnlyNotification(window, tab, options) {
|
||||
this.showErrorNotification(window, tab, options, getStr("responsive.remoteOnly"));
|
||||
showRemoteOnlyNotification(window, tab, { command } = {}) {
|
||||
showNotification(window, tab, {
|
||||
command,
|
||||
msg: l10n.getStr("responsive.remoteOnly"),
|
||||
priority: PriorityLevels.PRIORITY_CRITICAL_MEDIUM,
|
||||
});
|
||||
},
|
||||
|
||||
showNoContainerTabsNotification(window, tab, options) {
|
||||
this.showErrorNotification(window, tab, options,
|
||||
getStr("responsive.noContainerTabs"));
|
||||
},
|
||||
|
||||
showErrorNotification(window, tab, { command } = {}, msg) {
|
||||
// Default to using the browser's per-tab notification box
|
||||
let nbox = window.gBrowser.getNotificationBox(tab.linkedBrowser);
|
||||
|
||||
// If opening was initiated by GCLI command bar or toolbox button, check for an open
|
||||
// toolbox for the tab. If one exists, use the toolbox's notification box so that the
|
||||
// message is placed closer to the action taken by the user.
|
||||
if (command) {
|
||||
let target = TargetFactory.forTab(tab);
|
||||
let toolbox = gDevTools.getToolbox(target);
|
||||
if (toolbox) {
|
||||
nbox = toolbox.notificationBox;
|
||||
}
|
||||
}
|
||||
|
||||
let value = "devtools-responsive-error";
|
||||
if (nbox.getNotificationWithValue(value)) {
|
||||
// Notification already displayed
|
||||
return;
|
||||
}
|
||||
|
||||
nbox.appendNotification(
|
||||
msg,
|
||||
value,
|
||||
null,
|
||||
nbox.PRIORITY_CRITICAL_MEDIUM,
|
||||
[]);
|
||||
showNoContainerTabsNotification(window, tab, { command } = {}) {
|
||||
showNotification(window, tab, {
|
||||
command,
|
||||
msg: l10n.getStr("responsive.noContainerTabs"),
|
||||
priority: PriorityLevels.PRIORITY_CRITICAL_MEDIUM,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@ -405,10 +381,12 @@ ResponsiveUI.prototype = {
|
||||
// settings are left in a customized state.
|
||||
if (!isTabContentDestroying) {
|
||||
let reloadNeeded = false;
|
||||
reloadNeeded |= await this.updateDPPX();
|
||||
reloadNeeded |= await this.updateNetworkThrottling();
|
||||
reloadNeeded |= await this.updateUserAgent();
|
||||
reloadNeeded |= await this.updateTouchSimulation();
|
||||
await this.updateDPPX();
|
||||
await this.updateNetworkThrottling();
|
||||
reloadNeeded |= await this.updateUserAgent() &&
|
||||
this.reloadOnChange("userAgent");
|
||||
reloadNeeded |= await this.updateTouchSimulation() &&
|
||||
this.reloadOnChange("touchSimulation");
|
||||
if (reloadNeeded) {
|
||||
this.getViewportBrowser().reload();
|
||||
}
|
||||
@ -450,6 +428,25 @@ ResponsiveUI.prototype = {
|
||||
this.emulationFront = EmulationFront(this.client, tab);
|
||||
},
|
||||
|
||||
/**
|
||||
* Show one-time notification about reloads for emulation.
|
||||
*/
|
||||
showReloadNotification() {
|
||||
if (Services.prefs.getBoolPref(RELOAD_NOTIFICATION_PREF, false)) {
|
||||
showNotification(this.browserWindow, this.tab, {
|
||||
msg: l10n.getFormatStr("responsive.reloadNotification.description",
|
||||
l10n.getStr("responsive.reloadConditions.label")),
|
||||
});
|
||||
Services.prefs.setBoolPref(RELOAD_NOTIFICATION_PREF, false);
|
||||
}
|
||||
},
|
||||
|
||||
reloadOnChange(id) {
|
||||
this.showReloadNotification();
|
||||
let pref = RELOAD_CONDITION_PREF_PREFIX + id;
|
||||
return Services.prefs.getBoolPref(pref, false);
|
||||
},
|
||||
|
||||
handleEvent(event) {
|
||||
let { browserWindow, tab } = this;
|
||||
|
||||
@ -499,10 +496,12 @@ ResponsiveUI.prototype = {
|
||||
|
||||
async onChangeDevice(event) {
|
||||
let { userAgent, pixelRatio, touch } = event.data.device;
|
||||
// Bug 1428799: Should we reload on UA change as well?
|
||||
await this.updateUserAgent(userAgent);
|
||||
let reloadNeeded = false;
|
||||
await this.updateDPPX(pixelRatio);
|
||||
let reloadNeeded = await this.updateTouchSimulation(touch);
|
||||
reloadNeeded |= await this.updateUserAgent(userAgent) &&
|
||||
this.reloadOnChange("userAgent");
|
||||
reloadNeeded |= await this.updateTouchSimulation(touch) &&
|
||||
this.reloadOnChange("touchSimulation");
|
||||
if (reloadNeeded) {
|
||||
this.getViewportBrowser().reload();
|
||||
}
|
||||
@ -524,7 +523,8 @@ ResponsiveUI.prototype = {
|
||||
|
||||
async onChangeTouchSimulation(event) {
|
||||
let { enabled } = event.data;
|
||||
let reloadNeeded = await this.updateTouchSimulation(enabled);
|
||||
let reloadNeeded = await this.updateTouchSimulation(enabled) &&
|
||||
this.reloadOnChange("touchSimulation");
|
||||
if (reloadNeeded) {
|
||||
this.getViewportBrowser().reload();
|
||||
}
|
||||
@ -546,10 +546,12 @@ ResponsiveUI.prototype = {
|
||||
},
|
||||
|
||||
async onRemoveDeviceAssociation(event) {
|
||||
// Bug 1428799: Should we reload on UA change as well?
|
||||
await this.updateUserAgent();
|
||||
let reloadNeeded = false;
|
||||
await this.updateDPPX();
|
||||
let reloadNeeded = await this.updateTouchSimulation();
|
||||
reloadNeeded |= await this.updateUserAgent() &&
|
||||
this.reloadOnChange("userAgent");
|
||||
reloadNeeded |= await this.updateTouchSimulation() &&
|
||||
this.reloadOnChange("touchSimulation");
|
||||
if (reloadNeeded) {
|
||||
this.getViewportBrowser().reload();
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ exports.devices = require("./reducers/devices");
|
||||
exports.displayPixelRatio = require("./reducers/display-pixel-ratio");
|
||||
exports.location = require("./reducers/location");
|
||||
exports.networkThrottling = require("./reducers/network-throttling");
|
||||
exports.reloadConditions = require("./reducers/reload-conditions");
|
||||
exports.screenshot = require("./reducers/screenshot");
|
||||
exports.touchSimulation = require("./reducers/touch-simulation");
|
||||
exports.viewports = require("./reducers/viewports");
|
||||
|
@ -21,7 +21,7 @@ const INITIAL_DEVICES = {
|
||||
types: [],
|
||||
isModalOpen: false,
|
||||
modalOpenedFromViewport: null,
|
||||
listState: Types.deviceListState.INITIALIZED,
|
||||
listState: Types.loadableState.INITIALIZED,
|
||||
};
|
||||
|
||||
let reducers = {
|
||||
@ -55,19 +55,19 @@ let reducers = {
|
||||
|
||||
[LOAD_DEVICE_LIST_START](devices, action) {
|
||||
return Object.assign({}, devices, {
|
||||
listState: Types.deviceListState.LOADING,
|
||||
listState: Types.loadableState.LOADING,
|
||||
});
|
||||
},
|
||||
|
||||
[LOAD_DEVICE_LIST_ERROR](devices, action) {
|
||||
return Object.assign({}, devices, {
|
||||
listState: Types.deviceListState.ERROR,
|
||||
listState: Types.loadableState.ERROR,
|
||||
});
|
||||
},
|
||||
|
||||
[LOAD_DEVICE_LIST_END](devices, action) {
|
||||
return Object.assign({}, devices, {
|
||||
listState: Types.deviceListState.LOADED,
|
||||
listState: Types.loadableState.LOADED,
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -9,6 +9,7 @@ DevToolsModules(
|
||||
'display-pixel-ratio.js',
|
||||
'location.js',
|
||||
'network-throttling.js',
|
||||
'reload-conditions.js',
|
||||
'screenshot.js',
|
||||
'touch-simulation.js',
|
||||
'viewports.js',
|
||||
|
@ -0,0 +1,42 @@
|
||||
/* 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 {
|
||||
CHANGE_RELOAD_CONDITION,
|
||||
LOAD_RELOAD_CONDITIONS_END,
|
||||
} = require("../actions/index");
|
||||
|
||||
const Types = require("../types");
|
||||
|
||||
const INITIAL_RELOAD_CONDITIONS = {
|
||||
touchSimulation: false,
|
||||
userAgent: false,
|
||||
state: Types.loadableState.INITIALIZED,
|
||||
};
|
||||
|
||||
let reducers = {
|
||||
|
||||
[CHANGE_RELOAD_CONDITION](conditions, { id, value }) {
|
||||
return Object.assign({}, conditions, {
|
||||
[id]: value,
|
||||
});
|
||||
},
|
||||
|
||||
[LOAD_RELOAD_CONDITIONS_END](conditions) {
|
||||
return Object.assign({}, conditions, {
|
||||
state: Types.loadableState.LOADED,
|
||||
});
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
module.exports = function (conditions = INITIAL_RELOAD_CONDITIONS, action) {
|
||||
let reducer = reducers[action.type];
|
||||
if (!reducer) {
|
||||
return conditions;
|
||||
}
|
||||
return reducer(conditions, action);
|
||||
};
|
@ -31,9 +31,11 @@ addDeviceForTest(testDevice);
|
||||
addRDMTask(TEST_URL, async function ({ ui }) {
|
||||
let { store } = ui.toolWindow;
|
||||
|
||||
reloadOnUAChange(true);
|
||||
|
||||
// Wait until the viewport has been added and the device list has been loaded
|
||||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.deviceListState.LOADED);
|
||||
&& state.devices.listState == Types.loadableState.LOADED);
|
||||
|
||||
// Test defaults
|
||||
testViewportDimensions(ui, 320, 480);
|
||||
@ -72,6 +74,8 @@ addRDMTask(TEST_URL, async function ({ ui }) {
|
||||
await testUserAgent(ui, DEFAULT_UA);
|
||||
await testDevicePixelRatio(ui, 1);
|
||||
await testTouchEventsOverride(ui, false);
|
||||
|
||||
reloadOnUAChange(false);
|
||||
});
|
||||
|
||||
add_task(async function () {
|
||||
@ -80,9 +84,11 @@ add_task(async function () {
|
||||
|
||||
let { store } = ui.toolWindow;
|
||||
|
||||
reloadOnUAChange(true);
|
||||
|
||||
// Wait until the viewport has been added and the device list has been loaded
|
||||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.deviceListState.LOADED);
|
||||
&& state.devices.listState == Types.loadableState.LOADED);
|
||||
|
||||
// Select device with custom UA
|
||||
let reloaded = waitForViewportLoad(ui);
|
||||
@ -102,6 +108,8 @@ add_task(async function () {
|
||||
await testUserAgentFromBrowser(tab.linkedBrowser, DEFAULT_UA);
|
||||
|
||||
await removeTab(tab);
|
||||
|
||||
reloadOnUAChange(false);
|
||||
});
|
||||
|
||||
function testViewportDimensions(ui, w, h) {
|
||||
|
@ -32,7 +32,7 @@ addRDMTask(TEST_URL, async function ({ ui }) {
|
||||
|
||||
// Wait until the viewport has been added and the device list has been loaded
|
||||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.deviceListState.LOADED);
|
||||
&& state.devices.listState == Types.loadableState.LOADED);
|
||||
|
||||
let deviceSelector = document.querySelector(".viewport-device-selector");
|
||||
let submitButton = document.querySelector("#device-submit-button");
|
||||
@ -73,7 +73,7 @@ addRDMTask(TEST_URL, async function ({ ui }) {
|
||||
|
||||
// Wait until the viewport has been added and the device list has been loaded
|
||||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.deviceListState.LOADED);
|
||||
&& state.devices.listState == Types.loadableState.LOADED);
|
||||
|
||||
let deviceSelector = document.querySelector(".viewport-device-selector");
|
||||
let submitButton = document.querySelector("#device-submit-button");
|
||||
@ -116,7 +116,7 @@ addRDMTask(TEST_URL, async function ({ ui }) {
|
||||
|
||||
// Wait until the viewport has been added and the device list has been loaded
|
||||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.deviceListState.LOADED);
|
||||
&& state.devices.listState == Types.loadableState.LOADED);
|
||||
|
||||
let deviceSelector = document.querySelector(".viewport-device-selector");
|
||||
let submitButton = document.querySelector("#device-submit-button");
|
||||
@ -150,7 +150,7 @@ addRDMTask(TEST_URL, async function ({ ui }) {
|
||||
|
||||
// Wait until the viewport has been added and the device list has been loaded
|
||||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.deviceListState.LOADED);
|
||||
&& state.devices.listState == Types.loadableState.LOADED);
|
||||
|
||||
let deviceSelector = document.querySelector(".viewport-device-selector");
|
||||
|
||||
|
@ -32,7 +32,7 @@ addRDMTask(TEST_URL, async function ({ ui }) {
|
||||
|
||||
// Wait until the viewport has been added and the device list has been loaded
|
||||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.deviceListState.LOADED);
|
||||
&& state.devices.listState == Types.loadableState.LOADED);
|
||||
|
||||
let deviceSelector = document.querySelector(".viewport-device-selector");
|
||||
let submitButton = document.querySelector("#device-submit-button");
|
||||
@ -95,7 +95,7 @@ addRDMTask(TEST_URL, async function ({ ui }) {
|
||||
|
||||
// Wait until the viewport has been added and the device list has been loaded
|
||||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.deviceListState.LOADED);
|
||||
&& state.devices.listState == Types.loadableState.LOADED);
|
||||
|
||||
let deviceSelector = document.querySelector(".viewport-device-selector");
|
||||
|
||||
|
@ -23,7 +23,7 @@ addRDMTask(TEST_URL, async function ({ ui }) {
|
||||
// Wait until the viewport has been added and the device list state indicates
|
||||
// an error
|
||||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.deviceListState.ERROR);
|
||||
&& state.devices.listState == Types.loadableState.ERROR);
|
||||
|
||||
// The device selector placeholder should be set accordingly
|
||||
let placeholder = select.options[select.selectedIndex].innerHTML;
|
||||
|
@ -15,7 +15,7 @@ addRDMTask(TEST_URL, async function ({ ui }) {
|
||||
|
||||
// Wait until the viewport has been added and the device list has been loaded
|
||||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.deviceListState.LOADED);
|
||||
&& state.devices.listState == Types.loadableState.LOADED);
|
||||
|
||||
openDeviceModal(ui);
|
||||
|
||||
|
@ -29,7 +29,7 @@ addRDMTask(TEST_URL, async function ({ ui }) {
|
||||
|
||||
// Wait until the viewport has been added and the device list has been loaded
|
||||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.deviceListState.LOADED);
|
||||
&& state.devices.listState == Types.loadableState.LOADED);
|
||||
|
||||
openDeviceModal(ui);
|
||||
|
||||
@ -116,7 +116,7 @@ addRDMTask(TEST_URL, async function ({ ui }) {
|
||||
|
||||
// Wait until the viewport has been added and the device list has been loaded
|
||||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.deviceListState.LOADED);
|
||||
&& state.devices.listState == Types.loadableState.LOADED);
|
||||
|
||||
openDeviceModal(ui);
|
||||
|
||||
|
@ -38,7 +38,7 @@ async function waitStartup(ui) {
|
||||
|
||||
// Wait until the viewport has been added and the device list has been loaded
|
||||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.deviceListState.LOADED);
|
||||
&& state.devices.listState == Types.loadableState.LOADED);
|
||||
}
|
||||
|
||||
async function testDefaults(ui) {
|
||||
@ -56,9 +56,7 @@ async function testDefaults(ui) {
|
||||
async function testChangingDevice(ui) {
|
||||
info("Test Changing Device");
|
||||
|
||||
let reloaded = waitForViewportLoad(ui);
|
||||
await selectDevice(ui, testDevice.name);
|
||||
await reloaded;
|
||||
await waitForViewportResizeTo(ui, testDevice.width, testDevice.height);
|
||||
let dppx = await waitForDevicePixelRatio(ui, testDevice.pixelRatio);
|
||||
is(dppx, testDevice.pixelRatio, "Content has expected devicePixelRatio");
|
||||
@ -73,10 +71,9 @@ async function testResetWhenResizingViewport(ui) {
|
||||
info("Test reset when resizing the viewport");
|
||||
|
||||
let deviceRemoved = once(ui, "device-association-removed");
|
||||
let reloaded = waitForViewportLoad(ui);
|
||||
await testViewportResize(ui, ".viewport-vertical-resize-handle",
|
||||
[-10, -10], [testDevice.width, testDevice.height - 10], [0, -10], ui);
|
||||
await Promise.all([ deviceRemoved, reloaded ]);
|
||||
await deviceRemoved;
|
||||
|
||||
let dppx = await waitForDevicePixelRatio(ui, DEFAULT_DPPX);
|
||||
is(dppx, DEFAULT_DPPX, "Content has expected devicePixelRatio");
|
||||
|
@ -23,6 +23,8 @@ const testDevice = {
|
||||
addDeviceForTest(testDevice);
|
||||
|
||||
addRDMTask(TEST_URL, async function ({ ui, manager }) {
|
||||
reloadOnTouchChange(true);
|
||||
|
||||
await waitStartup(ui);
|
||||
|
||||
await testDefaults(ui);
|
||||
@ -31,6 +33,8 @@ addRDMTask(TEST_URL, async function ({ ui, manager }) {
|
||||
await testEnableTouchSimulation(ui);
|
||||
await testResizingViewport(ui, false, true);
|
||||
await testDisableTouchSimulation(ui);
|
||||
|
||||
reloadOnTouchChange(false);
|
||||
});
|
||||
|
||||
async function waitStartup(ui) {
|
||||
@ -38,7 +42,7 @@ async function waitStartup(ui) {
|
||||
|
||||
// Wait until the viewport has been added and the device list has been loaded
|
||||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.deviceListState.LOADED);
|
||||
&& state.devices.listState == Types.loadableState.LOADED);
|
||||
}
|
||||
|
||||
async function testDefaults(ui) {
|
||||
|
@ -9,6 +9,8 @@ const TEST_URL = `${URL_ROOT}touch.html`;
|
||||
const PREF_DOM_META_VIEWPORT_ENABLED = "dom.meta-viewport.enabled";
|
||||
|
||||
addRDMTask(TEST_URL, async function ({ ui }) {
|
||||
reloadOnTouchChange(true);
|
||||
|
||||
await injectEventUtilsInContentTask(ui.getViewportBrowser());
|
||||
|
||||
await waitBootstrap(ui);
|
||||
@ -18,6 +20,8 @@ addRDMTask(TEST_URL, async function ({ ui }) {
|
||||
await testWithMetaViewportEnabled(ui);
|
||||
await testWithMetaViewportDisabled(ui);
|
||||
testTouchButton(ui);
|
||||
|
||||
reloadOnTouchChange(false);
|
||||
});
|
||||
|
||||
async function testWithNoTouch(ui) {
|
||||
|
@ -34,6 +34,7 @@ Services.scriptloader.loadSubScript(
|
||||
const E10S_MULTI_ENABLED = Services.prefs.getIntPref("dom.ipc.processCount") > 1;
|
||||
const TEST_URI_ROOT = "http://example.com/browser/devtools/client/responsive.html/test/browser/";
|
||||
const OPEN_DEVICE_MODAL_VALUE = "OPEN_DEVICE_MODAL";
|
||||
const RELOAD_CONDITION_PREF_PREFIX = "devtools.responsive.reloadConditions.";
|
||||
|
||||
const { _loadPreferredDevices } = require("devtools/client/responsive.html/actions/devices");
|
||||
const asyncStorage = require("devtools/shared/async-storage");
|
||||
@ -48,14 +49,14 @@ SimpleTest.waitForExplicitFinish();
|
||||
requestLongerTimeout(2);
|
||||
|
||||
flags.testing = true;
|
||||
Services.prefs.clearUserPref("devtools.responsive.html.displayedDeviceList");
|
||||
Services.prefs.setCharPref("devtools.devices.url",
|
||||
TEST_URI_ROOT + "devices.json");
|
||||
Services.prefs.setCharPref("devtools.devices.url", TEST_URI_ROOT + "devices.json");
|
||||
|
||||
registerCleanupFunction(async () => {
|
||||
flags.testing = false;
|
||||
Services.prefs.clearUserPref("devtools.devices.url");
|
||||
Services.prefs.clearUserPref("devtools.responsive.html.displayedDeviceList");
|
||||
Services.prefs.clearUserPref("devtools.responsive.reloadConditions.touchSimulation");
|
||||
Services.prefs.clearUserPref("devtools.responsive.reloadConditions.userAgent");
|
||||
await asyncStorage.removeItem("devtools.devices.url_cache");
|
||||
await removeLocalDevices();
|
||||
});
|
||||
@ -419,3 +420,13 @@ function addDeviceInModal(ui, device) {
|
||||
Simulate.click(adderSave);
|
||||
return saved;
|
||||
}
|
||||
|
||||
function reloadOnUAChange(enabled) {
|
||||
let pref = RELOAD_CONDITION_PREF_PREFIX + "userAgent";
|
||||
Services.prefs.setBoolPref(pref, enabled);
|
||||
}
|
||||
|
||||
function reloadOnTouchChange(enabled) {
|
||||
let pref = RELOAD_CONDITION_PREF_PREFIX + "touchSimulation";
|
||||
Services.prefs.setBoolPref(pref, enabled);
|
||||
}
|
||||
|
@ -10,6 +10,18 @@ const { createEnum } = require("devtools/client/shared/enum");
|
||||
// React PropTypes are used to describe the expected "shape" of various common
|
||||
// objects that get passed down as props to components.
|
||||
|
||||
/* ENUMS */
|
||||
|
||||
/**
|
||||
* An enum containing the possible states for loadable things.
|
||||
*/
|
||||
exports.loadableState = createEnum([
|
||||
"INITIALIZED",
|
||||
"LOADING",
|
||||
"LOADED",
|
||||
"ERROR",
|
||||
]);
|
||||
|
||||
/* GLOBAL */
|
||||
|
||||
/**
|
||||
@ -17,6 +29,22 @@ const { createEnum } = require("devtools/client/shared/enum");
|
||||
*/
|
||||
exports.location = PropTypes.string;
|
||||
|
||||
/**
|
||||
* Whether to reload the page automatically when certain actions occur.
|
||||
*/
|
||||
exports.reloadConditions = {
|
||||
|
||||
// Whether to reload when touch simulation is toggled
|
||||
touchSimulation: PropTypes.bool,
|
||||
|
||||
// Whether to reload when user agent is changed
|
||||
userAgent: PropTypes.bool,
|
||||
|
||||
// Loaded state of these conditions
|
||||
state: PropTypes.oneOf(Object.keys(exports.loadableState)),
|
||||
|
||||
};
|
||||
|
||||
/* DEVICE */
|
||||
|
||||
/**
|
||||
@ -50,16 +78,6 @@ const device = {
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* An enum containing the possible values for the device list state
|
||||
*/
|
||||
exports.deviceListState = createEnum([
|
||||
"INITIALIZED",
|
||||
"LOADING",
|
||||
"LOADED",
|
||||
"ERROR",
|
||||
]);
|
||||
|
||||
/**
|
||||
* A list of devices and their types that can be displayed in the viewport.
|
||||
*/
|
||||
@ -93,7 +111,7 @@ exports.devices = {
|
||||
modalOpenedFromViewport: PropTypes.number,
|
||||
|
||||
// Device list state, possible values are exported above in an enum
|
||||
listState: PropTypes.oneOf(Object.keys(exports.deviceListState)),
|
||||
listState: PropTypes.oneOf(Object.keys(exports.loadableState)),
|
||||
|
||||
};
|
||||
|
||||
|
@ -10,5 +10,6 @@ DevToolsModules(
|
||||
'key.js',
|
||||
'l10n.js',
|
||||
'message.js',
|
||||
'notification.js',
|
||||
'window.js',
|
||||
)
|
||||
|
53
devtools/client/responsive.html/utils/notification.js
Normal file
53
devtools/client/responsive.html/utils/notification.js
Normal file
@ -0,0 +1,53 @@
|
||||
/* 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";
|
||||
|
||||
loader.lazyRequireGetter(this, "TargetFactory", "devtools/client/framework/target", true);
|
||||
loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
|
||||
|
||||
/**
|
||||
* Displays a notification either at the browser or toolbox level, depending on whether
|
||||
* a toolbox is currently open for this tab.
|
||||
*
|
||||
* @param window
|
||||
* The main browser chrome window.
|
||||
* @param tab
|
||||
* The browser tab.
|
||||
* @param options
|
||||
* Other options associated with opening. Currently includes:
|
||||
* - `command`: Whether initiated via GCLI command bar or toolbox button
|
||||
* - `msg`: String to show in the notification
|
||||
* - `priority`: Priority level for the notification, which affects the icon and
|
||||
* overall appearance.
|
||||
*/
|
||||
function showNotification(window, tab, { command, msg, priority } = {}) {
|
||||
// Default to using the browser's per-tab notification box
|
||||
let nbox = window.gBrowser.getNotificationBox(tab.linkedBrowser);
|
||||
|
||||
// If opening was initiated by GCLI command bar or toolbox button, check for an open
|
||||
// toolbox for the tab. If one exists, use the toolbox's notification box so that the
|
||||
// message is placed closer to the action taken by the user.
|
||||
if (command) {
|
||||
let target = TargetFactory.forTab(tab);
|
||||
let toolbox = gDevTools.getToolbox(target);
|
||||
if (toolbox) {
|
||||
nbox = toolbox.notificationBox;
|
||||
}
|
||||
}
|
||||
|
||||
let value = "devtools-responsive";
|
||||
if (nbox.getNotificationWithValue(value)) {
|
||||
// Notification already displayed
|
||||
return;
|
||||
}
|
||||
|
||||
if (!priority) {
|
||||
priority = nbox.PRIORITY_INFO_MEDIUM;
|
||||
}
|
||||
|
||||
nbox.appendNotification(msg, value, null, priority, []);
|
||||
}
|
||||
|
||||
exports.showNotification = showNotification;
|
@ -994,11 +994,6 @@ a.learn-more-link.webconsole-learn-more-link {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
/* Prefix text that can be set by ConsoleAPI option */
|
||||
.webconsole-output-wrapper .console-message-prefix {
|
||||
color: var(--theme-comment);
|
||||
}
|
||||
|
||||
/* Network Messages */
|
||||
|
||||
.webconsole-output-wrapper .message.network .method {
|
||||
|
@ -51,7 +51,6 @@ function ConsoleApiCall(props) {
|
||||
timeStamp,
|
||||
parameters,
|
||||
messageText,
|
||||
prefix,
|
||||
userProvidedStyles,
|
||||
} = message;
|
||||
|
||||
@ -75,11 +74,6 @@ function ConsoleApiCall(props) {
|
||||
messageBody = dom.span({className: "cm-variable"}, "console.table()");
|
||||
} else if (parameters) {
|
||||
messageBody = formatReps(messageBodyConfig);
|
||||
if (prefix) {
|
||||
messageBody.unshift(dom.span({
|
||||
className: "console-message-prefix"
|
||||
}, `${prefix}: `));
|
||||
}
|
||||
} else {
|
||||
messageBody = messageText;
|
||||
}
|
||||
|
@ -703,8 +703,6 @@ function passSearchFilters(message, filters) {
|
||||
|| isTextInMessageText(text, message.messageText)
|
||||
// Look for a match in notes.
|
||||
|| isTextInNotes(text, message.notes)
|
||||
// Look for a match in prefix.
|
||||
|| isTextInPrefix(text, message.prefix)
|
||||
);
|
||||
}
|
||||
|
||||
@ -806,17 +804,6 @@ function isTextInNotes(text, notes) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given text is included in prefix.
|
||||
*/
|
||||
function isTextInPrefix(text, prefix) {
|
||||
if (!prefix) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return `${prefix}: `.toLocaleLowerCase().includes(text.toLocaleLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a flat array of all the grips and their properties.
|
||||
*
|
||||
|
@ -19,7 +19,6 @@ const {
|
||||
MESSAGE_CLOSE,
|
||||
} = require("devtools/client/webconsole/new-console-output/constants");
|
||||
const { INDENT_WIDTH } = require("devtools/client/webconsole/new-console-output/components/MessageIndent");
|
||||
const {prepareMessage} = require("devtools/client/webconsole/new-console-output/utils/messages");
|
||||
|
||||
// Test fakes.
|
||||
const { stubPreparedMessages } = require("devtools/client/webconsole/new-console-output/test/fixtures/stubs/index");
|
||||
@ -88,37 +87,6 @@ describe("ConsoleAPICall component:", () => {
|
||||
expect(thirdElementStyle.color).toBe("blue");
|
||||
});
|
||||
|
||||
it("renders prefixed messages", () => {
|
||||
const stub = {
|
||||
"level": "debug",
|
||||
"filename": "resource:///modules/CustomizableUI.jsm",
|
||||
"lineNumber": 181,
|
||||
"functionName": "initialize",
|
||||
"timeStamp": 1519311532912,
|
||||
"arguments": [
|
||||
"Initializing"
|
||||
],
|
||||
"prefix": "MyNicePrefix",
|
||||
"workerType": "none",
|
||||
"styles": [],
|
||||
"category": "webdev",
|
||||
"_type": "ConsoleAPI"
|
||||
};
|
||||
const wrapper = render(ConsoleApiCall({
|
||||
message: prepareMessage(stub, {getNextId: () => "p"}),
|
||||
serviceContainer
|
||||
}));
|
||||
const prefix = wrapper.find(".console-message-prefix");
|
||||
expect(prefix.text()).toBe("MyNicePrefix: ");
|
||||
|
||||
expect(wrapper.find(".message-body").text()).toBe("MyNicePrefix: Initializing");
|
||||
|
||||
// There should be the location
|
||||
const locationLink = wrapper.find(`.message-location`);
|
||||
expect(locationLink.length).toBe(1);
|
||||
expect(locationLink.text()).toBe("CustomizableUI.jsm:181");
|
||||
});
|
||||
|
||||
it("renders repeat node", () => {
|
||||
const message = stubPreparedMessages.get("console.log('foobar', 'test')");
|
||||
const wrapper = render(ConsoleApiCall({
|
||||
|
@ -40,7 +40,7 @@ describe("Message - location element", () => {
|
||||
expect(onViewSource.notCalled).toBe(true);
|
||||
});
|
||||
|
||||
it("Calls onViewSource when clicked and onViewSourceInDebugger undefined", () => {
|
||||
it.only("Calls onViewSource when clicked and onViewSourceInDebugger undefined", () => {
|
||||
const onViewSource = sinon.spy();
|
||||
|
||||
const message = stubPreparedMessages.get("console.log('foobar', 'test')");
|
||||
|
@ -186,37 +186,6 @@ describe("Filtering", () => {
|
||||
expect(messages.length - numUnfilterableMessages).toEqual(1);
|
||||
});
|
||||
|
||||
it("matches prefixed log message", () => {
|
||||
const stub = {
|
||||
"level": "debug",
|
||||
"filename": "resource:///modules/CustomizableUI.jsm",
|
||||
"lineNumber": 181,
|
||||
"functionName": "initialize",
|
||||
"timeStamp": 1519311532912,
|
||||
"arguments": [
|
||||
"Initializing"
|
||||
],
|
||||
"prefix": "MyNicePrefix",
|
||||
"workerType": "none",
|
||||
"styles": [],
|
||||
"category": "webdev",
|
||||
"_type": "ConsoleAPI"
|
||||
};
|
||||
store.dispatch(messagesAdd([stub]));
|
||||
|
||||
store.dispatch(actions.filterTextSet("MyNice"));
|
||||
let messages = getVisibleMessages(store.getState());
|
||||
expect(messages.length - numUnfilterableMessages).toEqual(1);
|
||||
|
||||
store.dispatch(actions.filterTextSet("MyNicePrefix"));
|
||||
messages = getVisibleMessages(store.getState());
|
||||
expect(messages.length - numUnfilterableMessages).toEqual(1);
|
||||
|
||||
store.dispatch(actions.filterTextSet("MyNicePrefix:"));
|
||||
messages = getVisibleMessages(store.getState());
|
||||
expect(messages.length - numUnfilterableMessages).toEqual(1);
|
||||
});
|
||||
|
||||
it("restores all messages once text is cleared", () => {
|
||||
store.dispatch(actions.filterTextSet("danger"));
|
||||
store.dispatch(actions.filterTextSet(""));
|
||||
|
@ -43,7 +43,6 @@ exports.ConsoleMessage = function (props) {
|
||||
userProvidedStyles: null,
|
||||
notes: null,
|
||||
indent: 0,
|
||||
prefix: "",
|
||||
}, props);
|
||||
};
|
||||
|
||||
|
@ -20,6 +20,7 @@ const {
|
||||
} = require("../types");
|
||||
|
||||
function prepareMessage(packet, idGenerator) {
|
||||
// This packet is already in the expected packet structure. Simply return.
|
||||
if (!packet.source) {
|
||||
packet = transformPacket(packet);
|
||||
}
|
||||
@ -166,7 +167,6 @@ function transformConsoleAPICallPacket(packet) {
|
||||
frame,
|
||||
timeStamp: message.timeStamp,
|
||||
userProvidedStyles: message.styles,
|
||||
prefix: message.prefix,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1193,8 +1193,16 @@ GeckoChildProcessHost::LaunchAndroidService(const char* type,
|
||||
int32_t ipcFd = it->first;
|
||||
it++;
|
||||
// If the Crash Reporter is disabled, there will not be a second file descriptor.
|
||||
int32_t crashFd = (it != fds_to_remap.end()) ? it->first : -1;
|
||||
int32_t crashAnnotationFd = (it != fds_to_remap.end()) ? it->first : -1;
|
||||
int32_t crashFd = -1;
|
||||
int32_t crashAnnotationFd = -1;
|
||||
if (it != fds_to_remap.end() && !CrashReporter::IsDummy()) {
|
||||
crashFd = it->first;
|
||||
it++;
|
||||
}
|
||||
if (it != fds_to_remap.end()) {
|
||||
crashAnnotationFd = it->first;
|
||||
it++;
|
||||
}
|
||||
int32_t handle = java::GeckoProcessManager::Start(type, jargs, crashFd, ipcFd, crashAnnotationFd);
|
||||
|
||||
if (process_handle) {
|
||||
|
@ -22,10 +22,12 @@ ServoStyleContext::ResolveSameStructsAs(const ServoStyleContext* aOther)
|
||||
uint64_t otherBits = aOther->mBits & NS_STYLE_INHERIT_MASK;
|
||||
uint64_t newBits = otherBits & ~ourBits & NS_STYLE_INHERIT_MASK;
|
||||
|
||||
#define STYLE_STRUCT(name_, checkdata_cb) \
|
||||
if (nsStyle##name_::kHasFinishStyle && newBits & NS_STYLE_INHERIT_BIT(name_)) { \
|
||||
const nsStyle##name_* data = ComputedData()->GetStyle##name_(); \
|
||||
const_cast<nsStyle##name_*>(data)->FinishStyle(mPresContext); \
|
||||
#define STYLE_STRUCT(name_, checkdata_cb) \
|
||||
if (nsStyle##name_::kHasFinishStyle && \
|
||||
(newBits & NS_STYLE_INHERIT_BIT(name_))) { \
|
||||
const nsStyle##name_* data = ComputedData()->GetStyle##name_(); \
|
||||
const nsStyle##name_* oldData = aOther->ComputedData()->GetStyle##name_(); \
|
||||
const_cast<nsStyle##name_*>(data)->FinishStyle(mPresContext, oldData); \
|
||||
}
|
||||
#include "nsStyleStructList.h"
|
||||
#undef STYLE_STRUCT
|
||||
|
@ -105,28 +105,28 @@ const nsStyle##name_ * nsStyleContext::PeekStyle##name_() { \
|
||||
#endif
|
||||
|
||||
// Helper functions for GetStyle* and PeekStyle*
|
||||
#define STYLE_STRUCT_INHERITED(name_, checkdata_cb_) \
|
||||
template<bool aComputeData> \
|
||||
const nsStyle##name_ * nsStyleContext::DoGetStyle##name_() { \
|
||||
if (IsGecko()) { \
|
||||
DO_GET_STYLE_INHERITED_GECKO(name_, checkdata_cb_) \
|
||||
} \
|
||||
const bool needToCompute = !(mBits & NS_STYLE_INHERIT_BIT(name_));\
|
||||
if (!aComputeData && needToCompute) { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
const nsStyle##name_* data = ComputedData()->GetStyle##name_(); \
|
||||
\
|
||||
/* perform any remaining main thread work on the struct */ \
|
||||
if (needToCompute) { \
|
||||
MOZ_ASSERT(NS_IsMainThread()); \
|
||||
MOZ_ASSERT(!mozilla::ServoStyleSet::IsInServoTraversal()); \
|
||||
const_cast<nsStyle##name_*>(data)->FinishStyle(PresContext()); \
|
||||
/* the ServoStyleContext owns the struct */ \
|
||||
AddStyleBit(NS_STYLE_INHERIT_BIT(name_)); \
|
||||
} \
|
||||
return data; \
|
||||
#define STYLE_STRUCT_INHERITED(name_, checkdata_cb_) \
|
||||
template<bool aComputeData> \
|
||||
const nsStyle##name_ * nsStyleContext::DoGetStyle##name_() { \
|
||||
if (IsGecko()) { \
|
||||
DO_GET_STYLE_INHERITED_GECKO(name_, checkdata_cb_) \
|
||||
} \
|
||||
const bool needToCompute = !(mBits & NS_STYLE_INHERIT_BIT(name_)); \
|
||||
if (!aComputeData && needToCompute) { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
const nsStyle##name_* data = ComputedData()->GetStyle##name_(); \
|
||||
\
|
||||
/* perform any remaining main thread work on the struct */ \
|
||||
if (needToCompute) { \
|
||||
MOZ_ASSERT(NS_IsMainThread()); \
|
||||
MOZ_ASSERT(!mozilla::ServoStyleSet::IsInServoTraversal()); \
|
||||
const_cast<nsStyle##name_*>(data)->FinishStyle(PresContext(), nullptr); \
|
||||
/* the ServoStyleContext owns the struct */ \
|
||||
AddStyleBit(NS_STYLE_INHERIT_BIT(name_)); \
|
||||
} \
|
||||
return data; \
|
||||
}
|
||||
|
||||
#ifdef MOZ_OLD_STYLE
|
||||
@ -162,7 +162,7 @@ const nsStyle##name_ * nsStyleContext::DoGetStyle##name_() { \
|
||||
const nsStyle##name_* data = ComputedData()->GetStyle##name_(); \
|
||||
/* perform any remaining main thread work on the struct */ \
|
||||
if (needToCompute) { \
|
||||
const_cast<nsStyle##name_*>(data)->FinishStyle(PresContext()); \
|
||||
const_cast<nsStyle##name_*>(data)->FinishStyle(PresContext(), nullptr); \
|
||||
/* the ServoStyleContext owns the struct */ \
|
||||
AddStyleBit(NS_STYLE_INHERIT_BIT(name_)); \
|
||||
} \
|
||||
|
@ -393,12 +393,13 @@ nsStyleBorder::~nsStyleBorder()
|
||||
}
|
||||
|
||||
void
|
||||
nsStyleBorder::FinishStyle(nsPresContext* aPresContext)
|
||||
nsStyleBorder::FinishStyle(nsPresContext* aPresContext, const nsStyleBorder* aOldStyle)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aPresContext->StyleSet()->IsServo());
|
||||
|
||||
mBorderImageSource.ResolveImage(aPresContext);
|
||||
mBorderImageSource.ResolveImage(
|
||||
aPresContext, aOldStyle ? &aOldStyle->mBorderImageSource : nullptr);
|
||||
}
|
||||
|
||||
nsMargin
|
||||
@ -613,13 +614,14 @@ nsStyleList::nsStyleList(const nsStyleList& aSource)
|
||||
}
|
||||
|
||||
void
|
||||
nsStyleList::FinishStyle(nsPresContext* aPresContext)
|
||||
nsStyleList::FinishStyle(nsPresContext* aPresContext, const nsStyleList* aOldStyle)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aPresContext->StyleSet()->IsServo());
|
||||
|
||||
if (mListStyleImage && !mListStyleImage->IsResolved()) {
|
||||
mListStyleImage->Resolve(aPresContext);
|
||||
mListStyleImage->Resolve(
|
||||
aPresContext, aOldStyle ? aOldStyle->mListStyleImage.get() : nullptr);
|
||||
}
|
||||
mCounterStyle.Resolve(aPresContext->CounterStyleManager());
|
||||
}
|
||||
@ -1300,7 +1302,7 @@ nsStyleSVGReset::Destroy(nsPresContext* aContext)
|
||||
}
|
||||
|
||||
void
|
||||
nsStyleSVGReset::FinishStyle(nsPresContext* aPresContext)
|
||||
nsStyleSVGReset::FinishStyle(nsPresContext* aPresContext, const nsStyleSVGReset* aOldStyle)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aPresContext->StyleSet()->IsServo());
|
||||
@ -1313,7 +1315,12 @@ nsStyleSVGReset::FinishStyle(nsPresContext* aPresContext)
|
||||
// resolve this style image, since we do not depend on it to get the
|
||||
// SVG mask resource.
|
||||
if (!image.GetURLValue()->HasRef()) {
|
||||
image.ResolveImage(aPresContext);
|
||||
const nsStyleImage* oldImage =
|
||||
(aOldStyle && aOldStyle->mMask.mLayers.Length() > i)
|
||||
? &aOldStyle->mMask.mLayers[i].mImage
|
||||
: nullptr;
|
||||
|
||||
image.ResolveImage(aPresContext, oldImage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2191,7 +2198,9 @@ nsStyleImageRequest::~nsStyleImageRequest()
|
||||
}
|
||||
|
||||
bool
|
||||
nsStyleImageRequest::Resolve(nsPresContext* aPresContext)
|
||||
nsStyleImageRequest::Resolve(
|
||||
nsPresContext* aPresContext,
|
||||
const nsStyleImageRequest* aOldImageRequest)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!IsResolved(), "already resolved");
|
||||
@ -2211,14 +2220,29 @@ nsStyleImageRequest::Resolve(nsPresContext* aPresContext)
|
||||
}
|
||||
}
|
||||
|
||||
mDocGroup = doc->GetDocGroup();
|
||||
// TODO(emilio, bug 1440442): This is a hackaround to avoid flickering due the
|
||||
// lack of non-http image caching in imagelib (bug 1406134), which causes
|
||||
// stuff like bug 1439285. Cleanest fix if that doesn't get fixed is bug
|
||||
// 1440305, but that seems too risky, and a lot of work to do before 60.
|
||||
//
|
||||
// Once that's fixed, the "old style" argument to FinishStyle can go away.
|
||||
if (aPresContext->IsChrome() && aOldImageRequest &&
|
||||
aOldImageRequest->IsResolved() && DefinitelyEquals(*aOldImageRequest)) {
|
||||
MOZ_ASSERT(aOldImageRequest->mDocGroup == doc->GetDocGroup());
|
||||
MOZ_ASSERT(mModeFlags == aOldImageRequest->mModeFlags);
|
||||
|
||||
mImageValue->Initialize(doc);
|
||||
mDocGroup = aOldImageRequest->mDocGroup;
|
||||
mImageValue = aOldImageRequest->mImageValue;
|
||||
mRequestProxy = aOldImageRequest->mRequestProxy;
|
||||
} else {
|
||||
mDocGroup = doc->GetDocGroup();
|
||||
mImageValue->Initialize(doc);
|
||||
|
||||
nsCSSValue value;
|
||||
value.SetImageValue(mImageValue);
|
||||
mRequestProxy = value.GetPossiblyStaticImageValue(aPresContext->Document(),
|
||||
aPresContext);
|
||||
nsCSSValue value;
|
||||
value.SetImageValue(mImageValue);
|
||||
mRequestProxy = value.GetPossiblyStaticImageValue(aPresContext->Document(),
|
||||
aPresContext);
|
||||
}
|
||||
|
||||
if (!mRequestProxy) {
|
||||
// The URL resolution or image load failed.
|
||||
@ -2226,7 +2250,7 @@ nsStyleImageRequest::Resolve(nsPresContext* aPresContext)
|
||||
}
|
||||
|
||||
if (mModeFlags & Mode::Track) {
|
||||
mImageTracker = aPresContext->Document()->ImageTracker();
|
||||
mImageTracker = doc->ImageTracker();
|
||||
}
|
||||
|
||||
MaybeTrackAndLock();
|
||||
@ -3345,12 +3369,13 @@ nsStyleBackground::Destroy(nsPresContext* aContext)
|
||||
}
|
||||
|
||||
void
|
||||
nsStyleBackground::FinishStyle(nsPresContext* aPresContext)
|
||||
nsStyleBackground::FinishStyle(
|
||||
nsPresContext* aPresContext, const nsStyleBackground* aOldStyle)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aPresContext->StyleSet()->IsServo());
|
||||
|
||||
mImage.ResolveImages(aPresContext);
|
||||
mImage.ResolveImages(aPresContext, aOldStyle ? &aOldStyle->mImage : nullptr);
|
||||
}
|
||||
|
||||
nsChangeHint
|
||||
@ -3724,7 +3749,8 @@ nsStyleDisplay::~nsStyleDisplay()
|
||||
}
|
||||
|
||||
void
|
||||
nsStyleDisplay::FinishStyle(nsPresContext* aPresContext)
|
||||
nsStyleDisplay::FinishStyle(
|
||||
nsPresContext* aPresContext, const nsStyleDisplay* aOldStyle)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aPresContext->StyleSet()->IsServo());
|
||||
@ -3739,7 +3765,11 @@ nsStyleDisplay::FinishStyle(nsPresContext* aPresContext)
|
||||
shapeImage->GetImageRequest()->GetImageValue()->SetCORSMode(
|
||||
CORSMode::CORS_ANONYMOUS);
|
||||
}
|
||||
shapeImage->ResolveImage(aPresContext);
|
||||
const nsStyleImage* oldShapeImage =
|
||||
(aOldStyle &&
|
||||
aOldStyle->mShapeOutside.GetType() == StyleShapeSourceType::Image)
|
||||
? &*aOldStyle->mShapeOutside.GetShapeImage() : nullptr;
|
||||
shapeImage->ResolveImage(aPresContext, oldShapeImage);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4016,6 +4046,10 @@ nsStyleDisplay::CalcDifference(const nsStyleDisplay& aNewData) const
|
||||
void
|
||||
nsStyleDisplay::GenerateCombinedTransform()
|
||||
{
|
||||
// FIXME(emilio): This should probably be called from somewhere like what we
|
||||
// do for image layers, instead of FinishStyle.
|
||||
//
|
||||
// This does and undoes the work a ton of times in Stylo.
|
||||
mCombinedTransform = nullptr;
|
||||
|
||||
// Follow the order defined in the spec to append transform functions.
|
||||
@ -4208,12 +4242,16 @@ nsStyleContentData::operator==(const nsStyleContentData& aOther) const
|
||||
}
|
||||
|
||||
void
|
||||
nsStyleContentData::Resolve(nsPresContext* aPresContext)
|
||||
nsStyleContentData::Resolve(
|
||||
nsPresContext* aPresContext, const nsStyleContentData* aOldStyle)
|
||||
{
|
||||
switch (mType) {
|
||||
case eStyleContentType_Image:
|
||||
if (!mContent.mImage->IsResolved()) {
|
||||
mContent.mImage->Resolve(aPresContext);
|
||||
const nsStyleImageRequest* oldRequest =
|
||||
(aOldStyle && aOldStyle->mType == eStyleContentType_Image)
|
||||
? aOldStyle->mContent.mImage : nullptr;
|
||||
mContent.mImage->Resolve(aPresContext, oldRequest);
|
||||
}
|
||||
break;
|
||||
case eStyleContentType_Counter:
|
||||
@ -4250,10 +4288,14 @@ nsStyleContent::Destroy(nsPresContext* aContext)
|
||||
}
|
||||
|
||||
void
|
||||
nsStyleContent::FinishStyle(nsPresContext* aPresContext)
|
||||
nsStyleContent::FinishStyle(nsPresContext* aPresContext, const nsStyleContent* aOldStyle)
|
||||
{
|
||||
for (nsStyleContentData& data : mContents) {
|
||||
data.Resolve(aPresContext);
|
||||
for (size_t i = 0; i < mContents.Length(); ++i) {
|
||||
const nsStyleContentData* oldData =
|
||||
(aOldStyle && aOldStyle->mContents.Length() > i)
|
||||
? &aOldStyle->mContents[i]
|
||||
: nullptr;
|
||||
mContents[i].Resolve(aPresContext, oldData);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4631,14 +4673,22 @@ nsStyleUserInterface::~nsStyleUserInterface()
|
||||
}
|
||||
|
||||
void
|
||||
nsStyleUserInterface::FinishStyle(nsPresContext* aPresContext)
|
||||
nsStyleUserInterface::FinishStyle(
|
||||
nsPresContext* aPresContext, const nsStyleUserInterface* aOldStyle)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aPresContext->StyleSet()->IsServo());
|
||||
|
||||
for (nsCursorImage& cursor : mCursorImages) {
|
||||
for (size_t i = 0; i < mCursorImages.Length(); ++i) {
|
||||
nsCursorImage& cursor = mCursorImages[i];
|
||||
|
||||
if (cursor.mImage && !cursor.mImage->IsResolved()) {
|
||||
cursor.mImage->Resolve(aPresContext);
|
||||
const nsCursorImage* oldCursor =
|
||||
(aOldStyle && aOldStyle->mCursorImages.Length() > i)
|
||||
? &aOldStyle->mCursorImages[i]
|
||||
: nullptr;
|
||||
cursor.mImage->Resolve(
|
||||
aPresContext, oldCursor ? oldCursor->mImage.get() : nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleFont
|
||||
~nsStyleFont() {
|
||||
MOZ_COUNT_DTOR(nsStyleFont);
|
||||
}
|
||||
void FinishStyle(nsPresContext* aPresContext) {}
|
||||
void FinishStyle(nsPresContext*, const nsStyleFont*) {}
|
||||
const static bool kHasFinishStyle = false;
|
||||
|
||||
nsChangeHint CalcDifference(const nsStyleFont& aNewData) const;
|
||||
@ -358,7 +358,7 @@ public:
|
||||
Mode aModeFlags,
|
||||
mozilla::css::ImageValue* aImageValue);
|
||||
|
||||
bool Resolve(nsPresContext* aPresContext);
|
||||
bool Resolve(nsPresContext*, const nsStyleImageRequest* aOldImageRequest);
|
||||
bool IsResolved() const { return mResolved; }
|
||||
|
||||
imgRequestProxy* get() {
|
||||
@ -455,10 +455,13 @@ struct nsStyleImage
|
||||
void SetCropRect(mozilla::UniquePtr<nsStyleSides> aCropRect);
|
||||
void SetURLValue(already_AddRefed<URLValue> aData);
|
||||
|
||||
void ResolveImage(nsPresContext* aContext) {
|
||||
void ResolveImage(nsPresContext* aContext, const nsStyleImage* aOldImage) {
|
||||
MOZ_ASSERT(mType != eStyleImageType_Image || mImage);
|
||||
if (mType == eStyleImageType_Image && !mImage->IsResolved()) {
|
||||
mImage->Resolve(aContext);
|
||||
const nsStyleImageRequest* oldRequest =
|
||||
(aOldImage && aOldImage->GetType() == eStyleImageType_Image)
|
||||
? aOldImage->GetImageRequest() : nullptr;
|
||||
mImage->Resolve(aContext, oldRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@ -594,7 +597,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleColor
|
||||
~nsStyleColor() {
|
||||
MOZ_COUNT_DTOR(nsStyleColor);
|
||||
}
|
||||
void FinishStyle(nsPresContext* aPresContext) {}
|
||||
void FinishStyle(nsPresContext*, const nsStyleColor*) {}
|
||||
const static bool kHasFinishStyle = false;
|
||||
|
||||
nscolor CalcComplexColor(const mozilla::StyleComplexColor& aColor) const {
|
||||
@ -785,10 +788,8 @@ struct nsStyleImageLayers {
|
||||
// Initialize mRepeat and mOrigin by specified layer type
|
||||
void Initialize(LayerType aType);
|
||||
|
||||
void ResolveImage(nsPresContext* aContext) {
|
||||
if (mImage.GetType() == eStyleImageType_Image) {
|
||||
mImage.ResolveImage(aContext);
|
||||
}
|
||||
void ResolveImage(nsPresContext* aContext, const Layer* aOldLayer) {
|
||||
mImage.ResolveImage(aContext, aOldLayer ? &aOldLayer->mImage : nullptr);
|
||||
}
|
||||
|
||||
// True if the rendering of this layer might change when the size
|
||||
@ -837,9 +838,13 @@ struct nsStyleImageLayers {
|
||||
|
||||
const Layer& BottomLayer() const { return mLayers[mImageCount - 1]; }
|
||||
|
||||
void ResolveImages(nsPresContext* aContext) {
|
||||
void ResolveImages(nsPresContext* aContext, const nsStyleImageLayers* aOldLayers) {
|
||||
for (uint32_t i = 0; i < mImageCount; ++i) {
|
||||
mLayers[i].ResolveImage(aContext);
|
||||
const Layer* oldLayer =
|
||||
(aOldLayers && aOldLayers->mLayers.Length() > i)
|
||||
? &aOldLayers->mLayers[i]
|
||||
: nullptr;
|
||||
mLayers[i].ResolveImage(aContext, oldLayer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -873,7 +878,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleBackground {
|
||||
// Resolves and tracks the images in mImage. Only called with a Servo-backed
|
||||
// style system, where those images must be resolved later than the OMT
|
||||
// nsStyleBackground constructor call.
|
||||
void FinishStyle(nsPresContext* aPresContext);
|
||||
void FinishStyle(nsPresContext*, const nsStyleBackground*);
|
||||
const static bool kHasFinishStyle = true;
|
||||
|
||||
void* operator new(size_t sz, nsStyleBackground* aSelf) { return aSelf; }
|
||||
@ -916,7 +921,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleMargin
|
||||
~nsStyleMargin() {
|
||||
MOZ_COUNT_DTOR(nsStyleMargin);
|
||||
}
|
||||
void FinishStyle(nsPresContext* aPresContext) {}
|
||||
void FinishStyle(nsPresContext*, const nsStyleMargin*) {}
|
||||
const static bool kHasFinishStyle = false;
|
||||
|
||||
void* operator new(size_t sz, nsStyleMargin* aSelf) { return aSelf; }
|
||||
@ -955,7 +960,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStylePadding
|
||||
~nsStylePadding() {
|
||||
MOZ_COUNT_DTOR(nsStylePadding);
|
||||
}
|
||||
void FinishStyle(nsPresContext* aPresContext) {}
|
||||
void FinishStyle(nsPresContext*, const nsStylePadding*) {}
|
||||
const static bool kHasFinishStyle = false;
|
||||
|
||||
void* operator new(size_t sz, nsStylePadding* aSelf) { return aSelf; }
|
||||
@ -1122,7 +1127,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleBorder
|
||||
// Resolves and tracks mBorderImageSource. Only called with a Servo-backed
|
||||
// style system, where those images must be resolved later than the OMT
|
||||
// nsStyleBorder constructor call.
|
||||
void FinishStyle(nsPresContext* aPresContext);
|
||||
void FinishStyle(nsPresContext*, const nsStyleBorder*);
|
||||
const static bool kHasFinishStyle = true;
|
||||
|
||||
void* operator new(size_t sz, nsStyleBorder* aSelf) { return aSelf; }
|
||||
@ -1196,13 +1201,6 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleBorder
|
||||
return mBorderImageSource.IsLoaded();
|
||||
}
|
||||
|
||||
void ResolveImage(nsPresContext* aContext)
|
||||
{
|
||||
if (mBorderImageSource.GetType() == eStyleImageType_Image) {
|
||||
mBorderImageSource.ResolveImage(aContext);
|
||||
}
|
||||
}
|
||||
|
||||
nsMargin GetImageOutset() const;
|
||||
|
||||
imgIRequest* GetBorderImageRequest() const
|
||||
@ -1307,7 +1305,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleOutline
|
||||
~nsStyleOutline() {
|
||||
MOZ_COUNT_DTOR(nsStyleOutline);
|
||||
}
|
||||
void FinishStyle(nsPresContext* aPresContext) {}
|
||||
void FinishStyle(nsPresContext*, const nsStyleOutline*) {}
|
||||
const static bool kHasFinishStyle = false;
|
||||
|
||||
void* operator new(size_t sz, nsStyleOutline* aSelf) { return aSelf; }
|
||||
@ -1379,7 +1377,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleList
|
||||
nsStyleList(const nsStyleList& aStyleList);
|
||||
~nsStyleList();
|
||||
|
||||
void FinishStyle(nsPresContext* aPresContext);
|
||||
void FinishStyle(nsPresContext*, const nsStyleList*);
|
||||
const static bool kHasFinishStyle = true;
|
||||
|
||||
void* operator new(size_t sz, nsStyleList* aSelf) { return aSelf; }
|
||||
@ -1581,7 +1579,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStylePosition
|
||||
explicit nsStylePosition(const nsPresContext* aContext);
|
||||
nsStylePosition(const nsStylePosition& aOther);
|
||||
~nsStylePosition();
|
||||
void FinishStyle(nsPresContext* aPresContext) {}
|
||||
void FinishStyle(nsPresContext*, const nsStylePosition*) {}
|
||||
const static bool kHasFinishStyle = false;
|
||||
|
||||
void* operator new(size_t sz, nsStylePosition* aSelf) { return aSelf; }
|
||||
@ -1806,7 +1804,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleTextReset
|
||||
explicit nsStyleTextReset(const nsPresContext* aContext);
|
||||
nsStyleTextReset(const nsStyleTextReset& aOther);
|
||||
~nsStyleTextReset();
|
||||
void FinishStyle(nsPresContext* aPresContext) {}
|
||||
void FinishStyle(nsPresContext*, const nsStyleTextReset*) {}
|
||||
const static bool kHasFinishStyle = false;
|
||||
|
||||
void* operator new(size_t sz, nsStyleTextReset* aSelf) { return aSelf; }
|
||||
@ -1844,7 +1842,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText
|
||||
explicit nsStyleText(const nsPresContext* aContext);
|
||||
nsStyleText(const nsStyleText& aOther);
|
||||
~nsStyleText();
|
||||
void FinishStyle(nsPresContext* aPresContext) {}
|
||||
void FinishStyle(nsPresContext*, const nsStyleText*) {}
|
||||
const static bool kHasFinishStyle = false;
|
||||
|
||||
void* operator new(size_t sz, nsStyleText* aSelf) { return aSelf; }
|
||||
@ -2064,7 +2062,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleVisibility
|
||||
~nsStyleVisibility() {
|
||||
MOZ_COUNT_DTOR(nsStyleVisibility);
|
||||
}
|
||||
void FinishStyle(nsPresContext* aPresContext) {}
|
||||
void FinishStyle(nsPresContext*, const nsStyleVisibility*) {}
|
||||
const static bool kHasFinishStyle = false;
|
||||
|
||||
void* operator new(size_t sz, nsStyleVisibility* aSelf) { return aSelf; }
|
||||
@ -2485,7 +2483,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay
|
||||
nsStyleDisplay(const nsStyleDisplay& aOther);
|
||||
~nsStyleDisplay();
|
||||
|
||||
void FinishStyle(nsPresContext* aPresContext);
|
||||
void FinishStyle(nsPresContext*, const nsStyleDisplay*);
|
||||
const static bool kHasFinishStyle = true;
|
||||
|
||||
void* operator new(size_t sz, nsStyleDisplay* aSelf) { return aSelf; }
|
||||
@ -2874,7 +2872,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleTable
|
||||
explicit nsStyleTable(const nsPresContext* aContext);
|
||||
nsStyleTable(const nsStyleTable& aOther);
|
||||
~nsStyleTable();
|
||||
void FinishStyle(nsPresContext* aPresContext) {}
|
||||
void FinishStyle(nsPresContext*, const nsStyleTable*) {}
|
||||
const static bool kHasFinishStyle = false;
|
||||
|
||||
void* operator new(size_t sz, nsStyleTable* aSelf) { return aSelf; }
|
||||
@ -2899,7 +2897,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleTableBorder
|
||||
explicit nsStyleTableBorder(const nsPresContext* aContext);
|
||||
nsStyleTableBorder(const nsStyleTableBorder& aOther);
|
||||
~nsStyleTableBorder();
|
||||
void FinishStyle(nsPresContext* aPresContext) {}
|
||||
void FinishStyle(nsPresContext*, const nsStyleTableBorder*) {}
|
||||
const static bool kHasFinishStyle = false;
|
||||
|
||||
void* operator new(size_t sz, nsStyleTableBorder* aSelf) { return aSelf; }
|
||||
@ -3045,7 +3043,7 @@ public:
|
||||
MOZ_ASSERT(mContent.mImage);
|
||||
}
|
||||
|
||||
void Resolve(nsPresContext* aPresContext);
|
||||
void Resolve(nsPresContext*, const nsStyleContentData*);
|
||||
|
||||
private:
|
||||
nsStyleContentType mType;
|
||||
@ -3075,7 +3073,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleContent
|
||||
explicit nsStyleContent(const nsPresContext* aContext);
|
||||
nsStyleContent(const nsStyleContent& aContent);
|
||||
~nsStyleContent();
|
||||
void FinishStyle(nsPresContext* aPresContext);
|
||||
void FinishStyle(nsPresContext*, const nsStyleContent*);
|
||||
const static bool kHasFinishStyle = true;
|
||||
|
||||
void* operator new(size_t sz, nsStyleContent* aSelf) { return aSelf; }
|
||||
@ -3146,7 +3144,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUIReset
|
||||
explicit nsStyleUIReset(const nsPresContext* aContext);
|
||||
nsStyleUIReset(const nsStyleUIReset& aOther);
|
||||
~nsStyleUIReset();
|
||||
void FinishStyle(nsPresContext* aPresContext) {}
|
||||
void FinishStyle(nsPresContext*, const nsStyleUIReset*) {}
|
||||
const static bool kHasFinishStyle = false;
|
||||
|
||||
void* operator new(size_t sz, nsStyleUIReset* aSelf) { return aSelf; }
|
||||
@ -3200,7 +3198,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUserInterface
|
||||
nsStyleUserInterface(const nsStyleUserInterface& aOther);
|
||||
~nsStyleUserInterface();
|
||||
|
||||
void FinishStyle(nsPresContext* aPresContext);
|
||||
void FinishStyle(nsPresContext*, const nsStyleUserInterface*);
|
||||
const static bool kHasFinishStyle = true;
|
||||
|
||||
void* operator new(size_t sz, nsStyleUserInterface* aSelf) { return aSelf; }
|
||||
@ -3233,7 +3231,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleXUL
|
||||
explicit nsStyleXUL(const nsPresContext* aContext);
|
||||
nsStyleXUL(const nsStyleXUL& aSource);
|
||||
~nsStyleXUL();
|
||||
void FinishStyle(nsPresContext* aPresContext) {}
|
||||
void FinishStyle(nsPresContext*, const nsStyleXUL*) {}
|
||||
const static bool kHasFinishStyle = false;
|
||||
|
||||
void* operator new(size_t sz, nsStyleXUL* aSelf) { return aSelf; }
|
||||
@ -3263,7 +3261,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleColumn
|
||||
explicit nsStyleColumn(const nsPresContext* aContext);
|
||||
nsStyleColumn(const nsStyleColumn& aSource);
|
||||
~nsStyleColumn();
|
||||
void FinishStyle(nsPresContext* aPresContext) {}
|
||||
void FinishStyle(nsPresContext*, const nsStyleColumn*) {}
|
||||
const static bool kHasFinishStyle = false;
|
||||
|
||||
void* operator new(size_t sz, nsStyleColumn* aSelf) { return aSelf; }
|
||||
@ -3398,7 +3396,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleSVG
|
||||
explicit nsStyleSVG(const nsPresContext* aContext);
|
||||
nsStyleSVG(const nsStyleSVG& aSource);
|
||||
~nsStyleSVG();
|
||||
void FinishStyle(nsPresContext* aPresContext) {}
|
||||
void FinishStyle(nsPresContext*, const nsStyleSVG*) {}
|
||||
const static bool kHasFinishStyle = false;
|
||||
|
||||
void* operator new(size_t sz, nsStyleSVG* aSelf) { return aSelf; }
|
||||
@ -3535,7 +3533,7 @@ struct nsStyleFilter
|
||||
nsStyleFilter();
|
||||
nsStyleFilter(const nsStyleFilter& aSource);
|
||||
~nsStyleFilter();
|
||||
void FinishStyle(nsPresContext* aPresContext) {}
|
||||
void FinishStyle(nsPresContext*, const nsStyleFilter*) {}
|
||||
const static bool kHasFinishStyle = false;
|
||||
|
||||
nsStyleFilter& operator=(const nsStyleFilter& aOther);
|
||||
@ -3597,7 +3595,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleSVGReset
|
||||
// Resolves and tracks the images in mMask. Only called with a Servo-backed
|
||||
// style system, where those images must be resolved later than the OMT
|
||||
// nsStyleSVGReset constructor call.
|
||||
void FinishStyle(nsPresContext* aPresContext);
|
||||
void FinishStyle(nsPresContext*, const nsStyleSVGReset*);
|
||||
const static bool kHasFinishStyle = true;
|
||||
|
||||
void* operator new(size_t sz, nsStyleSVGReset* aSelf) { return aSelf; }
|
||||
@ -3640,7 +3638,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleVariables
|
||||
explicit nsStyleVariables(const nsPresContext* aContext);
|
||||
nsStyleVariables(const nsStyleVariables& aSource);
|
||||
~nsStyleVariables();
|
||||
void FinishStyle(nsPresContext* aPresContext) {}
|
||||
void FinishStyle(nsPresContext*, const nsStyleVariables*) {}
|
||||
const static bool kHasFinishStyle = false;
|
||||
|
||||
void* operator new(size_t sz, nsStyleVariables* aSelf) { return aSelf; }
|
||||
@ -3666,7 +3664,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleEffects
|
||||
explicit nsStyleEffects(const nsPresContext* aContext);
|
||||
nsStyleEffects(const nsStyleEffects& aSource);
|
||||
~nsStyleEffects();
|
||||
void FinishStyle(nsPresContext* aPresContext) {}
|
||||
void FinishStyle(nsPresContext*, const nsStyleEffects*) {}
|
||||
const static bool kHasFinishStyle = false;
|
||||
|
||||
void* operator new(size_t sz, nsStyleEffects* aSelf) { return aSelf; }
|
||||
|
@ -425,7 +425,7 @@ nsSVGMaskProperty::ResolveImage(uint32_t aIndex)
|
||||
|
||||
if (!image.IsResolved()) {
|
||||
MOZ_ASSERT(image.GetType() == nsStyleImageType::eStyleImageType_Image);
|
||||
image.ResolveImage(mFrame->PresContext());
|
||||
image.ResolveImage(mFrame->PresContext(), nullptr);
|
||||
|
||||
mozilla::css::ImageLoader* imageLoader =
|
||||
mFrame->PresContext()->Document()->StyleImageLoader();
|
||||
|
@ -112,6 +112,7 @@ pub enum Command {
|
||||
AddWebFont(LowercaseString, EffectiveSources, IpcSender<()>),
|
||||
AddDownloadedWebFont(LowercaseString, ServoUrl, Vec<u8>, IpcSender<()>),
|
||||
Exit(IpcSender<()>),
|
||||
Ping,
|
||||
}
|
||||
|
||||
/// Reply messages sent from the font cache thread to the FontContext caller.
|
||||
@ -204,6 +205,7 @@ impl FontCache {
|
||||
templates.add_template(Atom::from(url.to_string()), Some(bytes));
|
||||
drop(result.send(()));
|
||||
}
|
||||
Command::Ping => (),
|
||||
Command::Exit(result) => {
|
||||
let _ = result.send(());
|
||||
break;
|
||||
@ -472,10 +474,13 @@ impl FontSource for FontCacheThread {
|
||||
self.chan.send(Command::GetFontInstance(key, size, response_chan))
|
||||
.expect("failed to send message to font cache thread");
|
||||
|
||||
let instance_key = response_port.recv()
|
||||
.expect("failed to receive response to font request");
|
||||
|
||||
instance_key
|
||||
let instance_key = response_port.recv();
|
||||
if instance_key.is_err() {
|
||||
let font_thread_has_closed = self.chan.send(Command::Ping).is_err();
|
||||
assert!(font_thread_has_closed, "Failed to receive a response from live font cache");
|
||||
panic!("Font cache thread has already exited.");
|
||||
}
|
||||
instance_key.unwrap()
|
||||
}
|
||||
|
||||
fn find_font_template(&mut self, family: SingleFontFamily, desc: FontTemplateDescriptor)
|
||||
@ -485,10 +490,15 @@ impl FontSource for FontCacheThread {
|
||||
self.chan.send(Command::GetFontTemplate(family, desc, response_chan))
|
||||
.expect("failed to send message to font cache thread");
|
||||
|
||||
let reply = response_port.recv()
|
||||
.expect("failed to receive response to font request");
|
||||
let reply = response_port.recv();
|
||||
|
||||
match reply {
|
||||
if reply.is_err() {
|
||||
let font_thread_has_closed = self.chan.send(Command::Ping).is_err();
|
||||
assert!(font_thread_has_closed, "Failed to receive a response from live font cache");
|
||||
panic!("Font cache thread has already exited.");
|
||||
}
|
||||
|
||||
match reply.unwrap() {
|
||||
Reply::GetFontTemplateReply(data) => {
|
||||
data
|
||||
}
|
||||
@ -502,10 +512,14 @@ impl FontSource for FontCacheThread {
|
||||
self.chan.send(Command::GetLastResortFontTemplate(desc, response_chan))
|
||||
.expect("failed to send message to font cache thread");
|
||||
|
||||
let reply = response_port.recv()
|
||||
.expect("failed to receive response to font request");
|
||||
let reply = response_port.recv();
|
||||
if reply.is_err() {
|
||||
let font_thread_has_closed = self.chan.send(Command::Ping).is_err();
|
||||
assert!(font_thread_has_closed, "Failed to receive a response from live font cache");
|
||||
panic!("Font cache thread has already exited.");
|
||||
}
|
||||
|
||||
match reply {
|
||||
match reply.unwrap() {
|
||||
Reply::GetFontTemplateReply(data) => {
|
||||
data.unwrap()
|
||||
}
|
||||
|
@ -47,6 +47,8 @@ use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::ffi::CString;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use task::TaskCanceller;
|
||||
use task_source::file_reading::FileReadingTaskSource;
|
||||
use task_source::networking::NetworkingTaskSource;
|
||||
@ -55,6 +57,17 @@ use time::{Timespec, get_time};
|
||||
use timers::{IsInterval, OneshotTimerCallback, OneshotTimerHandle};
|
||||
use timers::{OneshotTimers, TimerCallback};
|
||||
|
||||
#[derive(JSTraceable)]
|
||||
pub struct AutoCloseWorker(
|
||||
Arc<AtomicBool>,
|
||||
);
|
||||
|
||||
impl Drop for AutoCloseWorker {
|
||||
fn drop(&mut self) {
|
||||
self.0.store(true, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GlobalScope {
|
||||
eventtarget: EventTarget,
|
||||
@ -110,6 +123,10 @@ pub struct GlobalScope {
|
||||
/// <https://html.spec.whatwg.org/multipage/#microtask-queue>
|
||||
#[ignore_malloc_size_of = "Rc<T> is hard"]
|
||||
microtask_queue: Rc<MicrotaskQueue>,
|
||||
|
||||
/// Vector storing closing references of all workers
|
||||
#[ignore_malloc_size_of = "Arc"]
|
||||
list_auto_close_worker: DomRefCell<Vec<AutoCloseWorker>>,
|
||||
}
|
||||
|
||||
impl GlobalScope {
|
||||
@ -142,9 +159,14 @@ impl GlobalScope {
|
||||
timers: OneshotTimers::new(timer_event_chan, scheduler_chan),
|
||||
origin,
|
||||
microtask_queue,
|
||||
list_auto_close_worker: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn track_worker(&self, closing_worker: Arc<AtomicBool>) {
|
||||
self.list_auto_close_worker.borrow_mut().push(AutoCloseWorker(closing_worker));
|
||||
}
|
||||
|
||||
/// Returns the global scope of the realm that the given DOM object's reflector
|
||||
/// was created in.
|
||||
#[allow(unsafe_code)]
|
||||
|
@ -48,7 +48,6 @@ use script_traits::ScriptToConstellationChan;
|
||||
use servo_atoms::Atom;
|
||||
use std::borrow::ToOwned;
|
||||
use std::cell::Cell;
|
||||
use std::mem;
|
||||
use std::ops::Range;
|
||||
use style::attr::AttrValue;
|
||||
use style::element_state::ElementState;
|
||||
@ -990,42 +989,34 @@ impl HTMLInputElement {
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#value-sanitization-algorithm
|
||||
fn sanitize_value(&self) {
|
||||
fn sanitize_value(&self, value: &mut DOMString) {
|
||||
match self.input_type() {
|
||||
InputType::Text | InputType::Search | InputType::Tel | InputType::Password => {
|
||||
self.textinput.borrow_mut().single_line_content_mut().strip_newlines();
|
||||
value.strip_newlines();
|
||||
}
|
||||
InputType::Url => {
|
||||
let mut textinput = self.textinput.borrow_mut();
|
||||
let content = textinput.single_line_content_mut();
|
||||
content.strip_newlines();
|
||||
content.strip_leading_and_trailing_ascii_whitespace();
|
||||
value.strip_newlines();
|
||||
value.strip_leading_and_trailing_ascii_whitespace();
|
||||
}
|
||||
InputType::Date => {
|
||||
let mut textinput = self.textinput.borrow_mut();
|
||||
if !textinput.single_line_content().is_valid_date_string() {
|
||||
textinput.single_line_content_mut().clear();
|
||||
if !value.is_valid_date_string() {
|
||||
value.clear();
|
||||
}
|
||||
}
|
||||
InputType::Month => {
|
||||
let mut textinput = self.textinput.borrow_mut();
|
||||
if !textinput.single_line_content().is_valid_month_string() {
|
||||
textinput.single_line_content_mut().clear();
|
||||
if !value.is_valid_month_string() {
|
||||
value.clear();
|
||||
}
|
||||
}
|
||||
InputType::Week => {
|
||||
let mut textinput = self.textinput.borrow_mut();
|
||||
if !textinput.single_line_content().is_valid_week_string() {
|
||||
textinput.single_line_content_mut().clear();
|
||||
if !value.is_valid_week_string() {
|
||||
value.clear();
|
||||
}
|
||||
}
|
||||
InputType::Color => {
|
||||
let mut textinput = self.textinput.borrow_mut();
|
||||
|
||||
let is_valid = {
|
||||
let content = textinput.single_line_content();
|
||||
let mut chars = content.chars();
|
||||
if content.len() == 7 && chars.next() == Some('#') {
|
||||
let mut chars = value.chars();
|
||||
if value.len() == 7 && chars.next() == Some('#') {
|
||||
chars.all(|c| c.is_digit(16))
|
||||
} else {
|
||||
false
|
||||
@ -1033,38 +1024,29 @@ impl HTMLInputElement {
|
||||
};
|
||||
|
||||
if is_valid {
|
||||
let content = textinput.single_line_content_mut();
|
||||
content.make_ascii_lowercase();
|
||||
value.make_ascii_lowercase();
|
||||
} else {
|
||||
textinput.set_content("#000000".into(), true);
|
||||
*value = "#000000".into();
|
||||
}
|
||||
}
|
||||
InputType::Time => {
|
||||
let mut textinput = self.textinput.borrow_mut();
|
||||
|
||||
if !textinput.single_line_content().is_valid_time_string() {
|
||||
textinput.single_line_content_mut().clear();
|
||||
if !value.is_valid_time_string() {
|
||||
value.clear();
|
||||
}
|
||||
}
|
||||
InputType::DatetimeLocal => {
|
||||
let mut textinput = self.textinput.borrow_mut();
|
||||
if textinput.single_line_content_mut()
|
||||
.convert_valid_normalized_local_date_and_time_string().is_err() {
|
||||
textinput.single_line_content_mut().clear();
|
||||
if value.convert_valid_normalized_local_date_and_time_string().is_err() {
|
||||
value.clear();
|
||||
}
|
||||
}
|
||||
InputType::Number => {
|
||||
let mut textinput = self.textinput.borrow_mut();
|
||||
if !textinput.single_line_content().is_valid_floating_point_number_string() {
|
||||
textinput.single_line_content_mut().clear();
|
||||
if !value.is_valid_floating_point_number_string() {
|
||||
value.clear();
|
||||
}
|
||||
}
|
||||
// https://html.spec.whatwg.org/multipage/#range-state-(type=range):value-sanitization-algorithm
|
||||
InputType::Range => {
|
||||
self.textinput
|
||||
.borrow_mut()
|
||||
.single_line_content_mut()
|
||||
.set_best_representation_of_the_floating_point_number();
|
||||
value.set_best_representation_of_the_floating_point_number();
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
@ -1075,20 +1057,23 @@ impl HTMLInputElement {
|
||||
TextControlSelection::new(&self, &self.textinput)
|
||||
}
|
||||
|
||||
fn update_text_contents(&self, value: DOMString, update_text_cursor: bool) -> ErrorResult {
|
||||
fn update_text_contents(&self, mut value: DOMString, update_text_cursor: bool) -> ErrorResult {
|
||||
match self.value_mode() {
|
||||
ValueMode::Value => {
|
||||
// Steps 1-2.
|
||||
let old_value = mem::replace(self.textinput.borrow_mut().single_line_content_mut(), value);
|
||||
// Step 3.
|
||||
self.value_dirty.set(true);
|
||||
|
||||
// Step 4.
|
||||
if update_text_cursor {
|
||||
self.sanitize_value();
|
||||
}
|
||||
// Step 5.
|
||||
if *self.textinput.borrow().single_line_content() != old_value {
|
||||
self.textinput.borrow_mut().clear_selection_to_limit(Direction::Forward, update_text_cursor);
|
||||
self.sanitize_value(&mut value);
|
||||
|
||||
let mut textinput = self.textinput.borrow_mut();
|
||||
|
||||
if *textinput.single_line_content() != value {
|
||||
// Steps 1-2
|
||||
textinput.set_content(value, update_text_cursor);
|
||||
|
||||
// Step 5.
|
||||
textinput.clear_selection_to_limit(Direction::Forward, update_text_cursor);
|
||||
}
|
||||
}
|
||||
ValueMode::Default |
|
||||
@ -1215,11 +1200,14 @@ impl VirtualMethods for HTMLInputElement {
|
||||
}
|
||||
|
||||
// Step 6
|
||||
self.sanitize_value();
|
||||
let mut textinput = self.textinput.borrow_mut();
|
||||
let mut value = textinput.single_line_content().clone();
|
||||
self.sanitize_value(&mut value);
|
||||
textinput.set_content(value, true);
|
||||
|
||||
// Steps 7-9
|
||||
if !previously_selectable && self.selection_api_applies() {
|
||||
self.textinput.borrow_mut().clear_selection_to_limit(Direction::Backward, true);
|
||||
textinput.clear_selection_to_limit(Direction::Backward, true);
|
||||
}
|
||||
},
|
||||
AttributeMutation::Removed => {
|
||||
@ -1240,9 +1228,10 @@ impl VirtualMethods for HTMLInputElement {
|
||||
},
|
||||
&local_name!("value") if !self.value_dirty.get() => {
|
||||
let value = mutation.new_value(attr).map(|value| (**value).to_owned());
|
||||
self.textinput.borrow_mut().set_content(
|
||||
value.map_or(DOMString::new(), DOMString::from), true);
|
||||
self.sanitize_value();
|
||||
let mut value = value.map_or(DOMString::new(), DOMString::from);
|
||||
|
||||
self.sanitize_value(&mut value);
|
||||
self.textinput.borrow_mut().set_content(value, true);
|
||||
self.update_placeholder_shown_state();
|
||||
},
|
||||
&local_name!("name") if self.input_type() == InputType::Radio => {
|
||||
@ -1252,10 +1241,12 @@ impl VirtualMethods for HTMLInputElement {
|
||||
&local_name!("maxlength") => {
|
||||
match *attr.value() {
|
||||
AttrValue::Int(_, value) => {
|
||||
let mut textinput = self.textinput.borrow_mut();
|
||||
|
||||
if value < 0 {
|
||||
self.textinput.borrow_mut().max_length = None
|
||||
textinput.set_max_length(None);
|
||||
} else {
|
||||
self.textinput.borrow_mut().max_length = Some(value as usize)
|
||||
textinput.set_max_length(Some(value as usize))
|
||||
}
|
||||
},
|
||||
_ => panic!("Expected an AttrValue::Int"),
|
||||
@ -1264,10 +1255,12 @@ impl VirtualMethods for HTMLInputElement {
|
||||
&local_name!("minlength") => {
|
||||
match *attr.value() {
|
||||
AttrValue::Int(_, value) => {
|
||||
let mut textinput = self.textinput.borrow_mut();
|
||||
|
||||
if value < 0 {
|
||||
self.textinput.borrow_mut().min_length = None
|
||||
textinput.set_min_length(None);
|
||||
} else {
|
||||
self.textinput.borrow_mut().min_length = Some(value as usize)
|
||||
textinput.set_min_length(Some(value as usize))
|
||||
}
|
||||
},
|
||||
_ => panic!("Expected an AttrValue::Int"),
|
||||
|
@ -323,7 +323,6 @@ impl HTMLTextAreaElement {
|
||||
|
||||
// Step 1
|
||||
let old_value = textinput.get_content();
|
||||
let old_selection = textinput.selection_origin;
|
||||
|
||||
// Step 2
|
||||
textinput.set_content(value, update_text_cursor);
|
||||
@ -334,8 +333,6 @@ impl HTMLTextAreaElement {
|
||||
if old_value != textinput.get_content() {
|
||||
// Step 4
|
||||
textinput.clear_selection_to_limit(Direction::Forward, update_text_cursor);
|
||||
} else {
|
||||
textinput.selection_origin = old_selection;
|
||||
}
|
||||
|
||||
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
||||
|
@ -257,7 +257,7 @@ impl<'a, E: TextControlElement> TextControlSelection<'a, E> {
|
||||
}
|
||||
|
||||
fn direction(&self) -> SelectionDirection {
|
||||
self.textinput.borrow().selection_direction
|
||||
self.textinput.borrow().selection_direction()
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#set-the-selection-range
|
||||
|
@ -79,6 +79,7 @@ impl Worker {
|
||||
let (sender, receiver) = channel();
|
||||
let closing = Arc::new(AtomicBool::new(false));
|
||||
let worker = Worker::new(global, sender.clone(), closing.clone());
|
||||
global.track_worker(closing.clone());
|
||||
let worker_ref = Trusted::new(&*worker);
|
||||
|
||||
let worker_load_origin = WorkerScriptLoadOrigin {
|
||||
|
@ -56,6 +56,18 @@ pub struct TextPoint {
|
||||
pub index: usize,
|
||||
}
|
||||
|
||||
impl TextPoint {
|
||||
/// Returns a TextPoint constrained to be a valid location within lines
|
||||
fn constrain_to(&self, lines: &[DOMString]) -> TextPoint {
|
||||
let line = min(self.line, lines.len() - 1);
|
||||
|
||||
TextPoint {
|
||||
line,
|
||||
index: min(self.index, lines[line].len()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub struct SelectionState {
|
||||
start: TextPoint,
|
||||
@ -68,21 +80,26 @@ pub struct SelectionState {
|
||||
pub struct TextInput<T: ClipboardProvider> {
|
||||
/// Current text input content, split across lines without trailing '\n'
|
||||
lines: Vec<DOMString>,
|
||||
|
||||
/// Current cursor input point
|
||||
pub edit_point: TextPoint,
|
||||
edit_point: TextPoint,
|
||||
|
||||
/// The current selection goes from the selection_origin until the edit_point. Note that the
|
||||
/// selection_origin may be after the edit_point, in the case of a backward selection.
|
||||
pub selection_origin: Option<TextPoint>,
|
||||
selection_origin: Option<TextPoint>,
|
||||
selection_direction: SelectionDirection,
|
||||
|
||||
/// Is this a multiline input?
|
||||
multiline: bool,
|
||||
|
||||
#[ignore_malloc_size_of = "Can't easily measure this generic type"]
|
||||
clipboard_provider: T,
|
||||
|
||||
/// The maximum number of UTF-16 code units this text input is allowed to hold.
|
||||
///
|
||||
/// <https://html.spec.whatwg.org/multipage/#attr-fe-maxlength>
|
||||
pub max_length: Option<usize>,
|
||||
pub min_length: Option<usize>,
|
||||
pub selection_direction: SelectionDirection,
|
||||
max_length: Option<usize>,
|
||||
min_length: Option<usize>,
|
||||
}
|
||||
|
||||
/// Resulting action to be taken by the owner of a text input that is handling an event.
|
||||
@ -175,6 +192,32 @@ impl<T: ClipboardProvider> TextInput<T> {
|
||||
i
|
||||
}
|
||||
|
||||
pub fn edit_point(&self) -> TextPoint {
|
||||
self.edit_point
|
||||
}
|
||||
|
||||
pub fn selection_origin(&self) -> Option<TextPoint> {
|
||||
self.selection_origin
|
||||
}
|
||||
|
||||
/// The selection origin, or the edit point if there is no selection. Note that the selection
|
||||
/// origin may be after the edit point, in the case of a backward selection.
|
||||
pub fn selection_origin_or_edit_point(&self) -> TextPoint {
|
||||
self.selection_origin.unwrap_or(self.edit_point)
|
||||
}
|
||||
|
||||
pub fn selection_direction(&self) -> SelectionDirection {
|
||||
self.selection_direction
|
||||
}
|
||||
|
||||
pub fn set_max_length(&mut self, length: Option<usize>) {
|
||||
self.max_length = length;
|
||||
}
|
||||
|
||||
pub fn set_min_length(&mut self, length: Option<usize>) {
|
||||
self.min_length = length;
|
||||
}
|
||||
|
||||
/// Remove a character at the current editing point
|
||||
pub fn delete_char(&mut self, dir: Direction) {
|
||||
if self.selection_origin.is_none() || self.selection_origin == Some(self.edit_point) {
|
||||
@ -196,12 +239,6 @@ impl<T: ClipboardProvider> TextInput<T> {
|
||||
self.replace_selection(DOMString::from(s.into()));
|
||||
}
|
||||
|
||||
/// The selection origin, or the edit point if there is no selection. Note that the selection
|
||||
/// origin may be after the edit point, in the case of a backward selection.
|
||||
pub fn selection_origin_or_edit_point(&self) -> TextPoint {
|
||||
self.selection_origin.unwrap_or(self.edit_point)
|
||||
}
|
||||
|
||||
/// The start of the selection (or the edit point, if there is no selection). Always less than
|
||||
/// or equal to selection_end(), regardless of the selection direction.
|
||||
pub fn selection_start(&self) -> TextPoint {
|
||||
@ -832,12 +869,6 @@ impl<T: ClipboardProvider> TextInput<T> {
|
||||
&self.lines[0]
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the contents of a single-line text input. Panics if self is a multiline input.
|
||||
pub fn single_line_content_mut(&mut self) -> &mut DOMString {
|
||||
assert!(!self.multiline);
|
||||
&mut self.lines[0]
|
||||
}
|
||||
|
||||
/// Set the current contents of the text input. If this is control supports multiple lines,
|
||||
/// any \n encountered will be stripped and force a new logical line.
|
||||
pub fn set_content(&mut self, content: DOMString, update_text_cursor: bool) {
|
||||
@ -850,11 +881,15 @@ impl<T: ClipboardProvider> TextInput<T> {
|
||||
} else {
|
||||
vec!(content)
|
||||
};
|
||||
|
||||
if update_text_cursor {
|
||||
self.edit_point.line = min(self.edit_point.line, self.lines.len() - 1);
|
||||
self.edit_point.index = min(self.edit_point.index, self.current_line_length());
|
||||
self.edit_point = self.edit_point.constrain_to(&self.lines);
|
||||
}
|
||||
self.selection_origin = None;
|
||||
|
||||
if let Some(origin) = self.selection_origin {
|
||||
self.selection_origin = Some(origin.constrain_to(&self.lines));
|
||||
}
|
||||
|
||||
self.assert_ok_selection();
|
||||
}
|
||||
|
||||
|
3
servo/tests/html/child.html
Normal file
3
servo/tests/html/child.html
Normal file
@ -0,0 +1,3 @@
|
||||
<script>
|
||||
var w = new Worker('work.js');
|
||||
</script>
|
8
servo/tests/html/parent.html
Normal file
8
servo/tests/html/parent.html
Normal file
@ -0,0 +1,8 @@
|
||||
<body>
|
||||
<script>
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.src = "child.html";
|
||||
iframe.onload = function() { iframe.remove(); }
|
||||
document.body.appendChild(iframe);
|
||||
</script>
|
||||
</body>
|
4
servo/tests/html/work.js
Normal file
4
servo/tests/html/work.js
Normal file
@ -0,0 +1,4 @@
|
||||
console.log("reached inside work.js file");
|
||||
setInterval(function() {
|
||||
console.log('hi');
|
||||
}, 500);
|
@ -42,7 +42,7 @@ fn test_textinput_when_inserting_multiple_lines_over_a_selection_respects_max_le
|
||||
SelectionDirection::None,
|
||||
);
|
||||
|
||||
textinput.edit_point = TextPoint { line: 0, index: 1 };
|
||||
textinput.adjust_horizontal(1, Selection::NotSelected);
|
||||
textinput.adjust_horizontal(3, Selection::Selected);
|
||||
textinput.adjust_vertical(1, Selection::Selected);
|
||||
|
||||
@ -67,8 +67,7 @@ fn test_textinput_when_inserting_multiple_lines_still_respects_max_length() {
|
||||
SelectionDirection::None
|
||||
);
|
||||
|
||||
textinput.edit_point = TextPoint { line: 1, index: 0 };
|
||||
|
||||
textinput.adjust_vertical(1, Selection::NotSelected);
|
||||
textinput.insert_string("cruel\nterrible".to_string());
|
||||
|
||||
assert_eq!(textinput.get_content(), "hello\ncruel\nworld");
|
||||
@ -117,7 +116,7 @@ fn test_single_line_textinput_with_max_length_doesnt_allow_appending_characters_
|
||||
SelectionDirection::None,
|
||||
);
|
||||
|
||||
textinput.edit_point = TextPoint { line: 0, index: 1 };
|
||||
textinput.adjust_horizontal(1, Selection::NotSelected);
|
||||
textinput.adjust_horizontal(3, Selection::Selected);
|
||||
|
||||
// Selection is now "abcde"
|
||||
@ -220,9 +219,7 @@ fn test_textinput_delete_char() {
|
||||
assert_eq!(textinput.get_content(), "ab");
|
||||
|
||||
let mut textinput = text_input(Lines::Single, "abcdefg");
|
||||
textinput.adjust_horizontal(2, Selection::NotSelected);
|
||||
// Set an empty selection range.
|
||||
textinput.selection_origin = Some(textinput.edit_point);
|
||||
textinput.set_selection_range(2, 2, SelectionDirection::None);
|
||||
textinput.delete_char(Direction::Backward);
|
||||
assert_eq!(textinput.get_content(), "acdefg");
|
||||
}
|
||||
@ -300,16 +297,16 @@ fn test_textinput_adjust_vertical() {
|
||||
let mut textinput = text_input(Lines::Multiple, "abc\nde\nf");
|
||||
textinput.adjust_horizontal(3, Selection::NotSelected);
|
||||
textinput.adjust_vertical(1, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 1);
|
||||
assert_eq!(textinput.edit_point.index, 2);
|
||||
assert_eq!(textinput.edit_point().line, 1);
|
||||
assert_eq!(textinput.edit_point().index, 2);
|
||||
|
||||
textinput.adjust_vertical(-1, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point.index, 2);
|
||||
assert_eq!(textinput.edit_point().line, 0);
|
||||
assert_eq!(textinput.edit_point().index, 2);
|
||||
|
||||
textinput.adjust_vertical(2, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 2);
|
||||
assert_eq!(textinput.edit_point.index, 1);
|
||||
assert_eq!(textinput.edit_point().line, 2);
|
||||
assert_eq!(textinput.edit_point().index, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -317,32 +314,32 @@ fn test_textinput_adjust_vertical_multibyte() {
|
||||
let mut textinput = text_input(Lines::Multiple, "áé\nae");
|
||||
|
||||
textinput.adjust_horizontal_by_one(Direction::Forward, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point.index, 2);
|
||||
assert_eq!(textinput.edit_point().line, 0);
|
||||
assert_eq!(textinput.edit_point().index, 2);
|
||||
|
||||
textinput.adjust_vertical(1, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 1);
|
||||
assert_eq!(textinput.edit_point.index, 1);
|
||||
assert_eq!(textinput.edit_point().line, 1);
|
||||
assert_eq!(textinput.edit_point().index, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_adjust_horizontal() {
|
||||
let mut textinput = text_input(Lines::Multiple, "abc\nde\nf");
|
||||
textinput.adjust_horizontal(4, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 1);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
assert_eq!(textinput.edit_point().line, 1);
|
||||
assert_eq!(textinput.edit_point().index, 0);
|
||||
|
||||
textinput.adjust_horizontal(1, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 1);
|
||||
assert_eq!(textinput.edit_point.index, 1);
|
||||
assert_eq!(textinput.edit_point().line, 1);
|
||||
assert_eq!(textinput.edit_point().index, 1);
|
||||
|
||||
textinput.adjust_horizontal(2, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 2);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
assert_eq!(textinput.edit_point().line, 2);
|
||||
assert_eq!(textinput.edit_point().index, 0);
|
||||
|
||||
textinput.adjust_horizontal(-1, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 1);
|
||||
assert_eq!(textinput.edit_point.index, 2);
|
||||
assert_eq!(textinput.edit_point().line, 1);
|
||||
assert_eq!(textinput.edit_point().index, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -351,45 +348,45 @@ fn test_textinput_adjust_horizontal_by_word() {
|
||||
let mut textinput = text_input(Lines::Single, "abc def");
|
||||
textinput.adjust_horizontal_by_word(Direction::Forward, Selection::NotSelected);
|
||||
textinput.adjust_horizontal_by_word(Direction::Forward, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point.index, 7);
|
||||
assert_eq!(textinput.edit_point().line, 0);
|
||||
assert_eq!(textinput.edit_point().index, 7);
|
||||
textinput.adjust_horizontal_by_word(Direction::Backward, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point.index, 4);
|
||||
assert_eq!(textinput.edit_point().line, 0);
|
||||
assert_eq!(textinput.edit_point().index, 4);
|
||||
textinput.adjust_horizontal_by_word(Direction::Backward, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
assert_eq!(textinput.edit_point().line, 0);
|
||||
assert_eq!(textinput.edit_point().index, 0);
|
||||
|
||||
// Test new line case of movement word by word based on UAX#29 rules
|
||||
let mut textinput_2 = text_input(Lines::Multiple, "abc\ndef");
|
||||
textinput_2.adjust_horizontal_by_word(Direction::Forward, Selection::NotSelected);
|
||||
textinput_2.adjust_horizontal_by_word(Direction::Forward, Selection::NotSelected);
|
||||
assert_eq!(textinput_2.edit_point.line, 1);
|
||||
assert_eq!(textinput_2.edit_point.index, 3);
|
||||
assert_eq!(textinput_2.edit_point().line, 1);
|
||||
assert_eq!(textinput_2.edit_point().index, 3);
|
||||
textinput_2.adjust_horizontal_by_word(Direction::Backward, Selection::NotSelected);
|
||||
assert_eq!(textinput_2.edit_point.line, 1);
|
||||
assert_eq!(textinput_2.edit_point.index, 0);
|
||||
assert_eq!(textinput_2.edit_point().line, 1);
|
||||
assert_eq!(textinput_2.edit_point().index, 0);
|
||||
textinput_2.adjust_horizontal_by_word(Direction::Backward, Selection::NotSelected);
|
||||
assert_eq!(textinput_2.edit_point.line, 0);
|
||||
assert_eq!(textinput_2.edit_point.index, 0);
|
||||
assert_eq!(textinput_2.edit_point().line, 0);
|
||||
assert_eq!(textinput_2.edit_point().index, 0);
|
||||
|
||||
// Test non-standard sized characters case of movement word by word based on UAX#29 rules
|
||||
let mut textinput_3 = text_input(Lines::Single, "áéc d🌠bc");
|
||||
textinput_3.adjust_horizontal_by_word(Direction::Forward, Selection::NotSelected);
|
||||
assert_eq!(textinput_3.edit_point.line, 0);
|
||||
assert_eq!(textinput_3.edit_point.index, 5);
|
||||
assert_eq!(textinput_3.edit_point().line, 0);
|
||||
assert_eq!(textinput_3.edit_point().index, 5);
|
||||
textinput_3.adjust_horizontal_by_word(Direction::Forward, Selection::NotSelected);
|
||||
assert_eq!(textinput_3.edit_point.line, 0);
|
||||
assert_eq!(textinput_3.edit_point.index, 7);
|
||||
assert_eq!(textinput_3.edit_point().line, 0);
|
||||
assert_eq!(textinput_3.edit_point().index, 7);
|
||||
textinput_3.adjust_horizontal_by_word(Direction::Forward, Selection::NotSelected);
|
||||
assert_eq!(textinput_3.edit_point.line, 0);
|
||||
assert_eq!(textinput_3.edit_point.index, 13);
|
||||
assert_eq!(textinput_3.edit_point().line, 0);
|
||||
assert_eq!(textinput_3.edit_point().index, 13);
|
||||
textinput_3.adjust_horizontal_by_word(Direction::Backward, Selection::NotSelected);
|
||||
assert_eq!(textinput_3.edit_point.line, 0);
|
||||
assert_eq!(textinput_3.edit_point.index, 11);
|
||||
assert_eq!(textinput_3.edit_point().line, 0);
|
||||
assert_eq!(textinput_3.edit_point().index, 11);
|
||||
textinput_3.adjust_horizontal_by_word(Direction::Backward, Selection::NotSelected);
|
||||
assert_eq!(textinput_3.edit_point.line, 0);
|
||||
assert_eq!(textinput_3.edit_point.index, 6);
|
||||
assert_eq!(textinput_3.edit_point().line, 0);
|
||||
assert_eq!(textinput_3.edit_point().index, 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -397,29 +394,29 @@ fn test_textinput_adjust_horizontal_to_line_end() {
|
||||
// Test standard case of movement to end based on UAX#29 rules
|
||||
let mut textinput = text_input(Lines::Single, "abc def");
|
||||
textinput.adjust_horizontal_to_line_end(Direction::Forward, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point.index, 7);
|
||||
assert_eq!(textinput.edit_point().line, 0);
|
||||
assert_eq!(textinput.edit_point().index, 7);
|
||||
|
||||
// Test new line case of movement to end based on UAX#29 rules
|
||||
let mut textinput_2 = text_input(Lines::Multiple, "abc\ndef");
|
||||
textinput_2.adjust_horizontal_to_line_end(Direction::Forward, Selection::NotSelected);
|
||||
assert_eq!(textinput_2.edit_point.line, 0);
|
||||
assert_eq!(textinput_2.edit_point.index, 3);
|
||||
assert_eq!(textinput_2.edit_point().line, 0);
|
||||
assert_eq!(textinput_2.edit_point().index, 3);
|
||||
textinput_2.adjust_horizontal_to_line_end(Direction::Forward, Selection::NotSelected);
|
||||
assert_eq!(textinput_2.edit_point.line, 0);
|
||||
assert_eq!(textinput_2.edit_point.index, 3);
|
||||
assert_eq!(textinput_2.edit_point().line, 0);
|
||||
assert_eq!(textinput_2.edit_point().index, 3);
|
||||
textinput_2.adjust_horizontal_to_line_end(Direction::Backward, Selection::NotSelected);
|
||||
assert_eq!(textinput_2.edit_point.line, 0);
|
||||
assert_eq!(textinput_2.edit_point.index, 0);
|
||||
assert_eq!(textinput_2.edit_point().line, 0);
|
||||
assert_eq!(textinput_2.edit_point().index, 0);
|
||||
|
||||
// Test non-standard sized characters case of movement to end based on UAX#29 rules
|
||||
let mut textinput_3 = text_input(Lines::Single, "áéc d🌠bc");
|
||||
textinput_3.adjust_horizontal_to_line_end(Direction::Forward, Selection::NotSelected);
|
||||
assert_eq!(textinput_3.edit_point.line, 0);
|
||||
assert_eq!(textinput_3.edit_point.index, 13);
|
||||
assert_eq!(textinput_3.edit_point().line, 0);
|
||||
assert_eq!(textinput_3.edit_point().index, 13);
|
||||
textinput_3.adjust_horizontal_to_line_end(Direction::Backward, Selection::NotSelected);
|
||||
assert_eq!(textinput_3.edit_point.line, 0);
|
||||
assert_eq!(textinput_3.edit_point.index, 0);
|
||||
assert_eq!(textinput_3.edit_point().line, 0);
|
||||
assert_eq!(textinput_3.edit_point().index, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -429,29 +426,29 @@ fn test_navigation_keyboard_shortcuts() {
|
||||
|
||||
// Test that CMD + Right moves to the end of the current line.
|
||||
textinput.handle_keydown_aux(None, Key::Right, KeyModifiers::SUPER);
|
||||
assert_eq!(textinput.edit_point.index, 11);
|
||||
assert_eq!(textinput.edit_point().index, 11);
|
||||
// Test that CMD + Right moves to the beginning of the current line.
|
||||
textinput.handle_keydown_aux(None, Key::Left, KeyModifiers::SUPER);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
assert_eq!(textinput.edit_point().index, 0);
|
||||
// Test that CTRL + ALT + E moves to the end of the current line also.
|
||||
textinput.handle_keydown_aux(None, Key::E, KeyModifiers::CONTROL | KeyModifiers::ALT);
|
||||
assert_eq!(textinput.edit_point.index, 11);
|
||||
assert_eq!(textinput.edit_point().index, 11);
|
||||
// Test that CTRL + ALT + A moves to the beginning of the current line also.
|
||||
textinput.handle_keydown_aux(None, Key::A, KeyModifiers::CONTROL | KeyModifiers::ALT);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
assert_eq!(textinput.edit_point().index, 0);
|
||||
|
||||
// Test that ALT + Right moves to the end of the word.
|
||||
textinput.handle_keydown_aux(None, Key::Right, KeyModifiers::ALT);
|
||||
assert_eq!(textinput.edit_point.index, 5);
|
||||
assert_eq!(textinput.edit_point().index, 5);
|
||||
// Test that CTRL + ALT + F moves to the end of the word also.
|
||||
textinput.handle_keydown_aux(None, Key::F, KeyModifiers::CONTROL | KeyModifiers::ALT);
|
||||
assert_eq!(textinput.edit_point.index, 11);
|
||||
assert_eq!(textinput.edit_point().index, 11);
|
||||
// Test that ALT + Left moves to the end of the word.
|
||||
textinput.handle_keydown_aux(None, Key::Left, KeyModifiers::ALT);
|
||||
assert_eq!(textinput.edit_point.index, 6);
|
||||
assert_eq!(textinput.edit_point().index, 6);
|
||||
// Test that CTRL + ALT + B moves to the end of the word also.
|
||||
textinput.handle_keydown_aux(None, Key::B, KeyModifiers::CONTROL | KeyModifiers::ALT);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
assert_eq!(textinput.edit_point().index, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -470,12 +467,12 @@ fn test_textinput_handle_return() {
|
||||
#[test]
|
||||
fn test_textinput_select_all() {
|
||||
let mut textinput = text_input(Lines::Multiple, "abc\nde\nf");
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
assert_eq!(textinput.edit_point().line, 0);
|
||||
assert_eq!(textinput.edit_point().index, 0);
|
||||
|
||||
textinput.select_all();
|
||||
assert_eq!(textinput.edit_point.line, 2);
|
||||
assert_eq!(textinput.edit_point.index, 1);
|
||||
assert_eq!(textinput.edit_point().line, 2);
|
||||
assert_eq!(textinput.edit_point().index, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -495,15 +492,15 @@ fn test_textinput_set_content() {
|
||||
textinput.set_content(DOMString::from("abc\nf"), true);
|
||||
assert_eq!(textinput.get_content(), "abc\nf");
|
||||
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
assert_eq!(textinput.edit_point().line, 0);
|
||||
assert_eq!(textinput.edit_point().index, 0);
|
||||
textinput.adjust_horizontal(3, Selection::Selected);
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point.index, 3);
|
||||
assert_eq!(textinput.edit_point().line, 0);
|
||||
assert_eq!(textinput.edit_point().index, 3);
|
||||
textinput.set_content(DOMString::from("de"), true);
|
||||
assert_eq!(textinput.get_content(), "de");
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point.index, 2);
|
||||
assert_eq!(textinput.edit_point().line, 0);
|
||||
assert_eq!(textinput.edit_point().index, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -520,7 +517,7 @@ fn test_clipboard_paste() {
|
||||
None,
|
||||
SelectionDirection::None);
|
||||
assert_eq!(textinput.get_content(), "defg");
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
assert_eq!(textinput.edit_point().index, 0);
|
||||
textinput.handle_keydown_aux(Some('v'), Key::V, MODIFIERS);
|
||||
assert_eq!(textinput.get_content(), "abcdefg");
|
||||
}
|
||||
@ -532,23 +529,23 @@ fn test_textinput_cursor_position_correct_after_clearing_selection() {
|
||||
// Single line - Forward
|
||||
textinput.adjust_horizontal(3, Selection::Selected);
|
||||
textinput.adjust_horizontal(1, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.index, 3);
|
||||
assert_eq!(textinput.edit_point().index, 3);
|
||||
|
||||
textinput.adjust_horizontal(-3, Selection::NotSelected);
|
||||
textinput.adjust_horizontal(3, Selection::Selected);
|
||||
textinput.adjust_horizontal_by_one(Direction::Forward, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.index, 3);
|
||||
assert_eq!(textinput.edit_point().index, 3);
|
||||
|
||||
// Single line - Backward
|
||||
textinput.adjust_horizontal(-3, Selection::NotSelected);
|
||||
textinput.adjust_horizontal(3, Selection::Selected);
|
||||
textinput.adjust_horizontal(-1, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
assert_eq!(textinput.edit_point().index, 0);
|
||||
|
||||
textinput.adjust_horizontal(-3, Selection::NotSelected);
|
||||
textinput.adjust_horizontal(3, Selection::Selected);
|
||||
textinput.adjust_horizontal_by_one(Direction::Backward, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
assert_eq!(textinput.edit_point().index, 0);
|
||||
|
||||
|
||||
let mut textinput = text_input(Lines::Multiple, "abc\nde\nf");
|
||||
@ -556,27 +553,27 @@ fn test_textinput_cursor_position_correct_after_clearing_selection() {
|
||||
// Multiline - Forward
|
||||
textinput.adjust_horizontal(4, Selection::Selected);
|
||||
textinput.adjust_horizontal(1, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
assert_eq!(textinput.edit_point.line, 1);
|
||||
assert_eq!(textinput.edit_point().index, 0);
|
||||
assert_eq!(textinput.edit_point().line, 1);
|
||||
|
||||
textinput.adjust_horizontal(-4, Selection::NotSelected);
|
||||
textinput.adjust_horizontal(4, Selection::Selected);
|
||||
textinput.adjust_horizontal_by_one(Direction::Forward, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
assert_eq!(textinput.edit_point.line, 1);
|
||||
assert_eq!(textinput.edit_point().index, 0);
|
||||
assert_eq!(textinput.edit_point().line, 1);
|
||||
|
||||
// Multiline - Backward
|
||||
textinput.adjust_horizontal(-4, Selection::NotSelected);
|
||||
textinput.adjust_horizontal(4, Selection::Selected);
|
||||
textinput.adjust_horizontal(-1, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point().index, 0);
|
||||
assert_eq!(textinput.edit_point().line, 0);
|
||||
|
||||
textinput.adjust_horizontal(-4, Selection::NotSelected);
|
||||
textinput.adjust_horizontal(4, Selection::Selected);
|
||||
textinput.adjust_horizontal_by_one(Direction::Backward, Selection::NotSelected);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point().index, 0);
|
||||
assert_eq!(textinput.edit_point().line, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -584,53 +581,53 @@ fn test_textinput_cursor_position_correct_after_clearing_selection() {
|
||||
fn test_textinput_set_selection_with_direction() {
|
||||
let mut textinput = text_input(Lines::Single, "abcdef");
|
||||
textinput.set_selection_range(2, 6, SelectionDirection::Forward);
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point.index, 6);
|
||||
assert_eq!(textinput.selection_direction, SelectionDirection::Forward);
|
||||
assert_eq!(textinput.edit_point().line, 0);
|
||||
assert_eq!(textinput.edit_point().index, 6);
|
||||
assert_eq!(textinput.selection_direction(), SelectionDirection::Forward);
|
||||
|
||||
assert!(textinput.selection_origin.is_some());
|
||||
assert_eq!(textinput.selection_origin.unwrap().line, 0);
|
||||
assert_eq!(textinput.selection_origin.unwrap().index, 2);
|
||||
assert!(textinput.selection_origin().is_some());
|
||||
assert_eq!(textinput.selection_origin().unwrap().line, 0);
|
||||
assert_eq!(textinput.selection_origin().unwrap().index, 2);
|
||||
|
||||
textinput.set_selection_range(2, 6, SelectionDirection::Backward);
|
||||
assert_eq!(textinput.edit_point.line, 0);
|
||||
assert_eq!(textinput.edit_point.index, 2);
|
||||
assert_eq!(textinput.selection_direction, SelectionDirection::Backward);
|
||||
assert_eq!(textinput.edit_point().line, 0);
|
||||
assert_eq!(textinput.edit_point().index, 2);
|
||||
assert_eq!(textinput.selection_direction(), SelectionDirection::Backward);
|
||||
|
||||
assert!(textinput.selection_origin.is_some());
|
||||
assert_eq!(textinput.selection_origin.unwrap().line, 0);
|
||||
assert_eq!(textinput.selection_origin.unwrap().index, 6);
|
||||
assert!(textinput.selection_origin().is_some());
|
||||
assert_eq!(textinput.selection_origin().unwrap().line, 0);
|
||||
assert_eq!(textinput.selection_origin().unwrap().index, 6);
|
||||
|
||||
textinput = text_input(Lines::Multiple, "\n\n");
|
||||
textinput.set_selection_range(0, 1, SelectionDirection::Forward);
|
||||
assert_eq!(textinput.edit_point.line, 1);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
assert_eq!(textinput.selection_direction, SelectionDirection::Forward);
|
||||
assert_eq!(textinput.edit_point().line, 1);
|
||||
assert_eq!(textinput.edit_point().index, 0);
|
||||
assert_eq!(textinput.selection_direction(), SelectionDirection::Forward);
|
||||
|
||||
assert!(textinput.selection_origin.is_some());
|
||||
assert_eq!(textinput.selection_origin.unwrap().line, 0);
|
||||
assert_eq!(textinput.selection_origin.unwrap().index, 0);
|
||||
assert!(textinput.selection_origin().is_some());
|
||||
assert_eq!(textinput.selection_origin().unwrap().line, 0);
|
||||
assert_eq!(textinput.selection_origin().unwrap().index, 0);
|
||||
|
||||
textinput = text_input(Lines::Multiple, "\n");
|
||||
textinput.set_selection_range(0, 1, SelectionDirection::Forward);
|
||||
assert_eq!(textinput.edit_point.line, 1);
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
assert_eq!(textinput.selection_direction, SelectionDirection::Forward);
|
||||
assert_eq!(textinput.edit_point().line, 1);
|
||||
assert_eq!(textinput.edit_point().index, 0);
|
||||
assert_eq!(textinput.selection_direction(), SelectionDirection::Forward);
|
||||
|
||||
assert!(textinput.selection_origin.is_some());
|
||||
assert_eq!(textinput.selection_origin.unwrap().line, 0);
|
||||
assert_eq!(textinput.selection_origin.unwrap().index, 0);
|
||||
assert!(textinput.selection_origin().is_some());
|
||||
assert_eq!(textinput.selection_origin().unwrap().line, 0);
|
||||
assert_eq!(textinput.selection_origin().unwrap().index, 0);
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textinput_unicode_handling() {
|
||||
let mut textinput = text_input(Lines::Single, "éèùµ$£");
|
||||
assert_eq!(textinput.edit_point.index, 0);
|
||||
assert_eq!(textinput.edit_point().index, 0);
|
||||
textinput.set_edit_point_index(1);
|
||||
assert_eq!(textinput.edit_point.index, 2);
|
||||
assert_eq!(textinput.edit_point().index, 2);
|
||||
textinput.set_edit_point_index(4);
|
||||
assert_eq!(textinput.edit_point.index, 8);
|
||||
assert_eq!(textinput.edit_point().index, 8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -514,52 +514,6 @@ android-api-16-old-id-nightly/opt:
|
||||
- linux64-sccache
|
||||
- proguard-jar
|
||||
|
||||
android-api-16-gradle/opt:
|
||||
description: "Android 4.0 api-16+ (non-Gradle) Opt"
|
||||
index:
|
||||
product: mobile
|
||||
job-name: android-api-16-gradle-opt
|
||||
treeherder:
|
||||
platform: android-api-16-gradle/opt
|
||||
symbol: Bng
|
||||
tier: 1
|
||||
worker-type: aws-provisioner-v1/gecko-{level}-b-android
|
||||
worker:
|
||||
docker-image: {in-tree: android-build}
|
||||
max-run-time: 7200
|
||||
env:
|
||||
TOOLTOOL_MANIFEST: "mobile/android/config/tooltool-manifests/android/releng.manifest"
|
||||
artifacts:
|
||||
- name: public/android/R
|
||||
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/app/R
|
||||
type: directory
|
||||
- name: public/android/maven
|
||||
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview/maven/
|
||||
type: directory
|
||||
- name: public/build/geckoview_example.apk
|
||||
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/officialWithGeckoBinariesNoMinApi/debug/geckoview_example-official-withGeckoBinaries-noMinApi-debug.apk
|
||||
type: file
|
||||
- name: public/build
|
||||
path: /builds/worker/artifacts/
|
||||
type: directory
|
||||
run:
|
||||
using: mozharness
|
||||
actions: [get-secrets build multi-l10n update]
|
||||
config:
|
||||
- builds/releng_base_android_64_builds.py
|
||||
- disable_signing.py
|
||||
script: "mozharness/scripts/fx_desktop_build.py"
|
||||
secrets: true
|
||||
custom-build-variant-cfg: api-16-gradle
|
||||
tooltool-downloads: internal
|
||||
toolchains:
|
||||
- android-ndk-linux
|
||||
- android-sdk-linux
|
||||
- linux64-clang
|
||||
- linux64-rust-android
|
||||
- linux64-sccache
|
||||
- proguard-jar
|
||||
|
||||
android-aarch64/opt:
|
||||
description: "Android 5.0 AArch64 Opt"
|
||||
index:
|
||||
|
@ -29,7 +29,6 @@ robocop:
|
||||
by-test-platform:
|
||||
# android-4.3-arm7-api-16/debug -- not run
|
||||
android-4.3-arm7-api-16/opt: 4
|
||||
android-4.3-arm7-api-16-gradle/opt: 4
|
||||
loopback-video: true
|
||||
e10s: false
|
||||
mozharness:
|
||||
|
@ -474,6 +474,7 @@ talos-tp6:
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
.*-qr/.*: ['mozilla-central', 'try']
|
||||
windows.*: []
|
||||
default: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
|
||||
max-run-time: 1200
|
||||
mozharness:
|
||||
@ -504,6 +505,7 @@ talos-tp6-stylo-threads:
|
||||
by-test-platform:
|
||||
.*-qr/.*: ['mozilla-central', 'try']
|
||||
macosx.*: ['mozilla-beta', 'autoland', 'try']
|
||||
windows.*: []
|
||||
default: ['mozilla-beta', 'mozilla-central', 'mozilla-inbound', 'autoland', 'try']
|
||||
mozharness:
|
||||
extra-options:
|
||||
|
@ -294,10 +294,3 @@ android-4.2-x86/opt:
|
||||
build-platform: android-x86/opt
|
||||
test-sets:
|
||||
- android-x86-tests
|
||||
|
||||
# android-4.3-arm7-api-16-gradle/opt actually uses the non-gradle build
|
||||
# which is tier 2, and requires only a smoketest, like robocop
|
||||
android-4.3-arm7-api-16-gradle/opt:
|
||||
build-platform: android-api-16-gradle/opt
|
||||
test-sets:
|
||||
- android-opt-tests
|
||||
|
@ -35,6 +35,7 @@ def enable_coalescing(config, jobs):
|
||||
'aws-provisioner-v1/gecko-t-win7-32-gpu',
|
||||
'aws-provisioner-v1/gecko-t-win10-64',
|
||||
'aws-provisioner-v1/gecko-t-win10-64-gpu',
|
||||
'releng-hardware/gecko-t-win10-64-hw',
|
||||
]:
|
||||
job['coalesce'] = {
|
||||
'job-identifier': sha256(job["label"]).hexdigest()[:20],
|
||||
|
@ -52,27 +52,27 @@ WINDOWS_WORKER_TYPES = {
|
||||
'windows7-32': {
|
||||
'virtual': 'aws-provisioner-v1/gecko-t-win7-32',
|
||||
'virtual-with-gpu': 'aws-provisioner-v1/gecko-t-win7-32-gpu',
|
||||
'hardware': 'releng-hardware/gecko-t-win7-32-hw',
|
||||
'hardware': 'releng-hardware/gecko-t-win10-64-hw',
|
||||
},
|
||||
'windows7-32-pgo': {
|
||||
'virtual': 'aws-provisioner-v1/gecko-t-win7-32',
|
||||
'virtual-with-gpu': 'aws-provisioner-v1/gecko-t-win7-32-gpu',
|
||||
'hardware': 'releng-hardware/gecko-t-win7-32-hw',
|
||||
'hardware': 'releng-hardware/gecko-t-win10-64-hw',
|
||||
},
|
||||
'windows7-32-nightly': {
|
||||
'virtual': 'aws-provisioner-v1/gecko-t-win7-32',
|
||||
'virtual-with-gpu': 'aws-provisioner-v1/gecko-t-win7-32-gpu',
|
||||
'hardware': 'releng-hardware/gecko-t-win7-32-hw',
|
||||
'hardware': 'releng-hardware/gecko-t-win10-64-hw',
|
||||
},
|
||||
'windows7-32-devedition': {
|
||||
'virtual': 'aws-provisioner-v1/gecko-t-win7-32',
|
||||
'virtual-with-gpu': 'aws-provisioner-v1/gecko-t-win7-32-gpu',
|
||||
'hardware': 'releng-hardware/gecko-t-win7-32-hw',
|
||||
'hardware': 'releng-hardware/gecko-t-win10-64-hw',
|
||||
},
|
||||
'windows7-32-stylo-disabled': {
|
||||
'virtual': 'aws-provisioner-v1/gecko-t-win7-32',
|
||||
'virtual-with-gpu': 'aws-provisioner-v1/gecko-t-win7-32-gpu',
|
||||
'hardware': 'releng-hardware/gecko-t-win7-32-hw',
|
||||
'hardware': 'releng-hardware/gecko-t-win10-64-hw',
|
||||
},
|
||||
'windows10-64': {
|
||||
'virtual': 'aws-provisioner-v1/gecko-t-win10-64',
|
||||
@ -916,25 +916,23 @@ def set_worker_type(config, tests):
|
||||
# during the taskcluster migration, this is a bit tortured, but it
|
||||
# will get simpler eventually!
|
||||
test_platform = test['test-platform']
|
||||
try_options = config.params['try_options'] if config.params['try_options'] else {}
|
||||
if test.get('worker-type'):
|
||||
# This test already has its worker type defined, so just use that (yields below)
|
||||
pass
|
||||
elif test_platform.startswith('macosx'):
|
||||
test['worker-type'] = MACOSX_WORKER_TYPES['macosx64']
|
||||
elif test_platform.startswith('win'):
|
||||
win_worker_type_platform = WINDOWS_WORKER_TYPES[
|
||||
test_platform.split('/')[0]
|
||||
]
|
||||
if test.get('suite', '') == 'talos' and 'ccov' not in test['build-platform']:
|
||||
if try_options.get('taskcluster_worker'):
|
||||
test['worker-type'] = win_worker_type_platform['hardware']
|
||||
elif test['virtualization'] == 'virtual':
|
||||
test['worker-type'] = win_worker_type_platform[test['virtualization']]
|
||||
else:
|
||||
test['worker-type'] = 'buildbot-bridge/buildbot-bridge'
|
||||
# figure out what platform the job needs to run on
|
||||
if test['virtualization'] == 'hardware':
|
||||
# some jobs like talos and reftest run on real h/w - those are all win10
|
||||
win_worker_type_platform = WINDOWS_WORKER_TYPES['windows10-64']
|
||||
else:
|
||||
test['worker-type'] = win_worker_type_platform[test['virtualization']]
|
||||
# the other jobs run on a vm which may or may not be a win10 vm
|
||||
win_worker_type_platform = WINDOWS_WORKER_TYPES[
|
||||
test_platform.split('/')[0]
|
||||
]
|
||||
# now we have the right platform set the worker type accordingly
|
||||
test['worker-type'] = win_worker_type_platform[test['virtualization']]
|
||||
elif test_platform.startswith('linux') or test_platform.startswith('android'):
|
||||
if test.get('suite', '') == 'talos' and test['build-platform'] != 'linux64-ccov/opt':
|
||||
test['worker-type'] = 'releng-hardware/gecko-t-linux-talos'
|
||||
@ -946,18 +944,6 @@ def set_worker_type(config, tests):
|
||||
yield test
|
||||
|
||||
|
||||
@transforms.add
|
||||
def skip_win10_hardware(config, tests):
|
||||
"""Windows 10 hardware isn't ready yet, don't even bother scheduling
|
||||
unless we're on try"""
|
||||
for test in tests:
|
||||
if 'releng-hardware/gecko-t-win10-64-hw' not in test['worker-type']:
|
||||
yield test
|
||||
if config.params == 'try':
|
||||
yield test
|
||||
# Silently drop the test on the floor if its win10 hardware and we're not try
|
||||
|
||||
|
||||
@transforms.add
|
||||
def make_job_description(config, tests):
|
||||
"""Convert *test* descriptions to *job* descriptions (input to
|
||||
|
@ -1,10 +0,0 @@
|
||||
config = {
|
||||
'base_name': 'Android armv7 api-16+ %(branch)s non-Gradle',
|
||||
'stage_platform': 'android-api-16-gradle',
|
||||
'build_type': 'api-16-gradle',
|
||||
'src_mozconfig': 'mobile/android/config/mozconfigs/android-api-16-gradle/nightly',
|
||||
'multi_locale_config_platform': 'android',
|
||||
'artifact_flag_build_variant_in_try': 'api-16-gradle-artifact',
|
||||
# Gradle is temporarily non-Gradle, and non-Gradle implies no geckoview.
|
||||
'postflight_build_mach_commands': [],
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
config = {
|
||||
'base_name': 'Android armv7 api-16+ %(branch)s non-Gradle Artifact build',
|
||||
'stage_platform': 'android-api-16-gradle',
|
||||
'build_type': 'api-16-gradle-artifact',
|
||||
'src_mozconfig': 'mobile/android/config/mozconfigs/android-api-16-gradle/nightly-artifact',
|
||||
'tooltool_manifest_src': 'mobile/android/config/tooltool-manifests/android/releng.manifest',
|
||||
'multi_locale_config_platform': 'android',
|
||||
# Gradle is temporarily non-Gradle, and non-Gradle implies no geckoview.
|
||||
'postflight_build_mach_commands': [],
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
|
||||
PYTHON = 'c:/mozilla-build/python27/python.exe'
|
||||
PYTHON = sys.executable
|
||||
PYTHON_DLL = 'c:/mozilla-build/python27/python27.dll'
|
||||
VENV_PATH = os.path.join(os.getcwd(), 'build/venv')
|
||||
|
||||
@ -22,7 +23,8 @@ config = {
|
||||
'%s/scripts/easy_install-2.7-script.py' % VENV_PATH],
|
||||
'mozinstall': ['%s/scripts/python' % VENV_PATH,
|
||||
'%s/scripts/mozinstall-script.py' % VENV_PATH],
|
||||
'hg': 'c:/mozilla-build/hg/hg',
|
||||
'hg': os.path.join(os.environ['PROGRAMFILES'], 'Mercurial', 'hg'),
|
||||
'tooltool.py': [PYTHON, os.path.join(os.environ['MOZILLABUILD'], 'tooltool.py')],
|
||||
},
|
||||
"title": socket.gethostname().split('.')[0],
|
||||
"default_actions": [
|
||||
|
Loading…
Reference in New Issue
Block a user