Merge autoland to central, a=merge
MozReview-Commit-ID: FOw9Q98gVXH
@ -8,6 +8,7 @@ support-files =
|
||||
|
||||
[test_aria_alert.html]
|
||||
[test_aria_menu.html]
|
||||
skip-if = stylo # bug 1390409
|
||||
[test_aria_objattr.html]
|
||||
[test_aria_owns.html]
|
||||
[test_aria_statechange.html]
|
||||
@ -20,6 +21,7 @@ support-files =
|
||||
[test_contextmenu.html]
|
||||
[test_descrchange.html]
|
||||
[test_docload.html]
|
||||
skip-if = stylo # bug 1390409
|
||||
[test_docload_aria.html]
|
||||
[test_dragndrop.html]
|
||||
[test_flush.html]
|
||||
@ -43,6 +45,7 @@ skip-if = os == 'win' || os == 'linux'
|
||||
[test_label.xul]
|
||||
[test_menu.xul]
|
||||
[test_mutation.html]
|
||||
skip-if = stylo # bug 1390409
|
||||
[test_mutation.xhtml]
|
||||
[test_namechange.xul]
|
||||
[test_namechange.html]
|
||||
|
@ -39,4 +39,5 @@ skip-if = buildapp == "mulet"
|
||||
[test_table.html]
|
||||
[test_textleaf.html]
|
||||
[test_visibility.html]
|
||||
skip-if = stylo # bug 1390409
|
||||
[test_whitespace.html]
|
||||
|
@ -1944,6 +1944,69 @@ var BookmarkingUI = {
|
||||
PanelUI.hide();
|
||||
},
|
||||
|
||||
showBookmarkingTools(triggerNode) {
|
||||
const panelID = "PanelUI-bookmarkingTools";
|
||||
let viewNode = document.getElementById(panelID);
|
||||
for (let button of [...viewNode.getElementsByTagName("toolbarbutton")]) {
|
||||
let update = true;
|
||||
switch (button.id) {
|
||||
case "panelMenu_toggleBookmarksMenu":
|
||||
let placement = CustomizableUI.getPlacementOfWidget(this.BOOKMARK_BUTTON_ID);
|
||||
button.setAttribute("checked", !!placement && placement.area == CustomizableUI.AREA_NAVBAR);
|
||||
break;
|
||||
case "panelMenu_viewBookmarksSidebar":
|
||||
button.setAttribute("checked", SidebarUI.currentID == "viewBookmarksSidebar");
|
||||
break;
|
||||
default:
|
||||
update = false;
|
||||
break;
|
||||
}
|
||||
if (update) {
|
||||
updateToggleControlLabel(button);
|
||||
}
|
||||
}
|
||||
PanelUI.showSubView(panelID, triggerNode);
|
||||
},
|
||||
|
||||
toggleMenuButtonInToolbar(triggerNode) {
|
||||
let placement = CustomizableUI.getPlacementOfWidget(this.BOOKMARK_BUTTON_ID);
|
||||
const area = CustomizableUI.AREA_NAVBAR;
|
||||
if (!placement) {
|
||||
// Button is in the palette, so we can move it to the navbar.
|
||||
let pos;
|
||||
let widgetIDs = CustomizableUI.getWidgetIdsInArea(CustomizableUI.AREA_NAVBAR);
|
||||
// If there's a spring inside the navbar, find it and use that as the
|
||||
// placement marker.
|
||||
let lastSpringID = null;
|
||||
for (let i = widgetIDs.length - 1; i >= 0; --i) {
|
||||
let id = widgetIDs[i];
|
||||
if (CustomizableUI.isSpecialWidget(id) && /spring/.test(id)) {
|
||||
lastSpringID = id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lastSpringID) {
|
||||
pos = CustomizableUI.getPlacementOfWidget(lastSpringID).position + 1;
|
||||
} else {
|
||||
// Next alternative is to use the searchbar as the placement marker.
|
||||
const searchWidgetID = "search-container";
|
||||
if (widgetIDs.includes(searchWidgetID)) {
|
||||
pos = CustomizableUI.getPlacementOfWidget(searchWidgetID).position + 1;
|
||||
} else {
|
||||
// Last alternative is to use the navbar as the placement marker.
|
||||
pos = CustomizableUI.getPlacementOfWidget("urlbar-container").position + 1;
|
||||
}
|
||||
}
|
||||
|
||||
CustomizableUI.addWidgetToArea(this.BOOKMARK_BUTTON_ID, area, pos);
|
||||
} else {
|
||||
// Move it back to the palette.
|
||||
CustomizableUI.removeWidgetFromArea(this.BOOKMARK_BUTTON_ID);
|
||||
}
|
||||
triggerNode.setAttribute("checked", !placement);
|
||||
updateToggleControlLabel(triggerNode);
|
||||
},
|
||||
|
||||
// nsINavBookmarkObserver
|
||||
onItemAdded(aItemId, aParentId, aIndex, aItemType, aURI, aTitle, aDateAdded, aGuid) {
|
||||
if (aURI && aURI.equals(this._uri)) {
|
||||
|
@ -288,10 +288,12 @@ var SidebarUI = {
|
||||
* with a different commandID, then the sidebar will be opened using the
|
||||
* specified commandID. Otherwise the sidebar will be hidden.
|
||||
*
|
||||
* @param {string} commandID ID of the xul:broadcaster element to use.
|
||||
* @param {string} commandID ID of the xul:broadcaster element to use.
|
||||
* @param {DOMNode} [triggerNode] Node, usually a button, that triggered the
|
||||
* visibility toggling of the sidebar.
|
||||
* @return {Promise}
|
||||
*/
|
||||
toggle(commandID = this.lastOpenedId) {
|
||||
toggle(commandID = this.lastOpenedId, triggerNode) {
|
||||
// First priority for a default value is this.lastOpenedId which is set during show()
|
||||
// and not reset in hide(), unlike currentID. If show() hasn't been called or the command
|
||||
// doesn't exist anymore, then fallback to a default sidebar.
|
||||
@ -300,10 +302,10 @@ var SidebarUI = {
|
||||
}
|
||||
|
||||
if (this.isOpen && commandID == this.currentID) {
|
||||
this.hide();
|
||||
this.hide(triggerNode);
|
||||
return Promise.resolve();
|
||||
}
|
||||
return this.show(commandID);
|
||||
return this.show(commandID, triggerNode);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -312,10 +314,15 @@ var SidebarUI = {
|
||||
*
|
||||
* This wraps the internal method, including a ping to telemetry.
|
||||
*
|
||||
* @param {string} commandID ID of the xul:broadcaster element to use.
|
||||
* @param {string} commandID ID of the xul:broadcaster element to use.
|
||||
* @param {DOMNode} [triggerNode] Node, usually a button, that triggered the
|
||||
* showing of the sidebar.
|
||||
*/
|
||||
show(commandID) {
|
||||
show(commandID, triggerNode) {
|
||||
return this._show(commandID).then(() => {
|
||||
if (triggerNode) {
|
||||
updateToggleControlLabel(triggerNode);
|
||||
}
|
||||
BrowserUITelemetry.countSidebarEvent(commandID, "show");
|
||||
});
|
||||
},
|
||||
@ -403,8 +410,11 @@ var SidebarUI = {
|
||||
|
||||
/**
|
||||
* Hide the sidebar.
|
||||
*
|
||||
* @param {DOMNode} [triggerNode] Node, usually a button, that triggered the
|
||||
* hiding of the sidebar.
|
||||
*/
|
||||
hide() {
|
||||
hide(triggerNode) {
|
||||
if (!this.isOpen) {
|
||||
return;
|
||||
}
|
||||
@ -437,6 +447,9 @@ var SidebarUI = {
|
||||
selBrowser.messageManager.sendAsyncMessage("Sidebar:VisibilityChange",
|
||||
{commandID, isOpen: false}
|
||||
);
|
||||
if (triggerNode) {
|
||||
updateToggleControlLabel(triggerNode);
|
||||
}
|
||||
BrowserUITelemetry.countSidebarEvent(commandID, "hide");
|
||||
},
|
||||
};
|
||||
|
@ -5481,9 +5481,11 @@ function onViewToolbarsPopupShowing(aEvent, aInsertPoint) {
|
||||
}
|
||||
|
||||
function onViewToolbarCommand(aEvent) {
|
||||
var toolbarId = aEvent.originalTarget.getAttribute("toolbarId");
|
||||
var isVisible = aEvent.originalTarget.getAttribute("checked") == "true";
|
||||
let node = aEvent.originalTarget;
|
||||
let toolbarId = node.getAttribute("toolbarId");
|
||||
let isVisible = node.getAttribute("checked") == "true";
|
||||
CustomizableUI.setToolbarVisibility(toolbarId, isVisible);
|
||||
updateToggleControlLabel(node);
|
||||
}
|
||||
|
||||
function setToolbarVisibility(toolbar, isVisible, persist = true) {
|
||||
@ -5515,6 +5517,18 @@ function setToolbarVisibility(toolbar, isVisible, persist = true) {
|
||||
BookmarkingUI.onToolbarVisibilityChange();
|
||||
}
|
||||
|
||||
function updateToggleControlLabel(control) {
|
||||
if (!control.hasAttribute("label-checked")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!control.hasAttribute("label-unchecked")) {
|
||||
control.setAttribute("label-unchecked", control.getAttribute("label"));
|
||||
}
|
||||
let prefix = (control.getAttribute("checked") == "true") ? "" : "un";
|
||||
control.setAttribute("label", control.getAttribute(`label-${prefix}checked`));
|
||||
}
|
||||
|
||||
var TabletModeUpdater = {
|
||||
init() {
|
||||
if (AppConstants.isPlatformAndVersionAtLeast("win", "10")) {
|
||||
|
@ -446,6 +446,7 @@
|
||||
type="arrow"
|
||||
hidden="true"
|
||||
flip="slide"
|
||||
photon="true"
|
||||
position="bottomcenter topright"
|
||||
tabspecific="true"
|
||||
noautofocus="true"
|
||||
|
@ -703,6 +703,12 @@ this.PanelMultiView = class {
|
||||
return;
|
||||
}
|
||||
|
||||
// If this instance was destructed in the meantime, there's no point in
|
||||
// trying to show anything here.
|
||||
if (!this.node) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._currentSubView = viewNode;
|
||||
viewNode.setAttribute("current", true);
|
||||
|
||||
|
@ -234,13 +234,11 @@
|
||||
observes="bookmarkThisPageBroadcaster"
|
||||
command="Browser:AddBookmarkAs"
|
||||
onclick="PanelUI.hide();"/>
|
||||
<toolbarbutton id="panelMenu_viewBookmarksSidebar"
|
||||
label="&viewBookmarksSidebar2.label;"
|
||||
class="subviewbutton subviewbutton-iconic"
|
||||
key="viewBookmarksSidebarKb"
|
||||
oncommand="SidebarUI.toggle('viewBookmarksSidebar'); PanelUI.hide();">
|
||||
<observes element="viewBookmarksSidebar" attribute="checked"/>
|
||||
</toolbarbutton>
|
||||
<toolbarbutton id="panelMenu_bookmarkingTools"
|
||||
label="&bookmarkingTools.label;"
|
||||
class="subviewbutton subviewbutton-iconic subviewbutton-nav"
|
||||
closemenu="none"
|
||||
oncommand="BookmarkingUI.showBookmarkingTools(this);"/>
|
||||
<toolbarbutton id="panelMenu_searchBookmarks"
|
||||
label="&searchBookmarks.label;"
|
||||
class="subviewbutton subviewbutton-iconic"
|
||||
@ -351,6 +349,7 @@
|
||||
type="arrow"
|
||||
noautofocus="true"
|
||||
position="bottomcenter topright"
|
||||
photon="true"
|
||||
hidden="true">
|
||||
<photonpanelmultiview mainViewId="widget-overflow-mainView">
|
||||
<panelview id="widget-overflow-mainView"
|
||||
@ -736,5 +735,31 @@
|
||||
oncommand="PanelUI.showSubView('PanelUI-remotetabs', this)"/>
|
||||
</vbox>
|
||||
</panelview>
|
||||
|
||||
<panelview id="PanelUI-bookmarkingTools" class="PanelUI-subView">
|
||||
<vbox class="panel-subview-body">
|
||||
<toolbarbutton id="panelMenu_toggleBookmarksMenu"
|
||||
label="&addBookmarksMenu.label;"
|
||||
label-checked="&removeBookmarksMenu.label;"
|
||||
class="subviewbutton subviewbutton-iconic"
|
||||
oncommand="BookmarkingUI.toggleMenuButtonInToolbar(this); PanelUI.hide();"/>
|
||||
<toolbarbutton id="panelMenu_viewBookmarksSidebar"
|
||||
label="&viewBookmarksSidebar2.label;"
|
||||
label-checked="&hideBookmarksSidebar.label;"
|
||||
class="subviewbutton subviewbutton-iconic"
|
||||
key="viewBookmarksSidebarKb"
|
||||
oncommand="SidebarUI.toggle('viewBookmarksSidebar', this); PanelUI.hide();">
|
||||
<observes element="viewBookmarksSidebar" attribute="checked"/>
|
||||
</toolbarbutton>
|
||||
<toolbarbutton id="panelMenu_viewBookmarksToolbar"
|
||||
class="subviewbutton subviewbutton-iconic"
|
||||
placesanonid="view-toolbar"
|
||||
toolbarId="PersonalToolbar"
|
||||
type="checkbox"
|
||||
oncommand="onViewToolbarCommand(event)"
|
||||
label="&viewBookmarksToolbar.label;"
|
||||
label-checked="&hideBookmarksToolbar.label;"/>
|
||||
</vbox>
|
||||
</panelview>
|
||||
</photonpanelmultiview>
|
||||
</panel>
|
||||
|
@ -948,7 +948,6 @@ var gMainPane = {
|
||||
let rv = Services.prompt.confirmEx(window, title, message, buttonFlags,
|
||||
okButton, cancelButton, null, null, {});
|
||||
if (rv == 0) {
|
||||
ContextualIdentityService.closeContainerTabs();
|
||||
Services.prefs.setBoolPref("privacy.userContext.enabled", false);
|
||||
return;
|
||||
}
|
||||
|
@ -87,7 +87,6 @@ var gPrivacyPane = {
|
||||
|
||||
let count = ContextualIdentityService.countContainerTabs();
|
||||
if (count == 0) {
|
||||
ContextualIdentityService.notifyAllContainersCleared();
|
||||
Services.prefs.setBoolPref("privacy.userContext.enabled", false);
|
||||
return;
|
||||
}
|
||||
@ -108,9 +107,6 @@ var gPrivacyPane = {
|
||||
okButton, cancelButton, null, null, {});
|
||||
if (rv == 0) {
|
||||
Services.prefs.setBoolPref("privacy.userContext.enabled", false);
|
||||
ContextualIdentityService.closeContainerTabs().then(() => {
|
||||
ContextualIdentityService.notifyAllContainersCleared();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -835,8 +835,8 @@ this.UITour = {
|
||||
node: aWindow.PanelUI.panel,
|
||||
events: [
|
||||
[ "popuphidden", this.onPanelHidden ],
|
||||
[ "popuphiding", this.hideAppMenuAnnotations ],
|
||||
[ "ViewShowing", this.hideAppMenuAnnotations ]
|
||||
[ "popuphiding", this.onAppMenuHiding ],
|
||||
[ "ViewShowing", this.onAppMenuSubviewShowing ]
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -844,8 +844,8 @@ this.UITour = {
|
||||
node: aWindow.BrowserPageActions.panelNode,
|
||||
events: [
|
||||
[ "popuphidden", this.onPanelHidden ],
|
||||
[ "popuphiding", this.hidePageActionPanelAnnotations ],
|
||||
[ "ViewShowing", this.hidePageActionPanelAnnotations ]
|
||||
[ "popuphiding", this.onPageActionPanelHiding ],
|
||||
[ "ViewShowing", this.onPageActionPanelSubviewShowing ]
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -853,7 +853,7 @@ this.UITour = {
|
||||
node: aWindow.gIdentityHandler._identityPopup,
|
||||
events: [
|
||||
[ "popuphidden", this.onPanelHidden ],
|
||||
[ "popuphiding", this.hideControlCenterAnnotations ]
|
||||
[ "popuphiding", this.onControlCenterHiding ]
|
||||
]
|
||||
},
|
||||
];
|
||||
@ -1125,7 +1125,7 @@ this.UITour = {
|
||||
* @see UITour.highlightEffects
|
||||
*/
|
||||
async showHighlight(aChromeWindow, aTarget, aEffect = "none") {
|
||||
let showHighlightPanel = (aAnchorEl) => {
|
||||
let showHighlightElement = (aAnchorEl) => {
|
||||
let highlighter = aChromeWindow.document.getElementById("UITourHighlight");
|
||||
|
||||
let effect = aEffect;
|
||||
@ -1185,17 +1185,21 @@ this.UITour = {
|
||||
try {
|
||||
await this._ensureTarget(aChromeWindow, aTarget);
|
||||
let anchorEl = await this._correctAnchor(aChromeWindow, aTarget);
|
||||
showHighlightPanel(anchorEl);
|
||||
showHighlightElement(anchorEl);
|
||||
} catch (e) {
|
||||
log.warn(e);
|
||||
}
|
||||
},
|
||||
|
||||
hideHighlight(aWindow) {
|
||||
_hideHighlightElement(aWindow) {
|
||||
let highlighter = aWindow.document.getElementById("UITourHighlight");
|
||||
this._removeAnnotationPanelMutationObserver(highlighter.parentElement);
|
||||
highlighter.parentElement.hidePopup();
|
||||
highlighter.removeAttribute("active");
|
||||
},
|
||||
|
||||
hideHighlight(aWindow) {
|
||||
this._hideHighlightElement(aWindow);
|
||||
this._setMenuStateForAnnotation(aWindow, false, "appMenu");
|
||||
this._setMenuStateForAnnotation(aWindow, false, "pageActionPanel");
|
||||
},
|
||||
@ -1215,7 +1219,7 @@ this.UITour = {
|
||||
*/
|
||||
async showInfo(aChromeWindow, aAnchor, aTitle = "", aDescription = "",
|
||||
aIconURL = "", aButtons = [], aOptions = {}) {
|
||||
let showInfoPanel = (aAnchorEl) => {
|
||||
let showInfoElement = (aAnchorEl) => {
|
||||
aAnchorEl.focus();
|
||||
|
||||
let document = aChromeWindow.document;
|
||||
@ -1314,7 +1318,7 @@ this.UITour = {
|
||||
try {
|
||||
await this._ensureTarget(aChromeWindow, aAnchor);
|
||||
let anchorEl = await this._correctAnchor(aChromeWindow, aAnchor);
|
||||
showInfoPanel(anchorEl);
|
||||
showInfoElement(anchorEl);
|
||||
} catch (e) {
|
||||
log.warn(e);
|
||||
}
|
||||
@ -1326,19 +1330,22 @@ this.UITour = {
|
||||
return tooltip.getAttribute("targetName") == aTargetName && tooltip.state != "closed";
|
||||
},
|
||||
|
||||
hideInfo(aWindow) {
|
||||
_hideInfoElement(aWindow) {
|
||||
let document = aWindow.document;
|
||||
let tooltip = document.getElementById("UITourTooltip");
|
||||
this._removeAnnotationPanelMutationObserver(tooltip);
|
||||
tooltip.hidePopup();
|
||||
this._setMenuStateForAnnotation(aWindow, false, "appMenu");
|
||||
this._setMenuStateForAnnotation(aWindow, false, "pageActionPanel");
|
||||
|
||||
let tooltipButtons = document.getElementById("UITourTooltipButtons");
|
||||
while (tooltipButtons.firstChild)
|
||||
tooltipButtons.firstChild.remove();
|
||||
},
|
||||
|
||||
hideInfo(aWindow) {
|
||||
this._hideInfoElement(aWindow);
|
||||
this._setMenuStateForAnnotation(aWindow, false, "appMenu");
|
||||
this._setMenuStateForAnnotation(aWindow, false, "pageActionPanel");
|
||||
},
|
||||
|
||||
showMenu(aWindow, aMenuName, aOpenCallback = null) {
|
||||
log.debug("showMenu:", aMenuName);
|
||||
function openMenuButton(aMenuBtn) {
|
||||
@ -1358,11 +1365,13 @@ this.UITour = {
|
||||
};
|
||||
if (aMenuName == "appMenu") {
|
||||
menu.node = aWindow.PanelUI.panel;
|
||||
menu.hideMenuAnnotations = this.hideAppMenuAnnotations;
|
||||
menu.onPopupHiding = this.onAppMenuHiding;
|
||||
menu.onViewShowing = this.onAppMenuSubviewShowing;
|
||||
menu.show = () => aWindow.PanelUI.show();
|
||||
} else {
|
||||
menu.node = aWindow.BrowserPageActions.panelNode;
|
||||
menu.hideMenuAnnotations = this.hidePageActionPanelAnnotations;
|
||||
menu.onPopupHiding = this.onPageActionPanelHiding;
|
||||
menu.onViewShowing = this.onPageActionPanelSubviewShowing;
|
||||
menu.show = () => aWindow.BrowserPageActions.showPanel();
|
||||
}
|
||||
|
||||
@ -1375,8 +1384,8 @@ this.UITour = {
|
||||
menu.node.addEventListener("popupshown", aOpenCallback, { once: true });
|
||||
}
|
||||
menu.node.addEventListener("popuphidden", menu.onPanelHidden);
|
||||
menu.node.addEventListener("popuphiding", menu.hideMenuAnnotations);
|
||||
menu.node.addEventListener("ViewShowing", menu.hideMenuAnnotations);
|
||||
menu.node.addEventListener("popuphiding", menu.onPopupHiding);
|
||||
menu.node.addEventListener("ViewShowing", menu.onViewShowing);
|
||||
menu.show();
|
||||
} else if (aMenuName == "bookmarks") {
|
||||
let menuBtn = aWindow.document.getElementById("bookmarks-menu-button");
|
||||
@ -1386,7 +1395,7 @@ this.UITour = {
|
||||
|
||||
// Add the listener even if the panel is already open since it will still
|
||||
// only get registered once even if it was UITour that opened it.
|
||||
popup.addEventListener("popuphiding", this.hideControlCenterAnnotations);
|
||||
popup.addEventListener("popuphiding", this.onControlCenterHiding);
|
||||
popup.addEventListener("popuphidden", this.onPanelHidden);
|
||||
|
||||
popup.setAttribute("noautohide", "true");
|
||||
@ -1491,12 +1500,22 @@ this.UITour = {
|
||||
aWindow.openLinkIn("about:newtab", "current", {targetBrowser: aBrowser});
|
||||
},
|
||||
|
||||
_hideAnnotationsForPanel(aEvent, aTargetPositionCallback) {
|
||||
_hideAnnotationsForPanel(aEvent, aShouldClosePanel, aTargetPositionCallback) {
|
||||
let win = aEvent.target.ownerGlobal;
|
||||
let hideHighlightMethod = null;
|
||||
let hideInfoMethod = null;
|
||||
if (aShouldClosePanel) {
|
||||
hideHighlightMethod = aWin => this.hideHighlight(aWin);
|
||||
hideInfoMethod = aWin => this.hideInfo(aWin);
|
||||
} else {
|
||||
// Don't have to close panel, let's only hide annotation elements
|
||||
hideHighlightMethod = aWin => this._hideHighlightElement(aWin);
|
||||
hideInfoMethod = aWin => this._hideInfoElement(aWin);
|
||||
}
|
||||
let annotationElements = new Map([
|
||||
// [annotationElement (panel), method to hide the annotation]
|
||||
[win.document.getElementById("UITourHighlightContainer"), UITour.hideHighlight.bind(UITour)],
|
||||
[win.document.getElementById("UITourTooltip"), UITour.hideInfo.bind(UITour)],
|
||||
[win.document.getElementById("UITourHighlightContainer"), hideHighlightMethod],
|
||||
[win.document.getElementById("UITourTooltip"), hideInfoMethod],
|
||||
]);
|
||||
annotationElements.forEach((hideMethod, annotationElement) => {
|
||||
if (annotationElement.state != "closed") {
|
||||
@ -1515,16 +1534,24 @@ this.UITour = {
|
||||
});
|
||||
},
|
||||
|
||||
hideAppMenuAnnotations(aEvent) {
|
||||
UITour._hideAnnotationsForPanel(aEvent, UITour.targetIsInAppMenu);
|
||||
onAppMenuHiding(aEvent) {
|
||||
UITour._hideAnnotationsForPanel(aEvent, true, UITour.targetIsInAppMenu);
|
||||
},
|
||||
|
||||
hidePageActionPanelAnnotations(aEvent) {
|
||||
UITour._hideAnnotationsForPanel(aEvent, UITour.targetIsInPageActionPanel);
|
||||
onAppMenuSubviewShowing(aEvent) {
|
||||
UITour._hideAnnotationsForPanel(aEvent, false, UITour.targetIsInAppMenu);
|
||||
},
|
||||
|
||||
hideControlCenterAnnotations(aEvent) {
|
||||
UITour._hideAnnotationsForPanel(aEvent, (aTarget) => {
|
||||
onPageActionPanelHiding(aEvent) {
|
||||
UITour._hideAnnotationsForPanel(aEvent, true, UITour.targetIsInPageActionPanel);
|
||||
},
|
||||
|
||||
onPageActionPanelSubviewShowing(aEvent) {
|
||||
UITour._hideAnnotationsForPanel(aEvent, false, UITour.targetIsInPageActionPanel);
|
||||
},
|
||||
|
||||
onControlCenterHiding(aEvent) {
|
||||
UITour._hideAnnotationsForPanel(aEvent, true, (aTarget) => {
|
||||
return aTarget.targetName.startsWith("controlCenter-");
|
||||
});
|
||||
},
|
||||
|
@ -28,6 +28,7 @@ skip-if = os == "linux" # Intermittent failures, bug 951965
|
||||
[browser_UITour2.js]
|
||||
[browser_UITour3.js]
|
||||
[browser_UITour4.js]
|
||||
[browser_UITour5.js]
|
||||
skip-if = os == "linux" # Linux: Bug 986760, Bug 989101.
|
||||
[browser_UITour_availableTargets.js]
|
||||
[browser_UITour_annotation_size_attributes.js]
|
||||
|
41
browser/components/uitour/test/browser_UITour5.js
Normal file
@ -0,0 +1,41 @@
|
||||
"use strict";
|
||||
|
||||
var gTestTab;
|
||||
var gContentAPI;
|
||||
var gContentWindow;
|
||||
|
||||
add_task(setup_UITourTest);
|
||||
|
||||
add_UITour_task(async function test_highlight_library_and_show_library_subview() {
|
||||
let highlight = document.getElementById("UITourHighlight");
|
||||
is_element_hidden(highlight, "Highlight should initially be hidden");
|
||||
|
||||
// Test highlighting the library button
|
||||
let appMenu = PanelUI.panel;
|
||||
let appMenuShownPromise = promisePanelElementShown(window, appMenu);
|
||||
let highlightVisiblePromise = elementVisiblePromise(highlight, "Should show highlight");
|
||||
gContentAPI.showHighlight("library");
|
||||
await appMenuShownPromise;
|
||||
await highlightVisiblePromise;
|
||||
is(appMenu.state, "open", "Should open the app menu to highlight the library button");
|
||||
is(getShowHighlightTargetName(), "library", "Should highlight the library button on the app menu");
|
||||
|
||||
// Click the library button to show the subview
|
||||
let ViewShownPromise = new Promise(resolve => {
|
||||
appMenu.addEventListener("ViewShown", resolve, { once: true });
|
||||
});
|
||||
let highlightHiddenPromise = elementHiddenPromise(highlight, "Should hide highlight");
|
||||
let libraryBtn = document.getElementById("appMenu-library-button");
|
||||
libraryBtn.dispatchEvent(new Event("command"));
|
||||
await highlightHiddenPromise;
|
||||
await ViewShownPromise;
|
||||
is(PanelUI.multiView.current.id, "appMenu-libraryView", "Should show the library subview");
|
||||
is(appMenu.state, "open", "Should still open the app menu for the library subview");
|
||||
|
||||
// Clean up
|
||||
let appMenuHiddenPromise = promisePanelElementHidden(window, appMenu);
|
||||
gContentAPI.hideMenu("appMenu");
|
||||
await appMenuHiddenPromise;
|
||||
is(appMenu.state, "closed", "Should close the app menu");
|
||||
});
|
||||
|
@ -34,8 +34,6 @@ class ProfileAutoCompleteResult {
|
||||
this.searchString = searchString;
|
||||
// The field name of the focused input.
|
||||
this._focusedFieldName = focusedFieldName;
|
||||
// All field names in the form which contains the focused input.
|
||||
this._allFieldNames = allFieldNames;
|
||||
// The matching profiles contains the information for filling forms.
|
||||
this._matchingProfiles = matchingProfiles;
|
||||
// The default item that should be entered if none is selected
|
||||
@ -44,6 +42,14 @@ class ProfileAutoCompleteResult {
|
||||
this.errorDescription = "";
|
||||
// The value used to determine whether the form is secure or not.
|
||||
this._isSecure = isSecure;
|
||||
// All fillable field names in the form including the field name of the currently-focused input.
|
||||
this._allFieldNames = [...this._matchingProfiles.reduce((fieldSet, curProfile) => {
|
||||
for (let field of Object.keys(curProfile)) {
|
||||
fieldSet.add(field);
|
||||
}
|
||||
|
||||
return fieldSet;
|
||||
}, new Set())].filter(field => allFieldNames.includes(field));
|
||||
|
||||
// The result code of this result object.
|
||||
if (resultCode) {
|
||||
|
@ -174,57 +174,41 @@
|
||||
);
|
||||
|
||||
/**
|
||||
* Update the text on the footer.
|
||||
* A handler for updating warning message once selectedIndex has been changed.
|
||||
*
|
||||
* There're three different states of warning message:
|
||||
* 1. None of addresses were selected: We show all the categories intersection of fields in the
|
||||
* form and fields in the results.
|
||||
* 2. An address was selested: Show the additional categories that will also be filled.
|
||||
* 3. An address was selected, but the focused category is the same as the only one category: Only show
|
||||
* the exact category that we're going to fill in.
|
||||
*
|
||||
* @private
|
||||
* @param {string|string[]} categories
|
||||
* A list of categories that used to generate the message.
|
||||
* @param {boolean} hasExtraCategories
|
||||
* Used to determine if it has the extra categories other than the focued category. If
|
||||
* the value is true, we show "Also fill ...", otherwise, show "Fill ..." only.
|
||||
* @param {string[]} data.categories
|
||||
* The categories of all the fields contained in the selected address.
|
||||
*/
|
||||
const namespace = "category.";
|
||||
this._updateText = (categories = this._allFieldCategories, hasExtraCategories = true) => {
|
||||
let warningTextTmplKey = hasExtraCategories ? "phishingWarningMessage" : "phishingWarningMessage2";
|
||||
let sep = this._stringBundle.GetStringFromName("fieldNameSeparator");
|
||||
this._updateWarningNote = ({data} = {}) => {
|
||||
let categories = (data && data.categories) ? data.categories : this._allFieldCategories;
|
||||
// If the length of categories is 1, that means all the fillable fields are in the same
|
||||
// category. We will change the way to inform user according to this flag. When the value
|
||||
// is true, we show "Also autofills ...", otherwise, show "Autofills ..." only.
|
||||
let hasExtraCategories = categories.length > 1;
|
||||
// Show the categories in certain order to conform with the spec.
|
||||
let orderedCategoryList = ["address", "name", "organization", "tel", "email"];
|
||||
let showCategories = hasExtraCategories ?
|
||||
orderedCategoryList.filter(category => categories.includes(category) && category != this._focusedCategory) :
|
||||
[this._focusedCategory];
|
||||
let categoriesText = showCategories.map(category => this._stringBundle.GetStringFromName(namespace + category)).join(sep);
|
||||
|
||||
let separator = this._stringBundle.GetStringFromName("fieldNameSeparator");
|
||||
let warningTextTmplKey = hasExtraCategories ? "phishingWarningMessage" : "phishingWarningMessage2";
|
||||
let categoriesText = showCategories.map(category => this._stringBundle.GetStringFromName(namespace + category)).join(separator);
|
||||
|
||||
this._warningTextBox.textContent = this._stringBundle.formatStringFromName(warningTextTmplKey,
|
||||
[categoriesText], 1);
|
||||
this.parentNode.parentNode.adjustHeight();
|
||||
};
|
||||
|
||||
/**
|
||||
* A handler for updating warning message once selectedIndex has been changed.
|
||||
*
|
||||
* There're three different states of warning message:
|
||||
* 1. None of addresses were selected: We show all the categories in the form.
|
||||
* 2. An address was selested: Show the additional categories that will also be filled.
|
||||
* 3. An address was selected, but the focused category is the same as the only all categories: Only show
|
||||
* the exact category that we're going to fill in.
|
||||
*
|
||||
* @private
|
||||
* @param {string[]} categories
|
||||
* The categories of all the fields contained in the selected address.
|
||||
*/
|
||||
this._updateWarningMsgHandler = ({data: {categories}} = {data: {}}) => {
|
||||
let hasSelectedAddress = this._focusedCategory && categories;
|
||||
// If the length of categories is 1, that means all the fillable fields are in the same
|
||||
// category. We will change the way to inform user according to this flag.
|
||||
let hasExtraCategories = hasSelectedAddress && categories.length > 1;
|
||||
if (!hasSelectedAddress) {
|
||||
this._updateText();
|
||||
return;
|
||||
}
|
||||
|
||||
this._updateText(categories, hasExtraCategories);
|
||||
};
|
||||
|
||||
this._adjustAcItem();
|
||||
]]>
|
||||
</constructor>
|
||||
@ -235,7 +219,7 @@
|
||||
/* global messageManager */
|
||||
|
||||
if (this.showWarningText) {
|
||||
messageManager.removeMessageListener("FormAutofill:UpdateWarningMessage", this._updateWarningMsgHandler);
|
||||
messageManager.removeMessageListener("FormAutofill:UpdateWarningMessage", this._updateWarningNote);
|
||||
}
|
||||
|
||||
this._itemBox.removeAttribute("no-warning");
|
||||
@ -268,9 +252,9 @@
|
||||
this.showWarningText = this._allFieldCategories && this._focusedCategory;
|
||||
|
||||
if (this.showWarningText) {
|
||||
messageManager.addMessageListener("FormAutofill:UpdateWarningMessage", this._updateWarningMsgHandler);
|
||||
messageManager.addMessageListener("FormAutofill:UpdateWarningMessage", this._updateWarningNote);
|
||||
|
||||
this._updateText();
|
||||
this._updateWarningNote();
|
||||
} else {
|
||||
this._itemBox.setAttribute("no-warning", "true");
|
||||
}
|
||||
|
@ -14,9 +14,10 @@ async function expectWarningText(browser, expectedText) {
|
||||
}
|
||||
|
||||
add_task(async function setup_storage() {
|
||||
await saveAddress(TEST_ADDRESS_1);
|
||||
await saveAddress(TEST_ADDRESS_2);
|
||||
await saveAddress(TEST_ADDRESS_3);
|
||||
await saveAddress(TEST_ADDRESS_4);
|
||||
await saveAddress(TEST_ADDRESS_5);
|
||||
});
|
||||
|
||||
add_task(async function test_click_on_footer() {
|
||||
@ -54,21 +55,32 @@ add_task(async function test_press_enter_on_footer() {
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_phishing_warning() {
|
||||
add_task(async function test_phishing_warning_single_category() {
|
||||
await BrowserTestUtils.withNewTab({gBrowser, url: URL}, async function(browser) {
|
||||
const {autoCompletePopup: {richlistbox: itemsBox}} = browser;
|
||||
|
||||
await openPopupOn(browser, "#street-address");
|
||||
await openPopupOn(browser, "#tel");
|
||||
const warningBox = itemsBox.querySelector(".autocomplete-richlistitem:last-child")._warningTextBox;
|
||||
ok(warningBox, "Got phishing warning box");
|
||||
await expectWarningText(browser, "Also autofills company, phone, email");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await expectWarningText(browser, "Also autofills company, phone, email");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await expectWarningText(browser, "Autofills address");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await expectWarningText(browser, "Also autofills company, phone, email");
|
||||
|
||||
await expectWarningText(browser, "Autofills phone");
|
||||
|
||||
await closePopup(browser);
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_phishing_warning_complex_categories() {
|
||||
await BrowserTestUtils.withNewTab({gBrowser, url: URL}, async function(browser) {
|
||||
await openPopupOn(browser, "#street-address");
|
||||
|
||||
await expectWarningText(browser, "Also autofills company, email");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await expectWarningText(browser, "Autofills address");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await expectWarningText(browser, "Also autofills company, email");
|
||||
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
|
||||
await expectWarningText(browser, "Also autofills company, email");
|
||||
|
||||
await closePopup(browser);
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* exported MANAGE_ADDRESSES_DIALOG_URL, EDIT_ADDRESS_DIALOG_URL, BASE_URL,
|
||||
TEST_ADDRESS_1, TEST_ADDRESS_2, TEST_ADDRESS_3,
|
||||
TEST_ADDRESS_1, TEST_ADDRESS_2, TEST_ADDRESS_3, TEST_ADDRESS_4, TEST_ADDRESS_5,
|
||||
TEST_CREDIT_CARD_1, TEST_CREDIT_CARD_2, TEST_CREDIT_CARD_3,
|
||||
sleep, expectPopupOpen, openPopupOn, expectPopupClose, closePopup, clickDoorhangerButton,
|
||||
getAddresses, saveAddress, removeAddresses, saveCreditCard,
|
||||
@ -35,6 +35,19 @@ const TEST_ADDRESS_3 = {
|
||||
"postal-code": "12345",
|
||||
};
|
||||
|
||||
const TEST_ADDRESS_4 = {
|
||||
"given-name": "Timothy",
|
||||
"family-name": "Berners-Lee",
|
||||
organization: "World Wide Web Consortium",
|
||||
"street-address": "32 Vassar Street\nMIT Room 32-G524",
|
||||
country: "US",
|
||||
email: "timbl@w3.org",
|
||||
};
|
||||
|
||||
const TEST_ADDRESS_5 = {
|
||||
tel: "+16172535702",
|
||||
};
|
||||
|
||||
const TEST_CREDIT_CARD_1 = {
|
||||
"cc-name": "John Doe",
|
||||
"cc-number": "1234567812345678",
|
||||
|
@ -244,11 +244,16 @@ These should match what Safari and other Apple applications use on OS X Lion. --
|
||||
<!ENTITY bookmarksCmd.commandkey "b">
|
||||
|
||||
<!ENTITY bookmarksMenuButton.label "Bookmarks">
|
||||
<!ENTITY bookmarksMenuButton.other.label "Other Bookmarks">
|
||||
<!ENTITY bookmarksMenuButton.mobile.label "Mobile Bookmarks">
|
||||
<!ENTITY bookmarksMenuButton.other.label "Other Bookmarks">
|
||||
<!ENTITY bookmarksMenuButton.mobile.label "Mobile Bookmarks">
|
||||
<!ENTITY viewBookmarksSidebar2.label "View Bookmarks Sidebar">
|
||||
<!ENTITY hideBookmarksSidebar.label "Hide Bookmarks Sidebar">
|
||||
<!ENTITY viewBookmarksToolbar.label "View Bookmarks Toolbar">
|
||||
<!ENTITY hideBookmarksToolbar.label "Hide Bookmarks Toolbar">
|
||||
<!ENTITY searchBookmarks.label "Search Bookmarks">
|
||||
<!ENTITY bookmarkingTools.label "Bookmarking Tools">
|
||||
<!ENTITY addBookmarksMenu.label "Add Bookmarks Menu to Toolbar">
|
||||
<!ENTITY removeBookmarksMenu.label "Remove Bookmarks Menu from Toolbar">
|
||||
|
||||
<!ENTITY containersMenu.label "Containers">
|
||||
|
||||
|
@ -263,6 +263,7 @@ removeContainerOkButton=Remove this Container
|
||||
removeContainerButton2=Don’t remove this Container
|
||||
|
||||
# Search Input
|
||||
# LOCALIZATION NOTE: Please keep the placeholder string shorter than around 30 characters to avoid truncation.
|
||||
searchInput.labelWin=Find in Options
|
||||
searchInput.labelUnix=Find in Preferences
|
||||
|
||||
|
@ -396,7 +396,7 @@ html|*.addon-webext-perm-list {
|
||||
}
|
||||
|
||||
.addon-addon-icon {
|
||||
list-style-image: url("chrome://browser/skin/addons.svg");
|
||||
list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric-16.svg");
|
||||
}
|
||||
|
||||
.addon-toolbar-icon {
|
||||
|
@ -1359,7 +1359,7 @@ html|*.addon-webext-perm-list {
|
||||
}
|
||||
|
||||
.addon-addon-icon {
|
||||
list-style-image: url("chrome://browser/skin/addons.svg");
|
||||
list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric-16.svg");
|
||||
}
|
||||
|
||||
.addon-toolbar-icon {
|
||||
|
@ -63,3 +63,8 @@ body {
|
||||
margin-top: 1.2em;
|
||||
text-align: end;
|
||||
}
|
||||
|
||||
#advisory_provider {
|
||||
color: white;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
@ -257,7 +257,6 @@ photonpanelmultiview .panel-subview-header {
|
||||
}
|
||||
|
||||
#appMenu-popup > .panel-arrowcontainer > .panel-arrowcontent,
|
||||
#PanelUI-popup > .panel-arrowcontainer > .panel-arrowcontent,
|
||||
panel[photon] > .panel-arrowcontainer > .panel-arrowcontent {
|
||||
overflow: hidden;
|
||||
}
|
||||
@ -1693,8 +1692,6 @@ menuitem[checked="true"].subviewbutton > .menu-iconic-left {
|
||||
}
|
||||
|
||||
.panel-mainview[panelid=customizationui-widget-panel],
|
||||
#customizationui-widget-multiview > .panel-viewcontainer,
|
||||
#customizationui-widget-multiview > .panel-viewcontainer > .panel-viewstack,
|
||||
#PanelUI-panicView > .panel-subview-body,
|
||||
#PanelUI-panicView {
|
||||
overflow: visible;
|
||||
@ -2034,10 +2031,6 @@ photonpanelmultiview .PanelUI-subView toolbarseparator {
|
||||
margin-inline-end: 0;
|
||||
}
|
||||
|
||||
photonpanelmultiview#customizationui-widget-multiview > .panel-viewcontainer {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* This is explicitly overriding the overflow properties set above. */
|
||||
photonpanelmultiview .cui-widget-panelview {
|
||||
overflow-x: visible;
|
||||
|
@ -1,6 +0,0 @@
|
||||
<!-- 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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<path fill="context-fill" d="M14.5 8c-.971 0-1 1-1.75 1a.765.765 0 0 1-.75-.75V5a1 1 0 0 0-1-1H7.75A.765.765 0 0 1 7 3.25c0-.75 1-.779 1-1.75C8 .635 7.1 0 6 0S4 .635 4 1.5c0 .971 1 1 1 1.75a.765.765 0 0 1-.75.75H1a1 1 0 0 0-1 1v2.25A.765.765 0 0 0 .75 8c.75 0 .779-1 1.75-1C3.365 7 4 7.9 4 9s-.635 2-1.5 2c-.971 0-1-1-1.75-1a.765.765 0 0 0-.75.75V15a1 1 0 0 0 1 1h3.25a.765.765 0 0 0 .75-.75c0-.75-1-.779-1-1.75 0-.865.9-1.5 2-1.5s2 .635 2 1.5c0 .971-1 1-1 1.75a.765.765 0 0 0 .75.75H11a1 1 0 0 0 1-1v-3.25a.765.765 0 0 1 .75-.75c.75 0 .779 1 1.75 1 .865 0 1.5-.9 1.5-2s-.635-2-1.5-2z"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 893 B |
6
browser/themes/shared/icons/toolbar.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<!-- 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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<path fill="context-fill" d="M13 1H3a3.007 3.007 0 0 0-3 3v8a3.009 3.009 0 0 0 3 3h10a3.005 3.005 0 0 0 3-3V4a3.012 3.012 0 0 0-3-3zM3 3h10a1 1 0 0 1 1 1v1H2V4a1 1 0 0 1 1-1zm11 3v1H2V6zm-1 7H3a1 1 0 0 1-1-1V8h12v4a1 1 0 0 1-1 1z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 538 B |
@ -676,7 +676,7 @@ groupbox {
|
||||
}
|
||||
|
||||
#searchInput {
|
||||
width: 230px;
|
||||
width: 250px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,6 @@
|
||||
skin/classic/browser/fxa/ios@2x.png (../shared/fxa/ios@2x.png)
|
||||
|
||||
|
||||
skin/classic/browser/addons.svg (../shared/icons/addons.svg)
|
||||
skin/classic/browser/arrow-dropdown-12.svg (../shared/icons/arrow-dropdown-12.svg)
|
||||
skin/classic/browser/arrow-dropdown-16.svg (../shared/icons/arrow-dropdown-16.svg)
|
||||
skin/classic/browser/arrow-left.svg (../shared/icons/arrow-left.svg)
|
||||
@ -158,6 +157,7 @@
|
||||
skin/classic/browser/stop-to-reload.svg (../shared/icons/stop-to-reload.svg)
|
||||
skin/classic/browser/sync.svg (../shared/icons/sync.svg)
|
||||
skin/classic/browser/synced-tabs.svg (../shared/icons/synced-tabs.svg)
|
||||
skin/classic/browser/toolbar.svg (../shared/icons/toolbar.svg)
|
||||
skin/classic/browser/webIDE.svg (../shared/icons/webIDE.svg)
|
||||
skin/classic/browser/zoom-in.svg (../shared/icons/zoom-in.svg)
|
||||
skin/classic/browser/zoom-out.svg (../shared/icons/zoom-out.svg)
|
||||
|
@ -23,7 +23,7 @@
|
||||
}
|
||||
|
||||
#appMenu-addons-button {
|
||||
list-style-image: url(chrome://browser/skin/addons.svg);
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.svg);
|
||||
}
|
||||
|
||||
#appMenu-preferences-button {
|
||||
@ -98,6 +98,14 @@
|
||||
list-style-image: url("chrome://browser/skin/sidebars.svg");
|
||||
}
|
||||
|
||||
#panelMenu_bookmarkingTools {
|
||||
list-style-image: url("chrome://browser/skin/developer.svg");
|
||||
}
|
||||
|
||||
#panelMenu_viewBookmarksToolbar {
|
||||
list-style-image: url("chrome://browser/skin/toolbar.svg");
|
||||
}
|
||||
|
||||
#appMenu-library-bookmarks-button,
|
||||
#panelMenuBookmarkThisPage {
|
||||
list-style-image: url("chrome://browser/skin/bookmark-hollow.svg");
|
||||
@ -108,7 +116,8 @@
|
||||
}
|
||||
|
||||
#bookmarks-menu-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #bookmarks-menu-button {
|
||||
toolbarpaletteitem[place="palette"] > #bookmarks-menu-button,
|
||||
#panelMenu_toggleBookmarksMenu {
|
||||
list-style-image: url("chrome://browser/skin/bookmark-star-on-tray.svg");
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@
|
||||
%ifndef XP_MACOSX
|
||||
/* Allow room for the checkbox drawn as a background image at the start of the toolbarbutton */
|
||||
#sidebarMenu-popup .subviewbutton-iconic > .toolbarbutton-icon {
|
||||
padding-inline-start: 16px;
|
||||
margin-inline-start: 16px;
|
||||
}
|
||||
#sidebarMenu-popup .subviewbutton-iconic > .toolbarbutton-text {
|
||||
padding-inline-start: 0;
|
||||
|
@ -2,6 +2,5 @@
|
||||
- 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/. -->
|
||||
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill">
|
||||
<rect x="7" y="1" width="2" height="14"/>
|
||||
<rect x="1" y="7" width="14" height="2"/>
|
||||
<path d="M14 7H9V2a1 1 0 0 0-2 0v5H2a1 1 0 1 0 0 2h5v5a1 1 0 0 0 2 0V9h5a1 1 0 0 0 0-2z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 391 B After Width: | Height: | Size: 396 B |
@ -206,7 +206,7 @@ toolbar:not([brighttext]) #bookmarks-menu-button[starred] > .toolbarbutton-menub
|
||||
}
|
||||
|
||||
#add-ons-button {
|
||||
list-style-image: url("chrome://browser/skin/addons.svg");
|
||||
list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric-16.svg");
|
||||
}
|
||||
|
||||
#open-file-button {
|
||||
|
@ -1109,7 +1109,7 @@ html|*.addon-webext-perm-list {
|
||||
}
|
||||
|
||||
.addon-addon-icon {
|
||||
list-style-image: url("chrome://browser/skin/addons.svg");
|
||||
list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric-16.svg");
|
||||
}
|
||||
|
||||
.addon-toolbar-icon {
|
||||
|
@ -2405,12 +2405,45 @@ Element::OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Element::SetSingleClassFromParser(nsIAtom* aSingleClassName)
|
||||
{
|
||||
// Keep this in sync with SetAttr and SetParsedAttr below.
|
||||
|
||||
if (!mAttrsAndChildren.CanFitMoreAttrs()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsAttrValue value(aSingleClassName);
|
||||
|
||||
nsIDocument* document = GetComposedDoc();
|
||||
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, false);
|
||||
|
||||
// In principle, BeforeSetAttr should be called here if a node type
|
||||
// existed that wanted to do something special for class, but there
|
||||
// is no such node type, so calling SetMayHaveClass() directly.
|
||||
SetMayHaveClass();
|
||||
|
||||
return SetAttrAndNotify(kNameSpaceID_None,
|
||||
nsGkAtoms::_class,
|
||||
nullptr, // prefix
|
||||
nullptr, // old value
|
||||
value,
|
||||
static_cast<uint8_t>(nsIDOMMutationEvent::ADDITION),
|
||||
false, // hasListeners
|
||||
false, // notify
|
||||
kCallAfterSetAttr,
|
||||
document,
|
||||
updateBatch);
|
||||
}
|
||||
|
||||
nsresult
|
||||
Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
// Keep this in sync with SetParsedAttr below
|
||||
// Keep this in sync with SetParsedAttr below and SetSingleClassFromParser
|
||||
// above.
|
||||
|
||||
NS_ENSURE_ARG_POINTER(aName);
|
||||
NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
|
||||
@ -2475,7 +2508,7 @@ Element::SetParsedAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, nsAttrValue& aParsedValue,
|
||||
bool aNotify)
|
||||
{
|
||||
// Keep this in sync with SetAttr above
|
||||
// Keep this in sync with SetAttr and SetSingleClassFromParser above
|
||||
|
||||
NS_ENSURE_ARG_POINTER(aName);
|
||||
NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
|
||||
@ -2709,6 +2742,10 @@ Element::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
// If it is ever made to be exact, we probably need to handle this
|
||||
// similarly to how ids are handled in PreIdMaybeChange and
|
||||
// PostIdMaybeChange.
|
||||
// Note that SetSingleClassFromParser inlines BeforeSetAttr and
|
||||
// calls SetMayHaveClass directly. Making a subclass take action
|
||||
// on the class attribute in a BeforeSetAttr override would
|
||||
// require revising SetSingleClassFromParser.
|
||||
SetMayHaveClass();
|
||||
}
|
||||
}
|
||||
|
@ -706,6 +706,13 @@ public:
|
||||
uint8_t* aModType, bool* aHasListeners,
|
||||
bool* aOldValueSet);
|
||||
|
||||
/**
|
||||
* Sets the class attribute to a value that contains no whitespace.
|
||||
* Assumes that we are not notifying and that the attribute hasn't been
|
||||
* set previously.
|
||||
*/
|
||||
nsresult SetSingleClassFromParser(nsIAtom* aSingleClassName);
|
||||
|
||||
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix,
|
||||
const nsAString& aValue, bool aNotify) override;
|
||||
// aParsedValue receives the old value of the attribute. That's useful if
|
||||
|
29
dom/base/crashtests/1385272-1.html
Normal file
@ -0,0 +1,29 @@
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
try { o1 = document.createElement("tr") } catch(e) { }
|
||||
try { o2 = document.createElement("td") } catch(e) { }
|
||||
try { o3 = document.createElement("tr") } catch(e) { }
|
||||
try { o4 = document.createElement("div") } catch(e) { }
|
||||
try { o5 = document.createElement("input") } catch(e) { }
|
||||
try { o6 = document.createElement('map') } catch(e) { }
|
||||
try { o7 = document.createElement('select') } catch(e) { }
|
||||
try { o8 = document.createElement("canvas") } catch(e) { }
|
||||
try { o9 = document.createElement("area") } catch(e) { };
|
||||
try { o1.appendChild(o2) } catch(e) { }
|
||||
try { document.documentElement.appendChild(o3) } catch(e) { }
|
||||
try { document.documentElement.appendChild(o4) } catch(e) { }
|
||||
try { document.documentElement.appendChild(o6) } catch(e) { }
|
||||
try { o3.appendChild(o7) } catch(e) { }
|
||||
try { o4.appendChild(o8) } catch(e) { }
|
||||
try { o3.appendChild(o5); } catch(e) { }
|
||||
try { o3.appendChild(o1); } catch(e) { }
|
||||
try { o6.contentEditable = "true" } catch(e) { };
|
||||
try { o6.offsetHeight } catch(e) { };
|
||||
try { o4.appendChild(o9) } catch(e) { };
|
||||
try { o2.insertAdjacentHTML("beforeBegin", "<button id='id0'></button>\n"); } catch(e) { }
|
||||
try { document.replaceChild(document.documentElement, document.documentElement); } catch(e) { }
|
||||
try { document.execCommand("selectall",false,null) } catch(e) { }
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
@ -221,3 +221,4 @@ load xhr_empty_datauri.html
|
||||
load xhr_html_nullresponse.html
|
||||
load 1383478.html
|
||||
load 1383780.html
|
||||
pref(clipboard.autocopy,true) load 1385272-1.html
|
||||
|
@ -1018,6 +1018,14 @@ nsDocumentEncoder::EncodeToString(nsAString& aOutputString)
|
||||
return EncodeToStringWithMaxLength(0, aOutputString);
|
||||
}
|
||||
|
||||
static bool ParentIsTR(nsIContent* aContent) {
|
||||
mozilla::dom::Element* parent = aContent->GetParentElement();
|
||||
if (!parent) {
|
||||
return false;
|
||||
}
|
||||
return parent->IsHTMLElement(nsGkAtoms::tr);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
|
||||
nsAString& aOutputString)
|
||||
@ -1088,7 +1096,7 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(node);
|
||||
if (content && content->IsHTMLElement(nsGkAtoms::tr)) {
|
||||
if (content && content->IsHTMLElement(nsGkAtoms::tr) && !ParentIsTR(content)) {
|
||||
nsINode* n = content;
|
||||
if (!prevNode) {
|
||||
// Went from a non-<tr> to a <tr>
|
||||
|
@ -2462,17 +2462,15 @@ DecodingState::MaybeStartBuffering()
|
||||
return;
|
||||
}
|
||||
|
||||
bool shouldBuffer;
|
||||
if (Reader()->UseBufferingHeuristics()) {
|
||||
shouldBuffer = IsExpectingMoreData()
|
||||
&& mMaster->HasLowDecodedData()
|
||||
&& mMaster->HasLowBufferedData();
|
||||
} else {
|
||||
shouldBuffer =
|
||||
(mMaster->OutOfDecodedAudio() && mMaster->IsWaitingAudioData())
|
||||
|| (mMaster->OutOfDecodedVideo() && mMaster->IsWaitingVideoData());
|
||||
// Note we could have a wait promise pending when playing non-MSE EME.
|
||||
if ((mMaster->OutOfDecodedAudio() && mMaster->IsWaitingAudioData()) ||
|
||||
(mMaster->OutOfDecodedVideo() && mMaster->IsWaitingVideoData())) {
|
||||
SetState<BufferingState>();
|
||||
return;
|
||||
}
|
||||
if (shouldBuffer) {
|
||||
|
||||
if (Reader()->UseBufferingHeuristics() && mMaster->HasLowDecodedData() &&
|
||||
mMaster->HasLowBufferedData() && !mMaster->mCanPlayThrough) {
|
||||
SetState<BufferingState>();
|
||||
}
|
||||
}
|
||||
@ -2547,17 +2545,24 @@ BufferingState::Step()
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
MOZ_ASSERT(!mBufferingStart.IsNull(), "Must know buffering start time.");
|
||||
|
||||
// With buffering heuristics we will remain in the buffering state if
|
||||
// we've not decoded enough data to begin playback, or if we've not
|
||||
// downloaded a reasonable amount of data inside our buffering time.
|
||||
if (Reader()->UseBufferingHeuristics()) {
|
||||
if (mMaster->IsWaitingAudioData() || mMaster->IsWaitingVideoData()) {
|
||||
// Can't exit buffering when we are still waiting for data.
|
||||
// Note we don't schedule next loop for we will do that when the wait
|
||||
// promise is resolved.
|
||||
return;
|
||||
}
|
||||
// With buffering heuristics, we exit buffering state when we:
|
||||
// 1. can play through or
|
||||
// 2. time out (specified by mBufferingWait) or
|
||||
// 3. have enough buffered data.
|
||||
TimeDuration elapsed = now - mBufferingStart;
|
||||
bool isLiveStream = Resource()->IsLiveStream();
|
||||
if ((isLiveStream || !mMaster->mCanPlayThrough)
|
||||
&& elapsed
|
||||
< TimeDuration::FromSeconds(mBufferingWait * mMaster->mPlaybackRate)
|
||||
&& mMaster->HasLowBufferedData(TimeUnit::FromSeconds(mBufferingWait))
|
||||
&& IsExpectingMoreData()) {
|
||||
TimeDuration timeout =
|
||||
TimeDuration::FromSeconds(mBufferingWait * mMaster->mPlaybackRate);
|
||||
bool stopBuffering =
|
||||
mMaster->mCanPlayThrough || elapsed >= timeout ||
|
||||
!mMaster->HasLowBufferedData(TimeUnit::FromSeconds(mBufferingWait));
|
||||
if (!stopBuffering) {
|
||||
SLOG("Buffering: wait %ds, timeout in %.3lfs",
|
||||
mBufferingWait, mBufferingWait - elapsed.ToSeconds());
|
||||
mMaster->ScheduleStateMachineIn(TimeUnit::FromMicroseconds(USECS_PER_S));
|
||||
|
@ -526,18 +526,78 @@ InterpolateForGecko(const ValueWrapper* aStartWrapper,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsPropertyDiscretelyAnimatable(nsCSSPropertyID aProperty)
|
||||
{
|
||||
// For shorthands, Servo_Property_IsDiscreteAnimatable will always return
|
||||
// false. That makes sense for shorthands like 'font' which have smoothly
|
||||
// interpolable longhand components. However, for shorthands where all the
|
||||
// components are discretely animatable, like 'font-variant', we should
|
||||
// treat the shorthand as discretely animatable so that we apply SMIL's
|
||||
// special discrete handling to it and all its longhand components.
|
||||
if (nsCSSProps::IsShorthand(aProperty)) {
|
||||
// We could iterate over all the longhand components and call
|
||||
// Servo_Property_IsDiscreteAnimatable on each of them, but that's a lot of
|
||||
// FFI calls do be doing each time we interpolate. Instead, since there are
|
||||
// only about six shorthands in the set of properties that can be animated
|
||||
// by SMIL, we just hard code the discrete ones below then add a debug-mode
|
||||
// check that this list matches what the result would be if we performed
|
||||
// all the FFI calls.
|
||||
bool result;
|
||||
switch (aProperty) {
|
||||
case eCSSProperty_font_variant:
|
||||
case eCSSProperty_marker:
|
||||
case eCSSProperty_overflow:
|
||||
result = true;
|
||||
break;
|
||||
default:
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool resultAccordingToServo = true;
|
||||
CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty,
|
||||
CSSEnabledState::eForAllContent) {
|
||||
// If the shorthand has one or more non-discrete components, it should not
|
||||
// be treated as discrete.
|
||||
if (!Servo_Property_IsDiscreteAnimatable(*p)) {
|
||||
resultAccordingToServo = false;
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(result == resultAccordingToServo,
|
||||
"Gecko and Servo should agree on which shorthands should be"
|
||||
" treated as discretely animatable");
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return Servo_Property_IsDiscreteAnimatable(aProperty);
|
||||
}
|
||||
|
||||
static nsresult
|
||||
InterpolateForServo(const ValueWrapper* aStartWrapper,
|
||||
const ValueWrapper& aEndWrapper,
|
||||
double aUnitDistance,
|
||||
nsSMILValue& aResult)
|
||||
{
|
||||
// For discretely-animated properties Servo_AnimationValues_Interpolate will
|
||||
// perform the discrete animation (i.e. 50% flip) and return a success result.
|
||||
// However, SMIL has its own special discrete animation behavior that it uses
|
||||
// when keyTimes are specified, but we won't run that unless that this method
|
||||
// returns a failure to indicate that the property cannot be smoothly
|
||||
// interpolated, i.e. that we need to use a discrete calcMode.
|
||||
if (IsPropertyDiscretelyAnimatable(aEndWrapper.mPropID)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ServoAnimationValues results;
|
||||
size_t len = aEndWrapper.mServoValues.Length();
|
||||
results.SetCapacity(len);
|
||||
MOZ_ASSERT(!aStartWrapper || aStartWrapper->mServoValues.Length() == len,
|
||||
"Start and end values length should be the same if "
|
||||
"The start value exists");
|
||||
"the start value exists");
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
const RefPtr<RawServoAnimationValue>*
|
||||
startValue = aStartWrapper
|
||||
|
@ -42,7 +42,6 @@ skip-if = toolkit == 'android'
|
||||
[test_smilInvalidValues.html]
|
||||
[test_smilKeySplines.xhtml]
|
||||
[test_smilKeyTimes.xhtml]
|
||||
skip-if = stylo
|
||||
[test_smilKeyTimesPacedMode.xhtml]
|
||||
[test_smilMappedAttrFromBy.xhtml]
|
||||
skip-if = stylo
|
||||
|
@ -19,12 +19,8 @@ interface StackFrame;
|
||||
Exposed=(Window,Worker)]
|
||||
interface ExceptionMembers
|
||||
{
|
||||
// A custom message set by the thrower.
|
||||
readonly attribute DOMString message;
|
||||
// The nsresult associated with this exception.
|
||||
readonly attribute unsigned long result;
|
||||
// The name of the error code (ie, a string repr of |result|).
|
||||
readonly attribute DOMString name;
|
||||
|
||||
// Filename location. This is the location that caused the
|
||||
// error, which may or may not be a source file location.
|
||||
@ -57,6 +53,10 @@ interface ExceptionMembers
|
||||
|
||||
[NoInterfaceObject, Exposed=(Window,Worker)]
|
||||
interface Exception {
|
||||
// The name of the error code (ie, a string repr of |result|).
|
||||
readonly attribute DOMString name;
|
||||
// A custom message set by the thrower.
|
||||
readonly attribute DOMString message;
|
||||
// A generic formatter - make it suitable to print, etc.
|
||||
stringifier;
|
||||
};
|
||||
@ -69,6 +69,12 @@ Exception implements ExceptionMembers;
|
||||
Exposed=(Window, Worker),
|
||||
Constructor(optional DOMString message = "", optional DOMString name)]
|
||||
interface DOMException {
|
||||
// The name of the error code (ie, a string repr of |result|).
|
||||
readonly attribute DOMString name;
|
||||
// A custom message set by the thrower.
|
||||
readonly attribute DOMString message;
|
||||
readonly attribute unsigned short code;
|
||||
|
||||
const unsigned short INDEX_SIZE_ERR = 1;
|
||||
const unsigned short DOMSTRING_SIZE_ERR = 2; // historical
|
||||
const unsigned short HIERARCHY_REQUEST_ERR = 3;
|
||||
@ -94,8 +100,6 @@ interface DOMException {
|
||||
const unsigned short TIMEOUT_ERR = 23;
|
||||
const unsigned short INVALID_NODE_TYPE_ERR = 24;
|
||||
const unsigned short DATA_CLONE_ERR = 25;
|
||||
|
||||
readonly attribute unsigned short code;
|
||||
};
|
||||
|
||||
// XXXkhuey copy all of Gecko's non-standard stuff onto DOMException, but leave
|
||||
|
@ -74,6 +74,9 @@ ComputeImageFlags(ImageURL* uri, const nsCString& aMimeType, bool isMultiPart)
|
||||
if (isMultiPart) {
|
||||
imageFlags |= Image::INIT_FLAG_TRANSIENT;
|
||||
}
|
||||
imageFlags |= Image::INIT_FLAG_SYNC_LOAD;
|
||||
// Always synchronously decode metadata (including size) so as to avoid
|
||||
// unnecessary reflows.
|
||||
|
||||
return imageFlags;
|
||||
}
|
||||
|
@ -125,6 +125,7 @@ skip-if = true # disabled - See bug 579139
|
||||
skip-if = os == 'android'
|
||||
[test_bug1180105.html]
|
||||
[test_bug1217571.html]
|
||||
[test_bug1325080.html]
|
||||
[test_bullet_animation.html]
|
||||
skip-if = os == 'android'
|
||||
[test_changeOfSource.html]
|
||||
|
37
image/test/mochitest/test_bug1325080.html
Normal file
@ -0,0 +1,37 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1325080
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1325080</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1325080">Mozilla Bug 1325080</a>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
/** Test for Bug 1325080 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function createImage() {
|
||||
// This function's code comes from the Acid3 test #72
|
||||
document.open();
|
||||
document.write('<!DOCTYPE html><head><style>img { height: 10px; }</style></head><body><img src="data:image/gif;base64,R0lGODlhAQABAID%2FAMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw%3D%3D" alt="alt-text"></body>');
|
||||
document.close();
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
createImage();
|
||||
SimpleTest.executeSoon(() => {
|
||||
ok(document.images[0].height == 10, "Style should set height of image.");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<style>
|
||||
@keyframes anim {
|
||||
from { content: 'content'; }
|
||||
to { content: ''; }
|
||||
}
|
||||
#target::before {
|
||||
content: 'initial';
|
||||
animation: anim 100s paused;
|
||||
}
|
||||
</style>
|
||||
<div id='target'></div>
|
||||
</html>
|
@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<style>
|
||||
@keyframes anim {
|
||||
from { content: ''; }
|
||||
to { content: 'content'; }
|
||||
}
|
||||
#target::before {
|
||||
content: 'initial';
|
||||
animation: anim 100s linear -50s paused;
|
||||
}
|
||||
</style>
|
||||
<div id='target'></div>
|
||||
</html>
|
@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<style>
|
||||
#target::before {
|
||||
content: 'content';
|
||||
}
|
||||
</style>
|
||||
<div id='target'></div>
|
||||
</html>
|
@ -54,4 +54,6 @@ fails == background-position-important.html background-position-ref.html # This
|
||||
== stop-animation-on-discarded-pseudo-element.html about:blank
|
||||
|
||||
== updating-animation-on-pseudo-element.html updating-animation-on-pseudo-element-ref.html
|
||||
== content-on-pseudo-element-at-beginning.html content-on-pseudo-element-ref.html
|
||||
== content-on-pseudo-element-at-half.html content-on-pseudo-element-ref.html
|
||||
== reframe-and-animation-starts-at-the-same-time.html reframe-and-animation-starts-at-the-same-time-ref.html
|
||||
|
@ -72,16 +72,10 @@ var skippedProperties = {
|
||||
"mask-position-y": true, // Bug 1387946
|
||||
"mask-size": true, // Bug 1387946
|
||||
"box-shadow": true, // Bug 1387973
|
||||
"caret-color": true, // Bug 1387951
|
||||
"clip": true, // Bug 1387951
|
||||
"column-count": true, // Bug 1387939
|
||||
"-moz-image-region": true, // Bug 1387951
|
||||
"order": true, // Bug 1387939
|
||||
"stroke-dasharray": true, // Bug 1387986
|
||||
"stroke-dashoffset": true, // Bug 1369614
|
||||
"stroke-width": true, // Bug 1369614
|
||||
"text-shadow": true, // Bug 1387973
|
||||
"z-index": true, // Bug 1387939
|
||||
};
|
||||
|
||||
var supported_properties = {
|
||||
|
@ -30,8 +30,13 @@ const BUF_SIZE_LIMIT: usize = 1024 * 1024;
|
||||
|
||||
// Max table length. Calculating in worth case for one week long video, one
|
||||
// frame per table entry in 30 fps.
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
const TABLE_SIZE_LIMIT: u32 = 30 * 60 * 60 * 24 * 7;
|
||||
|
||||
// Reduce max table length if it is in 32 arch for memory problem.
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
const TABLE_SIZE_LIMIT: u32 = 30 * 60 * 60 * 24;
|
||||
|
||||
static DEBUG_MODE: std::sync::atomic::AtomicBool = std::sync::atomic::ATOMIC_BOOL_INIT;
|
||||
|
||||
pub fn set_debug_mode(mode: bool) {
|
||||
@ -1333,13 +1338,12 @@ fn find_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> {
|
||||
let tag = des.read_u8()?;
|
||||
|
||||
let mut end = 0;
|
||||
// Extension descriptor could be variable size from 0x80 to
|
||||
// 0x80 0x80 0x80, the descriptor length is the byte after that,
|
||||
// so it loops four times.
|
||||
// MSB of extend_or_len indicates more bytes, up to 4 bytes.
|
||||
for _ in 0..4 {
|
||||
let extend_or_len = des.read_u8()?;
|
||||
if extend_or_len < 0x80 {
|
||||
end = extend_or_len + des.position() as u8;
|
||||
end = (end << 7) + (extend_or_len & 0x7F);
|
||||
if (extend_or_len & 0x80) == 0 {
|
||||
end += des.position() as u8;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
@ -974,6 +974,23 @@ fn read_esds_one_byte_extension_descriptor() {
|
||||
assert_eq!(es.audio_channel_count, Some(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_esds_byte_extension_descriptor() {
|
||||
let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
|
||||
s.B32(0) // reserved
|
||||
.B16(0x0003)
|
||||
.B16(0x8181) // extension byte length 0x81
|
||||
.append_repeated(0, 0x81)
|
||||
});
|
||||
let mut iter = super::BoxIter::new(&mut stream);
|
||||
let mut stream = iter.next_box().unwrap().unwrap();
|
||||
|
||||
match super::read_esds(&mut stream) {
|
||||
Ok(_) => (),
|
||||
_ => panic!("fail to parse descriptor extension byte length"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_f4v_stsd() {
|
||||
let mut stream = make_box(BoxSize::Auto, b".mp3", |s| {
|
||||
|
@ -2,7 +2,7 @@
|
||||
# Script to update mp4parse-rust sources to latest upstream
|
||||
|
||||
# Default version.
|
||||
VER=7563263b6804a81986cc93b557fe05bd57fd57b3
|
||||
VER=1d2d69df3380139ee208f58181c73b1947c91ac2
|
||||
|
||||
# Accept version or commit from the command line.
|
||||
if test -n "$1"; then
|
||||
|
@ -138,8 +138,9 @@ template<typename Ret, typename FunType, typename... Args>
|
||||
class runnable_args_func_ret : public detail::runnable_args_base<detail::ReturnsResult>
|
||||
{
|
||||
public:
|
||||
runnable_args_func_ret(Ret* ret, FunType f, Args&&... args)
|
||||
: mReturn(ret), mFunc(f), mArgs(Forward<Args>(args)...)
|
||||
template<typename... Arguments>
|
||||
runnable_args_func_ret(Ret* ret, FunType f, Arguments&&... args)
|
||||
: mReturn(ret), mFunc(f), mArgs(Forward<Arguments>(args)...)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
@ -154,18 +155,19 @@ private:
|
||||
};
|
||||
|
||||
template<typename R, typename FunType, typename... Args>
|
||||
runnable_args_func_ret<R, FunType, Args...>*
|
||||
WrapRunnableNMRet(R* ret, FunType f, Args... args)
|
||||
runnable_args_func_ret<R, FunType, typename mozilla::Decay<Args>::Type...>*
|
||||
WrapRunnableNMRet(R* ret, FunType f, Args&&... args)
|
||||
{
|
||||
return new runnable_args_func_ret<R, FunType, Args...>(ret, f, Move(args)...);
|
||||
return new runnable_args_func_ret<R, FunType, typename mozilla::Decay<Args>::Type...>(ret, f, Forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Class, typename M, typename... Args>
|
||||
class runnable_args_memfn : public detail::runnable_args_base<detail::NoResult>
|
||||
{
|
||||
public:
|
||||
runnable_args_memfn(Class obj, M method, Args&&... args)
|
||||
: mObj(obj), mMethod(method), mArgs(Forward<Args>(args)...)
|
||||
template<typename... Arguments>
|
||||
runnable_args_memfn(Class obj, M method, Arguments&&... args)
|
||||
: mObj(obj), mMethod(method), mArgs(Forward<Arguments>(args)...)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
@ -180,18 +182,19 @@ private:
|
||||
};
|
||||
|
||||
template<typename Class, typename M, typename... Args>
|
||||
runnable_args_memfn<Class, M, Args...>*
|
||||
WrapRunnable(Class obj, M method, Args... args)
|
||||
runnable_args_memfn<Class, M, typename mozilla::Decay<Args>::Type...>*
|
||||
WrapRunnable(Class obj, M method, Args&&... args)
|
||||
{
|
||||
return new runnable_args_memfn<Class, M, Args...>(obj, method, Move(args)...);
|
||||
return new runnable_args_memfn<Class, M, typename mozilla::Decay<Args>::Type...>(obj, method, Forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Ret, typename Class, typename M, typename... Args>
|
||||
class runnable_args_memfn_ret : public detail::runnable_args_base<detail::ReturnsResult>
|
||||
{
|
||||
public:
|
||||
runnable_args_memfn_ret(Ret* ret, Class obj, M method, Args... args)
|
||||
: mReturn(ret), mObj(obj), mMethod(method), mArgs(Forward<Args>(args)...)
|
||||
template<typename... Arguments>
|
||||
runnable_args_memfn_ret(Ret* ret, Class obj, M method, Arguments... args)
|
||||
: mReturn(ret), mObj(obj), mMethod(method), mArgs(Forward<Arguments>(args)...)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
@ -207,10 +210,10 @@ private:
|
||||
};
|
||||
|
||||
template<typename R, typename Class, typename M, typename... Args>
|
||||
runnable_args_memfn_ret<R, Class, M, Args...>*
|
||||
WrapRunnableRet(R* ret, Class obj, M method, Args... args)
|
||||
runnable_args_memfn_ret<R, Class, M, typename mozilla::Decay<Args>::Type...>*
|
||||
WrapRunnableRet(R* ret, Class obj, M method, Args&&... args)
|
||||
{
|
||||
return new runnable_args_memfn_ret<R, Class, M, Args...>(ret, obj, method, Move(args)...);
|
||||
return new runnable_args_memfn_ret<R, Class, M, typename mozilla::Decay<Args>::Type...>(ret, obj, method, Forward<Args>(args)...);
|
||||
}
|
||||
|
||||
static inline nsresult RUN_ON_THREAD(nsIEventTarget *thread, detail::runnable_args_base<detail::NoResult> *runnable, uint32_t flags) {
|
||||
|
Before Width: | Height: | Size: 88 B After Width: | Height: | Size: 113 B |
Before Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 14 KiB |
BIN
mobile/android/app/src/main/res/drawable-nodpi/firstrun_data.png
Normal file
After Width: | Height: | Size: 70 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 9.0 KiB |
Before Width: | Height: | Size: 13 KiB |
BIN
mobile/android/app/src/main/res/drawable-nodpi/firstrun_sync.png
Normal file
After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 9.9 KiB |
After Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 96 B After Width: | Height: | Size: 120 B |
@ -5,7 +5,7 @@
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true"
|
||||
android:drawable="@drawable/button_pressed_action_orange_round" />
|
||||
android:drawable="@drawable/button_pressed_action_photon_round" />
|
||||
<item android:state_enabled="true"
|
||||
android:drawable="@drawable/button_enabled_action_orange_round" />
|
||||
android:drawable="@drawable/button_enabled_action_photon_round" />
|
||||
</selector>
|
@ -5,7 +5,7 @@
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle" >
|
||||
<solid android:color="@color/action_orange" />
|
||||
<solid android:color="@color/ob_click" />
|
||||
<corners
|
||||
android:radius="@dimen/standard_corner_radius" />
|
||||
</shape>
|
@ -5,7 +5,7 @@
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle" >
|
||||
<solid android:color="@color/action_orange_pressed" />
|
||||
<solid android:color="@color/ob_press" />
|
||||
<corners
|
||||
android:radius="@dimen/standard_corner_radius" />
|
||||
android:radius="5dp" />
|
||||
</shape>
|
@ -20,8 +20,8 @@
|
||||
<ImageView android:id="@+id/firstrun_image"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/firstrun_background_height"
|
||||
android:layout_marginTop="40dp"
|
||||
android:layout_marginBottom="40dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:layout_marginBottom="18dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:layout_gravity="center"
|
||||
android:adjustViewBounds="true"/>
|
||||
@ -53,6 +53,7 @@
|
||||
android:padding="30dp"
|
||||
android:gravity="center"
|
||||
android:textAppearance="@style/TextAppearance.FirstrunRegular.Link"
|
||||
android:textAllCaps="true"
|
||||
android:text="@string/firstrun_button_next"/>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
@ -21,8 +21,8 @@
|
||||
<ImageView android:id="@+id/firstrun_image"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/firstrun_background_height"
|
||||
android:layout_marginTop="40dp"
|
||||
android:layout_marginBottom="40dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:layout_marginBottom="18dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:layout_gravity="center"
|
||||
android:adjustViewBounds="true"/>
|
||||
@ -31,24 +31,37 @@
|
||||
android:layout_width="@dimen/firstrun_content_width"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:paddingBottom="40dp"
|
||||
android:textAppearance="@style/TextAppearance.FirstrunLight.Main"/>
|
||||
|
||||
<TextView android:id="@+id/firstrun_subtext"
|
||||
android:layout_width="@dimen/firstrun_content_width"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="20dp"
|
||||
android:paddingBottom="30dp"
|
||||
android:gravity="center"
|
||||
android:textAppearance="@style/TextAppearance.FirstrunRegular.Body"/>
|
||||
|
||||
<Button android:id="@+id/welcome_account"
|
||||
style="@style/Widget.Firstrun.Button"
|
||||
android:background="@drawable/button_background_action_orange_round"
|
||||
android:background="@drawable/button_background_action_photon_round"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/firstrun_signin_button"/>
|
||||
|
||||
<View android:layout_weight="1"
|
||||
android:layout_height="0dp"
|
||||
android:layout_width="match_parent"/>
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/welcome_browse"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginBottom="30dp"
|
||||
android:text="@string/firstrun_welcome_button_browser"
|
||||
android:textAllCaps="true"
|
||||
android:textAppearance="@style/TextAppearance.FirstrunRegular.Link"/>
|
||||
</RelativeLayout>
|
||||
|
||||
<TextView android:id="@+id/welcome_browse"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="30dp"
|
||||
android:gravity="center"
|
||||
android:textAppearance="@style/TextAppearance.FirstrunRegular.Link"/>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
@ -56,6 +56,7 @@
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:background="@drawable/button_background_action_blue_round"
|
||||
android:textAllCaps="true"
|
||||
android:text="@string/firstrun_welcome_button_browser" />
|
||||
|
||||
<TextView
|
||||
|
@ -116,7 +116,7 @@
|
||||
android:layout_width="@dimen/overlay_prompt_button_width"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/button_background_action_orange_round"
|
||||
android:background="@drawable/button_background_action_photon_round"
|
||||
android:text="@string/tab_queue_prompt_positive_action_button"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="16sp"
|
||||
@ -128,7 +128,7 @@
|
||||
android:layout_width="@dimen/overlay_prompt_button_width"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/button_background_action_orange_round"
|
||||
android:background="@drawable/button_background_action_photon_round"
|
||||
android:text="@string/tab_queue_prompt_settings_button"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="16sp"
|
||||
|
@ -92,7 +92,7 @@
|
||||
|
||||
android:layout_height="52dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/button_background_action_orange_round"
|
||||
android:background="@drawable/button_background_action_photon_round"
|
||||
android:text="@string/tracking_protection_prompt_action_button"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="16sp"
|
||||
|
@ -137,11 +137,16 @@
|
||||
<color name="affirmative_green">#6FBE4A</color>
|
||||
<color name="rejection_red">#D23228</color>
|
||||
<color name="action_orange">#E66000</color>
|
||||
<color name="action_orange_pressed">#DC5600</color>
|
||||
<color name="link_blue">#0096DD</color>
|
||||
<color name="link_blue_pressed">#0082C6</color>
|
||||
<color name="private_browsing_purple">#CF68FF</color>
|
||||
|
||||
<!-- On boarding -->
|
||||
<color name="ob_click">#0A84FF</color>
|
||||
<color name="ob_press">#003EAA</color>
|
||||
<color name="ob_title">#212121</color>
|
||||
<color name="ob_subtitle">#737373</color>
|
||||
|
||||
<color name="placeholder_active_grey">#222222</color>
|
||||
<color name="placeholder_grey">#777777</color>
|
||||
<color name="private_toolbar_grey">#292C29</color>
|
||||
|
@ -727,18 +727,18 @@
|
||||
|
||||
<style name="TextAppearance.FirstrunLight.Main">
|
||||
<item name="android:textSize">20sp</item>
|
||||
<item name="android:textColor">@color/text_and_tabs_tray_grey</item>
|
||||
<item name="android:textColor">@color/ob_title</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.FirstrunRegular.Body">
|
||||
<item name="android:textSize">16sp</item>
|
||||
<item name="android:textColor">@color/placeholder_grey</item>
|
||||
<item name="android:textColor">@color/ob_subtitle</item>
|
||||
<item name="android:lineSpacingMultiplier">1.25</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.FirstrunRegular.Link">
|
||||
<item name="android:textSize">16sp</item>
|
||||
<item name="android:textColor">@color/link_blue</item>
|
||||
<item name="android:textColor">@color/ob_click</item>
|
||||
</style>
|
||||
|
||||
<!-- Remote Tabs home panel -->
|
||||
|
@ -1013,6 +1013,7 @@ public class BrowserApp extends GeckoApp
|
||||
|
||||
if (prefs.getBoolean(FirstrunAnimationContainer.PREF_FIRSTRUN_ENABLED_OLD, true) &&
|
||||
prefs.getBoolean(FirstrunAnimationContainer.PREF_FIRSTRUN_ENABLED, true)) {
|
||||
showSplashScreen = false;
|
||||
if (!Intent.ACTION_VIEW.equals(intent.getAction())) {
|
||||
// Check to see if a distribution has turned off the first run pager.
|
||||
final Distribution distribution = Distribution.getInstance(BrowserApp.this);
|
||||
@ -2833,12 +2834,6 @@ public class BrowserApp extends GeckoApp
|
||||
}
|
||||
|
||||
private void showFirstrunPager() {
|
||||
if (Experiments.isInExperimentLocal(this, Experiments.ONBOARDING3_A)) {
|
||||
Telemetry.startUISession(TelemetryContract.Session.EXPERIMENT, Experiments.ONBOARDING3_A);
|
||||
GeckoSharedPrefs.forProfile(this).edit().putString(Experiments.PREF_ONBOARDING_VERSION, Experiments.ONBOARDING3_A).apply();
|
||||
Telemetry.stopUISession(TelemetryContract.Session.EXPERIMENT, Experiments.ONBOARDING3_A);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mFirstrunAnimationContainer == null) {
|
||||
final ViewStub firstrunPagerStub = (ViewStub) findViewById(R.id.firstrun_pager_stub);
|
||||
|
@ -68,23 +68,6 @@ public class Experiments {
|
||||
// Enable processing of background telemetry.
|
||||
public static final String ENABLE_PROCESSING_BACKGROUND_TELEMETRY = "process-background-telemetry";
|
||||
|
||||
/**
|
||||
* Returns if a user is in certain local experiment.
|
||||
* @param experiment Name of experiment to look up
|
||||
* @return returns value for experiment or false if experiment does not exist.
|
||||
*/
|
||||
public static boolean isInExperimentLocal(Context context, String experiment) {
|
||||
if (SwitchBoard.isInBucket(context, 0, 20)) {
|
||||
return Experiments.ONBOARDING3_A.equals(experiment);
|
||||
} else if (SwitchBoard.isInBucket(context, 20, 60)) {
|
||||
return Experiments.ONBOARDING3_B.equals(experiment);
|
||||
} else if (SwitchBoard.isInBucket(context, 60, 100)) {
|
||||
return Experiments.ONBOARDING3_C.equals(experiment);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of all active experiments, remote and local.
|
||||
* @return List of experiment names Strings
|
||||
|
@ -29,7 +29,7 @@ public class DataPanel extends FirstrunPanel {
|
||||
public void onClick(View view) {
|
||||
// Set new state.
|
||||
isEnabled = !isEnabled;
|
||||
int newResource = isEnabled ? R.drawable.firstrun_data_on : R.drawable.firstrun_data_off;
|
||||
int newResource = isEnabled ? R.drawable.firstrun_data : R.drawable.firstrun_data;
|
||||
((ImageView) view).setImageResource(newResource);
|
||||
if (isEnabled) {
|
||||
// Always block images.
|
||||
|
@ -27,7 +27,8 @@ import org.mozilla.gecko.preferences.GeckoPreferences;
|
||||
public class FirstrunAnimationContainer extends LinearLayout {
|
||||
// See bug 1330714. Need NON_PREF_PREFIX to set from distribution.
|
||||
public static final String PREF_FIRSTRUN_ENABLED_OLD = "startpane_enabled";
|
||||
public static final String PREF_FIRSTRUN_ENABLED = GeckoPreferences.NON_PREF_PREFIX + "startpane_enabled";
|
||||
// After 57, the pref name will be changed. Thus all user since 57 will check this new pref.
|
||||
public static final String PREF_FIRSTRUN_ENABLED = GeckoPreferences.NON_PREF_PREFIX + "startpane_enabled_after_57";
|
||||
|
||||
public static interface OnFinishListener {
|
||||
public void onFinish();
|
||||
|
@ -20,6 +20,7 @@ import com.booking.rtlviewpager.RtlViewPager;
|
||||
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
import org.mozilla.gecko.fxa.FirefoxAccounts;
|
||||
import org.mozilla.gecko.home.HomePager.Decor;
|
||||
import org.mozilla.gecko.home.TabMenuStrip;
|
||||
import org.mozilla.gecko.restrictions.Restrictions;
|
||||
@ -67,6 +68,8 @@ public class FirstrunPager extends RtlViewPager {
|
||||
|
||||
if (Restrictions.isRestrictedProfile(context)) {
|
||||
panels = FirstrunPagerConfig.getRestricted();
|
||||
} else if (FirefoxAccounts.firefoxAccountsExist(context)) {
|
||||
panels = FirstrunPagerConfig.forFxAUser(appContext);
|
||||
} else {
|
||||
panels = FirstrunPagerConfig.getDefault(appContext);
|
||||
}
|
||||
|
@ -26,25 +26,20 @@ public class FirstrunPagerConfig {
|
||||
|
||||
public static List<FirstrunPanelConfig> getDefault(Context context) {
|
||||
final List<FirstrunPanelConfig> panels = new LinkedList<>();
|
||||
panels.add(SimplePanelConfigs.welcomePanelConfig);
|
||||
panels.add(SimplePanelConfigs.privatePanelConfig);
|
||||
panels.add(SimplePanelConfigs.customizePanelConfig);
|
||||
panels.add(SimplePanelConfigs.syncPanelConfig);
|
||||
|
||||
return panels;
|
||||
}
|
||||
|
||||
public static List<FirstrunPanelConfig> forFxAUser(Context context) {
|
||||
final List<FirstrunPanelConfig> panels = new LinkedList<>();
|
||||
panels.add(SimplePanelConfigs.welcomePanelConfig);
|
||||
panels.add(SimplePanelConfigs.privatePanelConfig);
|
||||
panels.add(SimplePanelConfigs.customizeLastPanelConfig);
|
||||
|
||||
if (Experiments.isInExperimentLocal(context, Experiments.ONBOARDING3_B)) {
|
||||
panels.add(SimplePanelConfigs.urlbarPanelConfig);
|
||||
panels.add(SimplePanelConfigs.bookmarksPanelConfig);
|
||||
panels.add(SimplePanelConfigs.dataPanelConfig);
|
||||
panels.add(SimplePanelConfigs.syncPanelConfig);
|
||||
panels.add(SimplePanelConfigs.signInPanelConfig);
|
||||
Telemetry.startUISession(TelemetryContract.Session.EXPERIMENT, Experiments.ONBOARDING3_B);
|
||||
GeckoSharedPrefs.forProfile(context).edit().putString(Experiments.PREF_ONBOARDING_VERSION, Experiments.ONBOARDING3_B).apply();
|
||||
} else if (Experiments.isInExperimentLocal(context, Experiments.ONBOARDING3_C)) {
|
||||
panels.add(SimplePanelConfigs.tabqueuePanelConfig);
|
||||
panels.add(SimplePanelConfigs.readerviewPanelConfig);
|
||||
panels.add(SimplePanelConfigs.accountPanelConfig);
|
||||
Telemetry.startUISession(TelemetryContract.Session.EXPERIMENT, Experiments.ONBOARDING3_C);
|
||||
GeckoSharedPrefs.forProfile(context).edit().putString(Experiments.PREF_ONBOARDING_VERSION, Experiments.ONBOARDING3_C).apply();
|
||||
} else {
|
||||
Log.e(LOGTAG, "Not in an experiment!");
|
||||
panels.add(SimplePanelConfigs.signInPanelConfig);
|
||||
}
|
||||
return panels;
|
||||
}
|
||||
|
||||
@ -94,14 +89,12 @@ public class FirstrunPagerConfig {
|
||||
}
|
||||
|
||||
private static class SimplePanelConfigs {
|
||||
public static final FirstrunPanelConfig urlbarPanelConfig = new FirstrunPanelConfig(FirstrunPanel.class.getName(), R.string.firstrun_panel_title_welcome, R.drawable.firstrun_urlbar, R.string.firstrun_urlbar_message, R.string.firstrun_urlbar_subtext);
|
||||
public static final FirstrunPanelConfig bookmarksPanelConfig = new FirstrunPanelConfig(FirstrunPanel.class.getName(), R.string.firstrun_bookmarks_title, R.drawable.firstrun_bookmarks, R.string.firstrun_bookmarks_message, R.string.firstrun_bookmarks_subtext);
|
||||
public static final FirstrunPanelConfig dataPanelConfig = new FirstrunPanelConfig(DataPanel.class.getName(), R.string.firstrun_data_title, R.drawable.firstrun_data_off, R.string.firstrun_data_message, R.string.firstrun_data_subtext);
|
||||
public static final FirstrunPanelConfig syncPanelConfig = new FirstrunPanelConfig(FirstrunPanel.class.getName(), R.string.firstrun_sync_title, R.drawable.firstrun_sync, R.string.firstrun_sync_message, R.string.firstrun_sync_subtext);
|
||||
public static final FirstrunPanelConfig signInPanelConfig = new FirstrunPanelConfig(SyncPanel.class.getName(), R.string.pref_sync, R.drawable.firstrun_signin, R.string.firstrun_signin_message, R.string.firstrun_welcome_button_browser);
|
||||
public static final FirstrunPanelConfig welcomePanelConfig = new FirstrunPanelConfig(FirstrunPanel.class.getName(), R.string.firstrun_panel_title_welcome, R.drawable.firstrun_welcome, R.string.firstrun_urlbar_message, R.string.firstrun_urlbar_subtext);
|
||||
public static final FirstrunPanelConfig privatePanelConfig = new FirstrunPanelConfig(FirstrunPanel.class.getName(), R.string.firstrun_panel_title_privacy, R.drawable.firstrun_private, R.string.firstrun_privacy_message, R.string.firstrun_privacy_subtext);
|
||||
public static final FirstrunPanelConfig customizePanelConfig = new FirstrunPanelConfig(FirstrunPanel.class.getName(), R.string.firstrun_panel_title_customize, R.drawable.firstrun_data, R.string.firstrun_customize_message, R.string.firstrun_customize_subtext);
|
||||
public static final FirstrunPanelConfig customizeLastPanelConfig = new FirstrunPanelConfig(LastPanel.class.getName(), R.string.firstrun_panel_title_customize, R.drawable.firstrun_data, R.string.firstrun_customize_message, R.string.firstrun_customize_subtext);
|
||||
|
||||
public static final FirstrunPanelConfig syncPanelConfig = new FirstrunPanelConfig(SyncPanel.class.getName(), R.string.firstrun_sync_title, R.drawable.firstrun_sync, R.string.firstrun_sync_message, R.string.firstrun_sync_subtext);
|
||||
|
||||
public static final FirstrunPanelConfig tabqueuePanelConfig = new FirstrunPanelConfig(TabQueuePanel.class.getName(), R.string.firstrun_tabqueue_title, R.drawable.firstrun_tabqueue_off, R.string.firstrun_tabqueue_message_off, R.string.firstrun_tabqueue_subtext_off);
|
||||
public static final FirstrunPanelConfig readerviewPanelConfig = new FirstrunPanelConfig(FirstrunPanel.class.getName(), R.string.firstrun_readerview_title, R.drawable.firstrun_readerview, R.string.firstrun_readerview_message, R.string.firstrun_readerview_subtext);
|
||||
public static final FirstrunPanelConfig accountPanelConfig = new FirstrunPanelConfig(SyncPanel.class.getName(), R.string.firstrun_account_title, R.drawable.firstrun_account, R.string.firstrun_account_message, R.string.firstrun_button_notnow);
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ public class FirstrunPanel extends Fragment {
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance) {
|
||||
final ViewGroup root = (ViewGroup) inflater.inflate(R.layout.firstrun_basepanel_checkable_fragment, container, false);
|
||||
Bundle args = getArguments();
|
||||
final Bundle args = getArguments();
|
||||
if (args != null) {
|
||||
final int imageRes = args.getInt(FirstrunPagerConfig.KEY_IMAGE);
|
||||
final int textRes = args.getInt(FirstrunPagerConfig.KEY_TEXT);
|
||||
|
@ -0,0 +1,47 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
|
||||
* 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/. */
|
||||
|
||||
package org.mozilla.gecko.firstrun;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
|
||||
public class LastPanel extends FirstrunPanel {
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance) {
|
||||
final ViewGroup root = (ViewGroup) inflater.inflate(R.layout.firstrun_basepanel_checkable_fragment, container, false);
|
||||
final Bundle args = getArguments();
|
||||
if (args != null) {
|
||||
final int imageRes = args.getInt(FirstrunPagerConfig.KEY_IMAGE);
|
||||
final int textRes = args.getInt(FirstrunPagerConfig.KEY_TEXT);
|
||||
final int subtextRes = args.getInt(FirstrunPagerConfig.KEY_SUBTEXT);
|
||||
|
||||
((ImageView) root.findViewById(R.id.firstrun_image)).setImageResource(imageRes);
|
||||
((TextView) root.findViewById(R.id.firstrun_text)).setText(textRes);
|
||||
((TextView) root.findViewById(R.id.firstrun_subtext)).setText(subtextRes);
|
||||
((TextView) root.findViewById(R.id.firstrun_link)).setText(R.string.firstrun_welcome_button_browser);
|
||||
|
||||
}
|
||||
|
||||
root.findViewById(R.id.firstrun_link).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.BUTTON, "firstrun-next");
|
||||
close();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return root;
|
||||
}
|
||||
}
|
@ -30,7 +30,7 @@ public class SyncPanel extends FirstrunPanel {
|
||||
|
||||
((ImageView) root.findViewById(R.id.firstrun_image)).setImageResource(imageRes);
|
||||
((TextView) root.findViewById(R.id.firstrun_text)).setText(textRes);
|
||||
((TextView) root.findViewById(R.id.welcome_browse)).setText(subtextRes);
|
||||
((TextView) root.findViewById(R.id.firstrun_subtext)).setText(subtextRes);
|
||||
}
|
||||
|
||||
root.findViewById(R.id.welcome_account).setOnClickListener(new View.OnClickListener() {
|
||||
|
@ -3,9 +3,14 @@
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!ENTITY firstrun_panel_title_welcome "Welcome">
|
||||
|
||||
<!ENTITY firstrun_urlbar_message "Welcome to &brandShortName;">
|
||||
<!ENTITY firstrun_urlbar_subtext "Find things faster with helpful search suggestion shortcuts.">
|
||||
<!ENTITY firstrun_urlbar_message2 "Thanks for choosing &brandShortName;">
|
||||
<!ENTITY firstrun_urlbar_subtext2 "A modern mobile browser from Mozilla, the non-profit committed to a free and open web.">
|
||||
<!ENTITY firstrun_panel_title_privacy "Privacy">
|
||||
<!ENTITY firstrun_privacy_message "Browse like no one\'s watching">
|
||||
<!ENTITY firstrun_privacy_subtext "Private Browsing with Tracking Protection blocks trackers while you browse and won’t remember your history when you finish browsing.">
|
||||
<!ENTITY firstrun_panel_title_customize "Customize">
|
||||
<!ENTITY firstrun_customize_message "Make Firefox your own.">
|
||||
<!ENTITY firstrun_customize_subtext "Customize Firefox with add-ons. Block ads, add features, or choose a new theme to reflect your personality.">
|
||||
<!ENTITY firstrun_bookmarks_title "History">
|
||||
<!ENTITY firstrun_bookmarks_message "Your faves, front and center">
|
||||
<!ENTITY firstrun_bookmarks_subtext "Get results from your bookmarks and history when you search.">
|
||||
@ -13,8 +18,8 @@
|
||||
<!ENTITY firstrun_data_message "Less data, more savings">
|
||||
<!ENTITY firstrun_data_subtext2 "Turn off images to spend less data on every site you visit.">
|
||||
<!ENTITY firstrun_sync_title "Sync">
|
||||
<!ENTITY firstrun_sync_message "&brandShortName;, always by your side">
|
||||
<!ENTITY firstrun_sync_subtext "Sync your tabs, passwords, and more everywhere you use it.">
|
||||
<!ENTITY firstrun_sync_message2 "Pick up where you left off.">
|
||||
<!ENTITY firstrun_sync_subtext2 "Use Sync to find the bookmarks, passwords, and other things you save to Firefox on all your devices.">
|
||||
<!ENTITY firstrun_signin_message "Get connected, get started">
|
||||
<!ENTITY firstrun_signin_button "Sign in to Sync">
|
||||
<!ENTITY onboard_start_button_browser "Start Browsing">
|
||||
|
@ -648,6 +648,7 @@ gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [
|
||||
'firstrun/FirstrunPager.java',
|
||||
'firstrun/FirstrunPagerConfig.java',
|
||||
'firstrun/FirstrunPanel.java',
|
||||
'firstrun/LastPanel.java',
|
||||
'firstrun/RestrictedWelcomePanel.java',
|
||||
'firstrun/SyncPanel.java',
|
||||
'firstrun/TabQueuePanel.java',
|
||||
|
@ -31,36 +31,26 @@
|
||||
|
||||
<string name="firstrun_panel_title_welcome">&firstrun_panel_title_welcome;</string>
|
||||
|
||||
<string name="firstrun_urlbar_message">&firstrun_urlbar_message;</string>
|
||||
<string name="firstrun_urlbar_subtext">&firstrun_urlbar_subtext;</string>
|
||||
<string name="firstrun_bookmarks_title">&firstrun_bookmarks_title;</string>
|
||||
<string name="firstrun_bookmarks_message">&firstrun_bookmarks_message;</string>
|
||||
<string name="firstrun_bookmarks_subtext">&firstrun_bookmarks_subtext;</string>
|
||||
<string name="firstrun_data_title">&firstrun_data_title;</string>
|
||||
<string name="firstrun_data_message">&firstrun_data_message;</string>
|
||||
<string name="firstrun_data_subtext">&firstrun_data_subtext2;</string>
|
||||
<string name="firstrun_urlbar_message">&firstrun_urlbar_message2;</string>
|
||||
<string name="firstrun_urlbar_subtext">&firstrun_urlbar_subtext2;</string>
|
||||
<string name="firstrun_panel_title_privacy">&firstrun_panel_title_privacy;</string>
|
||||
<string name="firstrun_privacy_message">&firstrun_privacy_message;</string>
|
||||
<string name="firstrun_privacy_subtext">&firstrun_privacy_subtext;</string>
|
||||
<string name="firstrun_panel_title_customize">&firstrun_panel_title_customize;</string>
|
||||
<string name="firstrun_customize_message">&firstrun_customize_message;</string>
|
||||
<string name="firstrun_customize_subtext">&firstrun_customize_subtext;</string>
|
||||
<string name="firstrun_sync_title">&firstrun_sync_title;</string>
|
||||
<string name="firstrun_sync_message">&firstrun_sync_message;</string>
|
||||
<string name="firstrun_sync_subtext">&firstrun_sync_subtext;</string>
|
||||
<string name="firstrun_signin_message">&firstrun_signin_message;</string>
|
||||
<string name="firstrun_sync_message">&firstrun_sync_message2;</string>
|
||||
<string name="firstrun_sync_subtext">&firstrun_sync_subtext2;</string>
|
||||
<string name="firstrun_signin_button">&firstrun_signin_button;</string>
|
||||
<string name="firstrun_welcome_button_browser">&onboard_start_button_browser;</string>
|
||||
<string name="firstrun_button_notnow">&firstrun_button_notnow;</string>
|
||||
<string name="firstrun_button_next">&firstrun_button_next;</string>
|
||||
|
||||
<string name="firstrun_tabqueue_title">&firstrun_tabqueue_title;</string>
|
||||
<string name="firstrun_tabqueue_message_off">&firstrun_tabqueue_message_off;</string>
|
||||
<string name="firstrun_tabqueue_subtext_off">&firstrun_tabqueue_subtext_off;</string>
|
||||
<string name="firstrun_tabqueue_message_on">&firstrun_tabqueue_message_on;</string>
|
||||
<string name="firstrun_tabqueue_subtext_on">&firstrun_tabqueue_subtext_on;</string>
|
||||
|
||||
<string name="firstrun_readerview_title">&firstrun_readerview_title;</string>
|
||||
<string name="firstrun_readerview_message">&firstrun_readerview_message;</string>
|
||||
<string name="firstrun_readerview_subtext">&firstrun_readerview_subtext;</string>
|
||||
|
||||
<string name="firstrun_account_title">&firstrun_account_title;</string>
|
||||
<string name="firstrun_account_message">&firstrun_account_message;</string>
|
||||
|
||||
<string name="firstrun_welcome_restricted">&onboard_start_restricted1;</string>
|
||||
|
||||
<string name="bookmarks_title">&bookmarks_title;</string>
|
||||
|
@ -4,8 +4,6 @@
|
||||
%htmlDTD;
|
||||
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
|
||||
%brandDTD;
|
||||
<!ENTITY % securityPrefsDTD SYSTEM "chrome://browser/locale/preferences/security.dtd">
|
||||
%securityPrefsDTD;
|
||||
<!ENTITY % aboutRightsDTD SYSTEM "chrome://global/locale/aboutRights.dtd">
|
||||
%aboutRightsDTD;
|
||||
]>
|
||||
|
@ -130,7 +130,6 @@ public class SyncClientsEngineStage extends AbstractSessionManagingSyncStage {
|
||||
public void handleRequestSuccess(SyncStorageResponse response) {
|
||||
final Context context = session.getContext();
|
||||
final Account account = FirefoxAccounts.getFirefoxAccount(context);
|
||||
final AndroidFxAccount fxAccount = new AndroidFxAccount(context, account);
|
||||
|
||||
// Hang onto the server's last modified timestamp to use
|
||||
// in X-If-Unmodified-Since for upload.
|
||||
@ -182,15 +181,17 @@ public class SyncClientsEngineStage extends AbstractSessionManagingSyncStage {
|
||||
uploadRemoteRecords();
|
||||
|
||||
// We will send a push notification later anyway.
|
||||
if (!isFirstLocalClientRecordUpload) {
|
||||
if (!isFirstLocalClientRecordUpload && account != null) {
|
||||
// Notify the clients who got their record written
|
||||
final AndroidFxAccount fxAccount = new AndroidFxAccount(context, account);
|
||||
notifyClients(fxAccount, devicesToNotify);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
checkAndUpload();
|
||||
if (isFirstLocalClientRecordUpload) {
|
||||
if (isFirstLocalClientRecordUpload && account != null) {
|
||||
final AndroidFxAccount fxAccount = new AndroidFxAccount(context, account);
|
||||
notifyAllClients(fxAccount);
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +90,7 @@
|
||||
android:layout_marginStart="100dp"
|
||||
android:layout_marginRight="30dp"
|
||||
android:layout_marginEnd="30dp"
|
||||
android:background="@drawable/button_background_action_orange_round"
|
||||
android:background="@drawable/button_background_action_photon_round"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingRight="16dp"
|
||||
|
@ -53,7 +53,7 @@
|
||||
<Button
|
||||
android:id="@+id/button"
|
||||
style="@style/Widget.Firstrun.Button"
|
||||
android:background="@drawable/button_background_action_orange_round"
|
||||
android:background="@drawable/button_background_action_photon_round"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="30dp"/>
|
||||
|
||||
|
@ -183,6 +183,11 @@ div[collapsed="true"] > .expander + * {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
#advisory_provider {
|
||||
color: white;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* On large screen devices (hopefully a 7+ inch tablet, we already center content (see #errorPageContainer above).
|
||||
Apply tablet specific styles here */
|
||||
@media (min-width: 550px) {
|
||||
|
@ -797,13 +797,13 @@ public abstract class MetaScanner {
|
||||
}
|
||||
if (contentIndex == CONTENT.length && content == null) {
|
||||
content = Portability.newStringFromBuffer(strBuf, 0, strBufLen
|
||||
// CPPONLY: , treeBuilder
|
||||
// CPPONLY: , treeBuilder, false
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (charsetIndex == CHARSET.length && charset == null) {
|
||||
charset = Portability.newStringFromBuffer(strBuf, 0, strBufLen
|
||||
// CPPONLY: , treeBuilder
|
||||
// CPPONLY: , treeBuilder, false
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ public final class Portability {
|
||||
}
|
||||
|
||||
public static String newStringFromBuffer(@NoLength char[] buf, int offset, int length
|
||||
// CPPONLY: , TreeBuilder treeBuilder
|
||||
// CPPONLY: , TreeBuilder treeBuilder, boolean maybeAtomize
|
||||
) {
|
||||
return new String(buf, offset, length);
|
||||
}
|
||||
|
@ -897,7 +897,7 @@ public class Tokenizer implements Locator {
|
||||
*/
|
||||
protected String strBufToString() {
|
||||
String str = Portability.newStringFromBuffer(strBuf, 0, strBufLen
|
||||
// CPPONLY: , tokenHandler
|
||||
// CPPONLY: , tokenHandler, !newAttributesEachTime && attributeName == AttributeName.CLASS
|
||||
);
|
||||
clearStrBufAfterUse();
|
||||
return str;
|
||||
|
@ -3293,7 +3293,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
|
||||
}
|
||||
charset = Portability.newStringFromBuffer(buffer, start, end
|
||||
- start
|
||||
// CPPONLY: , tb
|
||||
// CPPONLY: , tb, false
|
||||
);
|
||||
}
|
||||
return charset;
|
||||
|
@ -755,11 +755,13 @@ nsHtml5MetaScanner::handleAttributeValue()
|
||||
return;
|
||||
}
|
||||
if (contentIndex == CONTENT.length && !content) {
|
||||
content = nsHtml5Portability::newStringFromBuffer(strBuf, 0, strBufLen, treeBuilder);
|
||||
content = nsHtml5Portability::newStringFromBuffer(
|
||||
strBuf, 0, strBufLen, treeBuilder, false);
|
||||
return;
|
||||
}
|
||||
if (charsetIndex == CHARSET.length && !charset) {
|
||||
charset = nsHtml5Portability::newStringFromBuffer(strBuf, 0, strBufLen, treeBuilder);
|
||||
charset = nsHtml5Portability::newStringFromBuffer(
|
||||
strBuf, 0, strBufLen, treeBuilder, false);
|
||||
return;
|
||||
}
|
||||
if (httpEquivIndex == HTTP_EQUIV.length &&
|
||||
|
@ -16,12 +16,30 @@ nsHtml5Portability::newLocalNameFromBuffer(char16_t* buf, int32_t offset, int32_
|
||||
return interner->GetAtom(nsDependentSubstring(buf, buf + length));
|
||||
}
|
||||
|
||||
static bool
|
||||
ContainsWhiteSpace(mozilla::Span<char16_t> aSpan)
|
||||
{
|
||||
for (char16_t c : aSpan) {
|
||||
if (nsContentUtils::IsHTMLWhitespace(c)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
nsHtml5String
|
||||
nsHtml5Portability::newStringFromBuffer(char16_t* buf,
|
||||
int32_t offset,
|
||||
int32_t length,
|
||||
nsHtml5TreeBuilder* treeBuilder)
|
||||
nsHtml5TreeBuilder* treeBuilder,
|
||||
bool maybeAtomize)
|
||||
{
|
||||
if (!length) {
|
||||
return nsHtml5String::EmptyString();
|
||||
}
|
||||
if (maybeAtomize && !ContainsWhiteSpace(mozilla::MakeSpan(buf + offset, length))) {
|
||||
return nsHtml5String::FromAtom(NS_AtomizeMainThread(nsDependentSubstring(buf + offset, length)));
|
||||
}
|
||||
return nsHtml5String::FromBuffer(buf + offset, length, treeBuilder);
|
||||
}
|
||||
|
||||
|