Merge mozilla-central to mozilla-inbound

--HG--
rename : dom/media/platforms/apple/ReorderQueue.h => dom/media/platforms/ReorderQueue.h
This commit is contained in:
Carsten "Tomcat" Book 2016-08-03 17:08:41 +02:00
commit 423bdfd2fd
255 changed files with 3430 additions and 15844 deletions

View File

@ -31,6 +31,11 @@ scopes:
# - as_slugid: convert a label into a slugId # - as_slugid: convert a label into a slugId
# - from_now: generate a timestamp at a fixed offset from now # - from_now: generate a timestamp at a fixed offset from now
# The resulting tasks' taskGroupId will be equal to the taskId of the first
# task listed here, which should be the decision task. This gives other tools
# an easy way to determine the ID of the decision task that created a
# particular group.
tasks: tasks:
- taskId: '{{#as_slugid}}decision task{{/as_slugid}}' - taskId: '{{#as_slugid}}decision task{{/as_slugid}}'
task: task:
@ -80,7 +85,7 @@ tasks:
# Note: This task is built server side without the context or tooling that # Note: This task is built server side without the context or tooling that
# exist in tree so we must hard code the version # exist in tree so we must hard code the version
image: 'taskcluster/decision:0.1.3' image: 'taskcluster/decision:0.1.4'
maxRunTime: 1800 maxRunTime: 1800

View File

@ -308,6 +308,12 @@ pref("browser.urlbar.suggest.history.onlyTyped", false);
pref("browser.urlbar.formatting.enabled", true); pref("browser.urlbar.formatting.enabled", true);
pref("browser.urlbar.trimURLs", true); pref("browser.urlbar.trimURLs", true);
#if defined(NIGHTLY_BUILD)
pref("browser.urlbar.oneOffSearches", true);
#else
pref("browser.urlbar.oneOffSearches", false);
#endif
pref("browser.altClickSave", false); pref("browser.altClickSave", false);
// Enable logging downloads operations to the Console. // Enable logging downloads operations to the Console.

View File

@ -152,14 +152,7 @@
noautofocus="true" noautofocus="true"
hidden="true" hidden="true"
flip="none" flip="none"
level="parent"> level="parent"/>
#ifdef NIGHTLY_BUILD
<hbox id="urlbar-search-footer" flex="1" align="stretch" pack="end">
<button id="urlbar-search-settings" label="&changeSearchSettings.button;"
oncommand="BrowserUITelemetry.countSearchSettingsEvent('urlbar'); openPreferences('paneSearch')"/>
</hbox>
#endif
</panel>
<!-- for select dropdowns. The menupopup is what shows the list of options, <!-- for select dropdowns. The menupopup is what shows the list of options,
and the popuponly menulist makes things like the menuactive attributes and the popuponly menulist makes things like the menuactive attributes

View File

@ -56,6 +56,7 @@ support-files =
skip-if = os == "linux" # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s skip-if = os == "linux" # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s
[browser_urlbarHashChangeProxyState.js] [browser_urlbarHashChangeProxyState.js]
[browser_urlbarKeepStateAcrossTabSwitches.js] [browser_urlbarKeepStateAcrossTabSwitches.js]
[browser_urlbarOneOffs.js]
[browser_urlbarPrivateBrowsingWindowChange.js] [browser_urlbarPrivateBrowsingWindowChange.js]
[browser_urlbarRevert.js] [browser_urlbarRevert.js]
[browser_urlbarSearchSingleWordNotification.js] [browser_urlbarSearchSingleWordNotification.js]

View File

@ -6,6 +6,21 @@ function repeat(limit, func) {
function is_selected(index) { function is_selected(index) {
is(gURLBar.popup.richlistbox.selectedIndex, index, `Item ${index + 1} should be selected`); is(gURLBar.popup.richlistbox.selectedIndex, index, `Item ${index + 1} should be selected`);
// This is true because although both the listbox and the one-offs can have
// selections, the test doesn't check that.
is(gURLBar.popup.oneOffSearchButtons.selectedButton, null,
"A result is selected, so the one-offs should not have a selection");
}
function is_selected_one_off(index) {
is(gURLBar.popup.oneOffSearchButtons.selectedButtonIndex, index,
"Expected one-off button should be selected");
// This is true because although both the listbox and the one-offs can have
// selections, the test doesn't check that.
is(gURLBar.popup.richlistbox.selectedIndex, -1,
"A one-off is selected, so the listbox should not have a selection");
} }
add_task(function*() { add_task(function*() {
@ -37,12 +52,27 @@ add_task(function*() {
EventUtils.synthesizeKey("VK_DOWN", {}); EventUtils.synthesizeKey("VK_DOWN", {});
is_selected(1); is_selected(1);
info("Key Down maxResults times should wrap around all the way around"); info("Key Down maxResults-1 times should select the first one-off");
repeat(maxResults, () => EventUtils.synthesizeKey("VK_DOWN", {})); repeat(maxResults - 1, () => EventUtils.synthesizeKey("VK_DOWN", {}));
is_selected_one_off(0);
info("Key Down numButtons-1 should select the last one-off");
let numButtons =
gURLBar.popup.oneOffSearchButtons.getSelectableButtons(true).length;
repeat(numButtons - 1, () => EventUtils.synthesizeKey("VK_DOWN", {}));
is_selected_one_off(numButtons - 1);
info("Key Down twice more should select the second result");
repeat(2, () => EventUtils.synthesizeKey("VK_DOWN", {}));
is_selected(1); is_selected(1);
info("Key Up maxResults times should wrap around the other way"); info("Key Down maxResults + numButtons times should wrap around");
repeat(maxResults, () => EventUtils.synthesizeKey("VK_UP", {})); repeat(maxResults + numButtons,
() => EventUtils.synthesizeKey("VK_DOWN", {}));
is_selected(1);
info("Key Up maxResults + numButtons times should wrap around the other way");
repeat(maxResults + numButtons, () => EventUtils.synthesizeKey("VK_UP", {}));
is_selected(1); is_selected(1);
info("Page Up will go up the list, but not wrap"); info("Page Up will go up the list, but not wrap");

View File

@ -31,15 +31,18 @@ add_task(function*() {
EventUtils.synthesizeKey("VK_BACK_SPACE", {}); EventUtils.synthesizeKey("VK_BACK_SPACE", {});
yield promiseSearchComplete(); yield promiseSearchComplete();
let editedValue = gURLBar.value; let editedValue = gURLBar.textValue;
is(list.selectedIndex, initialIndex, "The initial index is selected again."); is(list.selectedIndex, initialIndex, "The initial index is selected again.");
isnot(editedValue, nextValue, "The URL has changed."); isnot(editedValue, nextValue, "The URL has changed.");
let docLoad = waitForDocLoadAndStopIt("http://" + editedValue);
info("Press return to load edited URL."); info("Press return to load edited URL.");
EventUtils.synthesizeKey("VK_RETURN", {}); EventUtils.synthesizeKey("VK_RETURN", {});
yield Promise.all([ yield Promise.all([
promisePopupHidden(gURLBar.popup), promisePopupHidden(gURLBar.popup),
waitForDocLoadAndStopIt("http://" + editedValue)]); docLoad,
]);
gBrowser.removeTab(gBrowser.selectedTab); gBrowser.removeTab(gBrowser.selectedTab);
}); });

View File

@ -43,7 +43,7 @@ add_task(function*() {
EventUtils.synthesizeKey("b", {}); EventUtils.synthesizeKey("b", {});
yield promiseSearchComplete(); yield promiseSearchComplete();
is(gURLBar.value, "keyword ab", "urlbar should have expected input"); is(gURLBar.textValue, "keyword ab", "urlbar should have expected input");
let result = gURLBar.popup.richlistbox.firstChild; let result = gURLBar.popup.richlistbox.firstChild;
isnot(result, null, "Should have first item"); isnot(result, null, "Should have first item");

View File

@ -44,8 +44,8 @@ function continue_test() {
EventUtils.synthesizeKey(aTyped.substr(-1), {}); EventUtils.synthesizeKey(aTyped.substr(-1), {});
waitForSearchComplete(function () { waitForSearchComplete(function () {
info(`Got value: ${gURLBar.value}`); info(`Got value: ${gURLBar.textValue}`);
is(gURLBar.value, aExpected, "Autofilled value is as expected"); is(gURLBar.textValue, aExpected, "Autofilled value is as expected");
aCallback(); aCallback();
}); });
} }

View File

@ -0,0 +1,233 @@
const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
let gMaxResults;
add_task(function* init() {
Services.prefs.setBoolPref("browser.urlbar.oneOffSearches", true);
gMaxResults = Services.prefs.getIntPref("browser.urlbar.maxRichResults");
// Add a search suggestion engine and move it to the front so that it appears
// as the first one-off.
let engine = yield promiseNewSearchEngine(TEST_ENGINE_BASENAME);
Services.search.moveEngine(engine, 0);
registerCleanupFunction(function* () {
yield hidePopup();
yield PlacesTestUtils.clearHistory();
});
yield PlacesTestUtils.clearHistory();
let visits = [];
for (let i = 0; i < gMaxResults; i++) {
visits.push({
uri: makeURI("http://example.com/browser_urlbarOneOffs.js/?" + i),
// TYPED so that the visit shows up when the urlbar's drop-down arrow is
// pressed.
transition: Ci.nsINavHistoryService.TRANSITION_TYPED,
});
}
yield PlacesTestUtils.addVisits(visits);
});
// Keys up and down through the history panel, i.e., the panel that's shown when
// there's no text in the textbox.
add_task(function* history() {
gURLBar.focus();
EventUtils.synthesizeKey("VK_DOWN", {})
yield promisePopupShown(gURLBar.popup);
assertState(-1, -1, "");
// Key down through each result.
for (let i = 0; i < gMaxResults; i++) {
EventUtils.synthesizeKey("VK_DOWN", {})
assertState(i, -1,
"example.com/browser_urlbarOneOffs.js/?" + (gMaxResults - i - 1));
}
// Key down through each one-off.
let numButtons =
gURLBar.popup.oneOffSearchButtons.getSelectableButtons(true).length;
for (let i = 0; i < numButtons; i++) {
EventUtils.synthesizeKey("VK_DOWN", {})
assertState(-1, i, "");
}
// Key down once more. Nothing should be selected.
EventUtils.synthesizeKey("VK_DOWN", {})
assertState(-1, -1, "");
// Once more. The first result should be selected.
EventUtils.synthesizeKey("VK_DOWN", {})
assertState(0, -1,
"example.com/browser_urlbarOneOffs.js/?" + (gMaxResults - 1));
// Now key up. Nothing should be selected again.
EventUtils.synthesizeKey("VK_UP", {})
assertState(-1, -1, "");
// Key up through each one-off.
for (let i = numButtons - 1; i >= 0; i--) {
EventUtils.synthesizeKey("VK_UP", {})
assertState(-1, i, "");
}
// Key up through each result.
for (let i = gMaxResults - 1; i >= 0; i--) {
EventUtils.synthesizeKey("VK_UP", {})
assertState(i, -1,
"example.com/browser_urlbarOneOffs.js/?" + (gMaxResults - i - 1));
}
// Key up once more. Nothing should be selected.
EventUtils.synthesizeKey("VK_UP", {})
assertState(-1, -1, "");
yield hidePopup();
});
// Keys up and down through the non-history panel, i.e., the panel that's shown
// when you type something in the textbox.
add_task(function* typedValue() {
// Use a typed value that returns the visits added above but that doesn't
// trigger autofill since that would complicate the test.
let typedValue = "browser_urlbarOneOffs";
yield promiseAutocompleteResultPopup(typedValue, window, true);
assertState(0, -1, typedValue);
// Key down through each result. The first result is already selected, which
// is why gMaxResults - 1 is the correct number of times to do this.
for (let i = 0; i < gMaxResults - 1; i++) {
EventUtils.synthesizeKey("VK_DOWN", {})
// i starts at zero so that the textValue passed to assertState is correct.
// But that means that i + 1 is the expected selected index, since initially
// (when this loop starts) the first result is selected.
assertState(i + 1, -1,
"example.com/browser_urlbarOneOffs.js/?" + (gMaxResults - i - 1));
}
// Key down through each one-off.
let numButtons =
gURLBar.popup.oneOffSearchButtons.getSelectableButtons(true).length;
for (let i = 0; i < numButtons; i++) {
EventUtils.synthesizeKey("VK_DOWN", {})
assertState(-1, i, typedValue);
}
// Key down once more. The selection should wrap around to the first result.
EventUtils.synthesizeKey("VK_DOWN", {})
assertState(0, -1, typedValue);
// Now key up. The selection should wrap back around to the one-offs. Key
// up through all the one-offs.
for (let i = numButtons - 1; i >= 0; i--) {
EventUtils.synthesizeKey("VK_UP", {})
assertState(-1, i, typedValue);
}
// Key up through each non-heuristic result.
for (let i = gMaxResults - 2; i >= 0; i--) {
EventUtils.synthesizeKey("VK_UP", {})
assertState(i + 1, -1,
"example.com/browser_urlbarOneOffs.js/?" + (gMaxResults - i - 1));
}
// Key up once more. The heuristic result should be selected.
EventUtils.synthesizeKey("VK_UP", {})
assertState(0, -1, typedValue);
yield hidePopup();
});
// Checks that "Search with Current Search Engine" items are updated to "Search
// with One-Off Engine" when a one-off is selected.
add_task(function* searchWith() {
let typedValue = "foo";
yield promiseAutocompleteResultPopup(typedValue);
assertState(0, -1, typedValue);
let item = gURLBar.popup.richlistbox.firstChild;
Assert.equal(item._actionText.textContent,
"Search with " + Services.search.currentEngine.name,
"Sanity check: first result's action text");
// Tab to the first one-off. Now the first result and the first one-off
// should both be selected.
EventUtils.synthesizeKey("VK_TAB", {})
assertState(0, 0, typedValue);
let engineName = gURLBar.popup.oneOffSearchButtons.selectedButton.engine.name;
Assert.notEqual(engineName, Services.search.currentEngine.name,
"Sanity check: First one-off engine should not be " +
"the current engine");
Assert.equal(item._actionText.textContent,
"Search with " + engineName,
"First result's action text should be updated");
yield hidePopup();
});
// Clicks a one-off.
add_task(function* oneOffClick() {
gBrowser.selectedTab = gBrowser.addTab();
let typedValue = "foo";
yield promiseAutocompleteResultPopup(typedValue);
assertState(0, -1, typedValue);
let oneOffs = gURLBar.popup.oneOffSearchButtons.getSelectableButtons(true);
let resultsPromise = promiseSearchResultsLoaded();
EventUtils.synthesizeMouseAtCenter(oneOffs[0], {});
yield resultsPromise;
gBrowser.removeTab(gBrowser.selectedTab);
});
// Presses the Return key when a one-off is selected.
add_task(function* oneOffReturn() {
gBrowser.selectedTab = gBrowser.addTab();
let typedValue = "foo";
yield promiseAutocompleteResultPopup(typedValue, window, true);
assertState(0, -1, typedValue);
// Tab to select the first one-off.
EventUtils.synthesizeKey("VK_TAB", {})
assertState(0, 0, typedValue);
let resultsPromise = promiseSearchResultsLoaded();
EventUtils.synthesizeKey("VK_RETURN", {})
yield resultsPromise;
gBrowser.removeTab(gBrowser.selectedTab);
});
function assertState(result, oneOff, textValue = undefined) {
Assert.equal(gURLBar.popup.selectedIndex, result,
"Expected result should be selected");
Assert.equal(gURLBar.popup.oneOffSearchButtons.selectedButtonIndex, oneOff,
"Expected one-off should be selected");
if (textValue !== undefined) {
Assert.equal(gURLBar.textValue, textValue, "Expected textValue");
}
}
function* hidePopup() {
EventUtils.synthesizeKey("VK_ESCAPE", {});
yield promisePopupHidden(gURLBar.popup);
}
function promiseSearchResultsLoaded() {
let tab = gBrowser.selectedTab;
return promiseTabLoadEvent(tab).then(() => {
Assert.equal(tab.linkedBrowser.currentURI.spec,
"http://mochi.test:8888/",
'Expected "search results" page loaded');
});
}

View File

@ -25,7 +25,10 @@ add_task(function* clickSuggestion() {
gBrowser.selectedTab = gBrowser.addTab(); gBrowser.selectedTab = gBrowser.addTab();
gURLBar.focus(); gURLBar.focus();
yield promiseAutocompleteResultPopup("foo"); yield promiseAutocompleteResultPopup("foo");
let [idx, suggestion] = yield promiseFirstSuggestion(); let [idx, suggestion, engineName] = yield promiseFirstSuggestion();
Assert.equal(engineName,
"browser_searchSuggestionEngine%20searchSuggestionEngine.xml",
"Expected suggestion engine");
let item = gURLBar.popup.richlistbox.getItemAtIndex(idx); let item = gURLBar.popup.richlistbox.getItemAtIndex(idx);
let loadPromise = promiseTabLoaded(gBrowser.selectedTab); let loadPromise = promiseTabLoaded(gBrowser.selectedTab);
item.click(); item.click();
@ -47,7 +50,7 @@ function getFirstSuggestion() {
let [, type, paramStr] = mozActionMatch; let [, type, paramStr] = mozActionMatch;
let params = JSON.parse(paramStr); let params = JSON.parse(paramStr);
if (type == "searchengine" && "searchSuggestion" in params) { if (type == "searchengine" && "searchSuggestion" in params) {
return [i, params.searchSuggestion]; return [i, params.searchSuggestion, params.engineName];
} }
} }
} }
@ -56,10 +59,10 @@ function getFirstSuggestion() {
function promiseFirstSuggestion() { function promiseFirstSuggestion() {
return new Promise(resolve => { return new Promise(resolve => {
let pair; let tuple;
waitForCondition(() => { waitForCondition(() => {
pair = getFirstSuggestion(); tuple = getFirstSuggestion();
return pair[0] >= 0; return tuple[0] >= 0;
}, () => resolve(pair)); }, () => resolve(tuple));
}); });
} }

View File

@ -23,6 +23,12 @@ add_task(function* prepare() {
gURLBar.blur(); gURLBar.blur();
Assert.ok(!gURLBar.popup.popupOpen, "popup should be closed"); Assert.ok(!gURLBar.popup.popupOpen, "popup should be closed");
}); });
// Move the mouse away from the urlbar one-offs so that a one-off engine is
// not inadvertently selected.
yield new Promise(resolve => {
EventUtils.synthesizeNativeMouseMove(window.document.documentElement, 0, 0,
resolve);
});
}); });
add_task(function* heuristicResult() { add_task(function* heuristicResult() {

View File

@ -20,12 +20,11 @@ add_task(function* () {
gBrowser.removeCurrentTab(); gBrowser.removeCurrentTab();
}); });
function typeAndSubmitAndStop(url) { function* typeAndSubmitAndStop(url) {
gBrowser.userTypedValue = url; yield promiseAutocompleteResultPopup(url, window, true);
URLBarSetURI();
is(gURLBar.textValue, gURLBar.trimValue(url), "location bar reflects loading page"); is(gURLBar.textValue, gURLBar.trimValue(url), "location bar reflects loading page");
let promise = waitForDocLoadAndStopIt(url, gBrowser.selectedBrowser, false); let promise = waitForDocLoadAndStopIt(url, gBrowser.selectedBrowser, false);
gURLBar.handleCommand(); gURLBar.handleCommand();
return promise; yield promise;
} }

View File

@ -7,13 +7,13 @@ function* test_autocomplete(data) {
info(desc); info(desc);
yield promiseAutocompleteResultPopup(typed); yield promiseAutocompleteResultPopup(typed);
is(gURLBar.value, autofilled, "autofilled value is as expected"); is(gURLBar.textValue, autofilled, "autofilled value is as expected");
if (onAutoFill) if (onAutoFill)
onAutoFill() onAutoFill()
keys.forEach(key => EventUtils.synthesizeKey(key, {})); keys.forEach(key => EventUtils.synthesizeKey(key, {}));
is(gURLBar.value, modified, "backspaced value is as expected"); is(gURLBar.textValue, modified, "backspaced value is as expected");
yield promiseSearchComplete(); yield promiseSearchComplete();

View File

@ -327,10 +327,18 @@ function promiseSearchComplete(win = window) {
}); });
} }
function promiseAutocompleteResultPopup(inputText, win = window) { function promiseAutocompleteResultPopup(inputText,
win = window,
fireInputEvent = false) {
waitForFocus(() => { waitForFocus(() => {
win.gURLBar.focus(); win.gURLBar.focus();
win.gURLBar.value = inputText; win.gURLBar.value = inputText;
if (fireInputEvent) {
// This is necessary to get the urlbar to set gBrowser.userTypedValue.
let event = document.createEvent("Events");
event.initEvent("input", true, true);
win.gURLBar.dispatchEvent(event);
}
win.gURLBar.controller.startSearch(inputText); win.gURLBar.controller.startSearch(inputText);
}, win); }, win);

View File

@ -108,6 +108,8 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
"gURLBar.select(); goDoCommand('cmd_paste'); gURLBar.handleCommand();"); "gURLBar.select(); goDoCommand('cmd_paste'); gURLBar.handleCommand();");
cxmenu.insertBefore(pasteAndGo, insertLocation.nextSibling); cxmenu.insertBefore(pasteAndGo, insertLocation.nextSibling);
} }
this._enableOrDisableOneOffSearches();
]]></constructor> ]]></constructor>
<destructor><![CDATA[ <destructor><![CDATA[
@ -197,7 +199,11 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
this.popup.selectedIndex = -1; this.popup.selectedIndex = -1;
break; break;
} }
if (this.popup.popupOpen &&
!this.popup.disableKeyNavigation &&
this.popup.handleKeyPress(aEvent)) {
return true;
}
return this.handleKeyPress(aEvent); return this.handleKeyPress(aEvent);
]]></body> ]]></body>
</method> </method>
@ -331,135 +337,224 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
]]></body> ]]></body>
</method> </method>
<!--
This is ultimately called by the autocomplete controller as the result
of handleEnter when the Return key is pressed in the textbox. Since
onPopupClick also calls handleEnter, this is also called as a result in
that case.
@param event
The event that triggered the command.
@param openUILinkWhere
Optional. The "where" to pass to openUILinkIn. This method
computes the appropriate "where" given the event, but you can
use this to override it.
@param openUILinkParams
Optional. The parameters to pass to openUILinkIn. As with
"where", this method computes the appropriate parameters, but
any parameters you supply here will override those.
-->
<method name="handleCommand"> <method name="handleCommand">
<parameter name="aTriggeringEvent"/> <parameter name="event"/>
<parameter name="openUILinkWhere"/>
<parameter name="openUILinkParams"/>
<body><![CDATA[ <body><![CDATA[
if (aTriggeringEvent instanceof MouseEvent && aTriggeringEvent.button == 2) let isMouseEvent = event instanceof MouseEvent;
return; // Do nothing for right clicks if (isMouseEvent && event.button == 2) {
// Do nothing for right clicks.
var url = this.value; return;
var mayInheritPrincipal = false;
var postData = null;
let action = this._parseActionUrl(this._value);
let lastLocationChange = gBrowser.selectedBrowser.lastLocationChange;
let matchLastLocationChange = true;
if (action) {
if (action.type == "switchtab") {
url = action.params.url;
if (this.hasAttribute("actiontype")) {
this.handleRevert();
let prevTab = gBrowser.selectedTab;
if (switchToTabHavingURI(url) && isTabEmpty(prevTab)) {
gBrowser.removeTab(prevTab);
}
return;
}
} else if (action.type == "remotetab") {
url = action.params.url;
} else if (action.type == "keyword") {
url = action.params.url;
} else if (action.type == "searchengine") {
[url, postData] = this._parseAndRecordSearchEngineAction(action);
} else if (action.type == "visiturl") {
url = action.params.url;
}
continueOperation.call(this);
}
else {
this._canonizeURL(aTriggeringEvent, response => {
[url, postData, mayInheritPrincipal] = response;
if (url) {
matchLastLocationChange = (lastLocationChange ==
gBrowser.selectedBrowser.lastLocationChange);
continueOperation.call(this);
}
});
} }
function continueOperation() // Do the command of the selected one-off if it's not an engine.
{ let selectedOneOff =
this.value = url; this.popup.oneOffSearchButtons.visuallySelectedButton;
gBrowser.userTypedValue = url; if (selectedOneOff && !selectedOneOff.engine) {
if (gInitialPages.includes(url)) { selectedOneOff.doCommand();
gBrowser.selectedBrowser.initialPageLoadedFromURLBar = url; return;
} }
try {
addToUrlbarHistory(url);
} catch (ex) {
// Things may go wrong when adding url to session history,
// but don't let that interfere with the loading of the url.
Cu.reportError(ex);
}
let loadCurrent = () => { let where = openUILinkWhere;
try { if (!where) {
openUILinkIn(url, "current", { if (isMouseEvent) {
allowThirdPartyFixup: true, where = whereToOpenLink(event, false, false);
indicateErrorPageLoad: true,
disallowInheritPrincipal: !mayInheritPrincipal,
allowPinnedTabHostChange: true,
postData: postData,
allowPopups: url.startsWith("javascript:"),
});
} catch (ex) {
// This load can throw an exception in certain cases, which means
// we'll want to replace the URL with the loaded URL:
if (ex.result != Cr.NS_ERROR_LOAD_SHOWED_ERRORPAGE) {
this.handleRevert();
}
}
// Ensure the start of the URL is visible for UX reasons:
this.selectionStart = this.selectionEnd = 0;
};
// Focus the content area before triggering loads, since if the load
// occurs in a new tab, we want focus to be restored to the content
// area when the current tab is re-selected.
gBrowser.selectedBrowser.focus();
let isMouseEvent = aTriggeringEvent instanceof MouseEvent;
// If the current tab is empty, ignore Alt+Enter (just reuse this tab)
let altEnter = !isMouseEvent && aTriggeringEvent &&
aTriggeringEvent.altKey && !isTabEmpty(gBrowser.selectedTab);
if (isMouseEvent || altEnter) {
// Use the standard UI link behaviors for clicks or Alt+Enter
let where = "tab";
if (isMouseEvent)
where = whereToOpenLink(aTriggeringEvent, false, false);
if (where == "current") {
if (matchLastLocationChange) {
loadCurrent();
}
} else {
this.handleRevert();
let params = { allowThirdPartyFixup: true,
postData: postData,
initiatingDoc: document };
openUILinkIn(url, where, params);
}
} else { } else {
if (matchLastLocationChange) { // If the current tab is empty, ignore Alt+Enter (reuse this tab)
loadCurrent(); let altEnter = !isMouseEvent &&
} event &&
event.altKey &&
!isTabEmpty(gBrowser.selectedTab);
where = altEnter ? "tab" : "current";
} }
} }
let url = this.value;
let mayInheritPrincipal = false;
let postData = null;
let lastLocationChange = gBrowser.selectedBrowser.lastLocationChange;
let matchLastLocationChange = true;
let action = this._parseActionUrl(url);
if (action) {
switch (action.type) {
case "visiturl":
case "keyword":
case "remotetab":
url = action.params.url;
break;
case "switchtab":
url = action.params.url;
if (this.hasAttribute("actiontype")) {
this.handleRevert();
let prevTab = gBrowser.selectedTab;
if (switchToTabHavingURI(url) && isTabEmpty(prevTab)) {
gBrowser.removeTab(prevTab);
}
return;
}
break;
case "searchengine":
if (selectedOneOff && selectedOneOff.engine) {
// Replace the engine with the selected one-off engine.
action.params.engineName = engine.name;
}
[url, postData] = this._recordSearchEngineLoad(
action.params.engineName,
action.params.searchSuggestion || action.params.searchQuery,
event,
where,
openUILinkParams
);
break;
}
this._loadURL(url, postData, where, openUILinkParams,
matchLastLocationChange, mayInheritPrincipal);
return;
}
// If there's a selected one-off button and the input value is a
// search query (or "keyword" in URI-fixup terminology), then load a
// search using the one-off's engine.
if (selectedOneOff && selectedOneOff.engine) {
// `url` (which is this.value) may be an autofilled string. Search
// only with the portion that the user typed, if any, by preferring
// the autocomplete controller's searchString.
let value = this._searchStringOnHandleEnter ||
this.mController.searchString ||
url;
let fixup;
try {
fixup = Services.uriFixup.getFixupURIInfo(
value,
Services.uriFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP
);
} catch (ex) {}
if (fixup && fixup.keywordProviderName) {
[url, postData] =
this._recordSearchEngineLoad(selectedOneOff.engine, value,
event, where, openUILinkParams);
this._loadURL(url, postData, where, openUILinkParams,
matchLastLocationChange, mayInheritPrincipal);
return;
}
}
this._canonizeURL(event, response => {
[url, postData, mayInheritPrincipal] = response;
if (url) {
matchLastLocationChange =
lastLocationChange ==
gBrowser.selectedBrowser.lastLocationChange;
this._loadURL(url, postData, where, openUILinkParams,
matchLastLocationChange, mayInheritPrincipal);
}
});
]]></body>
</method>
<method name="_loadURL">
<parameter name="url"/>
<parameter name="postData"/>
<parameter name="openUILinkWhere"/>
<parameter name="openUILinkParams"/>
<parameter name="matchLastLocationChange"/>
<parameter name="mayInheritPrincipal"/>
<body><![CDATA[
this.value = url;
gBrowser.userTypedValue = url;
if (gInitialPages.includes(url)) {
gBrowser.selectedBrowser.initialPageLoadedFromURLBar = url;
}
try {
addToUrlbarHistory(url);
} catch (ex) {
// Things may go wrong when adding url to session history,
// but don't let that interfere with the loading of the url.
Cu.reportError(ex);
}
let params = {
postData: postData,
allowThirdPartyFixup: true,
};
if (openUILinkWhere == "current") {
params.indicateErrorPageLoad = true;
params.allowPinnedTabHostChange = true;
params.disallowInheritPrincipal = !mayInheritPrincipal;
params.allowPopups = url.startsWith("javascript:");
} else {
params.initiatingDoc = document;
}
if (openUILinkParams) {
for (let key in openUILinkParams) {
params[key] = openUILinkParams[key];
}
}
// Focus the content area before triggering loads, since if the load
// occurs in a new tab, we want focus to be restored to the content
// area when the current tab is re-selected.
gBrowser.selectedBrowser.focus();
if (openUILinkWhere == "current" && !matchLastLocationChange) {
return;
}
if (openUILinkWhere != "current") {
this.handleRevert();
}
try {
openUILinkIn(url, openUILinkWhere, params);
} catch (ex) {
// This load can throw an exception in certain cases, which means
// we'll want to replace the URL with the loaded URL:
if (ex.result != Cr.NS_ERROR_LOAD_SHOWED_ERRORPAGE) {
this.handleRevert();
}
}
if (openUILinkWhere == "current") {
// Ensure the start of the URL is visible for usability reasons.
this.selectionStart = this.selectionEnd = 0;
}
]]></body> ]]></body>
</method> </method>
<method name="_parseAndRecordSearchEngineAction"> <method name="_recordSearchEngineLoad">
<parameter name="action"/> <parameter name="engineOrEngineName"/>
<parameter name="query"/>
<parameter name="event"/>
<parameter name="openUILinkWhere"/>
<parameter name="openUILinkParams"/>
<body><![CDATA[ <body><![CDATA[
let engine = let engine =
Services.search.getEngineByName(action.params.engineName); typeof(engineOrEngineName) == "string" ?
Services.search.getEngineByName(engineOrEngineName) :
engineOrEngineName;
BrowserSearch.recordSearchInTelemetry(engine, "urlbar"); BrowserSearch.recordSearchInTelemetry(engine, "urlbar");
let query = action.params.searchSuggestion || this.popup.oneOffSearchButtons
action.params.searchQuery; .maybeRecordTelemetry(event, openUILinkWhere, openUILinkParams);
let submission = engine.getSubmission(query, null, "keyword"); let submission = engine.getSubmission(query, null, "keyword");
return [submission.uri.spec, submission.postData]; return [submission.uri.spec, submission.postData];
]]></body> ]]></body>
@ -728,11 +823,21 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
case "trimURLs": case "trimURLs":
this._mayTrimURLs = this._prefs.getBoolPref(aData); this._mayTrimURLs = this._prefs.getBoolPref(aData);
break; break;
case "oneOffSearches":
this._enableOrDisableOneOffSearches();
break;
} }
} }
]]></body> ]]></body>
</method> </method>
<method name="_enableOrDisableOneOffSearches">
<body><![CDATA[
let enable = this._prefs.getBoolPref("oneOffSearches");
this.popup.enableOneOffSearches(enable);
]]></body>
</method>
<method name="handleEvent"> <method name="handleEvent">
<parameter name="aEvent"/> <parameter name="aEvent"/>
<body><![CDATA[ <body><![CDATA[
@ -903,6 +1008,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
</method> </method>
<method name="handleEnter"> <method name="handleEnter">
<parameter name="event"/>
<body><![CDATA[ <body><![CDATA[
// We need to ensure we're using a selected autocomplete result. // We need to ensure we're using a selected autocomplete result.
// A result should automatically be selected by default, // A result should automatically be selected by default,
@ -919,7 +1025,13 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
// ensure that it corresponds to the current input. // ensure that it corresponds to the current input.
if (this.popup.selectedIndex != 0 || this.gotResultForCurrentQuery) { if (this.popup.selectedIndex != 0 || this.gotResultForCurrentQuery) {
return this.mController.handleEnter(false); // Store the current search string so it can be used in
// handleCommand, which will be called as a result of
// mController.handleEnter(). handleEnter will reset it.
this._searchStringOnHandleEnter = this.mController.searchString;
let rv = this.mController.handleEnter(false, event);
delete this._searchStringOnHandleEnter;
return rv;
} }
this.handleEnterWhenGotResult = true; this.handleEnterWhenGotResult = true;
@ -1100,7 +1212,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Check for unmodified left-click, and use default behavior // Check for unmodified left-click, and use default behavior
if (aEvent.button == 0 && !aEvent.shiftKey && !aEvent.ctrlKey && if (aEvent.button == 0 && !aEvent.shiftKey && !aEvent.ctrlKey &&
!aEvent.altKey && !aEvent.metaKey) { !aEvent.altKey && !aEvent.metaKey) {
controller.handleEnter(true); controller.handleEnter(true, aEvent);
return; return;
} }
@ -1137,6 +1249,11 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
<binding id="urlbar-rich-result-popup" extends="chrome://global/content/bindings/autocomplete.xml#autocomplete-rich-result-popup"> <binding id="urlbar-rich-result-popup" extends="chrome://global/content/bindings/autocomplete.xml#autocomplete-rich-result-popup">
<resources>
<stylesheet src="chrome://browser/content/search/searchbarBindings.css"/>
<stylesheet src="chrome://browser/skin/searchbar.css"/>
</resources>
<content ignorekeys="true" level="top" consumeoutsideclicks="never" <content ignorekeys="true" level="top" consumeoutsideclicks="never"
aria-owns="richlistbox"> aria-owns="richlistbox">
<xul:hbox anonid="search-suggestions-notification" <xul:hbox anonid="search-suggestions-notification"
@ -1171,6 +1288,10 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
flex="1"/> flex="1"/>
<xul:hbox anonid="footer"> <xul:hbox anonid="footer">
<children/> <children/>
<xul:vbox anonid="one-off-search-buttons"
class="search-one-offs"
compact="true"
flex="1"/>
</xul:hbox> </xul:hbox>
</content> </content>
@ -1193,6 +1314,31 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
document.getAnonymousElementByAttribute(this, "anonid", "footer"); document.getAnonymousElementByAttribute(this, "anonid", "footer");
</field> </field>
<field name="oneOffSearchButtons" readonly="true">
document.getAnonymousElementByAttribute(this, "anonid",
"one-off-search-buttons");
</field>
<field name="_oneOffSearchesEnabled">false</field>
<method name="enableOneOffSearches">
<parameter name="enable"/>
<body><![CDATA[
this._oneOffSearchesEnabled = enable;
if (enable) {
this.oneOffSearchButtons.style.display = "-moz-box";
this.oneOffSearchButtons.popup = this;
this.oneOffSearchButtons.textbox = this.input;
this.oneOffSearchButtons.telemetryOrigin = "urlbar";
} else {
this.oneOffSearchButtons.style.display = "none";
this.oneOffSearchButtons.popup = null;
this.oneOffSearchButtons.textbox = null;
this.oneOffSearchButtons.telemetryOrigin = null;
}
]]></body>
</method>
<method name="openSearchSuggestionsNotificationLearnMoreURL"> <method name="openSearchSuggestionsNotificationLearnMoreURL">
<body><![CDATA[ <body><![CDATA[
let url = Services.urlFormatter.formatURL( let url = Services.urlFormatter.formatURL(
@ -1491,62 +1637,68 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
</body> </body>
</method> </method>
<method name="onPopupClick"> <method name="_visuallySelectedOneOffChanged">
<parameter name="aEvent"/> <body><![CDATA[
<body> // Update all searchengine result items to use the newly selected
<![CDATA[ // engine.
// Ignore right-clicks for (let item of this.richlistbox.childNodes) {
if (aEvent.button == 2) if (item.collapsed) {
return; break;
}
var controller = this.view.QueryInterface(Components.interfaces.nsIAutoCompleteController); let url = item.getAttribute("url");
if (url) {
// Check for unmodified left-click, and use default behavior let action = item._parseActionUrl(url);
if (aEvent.button == 0 && !aEvent.shiftKey && !aEvent.ctrlKey && if (action && action.type == "searchengine") {
!aEvent.altKey && !aEvent.metaKey) { item._adjustAcItem();
controller.handleEnter(true);
return;
}
// Check for middle-click or modified clicks on the URL bar
if (gURLBar && this.mInput == gURLBar) {
var url = controller.getValueAt(this.selectedIndex);
var options = {};
// close the autocomplete popup and revert the entered address
this.closePopup();
controller.handleEscape();
// Check if this is meant to be an action
let action = this.mInput._parseActionUrl(url);
if (action) {
// TODO (bug 1054816): Centralise the implementation of actions
// into a JS module.
switch (action.type) {
case "switchtab": // Fall through.
case "keyword": // Fall through.
case "visiturl": {
url = action.params.url;
break;
}
case "searchengine": {
[url, options.postData] =
this.input._parseAndRecordSearchEngineAction(action);
break;
}
default: {
return;
}
} }
} }
// respect the usual clicking subtleties
openUILink(url, aEvent, options);
} }
]]> ]]></body>
</body>
</method> </method>
<!-- This handles keypress changes to the selection among the one-off
search buttons and between the one-offs and the listbox. It returns
true if the keypress was consumed and false if not. -->
<method name="handleKeyPress">
<parameter name="aEvent"/>
<body><![CDATA[
this.oneOffSearchButtons.handleKeyPress(aEvent, this._matchCount,
!this._isFirstResultHeuristic,
gBrowser.userTypedValue);
return aEvent.defaultPrevented;
]]></body>
</method>
<!-- This is called when a one-off is clicked and when "search in new tab"
is selected from a one-off context menu. -->
<method name="handleOneOffSearch">
<parameter name="event"/>
<parameter name="engine"/>
<parameter name="where"/>
<parameter name="params"/>
<body><![CDATA[
this.input.handleCommand(event, where, params);
]]></body>
</method>
<!-- Result listitems call this to determine which search engine they
should show in their labels and include in their url attributes. -->
<property name="overrideSearchEngineName" readonly="true">
<getter><![CDATA[
// When building the popup, autocomplete reuses an item at index i if
// that item's url attribute matches the controller's value at index
// i, but only if overrideSearchEngineName matches the engine in the
// url attribute. To absolutely avoid reusing items that shouldn't be
// reused, always return a non-null name here by falling back to the
// current engine.
let engine =
(this.oneOffSearchButtons.visuallySelectedButton &&
this.oneOffSearchButtons.visuallySelectedButton.engine) ||
Services.search.currentEngine;
return engine ? engine.name : null;
]]></getter>
</property>
<method name="createResultLabel"> <method name="createResultLabel">
<parameter name="item"/> <parameter name="item"/>
<parameter name="proposedLabel"/> <parameter name="proposedLabel"/>
@ -1616,6 +1768,10 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
</implementation> </implementation>
<handlers> <handlers>
<handler event="OneOffsVisuallySelectedButtonChanged"><![CDATA[
this._visuallySelectedOneOffChanged();
]]></handler>
<handler event="mousedown"><![CDATA[ <handler event="mousedown"><![CDATA[
// Required to make the xul:label.text-link elements in the search // Required to make the xul:label.text-link elements in the search
// suggestions notification work correctly when clicked on Linux. // suggestions notification work correctly when clicked on Linux.

View File

@ -447,13 +447,15 @@ MenuItem.prototype = {
let targetPattern = this.targetUrlMatchPattern; let targetPattern = this.targetUrlMatchPattern;
if (targetPattern) { if (targetPattern) {
let isMedia = contextData.onImage || contextData.onAudio || contextData.onVideo; let targetUrls = [];
if (!isMedia) { if (contextData.onImage || contextData.onAudio || contextData.onVideo) {
return false; // TODO: double check if srcUrl is always set when we need it
targetUrls.push(contextData.srcUrl);
} }
let srcURI = Services.io.newURI(contextData.srcUrl, null, null); if (contextData.onLink) {
if (!targetPattern.matches(srcURI)) { targetUrls.push(contextData.linkUrl);
// TODO: double check if mediaURL is always set when we need it }
if (!targetUrls.some(targetUrl => targetPattern.matches(NetUtil.newURI(targetUrl)))) {
return false; return false;
} }
} }

View File

@ -15,7 +15,7 @@ add_task(function* () {
// Test menu items using targetUrlPatterns. // Test menu items using targetUrlPatterns.
browser.contextMenus.create({ browser.contextMenus.create({
title: "targetUrlPatterns-patternMatches-contextAll", title: "targetUrlPatterns-patternMatches-contextAll",
targetUrlPatterns: ["*://*/*ctxmenu-image.png"], targetUrlPatterns: ["*://*/*ctxmenu-image.png", "*://*/*some-link"],
contexts: ["all"], contexts: ["all"],
}); });
@ -25,6 +25,12 @@ add_task(function* () {
contexts: ["image"], contexts: ["image"],
}); });
browser.contextMenus.create({
title: "targetUrlPatterns-patternMatches-contextLink",
targetUrlPatterns: ["*://*/*some-link"],
contexts: ["link"],
});
browser.contextMenus.create({ browser.contextMenus.create({
title: "targetUrlPatterns-patternDoesNotMatch-contextAll", title: "targetUrlPatterns-patternDoesNotMatch-contextAll",
targetUrlPatterns: ["*://*/does-not-match"], targetUrlPatterns: ["*://*/does-not-match"],
@ -37,6 +43,12 @@ add_task(function* () {
contexts: ["image"], contexts: ["image"],
}); });
browser.contextMenus.create({
title: "targetUrlPatterns-patternDoesNotMatch-contextLink",
targetUrlPatterns: ["*://*/does-not-match"],
contexts: ["link"],
});
// Test menu items using documentUrlPatterns. // Test menu items using documentUrlPatterns.
browser.contextMenus.create({ browser.contextMenus.create({
title: "documentUrlPatterns-patternMatches-contextAll", title: "documentUrlPatterns-patternMatches-contextAll",
@ -50,6 +62,12 @@ add_task(function* () {
contexts: ["image"], contexts: ["image"],
}); });
browser.contextMenus.create({
title: "documentUrlPatterns-patternMatches-contextLink",
documentUrlPatterns: ["*://*/*context.html", "*://*/does-not-match"],
contexts: ["link"],
});
browser.contextMenus.create({ browser.contextMenus.create({
title: "documentUrlPatterns-patternDoesNotMatch-contextAll", title: "documentUrlPatterns-patternDoesNotMatch-contextAll",
documentUrlPatterns: ["*://*/does-not-match"], documentUrlPatterns: ["*://*/does-not-match"],
@ -62,6 +80,12 @@ add_task(function* () {
contexts: ["image"], contexts: ["image"],
}); });
browser.contextMenus.create({
title: "documentUrlPatterns-patternDoesNotMatch-contextLink",
documentUrlPatterns: ["*://*/does-not-match"],
contexts: ["link"],
});
// Test menu items using both targetUrlPatterns and documentUrlPatterns. // Test menu items using both targetUrlPatterns and documentUrlPatterns.
browser.contextMenus.create({ browser.contextMenus.create({
title: "documentUrlPatterns-patternMatches-targetUrlPatterns-patternMatches-contextAll", title: "documentUrlPatterns-patternMatches-targetUrlPatterns-patternMatches-contextAll",
@ -141,12 +165,16 @@ add_task(function* () {
let expected = [ let expected = [
["targetUrlPatterns-patternMatches-contextAll", true], ["targetUrlPatterns-patternMatches-contextAll", true],
["targetUrlPatterns-patternMatches-contextImage", true], ["targetUrlPatterns-patternMatches-contextImage", true],
["targetUrlPatterns-patternMatches-contextLink", false],
["targetUrlPatterns-patternDoesNotMatch-contextAll", false], ["targetUrlPatterns-patternDoesNotMatch-contextAll", false],
["targetUrlPatterns-patternDoesNotMatch-contextImage", false], ["targetUrlPatterns-patternDoesNotMatch-contextImage", false],
["targetUrlPatterns-patternDoesNotMatch-contextLink", false],
["documentUrlPatterns-patternMatches-contextAll", true], ["documentUrlPatterns-patternMatches-contextAll", true],
["documentUrlPatterns-patternMatches-contextImage", true], ["documentUrlPatterns-patternMatches-contextImage", true],
["documentUrlPatterns-patternMatches-contextLink", false],
["documentUrlPatterns-patternDoesNotMatch-contextAll", false], ["documentUrlPatterns-patternDoesNotMatch-contextAll", false],
["documentUrlPatterns-patternDoesNotMatch-contextImage", false], ["documentUrlPatterns-patternDoesNotMatch-contextImage", false],
["documentUrlPatterns-patternDoesNotMatch-contextLink", false],
["documentUrlPatterns-patternMatches-targetUrlPatterns-patternMatches-contextAll", true], ["documentUrlPatterns-patternMatches-targetUrlPatterns-patternMatches-contextAll", true],
["documentUrlPatterns-patternDoesNotMatch-targetUrlPatterns-patternMatches-contextAll", false], ["documentUrlPatterns-patternDoesNotMatch-targetUrlPatterns-patternMatches-contextAll", false],
["documentUrlPatterns-patternMatches-targetUrlPatterns-patternDoesNotMatch-contextAll", false], ["documentUrlPatterns-patternMatches-targetUrlPatterns-patternDoesNotMatch-contextAll", false],
@ -163,12 +191,16 @@ add_task(function* () {
expected = [ expected = [
["targetUrlPatterns-patternMatches-contextAll", false], ["targetUrlPatterns-patternMatches-contextAll", false],
["targetUrlPatterns-patternMatches-contextImage", false], ["targetUrlPatterns-patternMatches-contextImage", false],
["targetUrlPatterns-patternMatches-contextLink", false],
["targetUrlPatterns-patternDoesNotMatch-contextAll", false], ["targetUrlPatterns-patternDoesNotMatch-contextAll", false],
["targetUrlPatterns-patternDoesNotMatch-contextImage", false], ["targetUrlPatterns-patternDoesNotMatch-contextImage", false],
["targetUrlPatterns-patternDoesNotMatch-contextLink", false],
["documentUrlPatterns-patternMatches-contextAll", true], ["documentUrlPatterns-patternMatches-contextAll", true],
["documentUrlPatterns-patternMatches-contextImage", false], ["documentUrlPatterns-patternMatches-contextImage", false],
["documentUrlPatterns-patternMatches-contextLink", false],
["documentUrlPatterns-patternDoesNotMatch-contextAll", false], ["documentUrlPatterns-patternDoesNotMatch-contextAll", false],
["documentUrlPatterns-patternDoesNotMatch-contextImage", false], ["documentUrlPatterns-patternDoesNotMatch-contextImage", false],
["documentUrlPatterns-patternDoesNotMatch-contextLink", false],
["documentUrlPatterns-patternMatches-targetUrlPatterns-patternMatches-contextAll", false], ["documentUrlPatterns-patternMatches-targetUrlPatterns-patternMatches-contextAll", false],
["documentUrlPatterns-patternDoesNotMatch-targetUrlPatterns-patternMatches-contextAll", false], ["documentUrlPatterns-patternDoesNotMatch-targetUrlPatterns-patternMatches-contextAll", false],
["documentUrlPatterns-patternMatches-targetUrlPatterns-patternDoesNotMatch-contextAll", false], ["documentUrlPatterns-patternMatches-targetUrlPatterns-patternDoesNotMatch-contextAll", false],
@ -181,6 +213,42 @@ add_task(function* () {
yield confirmContextMenuItems(contextMenu, expected); yield confirmContextMenuItems(contextMenu, expected);
yield closeContextMenu(); yield closeContextMenu();
contextMenu = yield openContextMenu("#link1");
expected = [
["targetUrlPatterns-patternMatches-contextAll", true],
["targetUrlPatterns-patternMatches-contextImage", false],
["targetUrlPatterns-patternMatches-contextLink", true],
["targetUrlPatterns-patternDoesNotMatch-contextAll", false],
["targetUrlPatterns-patternDoesNotMatch-contextImage", false],
["targetUrlPatterns-patternDoesNotMatch-contextLink", false],
["documentUrlPatterns-patternMatches-contextAll", true],
["documentUrlPatterns-patternMatches-contextImage", false],
["documentUrlPatterns-patternMatches-contextLink", true],
["documentUrlPatterns-patternDoesNotMatch-contextAll", false],
["documentUrlPatterns-patternDoesNotMatch-contextImage", false],
["documentUrlPatterns-patternDoesNotMatch-contextLink", false],
];
yield confirmContextMenuItems(contextMenu, expected);
yield closeContextMenu();
contextMenu = yield openContextMenu("#img-wrapped-in-link");
expected = [
["targetUrlPatterns-patternMatches-contextAll", true],
["targetUrlPatterns-patternMatches-contextImage", true],
["targetUrlPatterns-patternMatches-contextLink", true],
["targetUrlPatterns-patternDoesNotMatch-contextAll", false],
["targetUrlPatterns-patternDoesNotMatch-contextImage", false],
["targetUrlPatterns-patternDoesNotMatch-contextLink", false],
["documentUrlPatterns-patternMatches-contextAll", true],
["documentUrlPatterns-patternMatches-contextImage", true],
["documentUrlPatterns-patternMatches-contextLink", true],
["documentUrlPatterns-patternDoesNotMatch-contextAll", false],
["documentUrlPatterns-patternDoesNotMatch-contextImage", false],
["documentUrlPatterns-patternDoesNotMatch-contextLink", false],
];
yield confirmContextMenuItems(contextMenu, expected);
yield closeContextMenu();
yield extension.unload(); yield extension.unload();
yield BrowserTestUtils.removeTab(tab1); yield BrowserTestUtils.removeTab(tab1);
}); });

View File

@ -4,5 +4,15 @@
<body> <body>
just some text 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 just some text 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
<img src="ctxmenu-image.png" id="img1"> <img src="ctxmenu-image.png" id="img1">
<p>
<a href="some-link" id="link1">Some link</a>
</p>
<p>
<a href="image-around-some-link">
<img src="ctxmenu-image.png" id="img-wrapped-in-link">
</a>
</p>
</body> </body>
</html> </html>

View File

@ -1135,7 +1135,7 @@ BrowserGlue.prototype = {
this._checkForOldBuildUpdates(); this._checkForOldBuildUpdates();
if ("release" != AppConstants.MOZ_UPDATE_CHANNEL) { if (!AppConstants.RELEASE_BUILD) {
this.checkForPendingCrashReports(); this.checkForPendingCrashReports();
} }

File diff suppressed because it is too large Load Diff

View File

@ -7,3 +7,12 @@
.searchbar-textbox { .searchbar-textbox {
-moz-binding: url("chrome://browser/content/search/search.xml#searchbar-textbox"); -moz-binding: url("chrome://browser/content/search/search.xml#searchbar-textbox");
} }
.search-one-offs {
-moz-binding: url("chrome://browser/content/search/search.xml#search-one-offs");
}
.search-setting-button[compact=true],
.search-setting-button-compact:not([compact=true]) {
display: none;
}

View File

@ -14,21 +14,6 @@ const diacritic_engine = "Foo \u2661";
var Preferences = var Preferences =
Cu.import("resource://gre/modules/Preferences.jsm", {}).Preferences; Cu.import("resource://gre/modules/Preferences.jsm", {}).Preferences;
// Get an array of the one-off buttons.
function getOneOffs() {
let oneOffs = [];
let oneOff =
document.getAnonymousElementByAttribute(searchPopup, "anonid",
"search-panel-one-offs");
for (oneOff = oneOff.firstChild; oneOff; oneOff = oneOff.nextSibling) {
if (oneOff.classList.contains("dummy"))
break;
oneOffs.push(oneOff);
}
return oneOffs;
}
add_task(function* init() { add_task(function* init() {
let currentEngine = Services.search.currentEngine; let currentEngine = Services.search.currentEngine;
yield promiseNewEngine("testEngine_diacritics.xml", {setAsCurrent: false}); yield promiseNewEngine("testEngine_diacritics.xml", {setAsCurrent: false});

View File

@ -10,11 +10,15 @@ const textbox = searchbar._textbox;
const searchPopup = document.getElementById("PopupSearchAutoComplete"); const searchPopup = document.getElementById("PopupSearchAutoComplete");
const searchIcon = document.getAnonymousElementByAttribute(searchbar, "anonid", const searchIcon = document.getAnonymousElementByAttribute(searchbar, "anonid",
"searchbar-search-button"); "searchbar-search-button");
const searchSettings =
const oneOffsContainer =
document.getAnonymousElementByAttribute(searchPopup, "anonid", document.getAnonymousElementByAttribute(searchPopup, "anonid",
"search-one-off-buttons");
const searchSettings =
document.getAnonymousElementByAttribute(oneOffsContainer, "anonid",
"search-settings"); "search-settings");
var header = var header =
document.getAnonymousElementByAttribute(searchPopup, "anonid", document.getAnonymousElementByAttribute(oneOffsContainer, "anonid",
"search-panel-one-offs-header"); "search-panel-one-offs-header");
function getHeaderText() { function getHeaderText() {
let headerChild = header.selectedPanel; let headerChild = header.selectedPanel;
@ -28,21 +32,6 @@ function getHeaderText() {
return headerStrings.join(""); return headerStrings.join("");
} }
// Get an array of the one-off buttons.
function getOneOffs() {
let oneOffs = [];
let oneOff =
document.getAnonymousElementByAttribute(searchPopup, "anonid",
"search-panel-one-offs");
for (oneOff = oneOff.firstChild; oneOff; oneOff = oneOff.nextSibling) {
if (oneOff.classList.contains("dummy"))
break;
oneOffs.push(oneOff);
}
return oneOffs;
}
const msg = isMac ? 5 : 1; const msg = isMac ? 5 : 1;
const utils = window.QueryInterface(Ci.nsIInterfaceRequestor) const utils = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils); .getInterface(Ci.nsIDOMWindowUtils);

View File

@ -3,29 +3,18 @@
const searchbar = document.getElementById("searchbar"); const searchbar = document.getElementById("searchbar");
const textbox = searchbar._textbox; const textbox = searchbar._textbox;
const searchPopup = document.getElementById("PopupSearchAutoComplete"); const searchPopup = document.getElementById("PopupSearchAutoComplete");
const oneOffsContainer =
document.getAnonymousElementByAttribute(searchPopup, "anonid",
"search-one-off-buttons");
const kValues = ["foo1", "foo2", "foo3"]; const kValues = ["foo1", "foo2", "foo3"];
const kUserValue = "foo"; const kUserValue = "foo";
// Get an array of the one-off buttons.
function getOneOffs() {
let oneOffs = [];
let oneOff = document.getAnonymousElementByAttribute(searchPopup, "anonid",
"search-panel-one-offs");
for (oneOff = oneOff.firstChild; oneOff; oneOff = oneOff.nextSibling) {
if (oneOff.classList.contains("dummy"))
break;
oneOffs.push(oneOff);
}
return oneOffs;
}
function getOpenSearchItems() { function getOpenSearchItems() {
let os = []; let os = [];
let addEngineList = let addEngineList =
document.getAnonymousElementByAttribute(searchPopup, "anonid", document.getAnonymousElementByAttribute(oneOffsContainer, "anonid",
"add-engines"); "add-engines");
for (let item = addEngineList.firstChild; item; item = item.nextSibling) for (let item = addEngineList.firstChild; item; item = item.nextSibling)
os.push(item); os.push(item);

View File

@ -3,30 +3,19 @@
const searchbar = document.getElementById("searchbar"); const searchbar = document.getElementById("searchbar");
const textbox = searchbar._textbox; const textbox = searchbar._textbox;
const searchPopup = document.getElementById("PopupSearchAutoComplete"); const searchPopup = document.getElementById("PopupSearchAutoComplete");
const oneOffsContainer =
document.getAnonymousElementByAttribute(searchPopup, "anonid",
"search-one-off-buttons");
const searchIcon = document.getAnonymousElementByAttribute(searchbar, "anonid", const searchIcon = document.getAnonymousElementByAttribute(searchbar, "anonid",
"searchbar-search-button"); "searchbar-search-button");
const kValues = ["foo1", "foo2", "foo3"]; const kValues = ["foo1", "foo2", "foo3"];
// Get an array of the one-off buttons.
function getOneOffs() {
let oneOffs = [];
let oneOff = document.getAnonymousElementByAttribute(searchPopup, "anonid",
"search-panel-one-offs");
for (oneOff = oneOff.firstChild; oneOff; oneOff = oneOff.nextSibling) {
if (oneOff.classList.contains("dummy"))
break;
oneOffs.push(oneOff);
}
return oneOffs;
}
function getOpenSearchItems() { function getOpenSearchItems() {
let os = []; let os = [];
let addEngineList = let addEngineList =
document.getAnonymousElementByAttribute(searchPopup, "anonid", document.getAnonymousElementByAttribute(oneOffsContainer, "anonid",
"add-engines"); "add-engines");
for (let item = addEngineList.firstChild; item; item = item.nextSibling) for (let item = addEngineList.firstChild; item; item = item.nextSibling)
os.push(item); os.push(item);

View File

@ -136,3 +136,24 @@ function promiseTabLoadEvent(tab, url)
// timeout promise as well, causing the all promise to resolve. // timeout promise as well, causing the all promise to resolve.
return Promise.all([deferred.promise, loaded]); return Promise.all([deferred.promise, loaded]);
} }
// Get an array of the one-off buttons.
function getOneOffs() {
let oneOffs = [];
let searchPopup = document.getElementById("PopupSearchAutoComplete");
let oneOffsContainer =
document.getAnonymousElementByAttribute(searchPopup, "anonid",
"search-one-off-buttons");
let oneOff =
document.getAnonymousElementByAttribute(oneOffsContainer, "anonid",
"search-panel-one-offs");
for (oneOff = oneOff.firstChild; oneOff; oneOff = oneOff.nextSibling) {
if (oneOff.nodeType == Node.ELEMENT_NODE) {
if (oneOff.classList.contains("dummy") ||
oneOff.classList.contains("search-setting-button-compact"))
break;
oneOffs.push(oneOff);
}
}
return oneOffs;
}

View File

@ -158,7 +158,7 @@ menuitem[cmd="cmd_clearhistory"][disabled] {
.search-panel-one-offs { .search-panel-one-offs {
margin: 0 -1px !important; margin: 0 -1px !important;
border-top: 1px solid rgba(0, 0, 0, 0.2); border-top: 1px solid #ccc;
} }
.searchbar-engine-one-off-item { .searchbar-engine-one-off-item {
@ -184,7 +184,15 @@ menuitem[cmd="cmd_clearhistory"][disabled] {
border-bottom: 1px solid rgba(0, 0, 0, 0.2); border-bottom: 1px solid rgba(0, 0, 0, 0.2);
} }
.searchbar-engine-one-off-item.last-of-row { .search-setting-button-compact {
border-bottom: none !important;
}
.search-panel-one-offs:not([compact=true]) > .searchbar-engine-one-off-item.last-of-row,
.search-panel-one-offs[compact=true] > .searchbar-engine-one-off-item.last-of-row:not(.dummy),
.search-panel-one-offs[compact=true] > .searchbar-engine-one-off-item.dummy:not(.last-of-row),
.search-panel-one-offs[compact=true] > .searchbar-engine-one-off-item.last-engine,
.search-setting-button-compact {
background-image: none; background-image: none;
} }
@ -298,3 +306,11 @@ menuitem[cmd="cmd_clearhistory"][disabled] {
color: HighlightText; color: HighlightText;
border-top-color: #bdbebe; border-top-color: #bdbebe;
} }
.search-setting-button-compact {
list-style-image: url("chrome://browser/skin/gear.svg#gear");
}
.search-setting-button-compact[selected] {
list-style-image: url("chrome://browser/skin/gear.svg#gear-inverted");
}

View File

@ -173,7 +173,15 @@
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
} }
.searchbar-engine-one-off-item.last-of-row { .search-setting-button-compact {
border-bottom: none !important;
}
.search-panel-one-offs:not([compact=true]) > .searchbar-engine-one-off-item.last-of-row,
.search-panel-one-offs[compact=true] > .searchbar-engine-one-off-item.last-of-row:not(.dummy),
.search-panel-one-offs[compact=true] > .searchbar-engine-one-off-item.dummy:not(.last-of-row),
.search-panel-one-offs[compact=true] > .searchbar-engine-one-off-item.last-engine,
.search-setting-button-compact {
background-image: none; background-image: none;
} }
@ -277,3 +285,11 @@
background-color: #d3d3d3; background-color: #d3d3d3;
border-top-color: #bdbebe; border-top-color: #bdbebe;
} }
.search-setting-button-compact {
list-style-image: url("chrome://browser/skin/gear.svg#gear");
}
.search-setting-button-compact[selected] {
list-style-image: url("chrome://browser/skin/gear.svg#gear-inverted");
}

View File

@ -8,9 +8,11 @@
#UITourHighlightContainer { #UITourHighlightContainer {
-moz-appearance: none; -moz-appearance: none;
-moz-window-shadow: none;
border: none; border: none;
background-color: transparent; background-color: transparent;
/* This is a buffer to compensate for the movement in the "wobble" effect */ /* This is a buffer to compensate for the movement in the "wobble" effect,
and for the box-shadow of #UITourHighlight. */
padding: 4px; padding: 4px;
} }

View File

@ -98,6 +98,7 @@
skin/classic/browser/search-history-icon.svg (../shared/search/history-icon.svg) skin/classic/browser/search-history-icon.svg (../shared/search/history-icon.svg)
skin/classic/browser/search-indicator-magnifying-glass.svg (../shared/search/search-indicator-magnifying-glass.svg) skin/classic/browser/search-indicator-magnifying-glass.svg (../shared/search/search-indicator-magnifying-glass.svg)
skin/classic/browser/search-arrow-go.svg (../shared/search/search-arrow-go.svg) skin/classic/browser/search-arrow-go.svg (../shared/search/search-arrow-go.svg)
skin/classic/browser/gear.svg (../shared/search/gear.svg)
skin/classic/browser/social/chat-icons.svg (../shared/social/chat-icons.svg) skin/classic/browser/social/chat-icons.svg (../shared/social/chat-icons.svg)
skin/classic/browser/social/gear_default.png (../shared/social/gear_default.png) skin/classic/browser/social/gear_default.png (../shared/social/gear_default.png)
skin/classic/browser/social/gear_clicked.png (../shared/social/gear_clicked.png) skin/classic/browser/social/gear_clicked.png (../shared/social/gear_clicked.png)

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 32 32">
<style>
use:not(:target) {
display: none;
}
use {
fill: GrayText;
}
use[id$="-inverted"] {
fill: highlighttext;
}
</style>
<defs>
<path id="glyphShape-gear" d="M28,16c0-1.7,0.9-3.1,2-3.3c-0.4-1.5-0.9-2.9-1.7-4.2c-0.9,0.7-2.6,0.3-3.8-0.9c-1.2-1.2-1.6-2.8-0.9-3.8 c-1.3-0.8-2.7-1.4-4.2-1.7c-0.2,1.1-1.6,2-3.3,2S13,3.1,12.8,2c-1.5,0.4-2.9,0.9-4.2,1.7c0.7,0.9,0.3,2.6-0.9,3.8 c-1.4,1.1-3,1.5-4,0.9C2.9,9.7,2.4,11.2,2,12.7c1.1,0.2,2,1.6,2,3.3s-0.9,3.1-2,3.3c0.4,1.5,0.9,2.9,1.7,4.2 c0.9-0.7,2.6-0.3,3.8,0.9c1.2,1.2,1.6,2.8,0.9,3.8c1.3,0.8,2.7,1.4,4.2,1.7c0.2-1.1,1.6-2,3.3-2s3.1,0.9,3.3,2 c1.5-0.4,2.9-0.9,4.2-1.7c-0.7-0.9-0.3-2.6,0.9-3.8c1.3-1.2,2.8-1.6,3.8-0.9c0.8-1.3,1.4-2.7,1.7-4.2C28.9,19.1,28,17.7,28,16z M16,24c-4.4,0-8-3.6-8-8s3.6-8,8-8s8,3.6,8,8S20.4,24,16,24z"/>
</defs>
<use id="gear" xlink:href="#glyphShape-gear"/>
<use id="gear-inverted" xlink:href="#glyphShape-gear"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -181,7 +181,15 @@
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
} }
.searchbar-engine-one-off-item.last-of-row { .search-setting-button-compact {
border-bottom: none !important;
}
.search-panel-one-offs:not([compact=true]) > .searchbar-engine-one-off-item.last-of-row,
.search-panel-one-offs[compact=true] > .searchbar-engine-one-off-item.last-of-row:not(.dummy),
.search-panel-one-offs[compact=true] > .searchbar-engine-one-off-item.dummy:not(.last-of-row),
.search-panel-one-offs[compact=true] > .searchbar-engine-one-off-item.last-engine,
.search-setting-button-compact {
background-image: none; background-image: none;
} }
@ -291,3 +299,11 @@
background-color: #d3d3d3; background-color: #d3d3d3;
border-top-color: #bdbebe; border-top-color: #bdbebe;
} }
.search-setting-button-compact {
list-style-image: url("chrome://browser/skin/gear.svg#gear");
}
.search-setting-button-compact[selected] {
list-style-image: url("chrome://browser/skin/gear.svg#gear-inverted");
}

View File

@ -178,7 +178,9 @@ def valid_ucrt_sdk_dir_result(value):
@depends_win(windows_sdk_dir, 'WINDOWSSDKDIR') @depends_win(windows_sdk_dir, 'WINDOWSSDKDIR')
@checking('for Universal CRT SDK', valid_ucrt_sdk_dir_result) @checking('for Universal CRT SDK', valid_ucrt_sdk_dir_result)
@imports('os')
@imports(_from='__builtin__', _import='sorted') @imports(_from='__builtin__', _import='sorted')
@imports(_import='mozpack.path', _as='mozpath')
def valid_ucrt_sdk_dir(windows_sdk_dir, windows_sdk_dir_env): def valid_ucrt_sdk_dir(windows_sdk_dir, windows_sdk_dir_env):
if windows_sdk_dir_env: if windows_sdk_dir_env:
windows_sdk_dir_env = windows_sdk_dir_env[0] windows_sdk_dir_env = windows_sdk_dir_env[0]
@ -196,6 +198,31 @@ def valid_ucrt_sdk_dir(windows_sdk_dir, windows_sdk_dir_env):
sdks[d] = Version(version), sdk sdks[d] = Version(version), sdk
continue continue
if d == windows_sdk_dir_env: if d == windows_sdk_dir_env:
# When WINDOWSSDKDIR is set in the environment and we can't find the
# Universal CRT SDK, chances are this is a start-shell-msvc*.bat
# setup, where INCLUDE and LIB already contain the UCRT paths.
ucrt_includes = [
p for p in os.environ.get('INCLUDE', '').split(os.pathsep)
if os.path.basename(p).lower() == 'ucrt'
]
ucrt_libs = [
p for p in os.environ.get('LIB', '').split(os.pathsep)
if os.path.basename(os.path.dirname(p)).lower() == 'ucrt'
]
if ucrt_includes and ucrt_libs:
# Pick the first of each, since they are the ones that the
# compiler would look first. Assume they contain the SDK files.
include = os.path.dirname(ucrt_includes[0])
lib = os.path.dirname(os.path.dirname(ucrt_libs[0]))
path = os.path.dirname(os.path.dirname(include))
version = os.path.basename(include)
if version != 'include' and mozpath.basedir(lib, [path]):
sdks[d] = Version(version), namespace(
path=path,
include=include,
lib=lib,
)
continue
raise FatalCheckError( raise FatalCheckError(
'The SDK in WINDOWSSDKDIR (%s) does not contain the Universal ' 'The SDK in WINDOWSSDKDIR (%s) does not contain the Universal '
'CRT.' % windows_sdk_dir_env) 'CRT.' % windows_sdk_dir_env)

View File

@ -29,8 +29,8 @@ FontInspector.prototype = {
this.inspector.selection.on("new-node", this.onNewNode); this.inspector.selection.on("new-node", this.onNewNode);
this.inspector.sidebar.on("fontinspector-selected", this.onNewNode); this.inspector.sidebar.on("fontinspector-selected", this.onNewNode);
this.showAll = this.showAll.bind(this); this.showAll = this.showAll.bind(this);
this.showAllButton = this.chromeDoc.getElementById("font-showall"); this.showAllLink = this.chromeDoc.getElementById("font-showall");
this.showAllButton.addEventListener("click", this.showAll); this.showAllLink.addEventListener("click", this.showAll);
this.previewTextChanged = this.previewTextChanged.bind(this); this.previewTextChanged = this.previewTextChanged.bind(this);
this.previewInput = this.previewInput =
this.chromeDoc.getElementById("font-preview-text-input"); this.chromeDoc.getElementById("font-preview-text-input");
@ -57,7 +57,7 @@ FontInspector.prototype = {
this.chromeDoc = null; this.chromeDoc = null;
this.inspector.sidebar.off("fontinspector-selected", this.onNewNode); this.inspector.sidebar.off("fontinspector-selected", this.onNewNode);
this.inspector.selection.off("new-node", this.onNewNode); this.inspector.selection.off("new-node", this.onNewNode);
this.showAllButton.removeEventListener("click", this.showAll); this.showAllLink.removeEventListener("click", this.showAll);
this.previewInput.removeEventListener("input", this.previewTextChanged); this.previewInput.removeEventListener("input", this.previewTextChanged);
gDevTools.off("theme-switched", this.onThemeChanged); gDevTools.off("theme-switched", this.onThemeChanged);

View File

@ -184,11 +184,11 @@
type="search" type="search"
placeholder="&previewHint;"/> placeholder="&previewHint;"/>
</html:div> </html:div>
<html:label id="font-showall" class="theme-link" title="&showAllFonts;">&showAllFontsUsed;</html:label>
</html:div> </html:div>
<html:div id="font-container"> <html:div id="font-container">
<html:ul id="all-fonts"></html:ul> <html:ul id="all-fonts"></html:ul>
<html:button id="font-showall">&showAllFonts;</html:button>
</html:div> </html:div>
<html:div id="font-template"> <html:div id="font-template">

View File

@ -87,9 +87,7 @@ define(function (require, exports, module) {
td({className: "netInfoParamName"}, td({className: "netInfoParamName"},
span({title: header.name}, header.name) span({title: header.name}, header.name)
), ),
td({className: "netInfoParamValue"}, td({className: "netInfoParamValue"}, header.value)
code({}, header.value)
)
) )
); );
}); });

View File

@ -212,8 +212,18 @@ let Converter = Class({
let themeVarsUrl = clientBaseUrl + "themes/variables.css"; let themeVarsUrl = clientBaseUrl + "themes/variables.css";
let commonUrl = clientBaseUrl + "themes/common.css"; let commonUrl = clientBaseUrl + "themes/common.css";
let os;
let platform = Services.appinfo.OS;
if (platform.startsWith("WINNT")) {
os = "win";
} else if (platform.startsWith("Darwin")) {
os = "mac";
} else {
os = "linux";
}
return "<!DOCTYPE html>\n" + return "<!DOCTYPE html>\n" +
"<html class=\"" + themeClassName + "\">" + "<html platform=\"" + os + "\" class=\"" + themeClassName + "\">" +
"<head><title>" + this.htmlEncode(title) + "</title>" + "<head><title>" + this.htmlEncode(title) + "</title>" +
"<base href=\"" + this.htmlEncode(baseUrl) + "\">" + "<base href=\"" + this.htmlEncode(baseUrl) + "\">" +
"<link rel=\"stylesheet\" type=\"text/css\" href=\"" + "<link rel=\"stylesheet\" type=\"text/css\" href=\"" +

View File

@ -7,10 +7,11 @@
/* General */ /* General */
body { body {
background-color: white; color: var(--theme-body-color);
background-color: var(--theme-body-background);
padding: 0; padding: 0;
margin: 0; margin: 0;
overflow: hidden; overflow-x: hidden;
} }
*:focus { *:focus {
@ -24,6 +25,7 @@ body {
pre { pre {
background-color: white; background-color: white;
border: none; border: none;
font-family: var(--monospace-font-family);
} }
#json, #json,

View File

@ -8,41 +8,37 @@
.headersPanelBox { .headersPanelBox {
height: 100%; height: 100%;
font-family: Lucida Grande, Tahoma, sans-serif;
font-size: 11px;
} }
.headersPanelBox .netInfoHeadersTable { .headersPanelBox .netInfoHeadersTable {
overflow: auto; overflow: auto;
height: 100%; height: 100%;
line-height: 12px;
} }
.headersPanelBox .netHeadersGroup { .headersPanelBox .netHeadersGroup {
padding: 10px; padding: 10px;
} }
.headersPanelBox td {
vertical-align: bottom;
}
.headersPanelBox .netInfoHeadersGroup { .headersPanelBox .netInfoHeadersGroup {
color: var(--theme-body-color-alt);
margin-bottom: 10px; margin-bottom: 10px;
border-bottom: 1px solid #D7D7D7; border-bottom: 1px solid var(--theme-splitter-color);
padding-top: 8px; padding-top: 8px;
padding-bottom: 4px; padding-bottom: 4px;
font-family: Lucida Grande, Tahoma, sans-serif;
font-weight: bold; font-weight: bold;
color: #565656;
-moz-user-select: none; -moz-user-select: none;
} }
.headersPanelBox .netInfoParamValue code { .headersPanelBox .netInfoParamValue {
display: block;
color: #18191A;
font-size: 11px;
word-wrap: break-word; word-wrap: break-word;
} }
.headersPanelBox .netInfoParamName { .headersPanelBox .netInfoParamName {
padding: 2px 10px 0 0; padding: 2px 10px 0 0;
font-family: Lucida Grande, Tahoma, sans-serif;
font-weight: bold; font-weight: bold;
vertical-align: top; vertical-align: top;
text-align: right; text-align: right;
@ -50,17 +46,33 @@
} }
/******************************************************************************/ /******************************************************************************/
/* Theme colors have been generated/copied from Network Panel's header view */
/* Light Theme */
.theme-light .netInfoParamName {
color: var(--theme-highlight-red);
}
.theme-light .netInfoParamValue {
color: var(--theme-highlight-purple);
}
/* Dark Theme */ /* Dark Theme */
.theme-dark .netInfoParamName {
color: var(--theme-highlight-purple);
.theme-dark .headersPanelBox .netInfoParamName {
color: var(--theme-highlight-blue);
} }
.theme-dark .headersPanelBox .netInfoParamValue code { .theme-dark .netInfoParamValue {
color: var(--theme-highlight-orange); color: var(--theme-highlight-gray);
} }
.theme-dark .headersPanelBox .netInfoHeadersGroup { /* Firebug Theme */
color: var(--theme-body-color-alt); .theme-firebug .netInfoHeadersTable {
font-family: Lucida Grande, Tahoma, sans-serif;
font-size: 11px;
line-height: 12px;
}
.theme-firebug .netInfoParamValue {
font-family: var(--monospace-font-family);
} }

View File

@ -14,20 +14,22 @@
@import "text-panel.css"; @import "text-panel.css";
@import "headers-panel.css"; @import "headers-panel.css";
/******************************************************************************/ /******************************************************************************/
/* Panel Content */ /* Panel Content */
.panelContent { .panelContent {
overflow-y: auto; overflow-y: auto;
font-size: 11px; width: 100%;
font-family: var(--monospace-font-family);
padding-right: 5px;
} }
/* The tree takes the entire horizontal space within the panel content. */ /* The tree takes the entire horizontal space within the panel content. */
.panelContent .treeTable { .panelContent .treeTable {
width: 100%; width: 100%;
font-family: var(--monospace-font-family);
}
:root[platform="linux"] .treeTable {
font-size: 80%; /* To handle big monospace font */
} }
/* Make sure there is a little space between label and value columns. */ /* Make sure there is a little space between label and value columns. */

View File

@ -18,7 +18,7 @@
color: var(--theme-content-color1); color: var(--theme-content-color1);
width: 200px; width: 200px;
margin-top: 0; margin-top: 0;
position: fixed; margin-right: 1px;
right: 1px; float: right;
padding-left: 20px; padding-left: 20px;
} }

View File

@ -11,19 +11,16 @@
} }
.textPanelBox .data { .textPanelBox .data {
font-size: 11px;
font-family: monospace;
overflow: auto; overflow: auto;
height: 100%; height: 100%;
} }
.textPanelBox pre { .textPanelBox pre {
margin: 0; margin: 0;
font-family: var(--monospace-font-family);
color: var(--theme-content-color1);
} }
/******************************************************************************/ :root[platform="linux"] .textPanelBox .data {
/* Dark Theme */ font-size: 80%; /* To handle big monospace font */
}
.theme-dark .textPanelBox {
color: var(--theme-content-color1);
}

View File

@ -24,7 +24,8 @@
vertical-align: middle; vertical-align: middle;
cursor: pointer; cursor: pointer;
-moz-user-select: none; -moz-user-select: none;
padding: 0 2px 1px 2px; padding: 0 2px;
border-radius: 2px;
} }
.toolbar .btn::-moz-focus-inner { .toolbar .btn::-moz-focus-inner {
@ -71,13 +72,11 @@
.theme-dark .toolbar .btn, .theme-dark .toolbar .btn,
.theme-light .toolbar .btn { .theme-light .toolbar .btn {
min-width: 78px;
min-height: 18px; min-height: 18px;
color: var(--theme-content-color1); color: var(--theme-content-color1);
text-shadow: none; text-shadow: none;
margin: 1px 2px 1px 2px; margin: 1px 2px 1px 2px;
border: none; border: none;
border-radius: 0;
background-color: rgba(170, 170, 170, .2); /* --toolbar-tab-hover */ background-color: rgba(170, 170, 170, .2); /* --toolbar-tab-hover */
transition: background 0.05s ease-in-out; transition: background 0.05s ease-in-out;
} }

View File

@ -6,6 +6,7 @@
- The Font Inspector is the panel accessible in the Inspector sidebar. --> - The Font Inspector is the panel accessible in the Inspector sidebar. -->
<!ENTITY showAllFonts "See all the fonts used in the page"> <!ENTITY showAllFonts "See all the fonts used in the page">
<!ENTITY showAllFontsUsed "Show all fonts used">
<!ENTITY usedAs "Used as: "> <!ENTITY usedAs "Used as: ">
<!ENTITY system "system"> <!ENTITY system "system">
<!ENTITY remote "remote"> <!ENTITY remote "remote">

View File

@ -44,12 +44,13 @@
.theme-dark .tabs, .theme-dark .tabs,
.theme-light .tabs { .theme-light .tabs {
background: var(--theme-tab-toolbar-background); background: var(--theme-body-background);
} }
.theme-dark .tabs .tabs-navigation, .theme-dark .tabs .tabs-navigation,
.theme-light .tabs .tabs-navigation { .theme-light .tabs .tabs-navigation {
border-bottom: 1px solid var(--theme-splitter-color); border-bottom: 1px solid var(--theme-splitter-color);
background: var(--theme-tab-toolbar-background);
} }
.theme-dark .tabs .tabs-menu-item, .theme-dark .tabs .tabs-menu-item,
@ -62,15 +63,14 @@
border-color: var(--theme-splitter-color); border-color: var(--theme-splitter-color);
} }
.theme-dark .tabs .tabs-menu-item:last-child,
.theme-light:not(.theme-firebug) .tabs .tabs-menu-item:last-child {
border-inline-end-width: 1px;
}
.theme-dark .tabs .tabs-menu-item a, .theme-dark .tabs .tabs-menu-item a,
.theme-light .tabs .tabs-menu-item a { .theme-light .tabs .tabs-menu-item a {
color: var(--theme-content-color1); color: var(--theme-content-color1);
}
.theme-dark .tabs .tabs-menu-item a:hover,
.theme-dark .tabs .tabs-menu-item a,
.theme-light .tabs .tabs-menu-item a:hover,
.theme-light .tabs .tabs-menu-item a {
padding: 3px 15px; padding: 3px 15px;
} }
@ -105,18 +105,18 @@
/* Firebug Theme */ /* Firebug Theme */
.theme-firebug .tabs { .theme-firebug .tabs .tabs-navigation {
background-color: rgb(219, 234, 249); background-color: rgb(219, 234, 249);
background-image: linear-gradient(rgba(253, 253, 253, 0.2), rgba(253, 253, 253, 0)); background-image: linear-gradient(rgba(253, 253, 253, 0.2), rgba(253, 253, 253, 0));
}
.theme-firebug .tabs .tabs-navigation {
padding-top: 3px; padding-top: 3px;
padding-left: 3px; padding-left: 3px;
height: 27px;
border-bottom: 1px solid rgb(170, 188, 207); border-bottom: 1px solid rgb(170, 188, 207);
} }
.theme-firebug .tabs .tabs-menu {
margin-bottom: -1px;
}
.theme-firebug .tabs .tabs-menu-item.is-active, .theme-firebug .tabs .tabs-menu-item.is-active,
.theme-firebug .tabs .tabs-menu-item.is-active:hover { .theme-firebug .tabs .tabs-menu-item.is-active:hover {
background-color: transparent; background-color: transparent;
@ -155,9 +155,5 @@
.theme-firebug .tabs .tabs-menu-item a { .theme-firebug .tabs .tabs-menu-item a {
border: 1px solid transparent; border: 1px solid transparent;
} padding: 4px 8px;
.theme-firebug .tabs .tabs-menu-item a:hover,
.theme-firebug .tabs .tabs-menu-item a {
padding: 4px 8px 4px 8px;
} }

View File

@ -26,7 +26,7 @@ define(function (require, exports, module) {
* <li class='tabs-menu-item'>Tab #2</li> * <li class='tabs-menu-item'>Tab #2</li>
* </ul> * </ul>
* </nav> * </nav>
* <div class='tab-panel'> * <div class='panels'>
* The content of active panel here * The content of active panel here
* </div> * </div>
* <div> * <div>
@ -184,11 +184,12 @@ define(function (require, exports, module) {
let ref = ("tab-menu-" + index); let ref = ("tab-menu-" + index);
let title = tab.props.title; let title = tab.props.title;
let tabClassName = tab.props.className; let tabClassName = tab.props.className;
let isTabSelected = this.state.tabActive === index;
let classes = [ let classes = [
"tabs-menu-item", "tabs-menu-item",
tabClassName, tabClassName,
this.state.tabActive === index ? "is-active" : "" isTabSelected ? "is-active" : ""
].join(" "); ].join(" ");
// Set tabindex to -1 (except the selected tab) so, it's focusable, // Set tabindex to -1 (except the selected tab) so, it's focusable,
@ -200,11 +201,18 @@ define(function (require, exports, module) {
DOM.li({ DOM.li({
ref: ref, ref: ref,
key: index, key: index,
className: classes}, id: "tab-" + index,
className: classes,
role: "presentation",
},
DOM.a({ DOM.a({
href: "#", href: "#",
tabIndex: this.state.tabActive === index ? 0 : -1, tabIndex: this.state.tabActive === index ? 0 : -1,
onClick: this.onClickTab.bind(this, index)}, "aria-controls": "panel-" + index,
"aria-selected": isTabSelected,
role: "tab",
onClick: this.onClickTab.bind(this, index),
},
title title
) )
) )
@ -213,7 +221,7 @@ define(function (require, exports, module) {
return ( return (
DOM.nav({className: "tabs-navigation"}, DOM.nav({className: "tabs-navigation"},
DOM.ul({className: "tabs-menu"}, DOM.ul({className: "tabs-menu", role: "tablist"},
tabs tabs
) )
) )
@ -251,8 +259,12 @@ define(function (require, exports, module) {
return ( return (
DOM.div({ DOM.div({
key: index, key: index,
id: "panel-" + index,
style: style, style: style,
className: "tab-panel-box"}, className: "tab-panel-box",
role: "tabpanel",
"aria-labelledby": "tab-" + index,
},
(selected || this.state.created[index]) ? tab : null (selected || this.state.created[index]) ? tab : null
) )
); );

View File

@ -27,6 +27,7 @@ support-files =
[test_reps_undefined.html] [test_reps_undefined.html]
[test_reps_window.html] [test_reps_window.html]
[test_sidebar_toggle.html] [test_sidebar_toggle.html]
[test_tabs_accessibility.html]
[test_tree_01.html] [test_tree_01.html]
[test_tree_02.html] [test_tree_02.html]
[test_tree_03.html] [test_tree_03.html]

View File

@ -0,0 +1,72 @@
<!DOCTYPE HTML>
<html>
<!--
Test tabs accessibility.
-->
<head>
<meta charset="utf-8">
<title>Tabs component accessibility test</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
</head>
<body>
<pre id="test">
<script src="head.js" type="application/javascript;version=1.8"></script>
<script type="application/javascript;version=1.8">
window.onload = Task.async(function* () {
try {
const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
const React = browserRequire("devtools/client/shared/vendor/react");
const { Simulate } = React.addons.TestUtils;
const InspectorTabPanel = React.createFactory(browserRequire("devtools/client/inspector/components/inspector-tab-panel"));
const Tabbar = React.createFactory(browserRequire("devtools/client/shared/components/tabs/tabbar"));
const tabbar = Tabbar();
const tabbarReact = ReactDOM.render(tabbar, window.document.body);
const tabbarEl = ReactDOM.findDOMNode(tabbarReact);
// Setup for InspectorTabPanel
const tabpanels = document.createElement("div");
tabpanels.id = "tabpanels";
document.body.appendChild(tabpanels);
yield addTabWithPanel(0);
yield addTabWithPanel(1);
const tabAnchors = tabbarEl.querySelectorAll("li.tabs-menu-item a");
is(tabAnchors[0].parentElement.getAttribute("role"), "presentation", "li role is set correctly");
is(tabAnchors[0].getAttribute("role"), "tab", "Anchor role is set correctly");
is(tabAnchors[0].getAttribute("aria-selected"), "true", "Anchor aria-selected is set correctly by default");
is(tabAnchors[0].getAttribute("aria-controls"), "panel-0", "Anchor aria-controls is set correctly");
is(tabAnchors[1].parentElement.getAttribute("role"), "presentation", "li role is set correctly");
is(tabAnchors[1].getAttribute("role"), "tab", "Anchor role is set correctly");
is(tabAnchors[1].getAttribute("aria-selected"), "false", "Anchor aria-selected is set correctly by default");
is(tabAnchors[1].getAttribute("aria-controls"), "panel-1", "Anchor aria-controls is set correctly");
yield setState(tabbarReact, Object.assign({}, tabbarReact.state, {
activeTab: 1
}));
is(tabAnchors[0].getAttribute("aria-selected"), "false", "Anchor aria-selected is reset correctly");
is(tabAnchors[1].getAttribute("aria-selected"), "true", "Anchor aria-selected is reset correctly");
function addTabWithPanel(tabId) {
// Setup for InspectorTabPanel
let panel = document.createElement("div");
panel.id = `sidebar-panel-${tabId}`;
document.body.appendChild(panel);
return setState(tabbarReact, Object.assign({}, tabbarReact.state, {
tabs: tabbarReact.state.tabs.concat({id: `${tabId}`, title: `tab-${tabId}`, panel: InspectorTabPanel}),
}));
}
} catch(e) {
ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
} finally {
SimpleTest.finish();
}
});
</script>
</pre>
</body>
</html>

View File

@ -137,14 +137,16 @@
/******************************************************************************/ /******************************************************************************/
/* Themes */ /* Themes */
/* Light Theme: toggle icon */ /* Light, Firebug Theme: toggle icon */
.theme-light .treeTable .treeRow.hasChildren > .treeLabelCell > .treeIcon { .theme-light .treeTable .treeRow.hasChildren > .treeLabelCell > .treeIcon,
.theme-firebug .treeTable .treeRow.hasChildren > .treeLabelCell > .treeIcon {
background-image: url(chrome://devtools/skin/images/controls.png); background-image: url(chrome://devtools/skin/images/controls.png);
background-size: 56px 28px; background-size: 56px 28px;
background-position: 0 -14px; background-position: 0 -14px;
} }
.theme-light .treeTable .treeRow.hasChildren.opened > .treeLabelCell > .treeIcon { .theme-light .treeTable .treeRow.hasChildren.opened > .treeLabelCell > .treeIcon,
.theme-firebug .treeTable .treeRow.hasChildren.opened > .treeLabelCell > .treeIcon {
background-image: url(chrome://devtools/skin/images/controls.png); background-image: url(chrome://devtools/skin/images/controls.png);
background-size: 56px 28px; background-size: 56px 28px;
background-position: -14px -14px; background-position: -14px -14px;
@ -163,11 +165,10 @@
background-position: -42px -14px; background-position: -42px -14px;
} }
/* Dark and Light Themes: Support for retina displays */ /* Support for retina displays */
@media (min-resolution: 1.1dppx) { @media (min-resolution: 1.1dppx) {
.theme-dark .treeTable .treeRow.hasChildren > .treeLabelCell > .treeIcon, .treeTable .treeRow.hasChildren > .treeLabelCell > .treeIcon {
.theme-light .treeTable .treeRow.hasChildren > .treeLabelCell > .treeIcon { background-image: url("chrome://devtools/skin/images/controls@2x.png") !important;
background-image: url("chrome://devtools/skin/images/controls@2x.png");
} }
} }
@ -185,7 +186,8 @@
color: var(--theme-highlight-pink); color: var(--theme-highlight-pink);
} }
.theme-light .treeTable .treeRow.hasChildren > .treeLabelCell > .treeLabel:hover { .theme-light .treeTable .treeRow.hasChildren > .treeLabelCell > .treeLabel:hover,
.theme-dark .treeTable .treeRow.hasChildren > .treeLabelCell > .treeLabel:hover {
color: var(--theme-highlight-pink); color: var(--theme-highlight-pink);
} }

View File

@ -26,13 +26,11 @@
} }
#font-showall { #font-showall {
border-radius: 0;
border: 1px solid black;
margin: 3px;
cursor: pointer; cursor: pointer;
position: absolute; }
bottom: 0;
offset-inline-end: 0; #font-showall:hover {
text-decoration: underline;
} }
.dim > #font-container, .dim > #font-container,

View File

@ -10,6 +10,13 @@
0 0 0 0 0.79 0 0 0 0 0.79
0 0 0 1 0"/> 0 0 0 1 0"/>
</filter> </filter>
<filter id="dark-theme-checked-icon-state">
<feColorMatrix in="SourceGraphic" type="matrix"
values="0 0 0 0 0
0 0 0 0 1
0 0 0 0 0.212
0 0 0 1 0"/>
</filter>
<!-- Web Audio Gradients --> <!-- Web Audio Gradients -->
<linearGradient id="bypass-light" x1="6%" y1="8%" x2="12%" y2="12%" spreadMethod="repeat"> <linearGradient id="bypass-light" x1="6%" y1="8%" x2="12%" y2="12%" spreadMethod="repeat">

Before

Width:  |  Height:  |  Size: 990 B

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -2,8 +2,6 @@
- License, v. 2.0. If a copy of the MPL was not distributed with this - 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/. --> - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#0b0b0b"> <svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#0b0b0b">
<path fill-opacity=".3" d="M12 3h2v10h-2z"/> <path fill-opacity=".3" d="M12,3h2v10h-2V3z M5,9.9V6.1L8,8L5,9.9z"/>
<path d="M2 3.002v9.996c0-.004.006.002.007.002h11.986c.005 0 .007-.002.007-.002V3.002c0 .004-.006-.002-.007-.002H2.007C2.002 3 2 3.002 2 3.002zm-1 0C1 2.45 1.45 2 2.007 2h11.986A1.01 1.01 0 0 1 15 3.002v9.996C15 13.55 14.55 14 13.993 14H2.007A1.01 1.01 0 0 1 1 12.998V3.002zm10 .453V13h1V3h-1v.455z"/> <path d="M14,2H2C1.4,2,1,2.4,1,3v10c0,0.6,0.4,1,1,1h12c0.6,0,1-0.4,1-1V3C15,2.4,14.6,2,14,2z M2,13L2,13V3h0h9v10 H2L2,13z M14,13C14,13,14,13,14,13h-2V3h2c0,0,0,0,0,0V13z M8.5,7.2l-3-1.9C4.6,4.7,4,5,4,6.1v3.8c0,1.1,0.6,1.4,1.5,0.8l3-1.9 C9.5,8.3,9.5,7.8,8.5,7.2z M5,9.9V6.1L8,8L5,9.9z"/>
<path d="M5 10.25l3-1.875L5 6.5v3.75zm-1 0V6.5a1 1 0 0 1 1.53-.848l3 1.875a1 1 0 0 1 0 1.696l-3 1.875A1 1 0 0 1 4 10.25z"/>
<path fill-opacity=".3" d="M4.5 10.75V6L9 8.375z"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 858 B

After

Width:  |  Height:  |  Size: 689 B

View File

@ -2,8 +2,6 @@
- License, v. 2.0. If a copy of the MPL was not distributed with this - 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/. --> - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#0b0b0b"> <svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#0b0b0b">
<path fill-opacity=".3" d="M12 3h2v10h-2z"/> <path fill-opacity=".3" d="M4,13H2V3h2V13z M11,6.1v3.8L8,8L11,6.1z"/>
<path d="M2 3.002v9.996c0-.004.006.002.007.002h11.986c.005 0 .007-.002.007-.002V3.002c0 .004-.006-.002-.007-.002H2.007C2.002 3 2 3.002 2 3.002zm-1 0C1 2.45 1.45 2 2.007 2h11.986A1.01 1.01 0 0 1 15 3.002v9.996C15 13.55 14.55 14 13.993 14H2.007A1.01 1.01 0 0 1 1 12.998V3.002zm10 .453V13h1V3h-1v.455z"/> <path d="M2,14h12c0.6,0,1-0.4,1-1V3c0-0.6-0.4-1-1-1H2C1.4,2,1,2.4,1,3v10C1,13.6,1.4,14,2,14z M14,3L14,3v10h0H5V3 H14L14,3z M2,3C2,3,2,3,2,3h2v10H2c0,0,0,0,0,0V3z M7.5,8.8l3,1.9c1,0.6,1.5,0.3,1.5-0.8V6.1c0-1.1-0.6-1.4-1.5-0.8l-3,1.9 C6.5,7.7,6.5,8.2,7.5,8.8z M11,6.1v3.8L8,8L11,6.1z"/>
<path d="M8 6.5L5 8.375l3 1.875V6.5zm1 0v3.75a1 1 0 0 1-1.53.848l-3-1.875a1 1 0 0 1 0-1.696l3-1.875A1 1 0 0 1 9 6.5z"/>
<path fill-opacity=".3" d="M8.5 6v4.75L4 8.375z"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 853 B

After

Width:  |  Height:  |  Size: 688 B

View File

@ -167,6 +167,10 @@
list-style-image: url("chrome://devtools/skin/images/close.svg"); list-style-image: url("chrome://devtools/skin/images/close.svg");
} }
.devtools-responsiveui-close > image {
filter: invert(1);
}
.devtools-responsiveui-rotate { .devtools-responsiveui-rotate {
list-style-image: url("chrome://devtools/skin/images/responsivemode/responsiveui-rotate.png"); list-style-image: url("chrome://devtools/skin/images/responsivemode/responsiveui-rotate.png");
} }

View File

@ -30,7 +30,7 @@
--filter-image: url(images/filter.svg); --filter-image: url(images/filter.svg);
--tool-options-image: url(images/tool-options.svg); --tool-options-image: url(images/tool-options.svg);
--icon-filter: invert(1); --icon-filter: invert(1);
--checked-icon-filter: url(images/filters.svg#checked-icon-state); --checked-icon-filter: url(images/filters.svg#dark-theme-checked-icon-state);
--toolbar-button-border-color: rgba(0, 0, 0, .4); --toolbar-button-border-color: rgba(0, 0, 0, .4);
} }

View File

@ -72,8 +72,14 @@ add_task(function* () {
is(hud.outputNode.textContent.indexOf("Permission denied"), -1, is(hud.outputNode.textContent.indexOf("Permission denied"), -1,
"no permission denied errors"); "no permission denied errors");
// Navigation clears messages. Wait for that clear to happen before
// continuing the test or it might destroy messages we wait later on (Bug
// 1270234).
let cleared = hud.jsterm.once("messages-cleared");
gBrowser.goBack(); gBrowser.goBack();
info("Waiting for page to navigate");
yield waitForSuccess({ yield waitForSuccess({
name: "go back", name: "go back",
validator: function () { validator: function () {
@ -81,10 +87,11 @@ add_task(function* () {
}, },
}); });
hud.jsterm.clearOutput(); info("Waiting for messages to be cleared due to navigation");
executeSoon(() => { yield cleared;
hud.jsterm.execute("window.location.href");
}); info("Messages cleared after navigation; checking location");
hud.jsterm.execute("window.location.href");
info("wait for window.location.href after goBack()"); info("wait for window.location.href after goBack()");
yield waitForMessages(msgForLocation1); yield waitForMessages(msgForLocation1);

View File

@ -130,7 +130,7 @@ This will generate a request handler whose request and response packets look lik
The client usage should be predictable: The client usage should be predictable:
echo.echo("hello").then(str => { assert(str === "hello... hello...") }) hello.echo("hello").then(str => { assert(str === "hello... hello...") })
The library tries hard to make using fronts feel like natural javascript (or as natural as you believe promises are, I guess). When building the response it will put the return value of the function where RetVal() is specified in the response template, and on the client side it will use the value in that position when resolving the promise. The library tries hard to make using fronts feel like natural javascript (or as natural as you believe promises are, I guess). When building the response it will put the return value of the function where RetVal() is specified in the response template, and on the client side it will use the value in that position when resolving the promise.

View File

@ -19,6 +19,7 @@
#include "nsIDOMRange.h" #include "nsIDOMRange.h"
#include "nsRange.h" #include "nsRange.h"
#include "imgIContainer.h" #include "imgIContainer.h"
#include "imgIRequest.h"
#include "nsIPresShell.h" #include "nsIPresShell.h"
#include "nsFocusManager.h" #include "nsFocusManager.h"
#include "mozilla/dom/DataTransfer.h" #include "mozilla/dom/DataTransfer.h"
@ -47,6 +48,16 @@
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsContentCID.h" #include "nsContentCID.h"
#ifdef XP_WIN
#include "nsCExternalHandlerService.h"
#include "nsEscape.h"
#include "nsIMimeInfo.h"
#include "nsIMIMEService.h"
#include "nsIURL.h"
#include "nsReadableUtils.h"
#include "nsXULAppAPI.h"
#endif
#include "mozilla/ContentEvents.h" #include "mozilla/ContentEvents.h"
#include "mozilla/dom/Element.h" #include "mozilla/dom/Element.h"
#include "mozilla/EventDispatcher.h" #include "mozilla/EventDispatcher.h"
@ -72,6 +83,13 @@ static nsresult AppendString(nsITransferable *aTransferable,
static nsresult AppendDOMNode(nsITransferable *aTransferable, static nsresult AppendDOMNode(nsITransferable *aTransferable,
nsINode* aDOMNode); nsINode* aDOMNode);
#ifdef XP_WIN
// copy image as file promise onto the transferable
static nsresult AppendImagePromise(nsITransferable* aTransferable,
imgIRequest* aImgRequest,
nsIImageLoadingContent* aImageElement);
#endif
// Helper used for HTMLCopy and GetTransferableForSelection since both routines // Helper used for HTMLCopy and GetTransferableForSelection since both routines
// share common code. // share common code.
static nsresult static nsresult
@ -439,11 +457,18 @@ nsCopySupport::ImageCopy(nsIImageLoadingContent* aImageElement,
} }
if (aCopyFlags & nsIContentViewerEdit::COPY_IMAGE_DATA) { if (aCopyFlags & nsIContentViewerEdit::COPY_IMAGE_DATA) {
// get the image data from the element // get the image data and its request from the element
nsCOMPtr<imgIRequest> imgRequest;
nsCOMPtr<imgIContainer> image = nsCOMPtr<imgIContainer> image =
nsContentUtils::GetImageFromContent(aImageElement); nsContentUtils::GetImageFromContent(aImageElement,
getter_AddRefs(imgRequest));
NS_ENSURE_TRUE(image, NS_ERROR_FAILURE); NS_ENSURE_TRUE(image, NS_ERROR_FAILURE);
#ifdef XP_WIN
rv = AppendImagePromise(trans, imgRequest, aImageElement);
NS_ENSURE_SUCCESS(rv, rv);
#endif
nsCOMPtr<nsISupportsInterfacePointer> nsCOMPtr<nsISupportsInterfacePointer>
imgPtr(do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv)); imgPtr(do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
@ -545,6 +570,91 @@ static nsresult AppendDOMNode(nsITransferable *aTransferable,
return AppendString(aTransferable, context, kHTMLContext); return AppendString(aTransferable, context, kHTMLContext);
} }
#ifdef XP_WIN
static nsresult AppendImagePromise(nsITransferable* aTransferable,
imgIRequest* aImgRequest,
nsIImageLoadingContent* aImageElement)
{
nsresult rv;
NS_ENSURE_TRUE(aImgRequest, NS_OK);
nsCOMPtr<nsINode> node = do_QueryInterface(aImageElement, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// Fix the file extension in the URL if necessary
nsCOMPtr<nsIMIMEService> mimeService =
do_GetService(NS_MIMESERVICE_CONTRACTID);
NS_ENSURE_TRUE(mimeService, NS_OK);
nsCOMPtr<nsIURI> imgUri;
rv = aImgRequest->GetCurrentURI(getter_AddRefs(imgUri));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIURL> imgUrl = do_QueryInterface(imgUri);
NS_ENSURE_TRUE(imgUrl, NS_OK);
nsAutoCString extension;
rv = imgUrl->GetFileExtension(extension);
NS_ENSURE_SUCCESS(rv, rv);
nsXPIDLCString mimeType;
rv = aImgRequest->GetMimeType(getter_Copies(mimeType));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMIMEInfo> mimeInfo;
mimeService->GetFromTypeAndExtension(mimeType, EmptyCString(),
getter_AddRefs(mimeInfo));
NS_ENSURE_TRUE(mimeInfo, NS_OK);
nsAutoCString spec;
rv = imgUrl->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
// pass out the image source string
nsString imageSourceString;
CopyUTF8toUTF16(spec, imageSourceString);
bool validExtension;
if (extension.IsEmpty() ||
NS_FAILED(mimeInfo->ExtensionExists(extension,
&validExtension)) ||
!validExtension) {
// Fix the file extension in the URL
rv = imgUrl->Clone(getter_AddRefs(imgUri));
NS_ENSURE_SUCCESS(rv, rv);
imgUrl = do_QueryInterface(imgUri);
nsAutoCString primaryExtension;
mimeInfo->GetPrimaryExtension(primaryExtension);
imgUrl->SetFileExtension(primaryExtension);
}
nsAutoCString fileName;
imgUrl->GetFileName(fileName);
NS_UnescapeURL(fileName);
// make the filename safe for the filesystem
fileName.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '-');
nsString imageDestFileName;
CopyUTF8toUTF16(fileName, imageDestFileName);
rv = AppendString(aTransferable, imageSourceString, kFilePromiseURLMime);
NS_ENSURE_SUCCESS(rv, rv);
rv = AppendString(aTransferable, imageDestFileName, kFilePromiseDestFilename);
NS_ENSURE_SUCCESS(rv, rv);
aTransferable->SetRequestingPrincipal(node->NodePrincipal());
// add the dataless file promise flavor
return aTransferable->AddDataFlavor(kFilePromiseMime);
}
#endif // XP_WIN
nsIContent* nsIContent*
nsCopySupport::GetSelectionForCopy(nsIDocument* aDocument, nsISelection** aSelection) nsCopySupport::GetSelectionForCopy(nsIDocument* aDocument, nsISelection** aSelection)
{ {

View File

@ -8,6 +8,46 @@ function createProfDFile() {
.get('ProfD', Ci.nsIFile); .get('ProfD', Ci.nsIFile);
} }
// Creates a parametric arity directory hierarchy as a function of depth.
// Each directory contains one leaf file, and subdirectories of depth [1, depth).
// e.g. for depth 3:
//
// subdir3
// - file.txt
// - subdir2
// - file.txt
// - subdir1
// - file.txt
// - subdir1
// - file.txt
//
// Returns the parent directory of the subtree.
function createTreeFile(depth, parent) {
if (!parent) {
parent = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIDirectoryService)
.QueryInterface(Ci.nsIProperties)
.get('TmpD', Ci.nsIFile);
parent.append('dir-tree-test');
parent.createUnique(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0o700);
}
var nextFile = parent.clone();
if (depth == 0) {
nextFile.append('file.txt');
nextFile.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0o600);
} else {
nextFile.append('subdir' + depth);
nextFile.createUnique(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0o700);
// Decrement the maximal depth by one for each level of nesting.
for (i = 0; i < depth; i++) {
createTreeFile(i, nextFile);
}
}
return parent;
}
function createRootFile() { function createRootFile() {
var testFile = createProfDFile(); var testFile = createProfDFile();
@ -52,6 +92,8 @@ addMessageListener("dir.open", function (e) {
switch (e.path) { switch (e.path) {
case 'ProfD': case 'ProfD':
// Note that files in the profile directory are not guaranteed to persist-
// see bug 1284742.
testFile = createProfDFile(); testFile = createProfDFile();
break; break;
@ -62,6 +104,10 @@ addMessageListener("dir.open", function (e) {
case 'test': case 'test':
testFile = createTestFile(); testFile = createTestFile();
break; break;
case 'tree':
testFile = createTreeFile(3);
break;
} }
sendAsyncMessage("dir.opened", { sendAsyncMessage("dir.opened", {

View File

@ -129,7 +129,7 @@ function test_inputGetFiles() {
var tests = [ var tests = [
function() { setup_tests(next); }, function() { setup_tests(next); },
function() { create_fileList('ProfD') }, function() { create_fileList('tree') },
function() { test_basic(directory, next); }, function() { test_basic(directory, next); },
function() { test_getFilesAndDirectories(directory, true, next); }, function() { test_getFilesAndDirectories(directory, true, next); },
function() { test_getFiles(directory, false, next); }, function() { test_getFiles(directory, false, next); },

View File

@ -2665,6 +2665,7 @@ ContentParent::RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissio
bool bool
ContentParent::RecvSetClipboard(const IPCDataTransfer& aDataTransfer, ContentParent::RecvSetClipboard(const IPCDataTransfer& aDataTransfer,
const bool& aIsPrivateData, const bool& aIsPrivateData,
const IPC::Principal& aRequestingPrincipal,
const int32_t& aWhichClipboard) const int32_t& aWhichClipboard)
{ {
nsresult rv; nsresult rv;
@ -2730,6 +2731,7 @@ ContentParent::RecvSetClipboard(const IPCDataTransfer& aDataTransfer,
} }
trans->SetIsPrivateData(aIsPrivateData); trans->SetIsPrivateData(aIsPrivateData);
trans->SetRequestingPrincipal(aRequestingPrincipal);
clipboard->SetData(trans, nullptr, aWhichClipboard); clipboard->SetData(trans, nullptr, aWhichClipboard);
return true; return true;

View File

@ -958,6 +958,7 @@ private:
virtual bool RecvSetClipboard(const IPCDataTransfer& aDataTransfer, virtual bool RecvSetClipboard(const IPCDataTransfer& aDataTransfer,
const bool& aIsPrivateData, const bool& aIsPrivateData,
const IPC::Principal& aRequestingPrincipal,
const int32_t& aWhichClipboard) override; const int32_t& aWhichClipboard) override;
virtual bool RecvGetClipboard(nsTArray<nsCString>&& aTypes, virtual bool RecvGetClipboard(nsTArray<nsCString>&& aTypes,

View File

@ -931,6 +931,7 @@ parent:
// Places the items within dataTransfer on the clipboard. // Places the items within dataTransfer on the clipboard.
async SetClipboard(IPCDataTransfer aDataTransfer, async SetClipboard(IPCDataTransfer aDataTransfer,
bool aIsPrivateData, bool aIsPrivateData,
Principal aRequestingPrincipal,
int32_t aWhichClipboard); int32_t aWhichClipboard);
// Given a list of supported types, returns the clipboard data for the // Given a list of supported types, returns the clipboard data for the

View File

@ -86,7 +86,7 @@ public:
// Returns the owner of this decoder or null when the decoder is shutting // Returns the owner of this decoder or null when the decoder is shutting
// down. The owner should only be used on the main thread. // down. The owner should only be used on the main thread.
virtual MediaDecoderOwner* GetOwner() = 0; virtual MediaDecoderOwner* GetOwner() const = 0;
// Set by Reader if the current audio track can be offloaded // Set by Reader if the current audio track can be offloaded
virtual void SetPlatformCanOffloadAudio(bool aCanOffloadAudio) {} virtual void SetPlatformCanOffloadAudio(bool aCanOffloadAudio) {}

View File

@ -1065,7 +1065,8 @@ bool
MediaDecoder::OwnerHasError() const MediaDecoder::OwnerHasError() const
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
return IsShutdown() || mOwner->HasError(); MOZ_ASSERT(!IsShutdown());
return mOwner->HasError();
} }
class MediaElementGMPCrashHelper : public GMPCrashHelper class MediaElementGMPCrashHelper : public GMPCrashHelper
@ -1114,10 +1115,9 @@ void
MediaDecoder::PlaybackEnded() MediaDecoder::PlaybackEnded()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!IsShutdown());
if (IsShutdown() || if (mLogicallySeeking || mPlayState == PLAY_STATE_LOADING) {
mLogicallySeeking ||
mPlayState == PLAY_STATE_LOADING) {
return; return;
} }
@ -1267,11 +1267,9 @@ void
MediaDecoder::OnSeekResolved(SeekResolveValue aVal) MediaDecoder::OnSeekResolved(SeekResolveValue aVal)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!IsShutdown());
mSeekRequest.Complete(); mSeekRequest.Complete();
if (IsShutdown())
return;
bool fireEnded = false; bool fireEnded = false;
{ {
// An additional seek was requested while the current seek was // An additional seek was requested while the current seek was
@ -1309,9 +1307,7 @@ void
MediaDecoder::SeekingStarted(MediaDecoderEventVisibility aEventVisibility) MediaDecoder::SeekingStarted(MediaDecoderEventVisibility aEventVisibility)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (IsShutdown()) MOZ_ASSERT(!IsShutdown());
return;
if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) { if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) {
mOwner->SeekStarted(); mOwner->SeekStarted();
} }
@ -1345,9 +1341,7 @@ void
MediaDecoder::UpdateLogicalPositionInternal(MediaDecoderEventVisibility aEventVisibility) MediaDecoder::UpdateLogicalPositionInternal(MediaDecoderEventVisibility aEventVisibility)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (IsShutdown()) { MOZ_ASSERT(!IsShutdown());
return;
}
double currentPosition = static_cast<double>(CurrentPosition()) / static_cast<double>(USECS_PER_S); double currentPosition = static_cast<double>(CurrentPosition()) / static_cast<double>(USECS_PER_S);
bool logicalPositionChanged = mLogicalPosition != currentPosition; bool logicalPositionChanged = mLogicalPosition != currentPosition;
@ -1369,10 +1363,7 @@ void
MediaDecoder::DurationChanged() MediaDecoder::DurationChanged()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!IsShutdown());
if (IsShutdown()) {
return;
}
double oldDuration = mDuration; double oldDuration = mDuration;
if (IsInfinite()) { if (IsInfinite()) {
@ -1842,7 +1833,7 @@ MediaMemoryTracker::CollectReports(nsIHandleReportCallback* aHandleReport,
} }
MediaDecoderOwner* MediaDecoderOwner*
MediaDecoder::GetOwner() MediaDecoder::GetOwner() const
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
// mOwner is valid until shutdown. // mOwner is valid until shutdown.

View File

@ -239,7 +239,7 @@ public:
bool IsEndedOrShutdown() const; bool IsEndedOrShutdown() const;
// Return true if the MediaDecoderOwner's error attribute is not null. // Return true if the MediaDecoderOwner's error attribute is not null.
// If the MediaDecoder is shutting down, OwnerHasError will return true. // Must be called before Shutdown().
bool OwnerHasError() const; bool OwnerHasError() const;
already_AddRefed<GMPCrashHelper> GetCrashHelper() override; already_AddRefed<GMPCrashHelper> GetCrashHelper() override;
@ -416,6 +416,7 @@ private:
void UpdateLogicalPosition() void UpdateLogicalPosition()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!IsShutdown());
// Per spec, offical position remains stable during pause and seek. // Per spec, offical position remains stable during pause and seek.
if (mPlayState == PLAY_STATE_PAUSED || IsSeeking()) { if (mPlayState == PLAY_STATE_PAUSED || IsSeeking()) {
return; return;
@ -433,7 +434,7 @@ private:
// Indicate whether the media is same-origin with the element. // Indicate whether the media is same-origin with the element.
void UpdateSameOriginStatus(bool aSameOrigin); void UpdateSameOriginStatus(bool aSameOrigin);
MediaDecoderOwner* GetOwner() override; MediaDecoderOwner* GetOwner() const override;
#ifdef MOZ_EME #ifdef MOZ_EME
typedef MozPromise<RefPtr<CDMProxy>, bool /* aIgnored */, /* IsExclusive = */ true> CDMProxyPromise; typedef MozPromise<RefPtr<CDMProxy>, bool /* aIgnored */, /* IsExclusive = */ true> CDMProxyPromise;
@ -541,6 +542,7 @@ protected:
void SetExplicitDuration(double aValue) void SetExplicitDuration(double aValue)
{ {
MOZ_ASSERT(!IsShutdown());
mExplicitDuration.Set(Some(aValue)); mExplicitDuration.Set(Some(aValue));
// We Invoke DurationChanged explicitly, rather than using a watcher, so // We Invoke DurationChanged explicitly, rather than using a watcher, so

View File

@ -1033,12 +1033,6 @@ RTCPeerConnection.prototype = {
stream.getTracks().forEach(track => this.addTrack(track, stream)); stream.getTracks().forEach(track => this.addTrack(track, stream));
}, },
removeStream: function(stream) {
// Bug 844295: Not implementing this functionality.
throw new this._win.DOMException("removeStream not yet implemented",
"NotSupportedError");
},
getStreamById: function(id) { getStreamById: function(id) {
throw new this._win.DOMException("getStreamById not yet implemented", throw new this._win.DOMException("getStreamById not yet implemented",
"NotSupportedError"); "NotSupportedError");

View File

@ -30,7 +30,7 @@ MediaSourceDecoder::MediaSourceDecoder(dom::HTMLMediaElement* aElement)
, mMediaSource(nullptr) , mMediaSource(nullptr)
, mEnded(false) , mEnded(false)
{ {
SetExplicitDuration(UnspecifiedNaN<double>()); mExplicitDuration.Set(Some(UnspecifiedNaN<double>()));
} }
MediaDecoder* MediaDecoder*
@ -225,6 +225,7 @@ void
MediaSourceDecoder::SetMediaSourceDuration(double aDuration) MediaSourceDecoder::SetMediaSourceDuration(double aDuration)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!IsShutdown());
if (aDuration >= 0) { if (aDuration >= 0) {
int64_t checkedDuration; int64_t checkedDuration;
if (NS_FAILED(SecondsToUsecs(aDuration, checkedDuration))) { if (NS_FAILED(SecondsToUsecs(aDuration, checkedDuration))) {

View File

@ -107,10 +107,6 @@
pc.addStream("Invalid Media Stream")}, pc.addStream("Invalid Media Stream")},
"addStream() on closed PC raised expected exception"); "addStream() on closed PC raised expected exception");
SimpleTest.doesThrow(function() {
pc.removeStream("Invalid Media Stream")},
"removeStream() on closed PC raised expected exception");
SimpleTest.doesThrow(function() { SimpleTest.doesThrow(function() {
pc.createDataChannel({})}, pc.createDataChannel({})},
"createDataChannel() on closed PC raised expected exception"); "createDataChannel() on closed PC raised expected exception");

View File

@ -62,7 +62,7 @@ BufferDecoder::GetImageContainer()
} }
MediaDecoderOwner* MediaDecoderOwner*
BufferDecoder::GetOwner() BufferDecoder::GetOwner() const
{ {
// unknown // unknown
return nullptr; return nullptr;

View File

@ -38,7 +38,7 @@ public:
VideoFrameContainer* GetVideoFrameContainer() final override; VideoFrameContainer* GetVideoFrameContainer() final override;
layers::ImageContainer* GetImageContainer() final override; layers::ImageContainer* GetImageContainer() final override;
MediaDecoderOwner* GetOwner() final override; MediaDecoderOwner* GetOwner() const final override;
already_AddRefed<GMPCrashHelper> GetCrashHelper() override; already_AddRefed<GMPCrashHelper> GetCrashHelper() override;

View File

@ -38,7 +38,11 @@ NS_IMPL_ISUPPORTS(MediaEngineDefaultVideoSource, nsITimerCallback)
*/ */
MediaEngineDefaultVideoSource::MediaEngineDefaultVideoSource() MediaEngineDefaultVideoSource::MediaEngineDefaultVideoSource()
#ifdef MOZ_WEBRTC
: MediaEngineCameraVideoSource("FakeVideo.Monitor") : MediaEngineCameraVideoSource("FakeVideo.Monitor")
#else
: MediaEngineVideoSource()
#endif
, mTimer(nullptr) , mTimer(nullptr)
, mMonitor("Fake video") , mMonitor("Fake video")
, mCb(16), mCr(16) , mCb(16), mCr(16)

View File

@ -18,7 +18,9 @@
#include "VideoSegment.h" #include "VideoSegment.h"
#include "AudioSegment.h" #include "AudioSegment.h"
#include "StreamTracks.h" #include "StreamTracks.h"
#ifdef MOZ_WEBRTC
#include "MediaEngineCameraVideoSource.h" #include "MediaEngineCameraVideoSource.h"
#endif
#include "MediaStreamGraph.h" #include "MediaStreamGraph.h"
#include "MediaTrackConstraints.h" #include "MediaTrackConstraints.h"
@ -34,7 +36,11 @@ class MediaEngineDefault;
* The default implementation of the MediaEngine interface. * The default implementation of the MediaEngine interface.
*/ */
class MediaEngineDefaultVideoSource : public nsITimerCallback, class MediaEngineDefaultVideoSource : public nsITimerCallback,
#ifdef MOZ_WEBRTC
public MediaEngineCameraVideoSource public MediaEngineCameraVideoSource
#else
public MediaEngineVideoSource
#endif
{ {
public: public:
MediaEngineDefaultVideoSource(); MediaEngineDefaultVideoSource();

View File

@ -123,7 +123,6 @@ interface RTCPeerConnection : EventTarget {
[UnsafeInPrerendering] [UnsafeInPrerendering]
MediaStream? getStreamById (DOMString streamId); MediaStream? getStreamById (DOMString streamId);
void addStream (MediaStream stream); void addStream (MediaStream stream);
void removeStream (MediaStream stream);
// replaces addStream; fails if already added // replaces addStream; fails if already added
// because a track can be part of multiple streams, stream parameters // because a track can be part of multiple streams, stream parameters

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<svg width="200" height="200">
<defs>
<pattern id="pattern-id" x="0" y="0" patternUnits="userSpaceOnUse" height="200" width="200">
<rect width="200" height="200" style="fill:rgb(0,0,255)" />
</pattern>
</defs>
<circle id="circle" cx="101" cy="101" r="50" fill="url(#pattern-id)" stroke="#000"/>
</svg>
</html>

View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html class="reftest-wait">
<svg width="200" height="200">
<defs>
<pattern id="pattern-id" x="0" y="0" patternUnits="userSpaceOnUse" height="200" width="200">
<rect width="200" height="200" style="fill:rgb(0,0,255)" />
</pattern>
</defs>
<circle id="drawPath" cx="101" cy="101" r="50" fill="url(#pattern-id)" stroke="#000">
</circle>
</svg>
<script>
function doTest() {
window.history.pushState(null, "", "new-page");
drawPath.style.display = "none";
window.setTimeout(() => {
drawPath.style.display = "inline";
document.documentElement.removeAttribute('class');
}, 0);
}
drawPath = document.getElementById("drawPath");
window.addEventListener("MozReftestInvalidate", doTest);
</script>
</html>

View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html class="reftest-wait">
<svg width="200" height="200">
<defs>
<pattern id="pattern-id" x="0" y="0" patternUnits="userSpaceOnUse" height="200" width="200">
<rect width="200" height="200" style="fill:rgb(0,0,255)" />
</pattern>
</defs>
<circle id="drawPath" cx="101" cy="101" r="50" style="fill: url(&quot;#pattern-id&quot;);" stroke="#000">
</circle>
</svg>
<script>
function doTest() {
window.history.pushState(null, "", "new-page");
drawPath.style.display = "none";
window.setTimeout(() => {
drawPath.style.display = "inline";
document.documentElement.removeAttribute('class');
}, 0);
}
drawPath = document.getElementById("drawPath");
window.addEventListener("MozReftestInvalidate", doTest);
</script>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<svg width="200" height="200">
<defs>
<clipPath id="myClip">
<circle cx="30" cy="30" r="20"/>
<circle cx="70" cy="70" r="20"/>
</clipPath>
</defs>
<rect x="10" y="10" width="100" height="100" clip-path="url(#myClip)"/>
</svg>
</html>

View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html class="reftest-wait">
<svg width="200" height="200">
<defs>
<clipPath id="myClip">
<circle cx="30" cy="30" r="20"/>
<circle cx="70" cy="70" r="20"/>
</clipPath>
</defs>
<rect id="drawPath" x="10" y="10" width="100" height="100" clip-path="url(#myClip)"/>
</svg>
<script>
function doTest() {
window.history.pushState(null, "", "new-page");
drawPath.style.display = "none";
window.setTimeout(() => {
drawPath.style.display = "inline";
document.documentElement.removeAttribute('class');
}, 0);
}
drawPath = document.getElementById("drawPath");
window.addEventListener("MozReftestInvalidate", doTest);
</script>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<svg width="200" height="200">
<defs>
<marker id="markerCircle" markerWidth="8" markerHeight="8" refX="5" refY="5">
<circle cx="5" cy="5" r="2" style="stroke: none; fill:#000000;"/>
</marker>
</defs>
<path id="drawPath" d="M10,10 L60,10 L110,10" style="stroke: #6666ff; stroke-width: 1px; fill: none; marker-start: url(#markerCircle); marker-mid: url(#markerCircle); marker-end: url(#markerCircle);"/>
</svg>
</html>

View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html class="reftest-wait">
<svg width="200" height="200">
<defs>
<marker id="markerCircle" markerWidth="8" markerHeight="8" refX="5" refY="5">
<circle cx="5" cy="5" r="2" style="stroke: none; fill:#000000;"/>
</marker>
</defs>
<path id="drawPath" d="M10,10 L60,10 L110,10"
style="stroke: #6666ff; stroke-width: 1px; fill: none; marker-start: url(#markerCircle); marker-mid: url(#markerCircle);; marker-end: url(#markerCircle);"/>
</svg>
<script>
function doTest() {
window.history.pushState(null, "", "new-page");
drawPath.style.display = "none";
window.setTimeout(() => {
drawPath.style.display = "inline";
document.documentElement.removeAttribute('class');
}, 0);
}
drawPath = document.getElementById("drawPath");
window.addEventListener("MozReftestInvalidate", doTest);
</script>
</html>

View File

@ -1962,3 +1962,8 @@ random-if(!winWidget) == 1273154-2.html 1273154-2-ref.html # depends on Windows
!= 1276161-1b.html 1276161-1-notref.html != 1276161-1b.html 1276161-1-notref.html
!= 1276161-1a.html 1276161-1b.html != 1276161-1a.html 1276161-1b.html
== 1275411-1.html 1275411-1-ref.html == 1275411-1.html 1275411-1-ref.html
HTTP == 652991-1a.html 652991-1-ref.html
HTTP == 652991-1b.html 652991-1-ref.html
HTTP == 652991-2.html 652991-2-ref.html
HTTP == 652991-3.html 652991-3-ref.html

View File

@ -433,3 +433,11 @@ pref(layout.css.mix-blend-mode.enabled,true) == blend-normal.svg blend-normal-re
#skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-screen.svg blend-screen-ref.svg #skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-screen.svg blend-screen-ref.svg
#skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-soft-light.svg blend-soft-light-ref.svg #skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-soft-light.svg blend-soft-light-ref.svg
skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-difference-stacking.html blend-difference-stacking-ref.html skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-difference-stacking.html blend-difference-stacking-ref.html
# test case for Fragment URLs
# https://drafts.csswg.org/css-values/#local-urls
== use-localRef-marker-01.svg use-localRef-marker-01-ref.svg
== use-localRef-clipPath-01.svg use-localRef-clipPath-01-ref.svg
== use-localRef-filter-01.svg use-localRef-filter-01-ref.svg
== use-localRef-fill-01.svg use-localRef-fill-01-ref.svg
== use-localRef-stroke-01.svg use-localRef-stroke-01-ref.svg

View File

@ -0,0 +1,17 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Reference for clipPath linked to local-ref URL</title>
<defs>
<clipPath id="clip1">
<circle cx="50" cy="50" r="50"/>
</clipPath>
<clipPath id="clip2">
<circle cx="50" cy="150" r="50"/>
</clipPath>
<clipPath id="clip3">
<circle cx="50" cy="250" r="50"/>
</clipPath>
</defs>
<rect x="0" y="0" width="100" height="100" fill="blue" clip-path="url(#clip1)"/>
<rect x="0" y="100" width="100" height="100" fill="blue" clip-path="url(#clip2)"/>
<rect x="0" y="200" width="100" height="100" fill="blue" clip-path="url(#clip3)"/>
</svg>

After

Width:  |  Height:  |  Size: 671 B

View File

@ -0,0 +1,23 @@
<?xml-stylesheet href="use-localRef.css" type="text/css"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Testcase for clipPath linked to local-ref URL</title>
<defs>
<clipPath id="circleClip1">
<circle cx="50" cy="50" r="0"/>
</clipPath>
<clipPath id="circleClip2">
<circle cx="50" cy="150" r="50"/>
</clipPath>
<clipPath id="circleClip3">
<circle cx="50" cy="250" r="50"/>
</clipPath>
</defs>
<style>
#cp3 {
clip-path: url(#circleClip3);
}
</style>
<use xlink:href="use-localRef-clipPath-resource.svg#cp1"/>
<use xlink:href="use-localRef-clipPath-resource.svg#cp2" clip-path="url(#circleClip2)"/>
<use xlink:href="use-localRef-clipPath-resource.svg#cp3"/>
</svg>

After

Width:  |  Height:  |  Size: 781 B

View File

@ -0,0 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<clipPath id="circleClip1">
<circle cx="50" cy="50" r="50"/>
</clipPath>
<clipPath id="circleClip2">
<circle cx="50" cy="150" r="0"/>
</clipPath>
<clipPath id="circleClip3">
<circle cx="50" cy="250" r="0"/>
</clipPath>
</defs>
<rect id="cp1" x="0" y="0" width="100" height="100" fill="blue" clip-path="url(#circleClip1)"/>
<rect id="cp2" x="0" y="100" width="100" height="100" fill="blue"/>
<rect id="cp3" x="0" y="200" width="100" height="100" fill="blue"/>
</svg>

After

Width:  |  Height:  |  Size: 608 B

View File

@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Reference for fill linked to local-ref URL</title>
<defs>
<linearGradient id="gradient1">
<stop offset="0%" stop-color="white"/>
<stop offset="100%" stop-color="blue"/>
</linearGradient>
</defs>
<rect x="10" y="10" width="80" height="80" fill="url(#gradient1)"/>
<rect x="10" y="110" width="80" height="80" fill="url(#gradient1)"/>
<rect x="10" y="210" width="80" height="80" fill="url(#gradient1)"/>
</svg>

After

Width:  |  Height:  |  Size: 530 B

View File

@ -0,0 +1,25 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Testcase for fill linked to local-ref URL</title>
<defs>
<linearGradient id="gradient1">
<stop offset="0%" stop-color="blue"/>
<stop offset="100%" stop-color="blue"/>
</linearGradient>
<linearGradient id="gradient2">
<stop offset="0%" stop-color="white"/>
<stop offset="100%" stop-color="blue"/>
</linearGradient>
<linearGradient id="gradient3">
<stop offset="0%" stop-color="white"/>
<stop offset="100%" stop-color="blue"/>
</linearGradient>
</defs>
<style>
#fill3 {
fill: url(#gradient3);
}
</style>
<use xlink:href="use-localRef-fill-resource.svg#fill1"/>
<use xlink:href="use-localRef-fill-resource.svg#fill2" fill="url(#gradient2)"/>
<use xlink:href="use-localRef-fill-resource.svg#fill3"/>
</svg>

After

Width:  |  Height:  |  Size: 884 B

View File

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="gradient1">
<stop offset="0%" stop-color="white"/>
<stop offset="100%" stop-color="blue"/>
</linearGradient>
<linearGradient id="gradient2">
<stop offset="0%" stop-color="blue"/>
<stop offset="100%" stop-color="blue"/>
</linearGradient>
<linearGradient id="gradient3">
<stop offset="0%" stop-color="blue"/>
<stop offset="100%" stop-color="blue"/>
</linearGradient>
</defs>
<rect id="fill1" x="10" y="10" width="80" height="80" fill="url(#gradient1)"/>
<rect id="fill2" x="10" y="110" width="80" height="80"/>
<rect id="fill3" x="10" y="210" width="80" height="80"/>
</svg>

After

Width:  |  Height:  |  Size: 753 B

View File

@ -0,0 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Reference for filter linked to local-ref URL</title>
<defs>
<filter id="blurFilter" x="-10" y="-10" width="100" height="100">
<feGaussianBlur in="SourceGraphic" stdDeviation="10" />
</filter>
</defs>
<rect x="10" y="10" width="80" height="80" fill="blue" filter="url(#blurFilter)"/>
<rect x="10" y="110" width="80" height="80" fill="blue" filter="url(#blurFilter)"/>
<rect x="10" y="210" width="80" height="80" fill="blue" filter="url(#blurFilter)"/>
</svg>

After

Width:  |  Height:  |  Size: 576 B

View File

@ -0,0 +1,22 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Testcase for filter linked to local-ref URL</title>
<defs>
<filter id="blurFilter1" x="-10" y="-10" width="100" height="100">
<feGaussianBlur in="SourceGraphic" stdDeviation="0" />
</filter>
<filter id="blurFilter2" x="-10" y="-10" width="100" height="100">
<feGaussianBlur in="SourceGraphic" stdDeviation="10" />
</filter>
<filter id="blurFilter3" x="-10" y="-10" width="100" height="100">
<feGaussianBlur in="SourceGraphic" stdDeviation="10" />
</filter>
</defs>
<style>
#f3 {
filter: url(#blurFilter3);
}
</style>
<use xlink:href="use-localRef-filter-resource.svg#f1"/>
<use xlink:href="use-localRef-filter-resource.svg#f2" filter="url(#blurFilter2)"/>
<use xlink:href="use-localRef-filter-resource.svg#f3"/>
</svg>

After

Width:  |  Height:  |  Size: 882 B

View File

@ -0,0 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<filter id="blurFilter1" x="-10" y="-10" width="100" height="100">
<feGaussianBlur in="SourceGraphic" stdDeviation="10" />
</filter>
<filter id="blurFilter2" x="-10" y="-10" width="100" height="100">
<feGaussianBlur in="SourceGraphic" stdDeviation="0" />
</filter>
<filter id="blurFilter3" x="-10" y="-10" width="100" height="100">
<feGaussianBlur in="SourceGraphic" stdDeviation="0" />
</filter>
</defs>
<rect id="f1" x="10" y="10" width="80" height="80" fill="blue" filter="url(#blurFilter1)"/>
<rect id="f2" x="10" y="110" width="80" height="80" fill="blue"/>
<rect id="f3" x="10" y="210" width="80" height="80" fill="blue"/>
</svg>

After

Width:  |  Height:  |  Size: 778 B

View File

@ -0,0 +1,29 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Reference for marker linked to local-ref URL</title>
<defs>
<marker id="limeCircle" markerWidth="8" markerHeight="8" refX="5" refY="5">
<circle cx="5" cy="5" r="2" style="stroke: none; fill:lime;"/>
</marker>
<marker id="blueCircle" markerWidth="8" markerHeight="8" refX="5" refY="5">
<circle cx="5" cy="5" r="2" style="stroke: none; fill:blue;"/>
</marker>
<marker id="purpleCircle" markerWidth="8" markerHeight="8" refX="5" refY="5">
<circle cx="5" cy="5" r="2" style="stroke: none; fill:purple;"/>
</marker>
</defs>
<style>
path {
stroke: blue;
stroke-width: 2px;
}
</style>
<path d="M20,20 L70,20 L120,20" style="marker-start: url(#limeCircle);"/>
<path d="M20,40 L70,40 L120,40" style="marker-start: url(#blueCircle);"/>
<path d="M20,60 L70,60 L120,60" style="marker-start: url(#blueCircle);"/>
<path d="M20,80 L70,80 L120,80" style="marker-mid: url(#limeCircle);"/>
<path d="M20,100 L70,100 L120,100" style="marker-mid: url(#blueCircle);"/>
<path d="M20,120 L70,120 L120,120" style="marker-mid: url(#blueCircle);"/>
<path d="M20,140 L70,140 L120,140" style="marker-end: url(#limeCircle);"/>
<path d="M20,160 L70,160 L120,160" style="marker-end: url(#blueCircle);"/>
<path d="M20,180 L70,180 L120,180" style="marker-end: url(#blueCircle);"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,30 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Testcase for marker linked to local-ref URL</title>
<defs>
<marker id="circleMarker" markerWidth="8" markerHeight="8" refX="5" refY="5">
<circle cx="5" cy="5" r="2" style="stroke: none; fill:blue;"/>
</marker>
</defs>
<style>
#markerA3 {
marker-start: url(#circleMarker);
}
#markerB3 {
marker-mid: url(#circleMarker);
}
#markerC3 {
marker-end: url(#circleMarker);
}
</style>
<use xlink:href="use-localRef-marker-resource.svg#markerA1"/>
<use xlink:href="use-localRef-marker-resource.svg#markerA2" style="marker-start: url(#circleMarker);"/>
<use xlink:href="use-localRef-marker-resource.svg#markerA3"/>
<use xlink:href="use-localRef-marker-resource.svg#markerB1"/>
<use xlink:href="use-localRef-marker-resource.svg#markerB2" style="marker-mid: url(#circleMarker);"/>
<use xlink:href="use-localRef-marker-resource.svg#markerB3"/>
<use xlink:href="use-localRef-marker-resource.svg#markerC1"/>
<use xlink:href="use-localRef-marker-resource.svg#markerC2" style="marker-end: url(#circleMarker);"/>
<use xlink:href="use-localRef-marker-resource.svg#markerC3"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,18 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<marker id="circleMarker" markerWidth="8" markerHeight="8" refX="5" refY="5">
<circle cx="5" cy="5" r="2" style="stroke: none; fill:lime;"/>
</marker>
</defs>
<path id="markerA1" d="M20,20 L70,20 L120,20" style="stroke: blue; stroke-width: 2px; marker-start: url(#circleMarker);"/>
<path id="markerA2" d="M20,40 L70,40 L120,40" style="stroke: blue; stroke-width: 2px;"/>
<path id="markerA3" d="M20,60 L70,60 L120,60" style="stroke: blue; stroke-width: 2px;"/>
<path id="markerB1" d="M20,80 L70,80 L120,80" style="stroke: blue; stroke-width: 2px; marker-mid: url(#circleMarker);"/>
<path id="markerB2" d="M20,100 L70,100 L120,100" style="stroke: blue; stroke-width: 2px;"/>
<path id="markerB3" d="M20,120 L70,120 L120,120" style="stroke: blue; stroke-width: 2px;"/>
<path id="markerC1" d="M20,140 L70,140 L120,140" style="stroke: blue; stroke-width: 2px; marker-end: url(#circleMarker);"/>
<path id="markerC2" d="M20,160 L70,160 L120,160" style="stroke: blue; stroke-width: 2px;"/>
<path id="markerC3" d="M20,180 L70,180 L120,180" style="stroke: blue; stroke-width: 2px;;"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Reference for stroke linked to local-ref URL</title>
<defs>
<linearGradient id="gradient1">
<stop offset="0%" stop-color="white"/>
<stop offset="100%" stop-color="blue"/>
</linearGradient>
</defs>
<rect x="10" y="10" width="80" height="80" stroke-width="5" fill="white" stroke="url(#gradient1)"/>
<rect x="10" y="110" width="80" height="80" stroke-width="5" fill="white" stroke="url(#gradient1)"/>
<rect x="10" y="210" width="80" height="80" stroke-width="5" fill="white" stroke="url(#gradient1)"/>
</svg>

After

Width:  |  Height:  |  Size: 628 B

View File

@ -0,0 +1,26 @@
<?xml-stylesheet href="use-localRef.css" type="text/css"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Testcase for stroke linked to local-ref URL</title>
<defs>
<linearGradient id="gradient1">
<stop offset="0%" stop-color="blue"/>
<stop offset="100%" stop-color="blue"/>
</linearGradient>
<linearGradient id="gradient2">
<stop offset="0%" stop-color="white"/>
<stop offset="100%" stop-color="blue"/>
</linearGradient>
<linearGradient id="gradient3">
<stop offset="0%" stop-color="white"/>
<stop offset="100%" stop-color="blue"/>
</linearGradient>
</defs>
<style>
#stroke3 {
stroke: url(#gradient3);
}
</style>
<use xlink:href="use-localRef-stroke-resource.svg#stroke1"/>
<use xlink:href="use-localRef-stroke-resource.svg#stroke2" stroke="url(#gradient2)"/>
<use xlink:href="use-localRef-stroke-resource.svg#stroke3"/>
</svg>

After

Width:  |  Height:  |  Size: 987 B

View File

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="gradient1">
<stop offset="0%" stop-color="white"/>
<stop offset="100%" stop-color="blue"/>
</linearGradient>
<linearGradient id="gradient2">
<stop offset="0%" stop-color="blue"/>
<stop offset="100%" stop-color="blue"/>
</linearGradient>
<linearGradient id="gradient3">
<stop offset="0%" stop-color="blue"/>
<stop offset="100%" stop-color="blue"/>
</linearGradient>
</defs>
<rect id="stroke1" x="10" y="10" width="80" height="80" fill="white" stroke-width="5" stroke="url(#gradient1)"/>
<rect id="stroke2" x="10" y="110" width="80" height="80" fill="white" stroke-width="5" />
<rect id="stroke3" x="10" y="210" width="80" height="80" fill="white" stroke-width="5" />
</svg>

After

Width:  |  Height:  |  Size: 853 B

View File

@ -727,6 +727,7 @@ Servo_DropNodeData(ServoNodeData* data)
RawServoStyleSheet* RawServoStyleSheet*
Servo_StylesheetFromUTF8Bytes(const uint8_t* bytes, uint32_t length, Servo_StylesheetFromUTF8Bytes(const uint8_t* bytes, uint32_t length,
mozilla::css::SheetParsingMode mode, mozilla::css::SheetParsingMode mode,
const uint8_t* base_bytes, uint32_t base_length,
ThreadSafeURIHolder* base, ThreadSafeURIHolder* base,
ThreadSafeURIHolder* referrer, ThreadSafeURIHolder* referrer,
ThreadSafePrincipalHolder* principal) ThreadSafePrincipalHolder* principal)

View File

@ -216,6 +216,7 @@ NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsStyleCoord::Calc, Calc);
RawServoStyleSheet* Servo_StylesheetFromUTF8Bytes( RawServoStyleSheet* Servo_StylesheetFromUTF8Bytes(
const uint8_t* bytes, uint32_t length, const uint8_t* bytes, uint32_t length,
mozilla::css::SheetParsingMode parsing_mode, mozilla::css::SheetParsingMode parsing_mode,
const uint8_t* base_bytes, uint32_t base_length,
ThreadSafeURIHolder* base, ThreadSafeURIHolder* base,
ThreadSafeURIHolder* referrer, ThreadSafeURIHolder* referrer,
ThreadSafePrincipalHolder* principal); ThreadSafePrincipalHolder* principal);

Some files were not shown because too many files have changed in this diff Show More