mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge inbound to m-c.
This commit is contained in:
commit
0a63e25ce6
@ -139,7 +139,7 @@ var shell = {
|
||||
if (Services.prefs.getBoolPref('app.reportCrashes')) {
|
||||
this.submitCrash(crashID);
|
||||
} else {
|
||||
debugCrashReport('app.reportCrashes is disabled');
|
||||
this.deleteCrash(crashID);
|
||||
}
|
||||
} catch (e) {
|
||||
debugCrashReport('Can\'t fetch app.reportCrashes. Exception: ' + e);
|
||||
@ -157,6 +157,13 @@ var shell = {
|
||||
}
|
||||
},
|
||||
|
||||
deleteCrash: function shell_deleteCrash(aCrashID) {
|
||||
if (aCrashID) {
|
||||
debugCrashReport('Deleting pending crash: ' + aCrashID);
|
||||
shell.CrashSubmit.delete(aCrashID);
|
||||
}
|
||||
},
|
||||
|
||||
// this function submit the pending crashes.
|
||||
// make sure you are online.
|
||||
submitQueuedCrashes: function shell_submitQueuedCrashes() {
|
||||
@ -1096,7 +1103,11 @@ window.addEventListener('ContentStart', function cr_onContentStart() {
|
||||
let content = shell.contentBrowser.contentWindow;
|
||||
content.addEventListener("mozContentEvent", function cr_onMozContentEvent(e) {
|
||||
if (e.detail.type == "submit-crash" && e.detail.crashID) {
|
||||
debugCrashReport("submitting crash at user request ", e.detail.crashID);
|
||||
shell.submitCrash(e.detail.crashID);
|
||||
} else if (e.detail.type == "delete-crash" && e.detail.crashID) {
|
||||
debugCrashReport("deleting crash at user request ", e.detail.crashID);
|
||||
shell.deleteCrash(e.detail.crashID);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -1,6 +1,6 @@
|
||||
[{
|
||||
"size": 659020310,
|
||||
"digest": "8201020a5214337cf19d43bb3fde8c4624d7a7a71f04a4522a34783194694fe5e66f8087acf6fe7080d7bf787b8311dd9ed8facfbac39198d0121f817b8eef32",
|
||||
"size": 677339898,
|
||||
"digest": "af1d883664bf4f02637060855d76026cceffd28a796ab3d65e16f1b0b6d1a8d5bb634388152ba63ecbfa2fbb1bd59317c0cfd508e163eaf950923b6b999369bc",
|
||||
"algorithm": "sha512",
|
||||
"filename": "emulator.zip"
|
||||
}]
|
||||
|
@ -128,12 +128,13 @@
|
||||
</menupopup>
|
||||
</toolbarbutton>
|
||||
|
||||
<toolbarbutton class="webconsole-clear-console-button devtools-toolbarbutton"
|
||||
label="&btnClear.label;" tooltiptext="&btnClear.tooltip;"/>
|
||||
|
||||
<spacer flex="1"/>
|
||||
|
||||
<textbox class="compact hud-filter-box devtools-searchinput" type="search"
|
||||
placeholder="&filterOutput.placeholder;"/>
|
||||
<toolbarbutton class="webconsole-clear-console-button devtools-toolbarbutton"
|
||||
label="&btnClear.label;" tooltiptext="&btnClear.tooltip;"/>
|
||||
</toolbar>
|
||||
|
||||
<richlistbox class="hud-output-node" orient="vertical" flex="1"
|
||||
|
@ -16,6 +16,11 @@ const WebProgress = {
|
||||
messageManager.addMessageListener("Content:LocationChange", this);
|
||||
messageManager.addMessageListener("Content:SecurityChange", this);
|
||||
Elements.progress.addEventListener("transitionend", this._progressTransEnd, true);
|
||||
Elements.tabList.addEventListener("TabSelect", this._onTabSelect, true);
|
||||
|
||||
let urlBar = document.getElementById("urlbar-edit");
|
||||
urlBar.addEventListener("input", this._onUrlBarInput, false);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
@ -58,12 +63,17 @@ const WebProgress = {
|
||||
},
|
||||
|
||||
_securityChange: function _securityChange(aJson, aTab) {
|
||||
// Don't need to do anything if the data we use to update the UI hasn't changed
|
||||
if (aTab.state == aJson.state && !aTab.hostChanged)
|
||||
return;
|
||||
let state = aJson.state;
|
||||
let identityBox = document.getElementById("identity-box-inner");
|
||||
let nsIWebProgressListener = Ci.nsIWebProgressListener;
|
||||
|
||||
aTab.hostChanged = false;
|
||||
aTab.state = aJson.state;
|
||||
if (state & nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL) {
|
||||
aTab._identityState = identityBox.className = "verifiedIdentity";
|
||||
} else if (state & nsIWebProgressListener.STATE_IS_SECURE) {
|
||||
aTab._identityState = identityBox.className = "verifiedDomain";
|
||||
} else {
|
||||
aTab._identityState = identityBox.className = "";
|
||||
}
|
||||
},
|
||||
|
||||
_locationChange: function _locationChange(aJson, aTab) {
|
||||
@ -77,7 +87,6 @@ const WebProgress = {
|
||||
if (locationHasChanged) {
|
||||
Browser.getNotificationBox(aTab.browser).removeTransientNotifications();
|
||||
aTab.resetZoomLevel();
|
||||
aTab.hostChanged = true;
|
||||
aTab.browser.lastLocation = location;
|
||||
aTab.browser.userTypedValue = "";
|
||||
aTab.browser.appIcon = { href: null, size:-1 };
|
||||
@ -204,6 +213,15 @@ const WebProgress = {
|
||||
Elements.progressContainer.setAttribute("collapsed", true);
|
||||
}
|
||||
},
|
||||
|
||||
_onTabSelect: function(aEvent) {
|
||||
let identityBox = document.getElementById("identity-box-inner");
|
||||
let tab = Browser.getTabFromChrome(aEvent.originalTarget);
|
||||
identityBox.className = tab._identityState || "";
|
||||
},
|
||||
|
||||
_onUrlBarInput: function(aEvent) {
|
||||
let identityBox = document.getElementById("identity-box-inner");
|
||||
Browser.selectedTab._identityState = identityBox.className = "";
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
"use strict";
|
||||
|
||||
var Appbar = {
|
||||
get appbar() { return document.getElementById('appbar'); },
|
||||
get consoleButton() { return document.getElementById('console-button'); },
|
||||
get jsShellButton() { return document.getElementById('jsshell-button'); },
|
||||
get zoomInButton() { return document.getElementById('zoomin-button'); },
|
||||
@ -17,8 +16,11 @@ var Appbar = {
|
||||
activeTileset: null,
|
||||
|
||||
init: function Appbar_init() {
|
||||
window.addEventListener('MozAppbarShowing', this, false);
|
||||
window.addEventListener('MozAppbarDismissing', this, false);
|
||||
window.addEventListener('MozContextUIShow', this);
|
||||
window.addEventListener('MozContextUIDismiss', this);
|
||||
window.addEventListener('MozAppbarDismiss', this);
|
||||
Elements.contextappbar.addEventListener('MozAppbarShowing', this, false);
|
||||
Elements.contextappbar.addEventListener('MozAppbarDismissing', this, false);
|
||||
window.addEventListener('MozPrecisePointer', this, false);
|
||||
window.addEventListener('MozImprecisePointer', this, false);
|
||||
window.addEventListener('MozContextActionsChange', this, false);
|
||||
@ -36,11 +38,16 @@ var Appbar = {
|
||||
|
||||
handleEvent: function Appbar_handleEvent(aEvent) {
|
||||
switch (aEvent.type) {
|
||||
case 'MozContextUIShow':
|
||||
Elements.appbar.show();
|
||||
break;
|
||||
case 'MozAppbarDismiss':
|
||||
case 'MozContextUIDismiss':
|
||||
case 'URLChanged':
|
||||
case 'TabSelect':
|
||||
case 'ToolPanelShown':
|
||||
case 'ToolPanelHidden':
|
||||
this.appbar.dismiss();
|
||||
Elements.appbar.dismiss();
|
||||
break;
|
||||
case 'MozAppbarShowing':
|
||||
this._updatePinButton();
|
||||
@ -122,7 +129,7 @@ var Appbar = {
|
||||
}
|
||||
|
||||
var x = this.moreButton.getBoundingClientRect().left;
|
||||
var y = this.appbar.getBoundingClientRect().top;
|
||||
var y = Elements.appbar.getBoundingClientRect().top;
|
||||
ContextMenuUI.showContextMenu({
|
||||
json: {
|
||||
types: typesArray,
|
||||
@ -171,16 +178,16 @@ var Appbar = {
|
||||
activeTileset.dispatchEvent(event);
|
||||
if (!event.defaultPrevented) {
|
||||
activeTileset.clearSelection();
|
||||
this.appbar.dismiss();
|
||||
Elements.contextappbar.dismiss();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
showContextualActions: function(aVerbs) {
|
||||
if (aVerbs.length)
|
||||
this.appbar.setAttribute("contextual", "true");
|
||||
Elements.contextappbar.show();
|
||||
else
|
||||
this.appbar.removeAttribute("contextual");
|
||||
Elements.contextappbar.hide();
|
||||
|
||||
let doc = document;
|
||||
// button element id to action verb lookup
|
||||
@ -196,7 +203,7 @@ var Appbar = {
|
||||
// sort buttons into 2 buckets - needing showing and needing hiding
|
||||
let toHide = [],
|
||||
toShow = [];
|
||||
for (let btnNode of this.appbar.querySelectorAll("#contextualactions-tray > toolbarbutton")) {
|
||||
for (let btnNode of Elements.contextappbar.querySelectorAll("#contextualactions-tray > toolbarbutton")) {
|
||||
// correct the hidden state for each button;
|
||||
// .. buttons present in the map should be visible, otherwise not
|
||||
if (buttonsMap.has(btnNode.id)) {
|
||||
@ -238,12 +245,12 @@ var Appbar = {
|
||||
let event = document.createEvent("Events");
|
||||
event.actions = verbs;
|
||||
event.initEvent("MozContextActionsChange", true, false);
|
||||
this.appbar.dispatchEvent(event);
|
||||
Elements.contextappbar.dispatchEvent(event);
|
||||
|
||||
if (verbs.length) {
|
||||
this.appbar.show(); // should be no-op if we're already showing
|
||||
Elements.contextappbar.show(); // should be no-op if we're already showing
|
||||
} else {
|
||||
this.appbar.dismiss();
|
||||
Elements.contextappbar.dismiss();
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -8,22 +8,6 @@
|
||||
</content>
|
||||
|
||||
<implementation implements="nsIDOMEventListener">
|
||||
<constructor>
|
||||
<![CDATA[
|
||||
window.addEventListener('MozContextUIShow', this);
|
||||
window.addEventListener('MozContextUIDismiss', this);
|
||||
window.addEventListener('MozAppbarDismiss', this);
|
||||
]]>
|
||||
</constructor>
|
||||
|
||||
<destructor>
|
||||
<![CDATA[
|
||||
window.removeEventListener('MozContextUIShow', this);
|
||||
window.removeEventListener('MozContextUIDismiss', this);
|
||||
window.removeEventListener('MozAppbarDismiss', this);
|
||||
]]>
|
||||
</destructor>
|
||||
|
||||
<field name="sticky">false</field>
|
||||
<field name="_toolbar" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "toolbar");</field>
|
||||
|
||||
@ -49,6 +33,9 @@
|
||||
<method name="dismiss">
|
||||
<body>
|
||||
<![CDATA[
|
||||
if (!this.isShowing)
|
||||
return;
|
||||
|
||||
this._fire("MozAppbarDismissing");
|
||||
this.removeAttribute("visible");
|
||||
]]>
|
||||
@ -58,6 +45,9 @@
|
||||
<method name="show">
|
||||
<body>
|
||||
<![CDATA[
|
||||
if (this.isShowing)
|
||||
return;
|
||||
|
||||
this._fire("MozAppbarShowing");
|
||||
this.setAttribute("visible", "true");
|
||||
]]>
|
||||
@ -75,23 +65,6 @@
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="handleEvent">
|
||||
<parameter name="aEvent"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
switch (aEvent.type) {
|
||||
case 'MozContextUIShow':
|
||||
this.show();
|
||||
break;
|
||||
case 'MozAppbarDismiss':
|
||||
case 'MozContextUIDismiss':
|
||||
this.dismiss();
|
||||
break;
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
</implementation>
|
||||
|
||||
<handlers>
|
||||
|
@ -54,16 +54,6 @@
|
||||
]]>
|
||||
</constructor>
|
||||
|
||||
<field name="_securityUI">null</field>
|
||||
<property name="securityUI">
|
||||
<getter><![CDATA[
|
||||
return this._securityUI || {};
|
||||
]]></getter>
|
||||
<setter><![CDATA[
|
||||
this._securityUI = val;
|
||||
]]></setter>
|
||||
</property>
|
||||
|
||||
<field name="_searchEngines">[]</field>
|
||||
<property name="searchEngines"
|
||||
onget="return this._searchEngines"
|
||||
@ -463,10 +453,6 @@
|
||||
}
|
||||
|
||||
let data = this._getIdentityData(SSLStatus);
|
||||
this._browser._securityUI = {
|
||||
SSLStatus: SSLStatus ? {serverCert: data} : null,
|
||||
state: json.state
|
||||
}
|
||||
this._browser.updateWindowId(json.contentWindowId);
|
||||
break;
|
||||
}
|
||||
@ -509,7 +495,11 @@
|
||||
|
||||
// Check whether this site is a security exception.
|
||||
let currentURI = this._browser.webNavigation._currentURI;
|
||||
result.isException = !!this._overrideService.hasMatchingOverride(currentURI.asciiHost, currentURI.port, cert, {}, {});
|
||||
if (currentURI) {
|
||||
result.isException = this._overrideService.hasMatchingOverride(currentURI.asciiHost, currentURI.port, cert, {}, {});
|
||||
} else {
|
||||
result.isException = false;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -44,6 +44,7 @@ let Elements = {};
|
||||
["toolbar", "toolbar"],
|
||||
["browsers", "browsers"],
|
||||
["appbar", "appbar"],
|
||||
["contextappbar", "contextappbar"],
|
||||
["contentViewport", "content-viewport"],
|
||||
["progress", "progress-control"],
|
||||
["progressContainer", "progress-container"],
|
||||
|
@ -1392,9 +1392,6 @@ function Tab(aURI, aParams, aOwner) {
|
||||
|
||||
this.owner = aOwner || null;
|
||||
|
||||
this.hostChanged = false;
|
||||
this.state = null;
|
||||
|
||||
// Set to 0 since new tabs that have not been viewed yet are good tabs to
|
||||
// toss if app needs more memory.
|
||||
this.lastSelected = 0;
|
||||
|
@ -355,7 +355,9 @@
|
||||
<toolbarbutton id="pin-button" type="checkbox" oncommand="Appbar.onPinButton()"/>
|
||||
<toolbarbutton id="more-button" onclick="Appbar.onMoreButton(event)"/>
|
||||
</toolbar>
|
||||
</appbar>
|
||||
|
||||
<appbar id="contextappbar">
|
||||
<toolbar id="contextualactions-tray" flex="1">
|
||||
<toolbarbutton id="delete-selected-button" hidden="true" fade="true" oncommand="Appbar.dispatchContextualAction('delete')"/>
|
||||
<toolbarbutton id="restore-selected-button" hidden="true" fade="true" oncommand="Appbar.dispatchContextualAction('restore')"/>
|
||||
|
@ -12,24 +12,24 @@ include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
BROWSER_TESTS = \
|
||||
head.js \
|
||||
browser_test.js \
|
||||
browser_bookmarks.js \
|
||||
browser_canonizeURL.js \
|
||||
browser_context_ui.js \
|
||||
browser_tiles.js \
|
||||
browser_tilegrid.xul \
|
||||
browser_onscreen_keyboard.js \
|
||||
browser_onscreen_keyboard.html \
|
||||
browser_remotetabs.js \
|
||||
browser_downloads.js \
|
||||
browser_context_menu_tests.js \
|
||||
browser_context_menu_tests_01.html \
|
||||
browser_context_menu_tests_02.html \
|
||||
browser_context_menu_tests_03.html \
|
||||
browser_prefs_ui.js \
|
||||
browser_topsites.js \
|
||||
browser_tabs.js \
|
||||
browser_bookmarks.js \
|
||||
browser_context_ui.js \
|
||||
browser_downloads.js \
|
||||
browser_history.js \
|
||||
browser_onscreen_keyboard.js \
|
||||
browser_onscreen_keyboard.html \
|
||||
browser_prefs_ui.js \
|
||||
browser_remotetabs.js \
|
||||
browser_tabs.js \
|
||||
browser_test.js \
|
||||
browser_tiles.js \
|
||||
browser_tilegrid.xul \
|
||||
browser_topsites.js \
|
||||
$(NULL)
|
||||
|
||||
# disabled due to timeouts and lack of plugin support.
|
||||
@ -58,6 +58,7 @@ BROWSER_TEST_RESOURCES = \
|
||||
res/image01.png \
|
||||
res/textblock01.html \
|
||||
res/textinput01.html \
|
||||
res/textarea01.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(BROWSER_TESTS)
|
||||
|
@ -16,14 +16,14 @@ function setup() {
|
||||
PanelUI.hide();
|
||||
BookmarksTestHelper.setup();
|
||||
|
||||
yield hideContextUI();
|
||||
|
||||
if (StartUI.isStartPageVisible)
|
||||
return;
|
||||
|
||||
yield addTab("about:start");
|
||||
|
||||
yield waitForCondition(() => StartUI.isStartPageVisible);
|
||||
|
||||
yield hideContextUI();
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
@ -149,14 +149,14 @@ gTests.push({
|
||||
|
||||
let item = gStartView._getItemForBookmarkId(2);
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item, 10, 10);
|
||||
yield promise;
|
||||
|
||||
ok(!unpinButton.hidden, "Unpin button is visible.");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
EventUtils.synthesizeMouse(unpinButton, 10, 10, {}, window);
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
unpinButton.click();
|
||||
yield promise;
|
||||
|
||||
item = gStartView._getItemForBookmarkId(2);
|
||||
@ -171,7 +171,7 @@ gTests.push({
|
||||
let item2 = gStartView._getItemForBookmarkId(5);
|
||||
let item3 = gStartView._getItemForBookmarkId(12);
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item1, 10, 10);
|
||||
sendContextMenuClickToElement(window, item2, 10, 10);
|
||||
sendContextMenuClickToElement(window, item3, 10, 10);
|
||||
@ -179,7 +179,7 @@ gTests.push({
|
||||
|
||||
ok(!unpinButton.hidden, "Unpin button is visible.");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
EventUtils.synthesizeMouse(unpinButton, 10, 10, {}, window);
|
||||
yield promise;
|
||||
|
||||
@ -206,7 +206,7 @@ gTests.push({
|
||||
let item = gStartView._getItemForBookmarkId(2);
|
||||
let initialLocation = gStartView._set.getIndexOfItem(item);
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item, 10, 10);
|
||||
yield promise;
|
||||
|
||||
@ -223,7 +223,7 @@ gTests.push({
|
||||
ok(!restoreButton.hidden, "Restore button is visible.");
|
||||
ok(gStartView._set.itemCount === gStartView._limit, "Grid repopulated");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
EventUtils.synthesizeMouse(restoreButton, 10, 10, {}, window);
|
||||
yield promise;
|
||||
|
||||
@ -235,7 +235,7 @@ gTests.push({
|
||||
|
||||
let item = gStartView._getItemForBookmarkId(2);
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item, 10, 10);
|
||||
yield promise;
|
||||
|
||||
@ -251,8 +251,8 @@ gTests.push({
|
||||
ok(BookmarksTestHelper._nodes[2], "Item not deleted yet");
|
||||
ok(!restoreButton.hidden, "Restore button is visible.");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
Elements.appbar.dismiss();
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
Elements.contextappbar.dismiss();
|
||||
yield promise;
|
||||
|
||||
item = gStartView._getItemForBookmarkId(2);
|
||||
@ -271,7 +271,7 @@ gTests.push({
|
||||
let initialLocation2 = gStartView._set.getIndexOfItem(item2);
|
||||
let initialLocation3 = gStartView._set.getIndexOfItem(item3);
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item1, 10, 10);
|
||||
sendContextMenuClickToElement(window, item2, 10, 10);
|
||||
sendContextMenuClickToElement(window, item3, 10, 10);
|
||||
@ -293,7 +293,7 @@ gTests.push({
|
||||
ok(!restoreButton.hidden, "Restore button is visible.");
|
||||
ok(gStartView._set.itemCount === gStartView._limit - 1, "Grid repopulated");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
EventUtils.synthesizeMouse(restoreButton, 10, 10, {}, window);
|
||||
yield promise;
|
||||
|
||||
@ -313,7 +313,7 @@ gTests.push({
|
||||
let item2 = gStartView._getItemForBookmarkId(5);
|
||||
let item3 = gStartView._getItemForBookmarkId(12);
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item1, 10, 10);
|
||||
sendContextMenuClickToElement(window, item2, 10, 10);
|
||||
sendContextMenuClickToElement(window, item3, 10, 10);
|
||||
@ -334,8 +334,8 @@ gTests.push({
|
||||
"Items not deleted yet");
|
||||
ok(!restoreButton.hidden, "Restore button is visible.");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
Elements.appbar.dismiss();
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
Elements.contextappbar.dismiss();
|
||||
yield promise;
|
||||
|
||||
item1 = gStartView._getItemForBookmarkId(0);
|
||||
@ -363,13 +363,15 @@ gTests.push({
|
||||
|
||||
let item = gPanelView._getItemForBookmarkId(2);
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item, 10, 10);
|
||||
yield promise;
|
||||
|
||||
yield waitForCondition(() => !unpinButton.hidden);
|
||||
|
||||
ok(!unpinButton.hidden, "Unpin button is visible.");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
EventUtils.synthesizeMouse(unpinButton, 10, 10, {}, window);
|
||||
yield promise;
|
||||
|
||||
@ -386,7 +388,7 @@ gTests.push({
|
||||
let item2 = gPanelView._getItemForBookmarkId(5);
|
||||
let item3 = gPanelView._getItemForBookmarkId(12);
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item1, 10, 10);
|
||||
sendContextMenuClickToElement(window, item2, 10, 10);
|
||||
sendContextMenuClickToElement(window, item3, 10, 10);
|
||||
@ -394,7 +396,7 @@ gTests.push({
|
||||
|
||||
ok(!unpinButton.hidden, "Unpin button is visible.");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
EventUtils.synthesizeMouse(unpinButton, 10, 10, {}, window);
|
||||
yield promise;
|
||||
|
||||
@ -413,7 +415,7 @@ gTests.push({
|
||||
|
||||
let item = gPanelView._getItemForBookmarkId(2);
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item, 10, 10);
|
||||
yield promise;
|
||||
|
||||
@ -422,7 +424,7 @@ gTests.push({
|
||||
|
||||
ok(!pinButton.hidden, "Pin button is visible.");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
EventUtils.synthesizeMouse(pinButton, 10, 10, {}, window);
|
||||
yield promise;
|
||||
|
||||
@ -439,7 +441,7 @@ gTests.push({
|
||||
let item2 = gPanelView._getItemForBookmarkId(5);
|
||||
let item3 = gPanelView._getItemForBookmarkId(12);
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item1, 10, 10);
|
||||
sendContextMenuClickToElement(window, item2, 10, 10);
|
||||
sendContextMenuClickToElement(window, item3, 10, 10);
|
||||
@ -450,7 +452,7 @@ gTests.push({
|
||||
|
||||
ok(!pinButton.hidden, "pin button is visible.");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
EventUtils.synthesizeMouse(pinButton, 10, 10, {}, window);
|
||||
yield promise;
|
||||
|
||||
@ -481,7 +483,7 @@ gTests.push({
|
||||
|
||||
let item = gPanelView._getItemForBookmarkId(2);
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item, 10, 10);
|
||||
yield promise;
|
||||
|
||||
@ -499,8 +501,8 @@ gTests.push({
|
||||
ok(BookmarksTestHelper._nodes[2], "Item exists");
|
||||
ok(!restoreButton.hidden, "Restore button is visible.");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
Elements.appbar.dismiss();
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
Elements.contextappbar.dismiss();
|
||||
yield promise;
|
||||
|
||||
item = gPanelView._getItemForBookmarkId(2);
|
||||
@ -516,7 +518,7 @@ gTests.push({
|
||||
let item2 = gPanelView._getItemForBookmarkId(5);
|
||||
let item3 = gPanelView._getItemForBookmarkId(12);
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item1, 10, 10);
|
||||
sendContextMenuClickToElement(window, item2, 10, 10);
|
||||
sendContextMenuClickToElement(window, item3, 10, 10);
|
||||
@ -541,8 +543,8 @@ gTests.push({
|
||||
ok(BookmarksTestHelper._nodes[0] && BookmarksTestHelper._nodes[5] && BookmarksTestHelper._nodes[12],
|
||||
"Items not deleted yet");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend");
|
||||
Elements.appbar.dismiss();
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
Elements.contextappbar.dismiss();
|
||||
yield promise;
|
||||
|
||||
item1 = gPanelView._getItemForBookmarkId(0);
|
||||
|
@ -50,6 +50,8 @@ gTests.push({
|
||||
let span = win.document.getElementById("text1");
|
||||
win.getSelection().selectAllChildren(span);
|
||||
|
||||
yield waitForMs(0);
|
||||
|
||||
// invoke selection context menu
|
||||
let promise = waitForEvent(document, "popupshown");
|
||||
sendContextMenuClickToElement(win, span, 85, 10);
|
||||
@ -283,6 +285,7 @@ gTests.push({
|
||||
// context in empty input, no data on clipboard (??)
|
||||
|
||||
emptyClipboard();
|
||||
ContextUI.dismiss();
|
||||
|
||||
input = win.document.getElementById("text3-input");
|
||||
input.value = "";
|
||||
|
@ -144,13 +144,13 @@ gTests.push({
|
||||
|
||||
let item = gStartView._set.getItemsByUrl(uriFromIndex(2))[0];
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item, 10, 10);
|
||||
yield promise;
|
||||
|
||||
ok(!unpinButton.hidden, "Unpin button is visible.");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
unpinButton.click();
|
||||
yield promise;
|
||||
|
||||
@ -166,7 +166,7 @@ gTests.push({
|
||||
let item2 = gStartView._set.getItemsByUrl(uriFromIndex(5))[0];
|
||||
let item3 = gStartView._set.getItemsByUrl(uriFromIndex(12))[0];
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item1, 10, 10);
|
||||
sendContextMenuClickToElement(window, item2, 10, 10);
|
||||
sendContextMenuClickToElement(window, item3, 10, 10);
|
||||
@ -174,7 +174,7 @@ gTests.push({
|
||||
|
||||
ok(!unpinButton.hidden, "Unpin button is visible.");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
EventUtils.synthesizeMouse(unpinButton, 10, 10, {}, window);
|
||||
yield promise;
|
||||
|
||||
@ -201,7 +201,7 @@ gTests.push({
|
||||
let item = gStartView._set.getItemsByUrl(uriFromIndex(2))[0];
|
||||
let initialLocation = gStartView._set.getIndexOfItem(item);
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item, 10, 10);
|
||||
yield promise;
|
||||
|
||||
@ -218,7 +218,7 @@ gTests.push({
|
||||
ok(!restoreButton.hidden, "Restore button is visible.");
|
||||
ok(gStartView._set.itemCount === gStartView._limit, "Grid repopulated");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
EventUtils.synthesizeMouse(restoreButton, 10, 10, {}, window);
|
||||
yield promise;
|
||||
|
||||
@ -231,7 +231,7 @@ gTests.push({
|
||||
|
||||
let item = gStartView._set.getItemsByUrl(uriFromIndex(2))[0];
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item, 10, 10);
|
||||
yield promise;
|
||||
|
||||
@ -249,8 +249,8 @@ gTests.push({
|
||||
ok(HistoryTestHelper._nodes[uriFromIndex(2)], "Item not deleted yet");
|
||||
ok(!restoreButton.hidden, "Restore button is visible.");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
Elements.appbar.dismiss();
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
Elements.contextappbar.dismiss();
|
||||
yield promise;
|
||||
|
||||
item = gStartView._set.getItemsByUrl(uriFromIndex(2))[0];
|
||||
@ -269,7 +269,7 @@ gTests.push({
|
||||
let initialLocation2 = gStartView._set.getIndexOfItem(item2);
|
||||
let initialLocation3 = gStartView._set.getIndexOfItem(item3);
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item1, 10, 10);
|
||||
sendContextMenuClickToElement(window, item2, 10, 10);
|
||||
sendContextMenuClickToElement(window, item3, 10, 10);
|
||||
@ -293,7 +293,7 @@ gTests.push({
|
||||
ok(!restoreButton.hidden, "Restore button is visible.");
|
||||
ok(gStartView._set.itemCount === gStartView._limit - 1, "Grid repopulated");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
EventUtils.synthesizeMouse(restoreButton, 10, 10, {}, window);
|
||||
yield promise;
|
||||
|
||||
@ -313,7 +313,7 @@ gTests.push({
|
||||
let item2 = gStartView._set.getItemsByUrl(uriFromIndex(5))[0];
|
||||
let item3 = gStartView._set.getItemsByUrl(uriFromIndex(12))[0];
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item1, 10, 10);
|
||||
sendContextMenuClickToElement(window, item2, 10, 10);
|
||||
sendContextMenuClickToElement(window, item3, 10, 10);
|
||||
@ -337,8 +337,8 @@ gTests.push({
|
||||
ok(!restoreButton.hidden, "Restore button is visible.");
|
||||
ok(gStartView._set.itemCount === gStartView._limit - 1, "Grid repopulated");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
Elements.appbar.dismiss();
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
Elements.contextappbar.dismiss();
|
||||
yield promise;
|
||||
|
||||
item1 = gStartView._set.getItemsByUrl(uriFromIndex(0))[0];
|
||||
@ -366,7 +366,7 @@ gTests.push({
|
||||
|
||||
let item = gPanelView._set.getItemsByUrl(uriFromIndex(2))[0];
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item, 10, 10);
|
||||
yield promise;
|
||||
|
||||
@ -374,7 +374,7 @@ gTests.push({
|
||||
|
||||
ok(!unpinButton.hidden, "Unpin button is visible.");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
EventUtils.synthesizeMouse(unpinButton, 10, 10, {}, window);
|
||||
yield promise;
|
||||
|
||||
@ -391,7 +391,7 @@ gTests.push({
|
||||
let item2 = gPanelView._set.getItemsByUrl(uriFromIndex(5))[0];
|
||||
let item3 = gPanelView._set.getItemsByUrl(uriFromIndex(12))[0];
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item1, 10, 10);
|
||||
sendContextMenuClickToElement(window, item2, 10, 10);
|
||||
sendContextMenuClickToElement(window, item3, 10, 10);
|
||||
@ -399,7 +399,7 @@ gTests.push({
|
||||
|
||||
ok(!unpinButton.hidden, "Unpin button is visible.");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
EventUtils.synthesizeMouse(unpinButton, 10, 10, {}, window);
|
||||
yield promise;
|
||||
|
||||
@ -418,7 +418,7 @@ gTests.push({
|
||||
|
||||
let item = gPanelView._set.getItemsByUrl(uriFromIndex(2))[0];
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item, 10, 10);
|
||||
yield promise;
|
||||
|
||||
@ -427,7 +427,7 @@ gTests.push({
|
||||
|
||||
ok(!pinButton.hidden, "Pin button is visible.");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
EventUtils.synthesizeMouse(pinButton, 10, 10, {}, window);
|
||||
yield promise;
|
||||
|
||||
@ -444,7 +444,7 @@ gTests.push({
|
||||
let item2 = gPanelView._set.getItemsByUrl(uriFromIndex(5))[0];
|
||||
let item3 = gPanelView._set.getItemsByUrl(uriFromIndex(12))[0];
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item1, 10, 10);
|
||||
sendContextMenuClickToElement(window, item2, 10, 10);
|
||||
sendContextMenuClickToElement(window, item3, 10, 10);
|
||||
@ -455,7 +455,7 @@ gTests.push({
|
||||
|
||||
ok(!pinButton.hidden, "pin button is visible.");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
EventUtils.synthesizeMouse(pinButton, 10, 10, {}, window);
|
||||
yield promise;
|
||||
|
||||
@ -486,7 +486,7 @@ gTests.push({
|
||||
|
||||
let item = gPanelView._set.getItemsByUrl(uriFromIndex(2))[0];
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item, 10, 10);
|
||||
yield promise;
|
||||
|
||||
@ -504,8 +504,8 @@ gTests.push({
|
||||
ok(HistoryTestHelper._nodes[uriFromIndex(2)], "Item exists");
|
||||
ok(!restoreButton.hidden, "Restore button is visible.");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
Elements.appbar.dismiss();
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
Elements.contextappbar.dismiss();
|
||||
yield promise;
|
||||
|
||||
item = gPanelView._set.getItemsByUrl(uriFromIndex(2))[0];
|
||||
@ -521,7 +521,7 @@ gTests.push({
|
||||
let item2 = gPanelView._set.getItemsByUrl(uriFromIndex(5))[0];
|
||||
let item3 = gPanelView._set.getItemsByUrl(uriFromIndex(12))[0];
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
sendContextMenuClickToElement(window, item1, 10, 10);
|
||||
sendContextMenuClickToElement(window, item2, 10, 10);
|
||||
sendContextMenuClickToElement(window, item3, 10, 10);
|
||||
@ -546,8 +546,8 @@ gTests.push({
|
||||
ok(HistoryTestHelper._nodes[uriFromIndex(0)] && HistoryTestHelper._nodes[uriFromIndex(5)] && HistoryTestHelper._nodes[uriFromIndex(12)],
|
||||
"Items not deleted yet");
|
||||
|
||||
let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
|
||||
Elements.appbar.dismiss();
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
Elements.contextappbar.dismiss();
|
||||
yield promise;
|
||||
|
||||
item1 = gPanelView._set.getItemsByUrl(uriFromIndex(0))[0];
|
||||
|
@ -1,12 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
#text { position: absolute; left: 1em; bottom: 1em; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="margin: 0; padding: 0; max-width:500px;">
|
||||
<div style="margin: 0; padding: 0; max-width:31.25em; font-size: 95%;">
|
||||
There was nothing so VERY remarkable in that; nor did Alice think it so VERY much out of
|
||||
the way to hear the Rabbit say to itself, `Oh dear! Oh dear! I shall be late!' (when she
|
||||
thought it over afterwards, it occurred to her that she ought to have wondered at this,
|
||||
@ -61,6 +58,42 @@ found herself falling down a very deep well.
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -4,7 +4,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<iframe id="frame1" width="800" height="600" src="res/textblock01.html"></iframe>
|
||||
<iframe id="frame1" style="width:50em; font-size: 95%;" height="600" src="res/textblock01.html"></iframe>
|
||||
<br />
|
||||
<br />
|
||||
Hello there. <a id="rlink1" href="#hello">Hi!</a>
|
||||
|
@ -55,7 +55,7 @@ gTests.push({
|
||||
run: function test() {
|
||||
gFrame.focus();
|
||||
|
||||
sendContextMenuClick(130, 95);
|
||||
sendContextMenuClick(165, 35);
|
||||
|
||||
yield waitForCondition(function () {
|
||||
return SelectionHelperUI.isSelectionUIVisible;
|
||||
@ -88,7 +88,7 @@ gTests.push({
|
||||
let ypos = SelectionHelperUI.endMark.yPos + kMarkerOffsetY;
|
||||
|
||||
let touchdrag = new TouchDragAndHold();
|
||||
yield touchdrag.start(gWindow, SelectionHelperUI.endMark.xPos, ypos, 600, ypos);
|
||||
yield touchdrag.start(gWindow, SelectionHelperUI.endMark.xPos, ypos, 640, ypos);
|
||||
touchdrag.end();
|
||||
|
||||
yield waitForCondition(function () {
|
||||
@ -101,7 +101,7 @@ gTests.push({
|
||||
"selection test");
|
||||
|
||||
touchdrag = new TouchDragAndHold();
|
||||
yield touchdrag.start(gWindow, SelectionHelperUI.endMark.xPos, ypos, 300, ypos);
|
||||
yield touchdrag.start(gWindow, SelectionHelperUI.endMark.xPos, ypos, 320, ypos);
|
||||
touchdrag.end();
|
||||
|
||||
yield waitForCondition(function () {
|
||||
@ -124,7 +124,7 @@ gTests.push({
|
||||
gFrame.contentDocument.defaultView.scrollBy(0, 200);
|
||||
yield scrollPromise;
|
||||
|
||||
sendContextMenuClick(527, 188);
|
||||
sendContextMenuClick(30, 240);
|
||||
|
||||
yield waitForCondition(function () {
|
||||
return SelectionHelperUI.isSelectionUIVisible;
|
||||
@ -186,7 +186,7 @@ gTests.push({
|
||||
yield scrollPromise;
|
||||
|
||||
InputSourceHelper.isPrecise = false;
|
||||
sendContextMenuClick(114, 91);
|
||||
sendContextMenuClick(114, 130);
|
||||
|
||||
yield waitForCondition(function () {
|
||||
return SelectionHelperUI.isSelectionUIVisible;
|
||||
|
@ -4,7 +4,7 @@
|
||||
<style>
|
||||
</style>
|
||||
</head>
|
||||
<body style="margin: 5px 5px 5px 85px;">
|
||||
<body style="margin: 5px 5px 5px 85px; font-size: 95%">
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
|
@ -65,7 +65,7 @@ gTests.push({
|
||||
gInput.selectionStart = gInput.selectionEnd = 0;
|
||||
|
||||
let promise = waitForEvent(document, "popupshown");
|
||||
sendContextMenuClick(232, 583);
|
||||
sendContextMenuClickToElement(gWindow, gFrame, 135, 10);
|
||||
yield promise;
|
||||
|
||||
checkContextUIMenuItemVisibility(["context-select",
|
||||
@ -84,8 +84,9 @@ gTests.push({
|
||||
|
||||
is(getTrimmedSelection(gInput).toString(), "straight", "selection test");
|
||||
|
||||
checkMonoclePositionRange("start", 210, 220, 600, 605);
|
||||
checkMonoclePositionRange("end", 250, 260, 600, 605);
|
||||
let rect = gFrame.getBoundingClientRect();
|
||||
checkMonoclePositionRange("start", rect.left + 125, rect.left + 135, rect.top + 20, rect.top + 30);
|
||||
checkMonoclePositionRange("end", rect.left + 165, rect.left + 175, rect.top + 20, rect.top + 30);
|
||||
},
|
||||
});
|
||||
|
||||
@ -98,7 +99,7 @@ gTests.push({
|
||||
gInput.selectionStart = gInput.selectionEnd = 0;
|
||||
|
||||
let promise = waitForEvent(document, "popupshown");
|
||||
sendContextMenuClick(232, 583);
|
||||
sendContextMenuClickToElement(gWindow, gFrame, 135, 10);
|
||||
yield promise;
|
||||
|
||||
checkContextUIMenuItemVisibility(["context-select",
|
||||
|
@ -4,7 +4,7 @@
|
||||
<style>
|
||||
</style>
|
||||
</head>
|
||||
<body style="margin: 5px 5px 5px 85px;">
|
||||
<body style="margin: 5px 5px 5px 85px; font-size: 95%">
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
|
@ -64,7 +64,7 @@ gTests.push({
|
||||
gTextArea.selectionStart = gTextArea.selectionEnd = 0;
|
||||
|
||||
let promise = waitForEvent(document, "popupshown");
|
||||
sendContextMenuClick(275, 663);
|
||||
sendContextMenuClickToElement(gWindow, gFrame, 195, 80);
|
||||
yield promise;
|
||||
|
||||
checkContextUIMenuItemVisibility(["context-select",
|
||||
@ -83,8 +83,8 @@ gTests.push({
|
||||
|
||||
is(getTrimmedSelection(gTextArea).toString(), "wondered", "selection test");
|
||||
|
||||
checkMonoclePositionRange("start", 260, 275, 675, 685);
|
||||
checkMonoclePositionRange("end", 320, 335, 675, 685);
|
||||
checkMonoclePositionRange("start", 260, 280, 675, 690);
|
||||
checkMonoclePositionRange("end", 320, 340, 675, 690);
|
||||
},
|
||||
});
|
||||
|
||||
@ -97,7 +97,7 @@ gTests.push({
|
||||
gTextArea.selectionStart = gTextArea.selectionEnd = 0;
|
||||
|
||||
let promise = waitForEvent(document, "popupshown");
|
||||
sendContextMenuClick(275, 663);
|
||||
sendContextMenuClickToElement(gWindow, gFrame, 195, 80);
|
||||
yield promise;
|
||||
|
||||
checkContextUIMenuItemVisibility(["context-select",
|
||||
@ -178,7 +178,7 @@ gTests.push({
|
||||
yield scrollPromise;
|
||||
|
||||
let promise = waitForEvent(document, "popupshown");
|
||||
sendContextMenuClick(275, 463);
|
||||
sendContextMenuClickToElement(gWindow, gFrame, 195, 80);
|
||||
yield promise;
|
||||
|
||||
checkContextUIMenuItemVisibility(["context-select",
|
||||
|
@ -185,7 +185,7 @@ gTests.push({
|
||||
// left and up - selection should shrink
|
||||
let xpos = SelectionHelperUI.endMark.xPos;
|
||||
let ypos = SelectionHelperUI.endMark.yPos + 10;
|
||||
yield touchdrag.start(gWindow, xpos, ypos, 105, 25);
|
||||
yield touchdrag.start(gWindow, xpos, ypos, 110, 25);
|
||||
yield waitForCondition(function () {
|
||||
return getTrimmedSelection(gInput).toString() ==
|
||||
"straight on like a tunnel for";
|
||||
|
@ -156,15 +156,23 @@ function clearSelection(aTarget) {
|
||||
function hideContextUI()
|
||||
{
|
||||
purgeEventQueue();
|
||||
if (ContextUI.isVisible) {
|
||||
let promise = waitForEvent(Elements.tray, "transitionend", null, Elements.tray);
|
||||
if (ContextUI.dismiss())
|
||||
{
|
||||
info("ContextUI dismissed, waiting...");
|
||||
return promise;
|
||||
|
||||
return Task.spawn(function() {
|
||||
if (ContextUI.isExpanded) {
|
||||
let promise = waitForEvent(Elements.tray, "transitionend", null, Elements.tray);
|
||||
if (ContextUI.dismiss())
|
||||
{
|
||||
info("ContextUI dismissed, waiting...");
|
||||
yield promise;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Elements.contextappbar.isShowing) {
|
||||
let promise = waitForEvent(Elements.contextappbar, "transitionend", null, Elements.contextappbar);
|
||||
Elements.contextappbar.dismiss();
|
||||
yield promise;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showNavBar()
|
||||
@ -253,9 +261,10 @@ function cleanUpOpenedTabs() {
|
||||
function waitForEvent(aSubject, aEventName, aTimeoutMs, aTarget) {
|
||||
let eventDeferred = Promise.defer();
|
||||
let timeoutMs = aTimeoutMs || kDefaultWait;
|
||||
let stack = new Error().stack;
|
||||
let timerID = setTimeout(function wfe_canceller() {
|
||||
aSubject.removeEventListener(aEventName, onEvent);
|
||||
eventDeferred.reject( new Error(aEventName+" event timeout") );
|
||||
eventDeferred.reject( new Error(aEventName+" event timeout at " + stack) );
|
||||
}, timeoutMs);
|
||||
|
||||
function onEvent(aEvent) {
|
||||
|
@ -377,12 +377,12 @@ documenttab[selected] .documenttab-selection {
|
||||
list-style-image: url(chrome://browser/skin/images/identity-icons-generic.png);
|
||||
}
|
||||
|
||||
#identity-box[mode="verifiedDomain"] > #identity-icon[pageproxystate="valid"] {
|
||||
list-style-image: url(chrome://browser/skin/images/identity-icons-https.png);
|
||||
#identity-box-inner.verifiedDomain > #identity-icon {
|
||||
list-style-image: url(chrome://browser/skin/images/locked-hdpi.png);
|
||||
}
|
||||
|
||||
#identity-box[mode="verifiedIdentity"] > #identity-icon[pageproxystate="valid"] {
|
||||
list-style-image: url(chrome://browser/skin/identity-icons-https-ev.png);
|
||||
|
||||
#identity-box-inner.verifiedIdentity > #identity-icon {
|
||||
list-style-image: url(chrome://browser/skin/images/locked-hdpi.png);
|
||||
}
|
||||
|
||||
/* Main URL textbox */
|
||||
@ -417,7 +417,7 @@ appbar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
transform: translateY(@toolbar_height@);
|
||||
transform: translateY(100%);
|
||||
transition: transform @metro_animation_duration@ @metro_animation_easing@;
|
||||
font-size: 0;
|
||||
}
|
||||
@ -444,18 +444,18 @@ appbar > toolbar > toolbarbutton[disabled] {
|
||||
}
|
||||
|
||||
#appbar[startpage],
|
||||
#appbar[visible] {
|
||||
appbar[visible] {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
#appbar > toolbar > toolbarbutton {
|
||||
appbar > toolbar > toolbarbutton {
|
||||
list-style-image: url(chrome://browser/skin/images/appbar-icons.png);
|
||||
-moz-image-region: rect(0px, 200px, 40px, 160px); /* Gear icon is default. */
|
||||
}
|
||||
#appbar > toolbar > toolbarbutton:hover {
|
||||
appbar > toolbar > toolbarbutton:hover {
|
||||
-moz-image-region: rect(40px, 200px, 80px, 160px);
|
||||
}
|
||||
#appbar > toolbar > toolbarbutton:active {
|
||||
appbar > toolbar > toolbarbutton:active {
|
||||
-moz-image-region: rect(80px, 200px, 120px, 160px);
|
||||
}
|
||||
|
||||
@ -525,12 +525,6 @@ appbar > toolbar > toolbarbutton[disabled] {
|
||||
-moz-image-region: rect(80px, 360px, 120px, 320px) !important;
|
||||
}
|
||||
|
||||
/* Tile-selection-Specific */
|
||||
#appbar[contextual] > #toolbar,
|
||||
#appbar:not([contextual]) > #contextualactions-tray {
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
#contextualactions-tray {
|
||||
background-color: @metro_orange@;
|
||||
}
|
||||
|
@ -248,6 +248,8 @@
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Security styles */
|
||||
|
||||
.webconsole-msg-security > .webconsole-msg-icon-container {
|
||||
-moz-border-start: solid red 6px;
|
||||
}
|
||||
@ -256,3 +258,11 @@
|
||||
background-image: linear-gradient(#FF3030, #FF7D7D);
|
||||
border-color: #D12C2C;
|
||||
}
|
||||
|
||||
.webconsole-msg-security.webconsole-msg-error {
|
||||
-moz-image-region: rect(32px, 16px, 40px, 8px);
|
||||
}
|
||||
|
||||
.webconsole-msg-security.webconsole-msg-warn {
|
||||
-moz-image-region: rect(32px, 24px, 40px, 16px);
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.9 KiB |
@ -252,6 +252,8 @@
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Security styles */
|
||||
|
||||
.webconsole-msg-security > .webconsole-msg-icon-container {
|
||||
-moz-border-start: solid red 6px;
|
||||
}
|
||||
@ -260,3 +262,11 @@
|
||||
background-image: linear-gradient(#FF3030, #FF7D7D);
|
||||
border-color: #D12C2C;
|
||||
}
|
||||
|
||||
.webconsole-msg-security.webconsole-msg-error {
|
||||
-moz-image-region: rect(32px, 16px, 40px, 8px);
|
||||
}
|
||||
|
||||
.webconsole-msg-security.webconsole-msg-warn {
|
||||
-moz-image-region: rect(32px, 24px, 40px, 16px);
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.9 KiB |
@ -257,6 +257,8 @@
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Security styles */
|
||||
|
||||
.webconsole-msg-security > .webconsole-msg-icon-container {
|
||||
-moz-border-start: solid red 6px;
|
||||
}
|
||||
@ -265,3 +267,11 @@
|
||||
background-image: linear-gradient(#FF3030, #FF7D7D);
|
||||
border-color: #D12C2C;
|
||||
}
|
||||
|
||||
.webconsole-msg-security.webconsole-msg-error {
|
||||
-moz-image-region: rect(32px, 16px, 40px, 8px);
|
||||
}
|
||||
|
||||
.webconsole-msg-security.webconsole-msg-warn {
|
||||
-moz-image-region: rect(32px, 24px, 40px, 16px);
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.9 KiB |
@ -116,7 +116,33 @@ class RemoteAutomation(Automation):
|
||||
break
|
||||
return found_exception
|
||||
|
||||
def deleteANRs(self):
|
||||
# delete ANR traces.txt file; usually need root permissions
|
||||
traces = "/data/anr/traces.txt"
|
||||
try:
|
||||
self._devicemanager.shellCheckOutput(['rm', traces], root=True)
|
||||
except DMError:
|
||||
print "Error deleting %s" % traces
|
||||
pass
|
||||
|
||||
def checkForANRs(self):
|
||||
traces = "/data/anr/traces.txt"
|
||||
if self._devicemanager.fileExists(traces):
|
||||
try:
|
||||
t = self._devicemanager.pullFile(traces)
|
||||
print "Contents of %s:" % traces
|
||||
print t
|
||||
# Once reported, delete traces
|
||||
self.deleteANRs()
|
||||
except DMError:
|
||||
print "Error pulling %s" % traces
|
||||
pass
|
||||
else:
|
||||
print "%s not found" % traces
|
||||
|
||||
def checkForCrashes(self, directory, symbolsPath):
|
||||
self.checkForANRs()
|
||||
|
||||
logcat = self._devicemanager.getLogcat(filterOutRegexps=fennecLogcatFilters)
|
||||
javaException = self.checkForJavaException(logcat)
|
||||
if javaException:
|
||||
|
@ -1183,18 +1183,12 @@ nsDocumentEncoder::EncodeToStream(nsIOutputStream* aStream)
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
bool chromeCaller = nsContentUtils::IsCallerChrome();
|
||||
if (chromeCaller) {
|
||||
mStream = aStream;
|
||||
}
|
||||
mStream = aStream;
|
||||
|
||||
nsAutoString buf;
|
||||
|
||||
rv = EncodeToString(buf);
|
||||
|
||||
if (!chromeCaller) {
|
||||
mStream = aStream;
|
||||
}
|
||||
|
||||
// Force a flush of the last chunk of data.
|
||||
FlushText(buf, true);
|
||||
|
||||
|
@ -804,6 +804,10 @@ nsObjectLoadingContent::InstantiatePluginInstance(bool aIsLoading)
|
||||
nsIFrame* frame = thisContent->GetPrimaryFrame();
|
||||
if (frame && mInstanceOwner) {
|
||||
mInstanceOwner->SetFrame(static_cast<nsObjectFrame*>(frame));
|
||||
|
||||
// Bug 870216 - Adobe Reader renders with incorrect dimensions until it gets
|
||||
// a second SetWindow call. This is otherwise redundant.
|
||||
mInstanceOwner->CallSetWindow();
|
||||
}
|
||||
|
||||
// Set up scripting interfaces.
|
||||
|
@ -2318,12 +2318,8 @@ GetRequestBody(nsIDOMDocument* aDoc, nsIInputStream** aResult,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Make sure to use the encoding we'll send
|
||||
{
|
||||
nsCxPusher pusher;
|
||||
pusher.PushNull();
|
||||
rv = serializer->SerializeToStream(aDoc, output, aCharset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
rv = serializer->SerializeToStream(aDoc, output, aCharset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
output->Close();
|
||||
|
||||
|
@ -1199,10 +1199,9 @@ ObjectToMatrix(JSContext* cx, JS::Handle<JSObject*> obj, Matrix& matrix,
|
||||
|
||||
void
|
||||
CanvasRenderingContext2D::SetMozCurrentTransform(JSContext* cx,
|
||||
JSObject& currentTransform_,
|
||||
JS::Handle<JSObject*> currentTransform,
|
||||
ErrorResult& error)
|
||||
{
|
||||
JS::Rooted<JSObject*> currentTransform(cx, ¤tTransform_);
|
||||
EnsureTarget();
|
||||
if (!IsTargetValid()) {
|
||||
error.Throw(NS_ERROR_FAILURE);
|
||||
@ -1224,10 +1223,9 @@ CanvasRenderingContext2D::GetMozCurrentTransform(JSContext* cx,
|
||||
|
||||
void
|
||||
CanvasRenderingContext2D::SetMozCurrentTransformInverse(JSContext* cx,
|
||||
JSObject& currentTransform_,
|
||||
JS::Handle<JSObject*> currentTransform,
|
||||
ErrorResult& error)
|
||||
{
|
||||
JS::Rooted<JSObject*> currentTransform(cx, ¤tTransform_);
|
||||
EnsureTarget();
|
||||
if (!IsTargetValid()) {
|
||||
error.Throw(NS_ERROR_FAILURE);
|
||||
|
@ -307,11 +307,13 @@ public:
|
||||
|
||||
JSObject* GetMozCurrentTransform(JSContext* cx,
|
||||
mozilla::ErrorResult& error) const;
|
||||
void SetMozCurrentTransform(JSContext* cx, JSObject& currentTransform,
|
||||
void SetMozCurrentTransform(JSContext* cx,
|
||||
JS::Handle<JSObject*> currentTransform,
|
||||
mozilla::ErrorResult& error);
|
||||
JSObject* GetMozCurrentTransformInverse(JSContext* cx,
|
||||
mozilla::ErrorResult& error) const;
|
||||
void SetMozCurrentTransformInverse(JSContext* cx, JSObject& currentTransform,
|
||||
void SetMozCurrentTransformInverse(JSContext* cx,
|
||||
JS::Handle<JSObject*> currentTransform,
|
||||
mozilla::ErrorResult& error);
|
||||
void GetFillRule(nsAString& fillRule);
|
||||
void SetFillRule(const nsAString& fillRule);
|
||||
@ -472,7 +474,7 @@ protected:
|
||||
|
||||
// Some helpers. Doesn't modify a color on failure.
|
||||
void SetStyleFromJSValue(JSContext* cx, JS::Handle<JS::Value> value,
|
||||
Style whichStyle);
|
||||
Style whichStyle);
|
||||
void SetStyleFromString(const nsAString& str, Style whichStyle);
|
||||
|
||||
void SetStyleFromGradient(CanvasGradient *gradient, Style whichStyle)
|
||||
|
@ -196,6 +196,8 @@ WebGLContext::WebGLContext()
|
||||
mMinInUseAttribArrayLength = 0;
|
||||
|
||||
mIsScreenCleared = false;
|
||||
|
||||
mDisableFragHighP = false;
|
||||
}
|
||||
|
||||
WebGLContext::~WebGLContext()
|
||||
|
@ -857,6 +857,7 @@ protected:
|
||||
bool mCanLoseContextInForeground;
|
||||
bool mShouldPresent;
|
||||
bool mIsScreenCleared;
|
||||
bool mDisableFragHighP;
|
||||
|
||||
template<typename WebGLObjectType>
|
||||
void DeleteWebGLObjectsArray(nsTArray<WebGLObjectType>& array);
|
||||
|
@ -4255,9 +4255,14 @@ WebGLContext::CompileShader(WebGLShader *shader)
|
||||
resources.MaxTextureImageUnits = mGLMaxTextureImageUnits;
|
||||
resources.MaxFragmentUniformVectors = mGLMaxFragmentUniformVectors;
|
||||
resources.MaxDrawBuffers = 1;
|
||||
|
||||
if (IsExtensionEnabled(OES_standard_derivatives))
|
||||
resources.OES_standard_derivatives = 1;
|
||||
|
||||
// Tell ANGLE to allow highp in frag shaders. (unless disabled)
|
||||
// If underlying GLES doesn't have highp in frag shaders, it should complain anyways.
|
||||
resources.FragmentPrecisionHigh = mDisableFragHighP ? 0 : 1;
|
||||
|
||||
// We're storing an actual instance of StripComments because, if we don't, the
|
||||
// cleanSource nsAString instance will be destroyed before the reference is
|
||||
// actually used.
|
||||
@ -4677,9 +4682,19 @@ WebGLContext::GetShaderPrecisionFormat(WebGLenum shadertype, WebGLenum precision
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
GLint range[2], precision;
|
||||
gl->fGetShaderPrecisionFormat(shadertype, precisiontype, range, &precision);
|
||||
|
||||
if (mDisableFragHighP &&
|
||||
shadertype == LOCAL_GL_FRAGMENT_SHADER &&
|
||||
(precisiontype == LOCAL_GL_HIGH_FLOAT ||
|
||||
precisiontype == LOCAL_GL_HIGH_INT))
|
||||
{
|
||||
precision = 0;
|
||||
range[0] = 0;
|
||||
range[1] = 0;
|
||||
} else {
|
||||
gl->fGetShaderPrecisionFormat(shadertype, precisiontype, range, &precision);
|
||||
}
|
||||
|
||||
nsRefPtr<WebGLShaderPrecisionFormat> retShaderPrecisionFormat
|
||||
= new WebGLShaderPrecisionFormat(this, range[0], range[1], precision);
|
||||
|
@ -878,6 +878,10 @@ WebGLContext::InitAndValidateGL()
|
||||
mLoseContextOnHeapMinimize = Preferences::GetBool("webgl.lose-context-on-heap-minimize", false);
|
||||
mCanLoseContextInForeground = Preferences::GetBool("webgl.can-lose-context-in-foreground", true);
|
||||
|
||||
if (MinCapabilityMode()) {
|
||||
mDisableFragHighP = true;
|
||||
}
|
||||
|
||||
mActiveTexture = 0;
|
||||
mWebGLError = LOCAL_GL_NO_ERROR;
|
||||
|
||||
|
@ -92,7 +92,8 @@ public:
|
||||
}
|
||||
already_AddRefed<nsISupports>
|
||||
GetContext(JSContext* aCx, const nsAString& aContextId,
|
||||
const Optional<LazyRootedValue>& aContextOptions, ErrorResult& aRv)
|
||||
const Optional<JS::Handle<JS::Value> >& aContextOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
JS::Value contextOptions = aContextOptions.WasPassed()
|
||||
? aContextOptions.Value()
|
||||
@ -102,8 +103,8 @@ public:
|
||||
return context.forget();
|
||||
}
|
||||
void ToDataURL(JSContext* aCx, const nsAString& aType,
|
||||
const Optional<LazyRootedValue>& aParams, nsAString& aDataURL,
|
||||
ErrorResult& aRv)
|
||||
const Optional<JS::Handle<JS::Value> >& aParams,
|
||||
nsAString& aDataURL, ErrorResult& aRv)
|
||||
{
|
||||
JS::Value params = aParams.WasPassed()
|
||||
? aParams.Value()
|
||||
|
@ -233,9 +233,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_ADDREF_INHERITED(nsHTMLDocument, nsDocument)
|
||||
NS_IMPL_RELEASE_INHERITED(nsHTMLDocument, nsDocument)
|
||||
|
||||
|
||||
DOMCI_NODE_DATA(HTMLDocument, nsHTMLDocument)
|
||||
|
||||
// QueryInterface implementation for nsHTMLDocument
|
||||
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLDocument)
|
||||
NS_DOCUMENT_INTERFACE_TABLE_BEGIN(nsHTMLDocument)
|
||||
@ -243,7 +240,6 @@ NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLDocument)
|
||||
NS_INTERFACE_TABLE_ENTRY(nsHTMLDocument, nsIDOMHTMLDocument)
|
||||
NS_OFFSET_AND_INTERFACE_TABLE_END
|
||||
NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(HTMLDocument)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDocument)
|
||||
|
||||
JSObject*
|
||||
|
@ -167,8 +167,6 @@ public:
|
||||
return nsDocument::GetElementById(aElementId);
|
||||
}
|
||||
|
||||
virtual nsXPCClassInfo* GetClassInfo();
|
||||
|
||||
virtual void DocSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const;
|
||||
// DocSizeOfIncludingThis is inherited from nsIDocument.
|
||||
|
||||
|
@ -23,8 +23,7 @@ class SVGIRect : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
SVGIRect(nsIContent* aParent)
|
||||
: mParent(aParent)
|
||||
SVGIRect()
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
@ -38,10 +37,7 @@ public:
|
||||
return SVGRectBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
nsIContent* GetParentObject() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
virtual nsIContent* GetParentObject() const = 0;
|
||||
|
||||
virtual float X() const = 0;
|
||||
|
||||
@ -58,9 +54,6 @@ public:
|
||||
virtual float Height() const = 0;
|
||||
|
||||
virtual void SetHeight(float aHeight, ErrorResult& aRv) = 0;
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIContent> mParent;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -17,17 +17,20 @@ namespace dom {
|
||||
// implementation:
|
||||
|
||||
SVGRect::SVGRect(nsIContent* aParent, float x, float y, float w, float h)
|
||||
: SVGIRect(aParent), mX(x), mY(y), mWidth(w), mHeight(h)
|
||||
: SVGIRect(), mParent(aParent), mX(x), mY(y), mWidth(w), mHeight(h)
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsISupports methods:
|
||||
|
||||
NS_IMPL_ADDREF(SVGRect)
|
||||
NS_IMPL_RELEASE(SVGRect)
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(SVGRect, mParent)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(SVGRect)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(SVGRect)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(SVGRect)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SVGRect)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
|
@ -22,8 +22,8 @@ public:
|
||||
SVGRect(nsIContent* aParent, float x=0.0f, float y=0.0f, float w=0.0f,
|
||||
float h=0.0f);
|
||||
|
||||
// nsISupports interface:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(SVGRect)
|
||||
|
||||
// WebIDL
|
||||
virtual float X() const MOZ_OVERRIDE MOZ_FINAL
|
||||
@ -66,7 +66,13 @@ public:
|
||||
mHeight = aHeight;
|
||||
}
|
||||
|
||||
virtual nsIContent* GetParentObject() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIContent> mParent;
|
||||
float mX, mY, mWidth, mHeight;
|
||||
};
|
||||
|
||||
|
@ -34,8 +34,8 @@ nsSVGViewBoxRect::operator==(const nsSVGViewBoxRect& aOther) const
|
||||
|
||||
/* Cycle collection macros for nsSVGViewBox */
|
||||
|
||||
NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGViewBox::DOMBaseVal, mSVGElement)
|
||||
NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGViewBox::DOMAnimVal, mSVGElement)
|
||||
NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(nsSVGViewBox::DOMBaseVal, mSVGElement)
|
||||
NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(nsSVGViewBox::DOMAnimVal, mSVGElement)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGViewBox::DOMBaseVal)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGViewBox::DOMBaseVal)
|
||||
@ -44,10 +44,12 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGViewBox::DOMAnimVal)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGViewBox::DOMAnimVal)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGViewBox::DOMBaseVal)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGViewBox::DOMAnimVal)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
|
@ -99,10 +99,10 @@ public:
|
||||
struct DOMBaseVal MOZ_FINAL : public mozilla::dom::SVGIRect
|
||||
{
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(DOMBaseVal)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMBaseVal)
|
||||
|
||||
DOMBaseVal(nsSVGViewBox *aVal, nsSVGElement *aSVGElement)
|
||||
: mozilla::dom::SVGIRect(aSVGElement)
|
||||
: mozilla::dom::SVGIRect()
|
||||
, mVal(aVal)
|
||||
, mSVGElement(aSVGElement)
|
||||
{}
|
||||
@ -135,15 +135,20 @@ public:
|
||||
void SetY(float aY, mozilla::ErrorResult& aRv) MOZ_FINAL;
|
||||
void SetWidth(float aWidth, mozilla::ErrorResult& aRv) MOZ_FINAL;
|
||||
void SetHeight(float aHeight, mozilla::ErrorResult& aRv) MOZ_FINAL;
|
||||
|
||||
virtual nsIContent* GetParentObject() const
|
||||
{
|
||||
return mSVGElement;
|
||||
}
|
||||
};
|
||||
|
||||
struct DOMAnimVal MOZ_FINAL : public mozilla::dom::SVGIRect
|
||||
{
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(DOMAnimVal)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMAnimVal)
|
||||
|
||||
DOMAnimVal(nsSVGViewBox *aVal, nsSVGElement *aSVGElement)
|
||||
: mozilla::dom::SVGIRect(aSVGElement)
|
||||
: mozilla::dom::SVGIRect()
|
||||
, mVal(aVal)
|
||||
, mSVGElement(aSVGElement)
|
||||
{}
|
||||
@ -197,6 +202,11 @@ public:
|
||||
{
|
||||
aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
|
||||
}
|
||||
|
||||
virtual nsIContent* GetParentObject() const
|
||||
{
|
||||
return mSVGElement;
|
||||
}
|
||||
};
|
||||
|
||||
struct SMILViewBox : public nsISMILAttr
|
||||
|
@ -43,6 +43,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=821850
|
||||
is(bound.primitiveField, undefined, "Xrays don't show fields");
|
||||
is(bound.wrappedJSObject.primitiveField, 2, "Waiving Xrays show fields");
|
||||
|
||||
// Check that here document.QueryInterface works
|
||||
ok("QueryInterface" in document,
|
||||
"Should have a document.QueryInterface here");
|
||||
is(document.QueryInterface(Components.interfaces.nsIDOMDocument),
|
||||
document, "Should be able to QI the document");
|
||||
|
||||
// This gets invoked by an event handler.
|
||||
window.finish = function() {
|
||||
// Content messed with stuff. Make sure we still see the right thing.
|
||||
@ -103,6 +109,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=821850
|
||||
window.contentVal = { foo: 10, rabbit: { hole: { bar: 100, win: window} } };
|
||||
ok(true, "Set contentVal");
|
||||
|
||||
// Check that we're not exposing QueryInterface to non-XBL code
|
||||
ok(!("QueryInterface" in document),
|
||||
"Should not have a document.QueryInterface here");
|
||||
|
||||
function go() {
|
||||
"use strict";
|
||||
|
||||
|
@ -372,11 +372,6 @@ static const char kDOMStringBundleURL[] =
|
||||
((NODE_SCRIPTABLE_FLAGS & ~nsIXPCScriptable::CLASSINFO_INTERFACES_ONLY) | \
|
||||
nsIXPCScriptable::WANT_POSTCREATE)
|
||||
|
||||
#define DOCUMENT_SCRIPTABLE_FLAGS \
|
||||
(NODE_SCRIPTABLE_FLAGS | \
|
||||
nsIXPCScriptable::WANT_POSTCREATE | \
|
||||
nsIXPCScriptable::WANT_ENUMERATE)
|
||||
|
||||
#define ARRAY_SCRIPTABLE_FLAGS \
|
||||
(DOM_DEFAULT_SCRIPTABLE_FLAGS | \
|
||||
nsIXPCScriptable::WANT_GETPROPERTY | \
|
||||
@ -591,10 +586,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||
NS_DEFINE_CLASSINFO_DATA(DeviceRotationRate, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
|
||||
// Misc HTML classes
|
||||
NS_DEFINE_CLASSINFO_DATA(HTMLDocument, nsHTMLDocumentSH,
|
||||
DOCUMENT_SCRIPTABLE_FLAGS |
|
||||
nsIXPCScriptable::WANT_GETPROPERTY)
|
||||
// HTML element classes
|
||||
NS_DEFINE_CLASSINFO_DATA(HTMLFormElement, nsHTMLFormElementSH,
|
||||
ELEMENT_SCRIPTABLE_FLAGS |
|
||||
@ -1034,7 +1025,6 @@ jsid nsDOMClassInfo::sFrames_id = JSID_VOID;
|
||||
jsid nsDOMClassInfo::sSelf_id = JSID_VOID;
|
||||
jsid nsDOMClassInfo::sAll_id = JSID_VOID;
|
||||
jsid nsDOMClassInfo::sTags_id = JSID_VOID;
|
||||
jsid nsDOMClassInfo::sDocumentURIObject_id=JSID_VOID;
|
||||
jsid nsDOMClassInfo::sWrappedJSObject_id = JSID_VOID;
|
||||
jsid nsDOMClassInfo::sURL_id = JSID_VOID;
|
||||
jsid nsDOMClassInfo::sOnload_id = JSID_VOID;
|
||||
@ -1295,7 +1285,6 @@ nsDOMClassInfo::DefineStaticJSVals(JSContext *cx)
|
||||
SET_JSID_TO_STRING(sSelf_id, cx, "self");
|
||||
SET_JSID_TO_STRING(sAll_id, cx, "all");
|
||||
SET_JSID_TO_STRING(sTags_id, cx, "tags");
|
||||
SET_JSID_TO_STRING(sDocumentURIObject_id,cx,"documentURIObject");
|
||||
SET_JSID_TO_STRING(sWrappedJSObject_id, cx, "wrappedJSObject");
|
||||
SET_JSID_TO_STRING(sURL_id, cx, "URL");
|
||||
SET_JSID_TO_STRING(sOnload_id, cx, "onload");
|
||||
@ -1771,13 +1760,6 @@ nsDOMClassInfo::Init()
|
||||
DOM_CLASSINFO_EVENT_MAP_ENTRIES
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(HTMLDocument, nsIDOMHTMLDocument)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLDocument)
|
||||
DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDocumentRegister,
|
||||
nsDocument::RegisterEnabled())
|
||||
DOM_CLASSINFO_DOCUMENT_MAP_ENTRIES
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(HTMLFormElement, nsIDOMHTMLFormElement)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLFormElement)
|
||||
DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
|
||||
@ -3014,7 +2996,6 @@ nsDOMClassInfo::ShutDown()
|
||||
sSelf_id = JSID_VOID;
|
||||
sAll_id = JSID_VOID;
|
||||
sTags_id = JSID_VOID;
|
||||
sDocumentURIObject_id=JSID_VOID;
|
||||
sWrappedJSObject_id = JSID_VOID;
|
||||
sOnload_id = JSID_VOID;
|
||||
sOnerror_id = JSID_VOID;
|
||||
@ -6067,134 +6048,8 @@ nsNamedArraySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocumentSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *aObj, jsid aId, uint32_t flags,
|
||||
JSObject **objp, bool *_retval)
|
||||
{
|
||||
JS::Rooted<JSObject*> obj(cx, aObj);
|
||||
JS::Rooted<jsid> id(cx, aId);
|
||||
nsresult rv;
|
||||
|
||||
if (id == sLocation_id) {
|
||||
// Define the location property on the document object itself so
|
||||
// that we can intercept getting and setting of document.location.
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> doc = do_QueryWrappedNative(wrapper, obj);
|
||||
NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
|
||||
|
||||
nsCOMPtr<nsIDOMLocation> location;
|
||||
rv = doc->GetLocation(getter_AddRefs(location));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
||||
rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), location,
|
||||
&NS_GET_IID(nsIDOMLocation), true, v.address(),
|
||||
getter_AddRefs(holder));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
JSBool ok = ::JS_DefinePropertyById(cx, obj, id, v, JS_PropertyStub,
|
||||
LocationSetter<nsIDOMDocument>,
|
||||
JSPROP_PERMANENT | JSPROP_ENUMERATE);
|
||||
|
||||
if (!ok) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*objp = obj;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return nsNodeSH::NewResolve(wrapper, cx, obj, id, flags, objp, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocumentSH::GetFlags(uint32_t* aFlags)
|
||||
{
|
||||
*aFlags = DOMCLASSINFO_STANDARD_FLAGS;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocumentSH::PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *aObj)
|
||||
{
|
||||
JS::Rooted<JSObject*> obj(cx, aObj);
|
||||
// If this is the current document for the window that's the script global
|
||||
// object of this document, then define this document object on the window.
|
||||
// That will make sure that the document is referenced (via window.document)
|
||||
// and prevent it from going away in GC.
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryWrappedNative(wrapper);
|
||||
if (!doc) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsIScriptGlobalObject *sgo = doc->GetScriptGlobalObject();
|
||||
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(sgo);
|
||||
if (!win) {
|
||||
// No window, nothing else to do here
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIDocument* currentDoc = win->GetExtantDoc();
|
||||
|
||||
if (SameCOMIdentity(doc, currentDoc)) {
|
||||
JS::Rooted<JS::Value> winVal(cx);
|
||||
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
||||
nsresult rv = WrapNative(cx, obj, win, &NS_GET_IID(nsIDOMWindow), false,
|
||||
winVal.address(), getter_AddRefs(holder));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_NAMED_LITERAL_STRING(doc_str, "document");
|
||||
|
||||
if (!::JS_DefineUCProperty(cx, JSVAL_TO_OBJECT(winVal),
|
||||
reinterpret_cast<const jschar *>
|
||||
(doc_str.get()),
|
||||
doc_str.Length(), OBJECT_TO_JSVAL(obj),
|
||||
JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JSPROP_READONLY | JSPROP_ENUMERATE)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocumentSH::PostTransplant(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj)
|
||||
{
|
||||
// Nothing to do here.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// HTMLDocument helper
|
||||
|
||||
static nsresult
|
||||
ResolveImpl(JSContext *cx, nsIXPConnectWrappedNative *wrapper, jsid id,
|
||||
nsISupports **result, nsWrapperCache **aCache)
|
||||
{
|
||||
nsHTMLDocument *doc =
|
||||
static_cast<nsHTMLDocument*>(static_cast<nsINode*>(wrapper->Native()));
|
||||
|
||||
// 'id' is not always a string, it can be a number since document.1
|
||||
// should map to <input name="1">. Thus we can't use
|
||||
// JSVAL_TO_STRING() here.
|
||||
JSString *str = IdToString(cx, id);
|
||||
NS_ENSURE_TRUE(str, NS_ERROR_UNEXPECTED);
|
||||
|
||||
nsDependentJSString depStr;
|
||||
NS_ENSURE_TRUE(depStr.init(cx, str), NS_ERROR_UNEXPECTED);
|
||||
|
||||
NS_IF_ADDREF(*result = doc->ResolveName(depStr, aCache));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
static JSClass sHTMLDocumentAllClass = {
|
||||
"HTML document.all class",
|
||||
JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_NEW_RESOLVE |
|
||||
@ -6266,7 +6121,7 @@ nsHTMLDocumentSH::GetDocumentAllNodeList(JSContext *cx,
|
||||
NS_ADDREF(*nodeList = static_cast<nsContentList*>(htmlCollection));
|
||||
}
|
||||
else {
|
||||
nsISupports *native = sXPConnect->GetNativeOfWrapper(cx, obj);
|
||||
nsISupports *native = nsDOMClassInfo::XPConnect()->GetNativeOfWrapper(cx, obj);
|
||||
if (native) {
|
||||
NS_ADDREF(*nodeList = nsContentList::FromSupports(native));
|
||||
rv = NS_OK;
|
||||
@ -6317,7 +6172,7 @@ nsHTMLDocumentSH::DocumentAllGetProperty(JSContext *cx, JSHandleObject obj_,
|
||||
// newResolve hook, so nothing to do for those properties here. And
|
||||
// we need to return early to prevent <div id="item"> from shadowing
|
||||
// document.all.item(), etc.
|
||||
if (sItem_id == id || sNamedItem_id == id) {
|
||||
if (nsDOMClassInfo::sItem_id == id || nsDOMClassInfo::sNamedItem_id == id) {
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
@ -6341,7 +6196,7 @@ nsHTMLDocumentSH::DocumentAllGetProperty(JSContext *cx, JSHandleObject obj_,
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (JSID_IS_STRING(id)) {
|
||||
if (sLength_id == id) {
|
||||
if (nsDOMClassInfo::sLength_id == id) {
|
||||
// Map document.all.length to the length of the collection
|
||||
// document.getElementsByTagName("*"), and make sure <div
|
||||
// id="length"> doesn't shadow document.all.length.
|
||||
@ -6363,7 +6218,7 @@ nsHTMLDocumentSH::DocumentAllGetProperty(JSContext *cx, JSHandleObject obj_,
|
||||
vp.set(INT_TO_JSVAL(length));
|
||||
|
||||
return JS_TRUE;
|
||||
} else if (sTags_id != id) {
|
||||
} else if (nsDOMClassInfo::sTags_id != id) {
|
||||
// For all other strings, look for an element by id or name.
|
||||
|
||||
nsDependentJSString str(id);
|
||||
@ -6416,7 +6271,7 @@ nsHTMLDocumentSH::DocumentAllNewResolve(JSContext *cx, JSHandleObject obj, JSHan
|
||||
{
|
||||
JS::RootedValue v(cx);
|
||||
|
||||
if (sItem_id == id || sNamedItem_id == id) {
|
||||
if (nsDOMClassInfo::sItem_id == id || nsDOMClassInfo::sNamedItem_id == id) {
|
||||
// Define the item() or namedItem() method.
|
||||
|
||||
JSFunction *fnc = ::JS_DefineFunctionById(cx, obj, id, CallToGetPropMapper,
|
||||
@ -6426,14 +6281,14 @@ nsHTMLDocumentSH::DocumentAllNewResolve(JSContext *cx, JSHandleObject obj, JSHan
|
||||
return fnc != nullptr;
|
||||
}
|
||||
|
||||
if (sLength_id == id) {
|
||||
if (nsDOMClassInfo::sLength_id == id) {
|
||||
// document.all.length. Any jsval other than undefined would do
|
||||
// here, all we need is to get into the code below that defines
|
||||
// this propery on obj, the rest happens in
|
||||
// DocumentAllGetProperty().
|
||||
|
||||
v = JSVAL_ONE;
|
||||
} else if (sTags_id == id) {
|
||||
} else if (nsDOMClassInfo::sTags_id == id) {
|
||||
nsHTMLDocument *doc = GetDocument(obj);
|
||||
|
||||
JSObject *tags = ::JS_NewObject(cx, &sHTMLDocumentAllTagsClass, nullptr,
|
||||
@ -6720,87 +6575,13 @@ nsresult
|
||||
nsHTMLDocumentSH::TryResolveAll(JSContext* cx, nsHTMLDocument* doc,
|
||||
JS::Handle<JSObject*> obj)
|
||||
{
|
||||
if (sDisableDocumentAllSupport) {
|
||||
if (nsDOMClassInfo::sDisableDocumentAllSupport) {
|
||||
return NS_OK;
|
||||
}
|
||||
JSAutoCompartment ac(cx, obj);
|
||||
return ResolveAll(cx, doc, obj);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLDocumentSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *aObj, jsid aId, uint32_t flags,
|
||||
JSObject **objp, bool *_retval)
|
||||
{
|
||||
JS::Rooted<JSObject*> obj(cx, aObj);
|
||||
JS::Rooted<jsid> id(cx, aId);
|
||||
// nsDocumentSH::NewResolve() does a security check that we'd kinda
|
||||
// want to do here too before doing anything else. But given that we
|
||||
// only define dynamic properties here before the call to
|
||||
// nsDocumentSH::NewResolve() we're ok, since once those properties
|
||||
// are accessed, we'll do the necessary security check.
|
||||
|
||||
if (!(flags & JSRESOLVE_ASSIGNING)) {
|
||||
// For native wrappers, do not resolve random names on document
|
||||
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
if (!ObjectIsNativeWrapper(cx, obj) ||
|
||||
xpc::WrapperFactory::XrayWrapperNotShadowing(obj, id)) {
|
||||
nsCOMPtr<nsISupports> result;
|
||||
nsWrapperCache *cache;
|
||||
nsresult rv = ResolveImpl(cx, wrapper, id, getter_AddRefs(result),
|
||||
&cache);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (result) {
|
||||
JSBool ok = *_retval =
|
||||
::JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, nullptr, nullptr, 0);
|
||||
*objp = obj;
|
||||
|
||||
return ok ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (id == sAll_id && !sDisableDocumentAllSupport &&
|
||||
!ObjectIsNativeWrapper(cx, obj)) {
|
||||
nsIDocument *doc = static_cast<nsIDocument*>(wrapper->Native());
|
||||
if (doc->GetCompatibilityMode() != eCompatibility_NavQuirks) {
|
||||
return NS_OK;
|
||||
}
|
||||
return ResolveAll(cx, doc, obj);
|
||||
}
|
||||
}
|
||||
|
||||
return nsDocumentSH::NewResolve(wrapper, cx, obj, id, flags, objp, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLDocumentSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
|
||||
JSContext *cx, JSObject *aObj, jsid aId,
|
||||
jsval *vp, bool *_retval)
|
||||
{
|
||||
JS::Rooted<JSObject*> obj(cx, aObj);
|
||||
JS::Rooted<jsid> id(cx, aId);
|
||||
nsCOMPtr<nsISupports> result;
|
||||
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
nsWrapperCache *cache;
|
||||
nsresult rv = ResolveImpl(cx, wrapper, id, getter_AddRefs(result), &cache);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (result) {
|
||||
rv = WrapNative(cx, obj, result, cache, true, vp);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = NS_SUCCESS_I_DID_SOMETHING;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// HTMLFormElement helper
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -25,7 +25,6 @@ class nsContentList;
|
||||
class nsGlobalWindow;
|
||||
class nsIDOMWindow;
|
||||
class nsIForm;
|
||||
class nsIHTMLDocument;
|
||||
class nsNPAPIPluginInstance;
|
||||
class nsObjectLoadingContent;
|
||||
class nsIObjectLoadingContent;
|
||||
@ -81,6 +80,7 @@ struct nsExternalDOMClassInfoData : public nsDOMClassInfoData
|
||||
|
||||
class nsDOMClassInfo : public nsXPCClassInfo
|
||||
{
|
||||
friend class nsHTMLDocumentSH;
|
||||
public:
|
||||
nsDOMClassInfo(nsDOMClassInfoData* aData);
|
||||
virtual ~nsDOMClassInfo();
|
||||
@ -219,7 +219,6 @@ public:
|
||||
static jsid sSelf_id;
|
||||
static jsid sAll_id;
|
||||
static jsid sTags_id;
|
||||
static jsid sDocumentURIObject_id;
|
||||
static jsid sJava_id;
|
||||
static jsid sPackages_id;
|
||||
static jsid sWrappedJSObject_id;
|
||||
@ -593,53 +592,14 @@ private:
|
||||
};
|
||||
|
||||
|
||||
// Document helper, for document.location and document.on*
|
||||
|
||||
class nsDocumentSH : public nsNodeSH
|
||||
{
|
||||
public:
|
||||
nsDocumentSH(nsDOMClassInfoData* aData) : nsNodeSH(aData)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~nsDocumentSH()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj, jsid id, uint32_t flags,
|
||||
JSObject **objp, bool *_retval);
|
||||
NS_IMETHOD GetFlags(uint32_t* aFlags);
|
||||
NS_IMETHOD PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj);
|
||||
NS_IMETHOD PostTransplant(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj);
|
||||
|
||||
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
|
||||
{
|
||||
return new nsDocumentSH(aData);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// HTMLDocument helper
|
||||
|
||||
class nsHTMLDocumentSH : public nsDocumentSH
|
||||
class nsHTMLDocumentSH
|
||||
{
|
||||
protected:
|
||||
nsHTMLDocumentSH(nsDOMClassInfoData* aData) : nsDocumentSH(aData)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~nsHTMLDocumentSH()
|
||||
{
|
||||
}
|
||||
|
||||
static JSBool GetDocumentAllNodeList(JSContext *cx, JS::Handle<JSObject*> obj,
|
||||
nsDocument *doc,
|
||||
nsContentList **nodeList);
|
||||
|
||||
public:
|
||||
static JSBool DocumentAllGetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id,
|
||||
JSMutableHandleValue vp);
|
||||
@ -656,19 +616,8 @@ public:
|
||||
JSHandleId id, unsigned flags,
|
||||
JS::MutableHandle<JSObject*> objp);
|
||||
|
||||
NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj, jsid id, uint32_t flags,
|
||||
JSObject **objp, bool *_retval);
|
||||
NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj, jsid id, jsval *vp, bool *_retval);
|
||||
|
||||
static nsresult TryResolveAll(JSContext* cx, nsHTMLDocument* doc,
|
||||
JS::Handle<JSObject*> obj);
|
||||
|
||||
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
|
||||
{
|
||||
return new nsHTMLDocumentSH(aData);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -38,9 +38,6 @@ DOMCI_CLASS(DeviceMotionEvent)
|
||||
DOMCI_CLASS(DeviceAcceleration)
|
||||
DOMCI_CLASS(DeviceRotationRate)
|
||||
|
||||
// HTML classes
|
||||
DOMCI_CLASS(HTMLDocument)
|
||||
|
||||
// HTML element classes
|
||||
DOMCI_CLASS(HTMLFormElement)
|
||||
|
||||
|
@ -31,7 +31,13 @@ class nsGlobalWindow;
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct MainThreadDictionaryBase
|
||||
// Struct that serves as a base class for all dictionaries. Particularly useful
|
||||
// so we can use IsBaseOf to detect dictionary template arguments.
|
||||
struct DictionaryBase
|
||||
{
|
||||
};
|
||||
|
||||
struct MainThreadDictionaryBase : public DictionaryBase
|
||||
{
|
||||
protected:
|
||||
bool ParseJSON(JSContext *aCx, const nsAString& aJSON,
|
||||
@ -219,18 +225,24 @@ private:
|
||||
};
|
||||
|
||||
// Class for representing optional arguments.
|
||||
template<typename T>
|
||||
class Optional
|
||||
template<typename T, typename InternalType>
|
||||
class Optional_base
|
||||
{
|
||||
public:
|
||||
Optional()
|
||||
Optional_base()
|
||||
{}
|
||||
|
||||
explicit Optional(const T& aValue)
|
||||
explicit Optional_base(const T& aValue)
|
||||
{
|
||||
mImpl.construct(aValue);
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
explicit Optional_base(const T1& aValue1, const T2& aValue2)
|
||||
{
|
||||
mImpl.construct(aValue1, aValue2);
|
||||
}
|
||||
|
||||
bool WasPassed() const
|
||||
{
|
||||
return !mImpl.empty();
|
||||
@ -253,12 +265,12 @@ public:
|
||||
mImpl.construct(t1, t2);
|
||||
}
|
||||
|
||||
const T& Value() const
|
||||
const InternalType& Value() const
|
||||
{
|
||||
return mImpl.ref();
|
||||
}
|
||||
|
||||
T& Value()
|
||||
InternalType& Value()
|
||||
{
|
||||
return mImpl.ref();
|
||||
}
|
||||
@ -269,10 +281,37 @@ public:
|
||||
|
||||
private:
|
||||
// Forbid copy-construction and assignment
|
||||
Optional(const Optional& other) MOZ_DELETE;
|
||||
const Optional &operator=(const Optional &other) MOZ_DELETE;
|
||||
Optional_base(const Optional_base& other) MOZ_DELETE;
|
||||
const Optional_base &operator=(const Optional_base &other) MOZ_DELETE;
|
||||
|
||||
Maybe<T> mImpl;
|
||||
Maybe<InternalType> mImpl;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class Optional : public Optional_base<T, T>
|
||||
{
|
||||
public:
|
||||
Optional() :
|
||||
Optional_base<T, T>()
|
||||
{}
|
||||
|
||||
explicit Optional(const T& aValue) :
|
||||
Optional_base<T, T>(aValue)
|
||||
{}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class Optional<JS::Handle<T> > :
|
||||
public Optional_base<JS::Handle<T>, JS::Rooted<T> >
|
||||
{
|
||||
public:
|
||||
Optional() :
|
||||
Optional_base<JS::Handle<T>, JS::Rooted<T> >()
|
||||
{}
|
||||
|
||||
Optional(JSContext* cx, const T& aValue) :
|
||||
Optional_base<JS::Handle<T>, JS::Rooted<T> >(cx, aValue)
|
||||
{}
|
||||
};
|
||||
|
||||
// Specialization for strings.
|
||||
@ -470,77 +509,6 @@ private:
|
||||
double mMsecSinceEpoch;
|
||||
};
|
||||
|
||||
class NonNullLazyRootedObject : public Maybe<JS::Rooted<JSObject*> >
|
||||
{
|
||||
public:
|
||||
operator JSObject&() const
|
||||
{
|
||||
MOZ_ASSERT(!empty() && ref(), "Can not alias null.");
|
||||
return *ref();
|
||||
}
|
||||
|
||||
operator JS::Rooted<JSObject*>&()
|
||||
{
|
||||
// Assert if we're empty, on purpose
|
||||
return ref();
|
||||
}
|
||||
|
||||
JSObject** Slot() // To make us look like a NonNull
|
||||
{
|
||||
// Assert if we're empty, on purpose
|
||||
return ref().address();
|
||||
}
|
||||
};
|
||||
|
||||
class LazyRootedObject : public Maybe<JS::Rooted<JSObject*> >
|
||||
{
|
||||
public:
|
||||
operator JSObject*() const
|
||||
{
|
||||
return empty() ? static_cast<JSObject*>(nullptr) : ref();
|
||||
}
|
||||
|
||||
operator JS::Rooted<JSObject*>&()
|
||||
{
|
||||
// Assert if we're empty, on purpose
|
||||
return ref();
|
||||
}
|
||||
|
||||
JSObject** operator&()
|
||||
{
|
||||
// Assert if we're empty, on purpose
|
||||
return ref().address();
|
||||
}
|
||||
};
|
||||
|
||||
class LazyRootedValue : public Maybe<JS::Rooted<JS::Value> >
|
||||
{
|
||||
public:
|
||||
operator JS::Value() const
|
||||
{
|
||||
// Assert if we're empty, on purpose
|
||||
return ref();
|
||||
}
|
||||
|
||||
operator JS::Rooted<JS::Value>& ()
|
||||
{
|
||||
// Assert if we're empty, on purpose
|
||||
return ref();
|
||||
}
|
||||
|
||||
operator JS::Handle<JS::Value>()
|
||||
{
|
||||
// Assert if we're empty, on purpose
|
||||
return ref();
|
||||
}
|
||||
|
||||
JS::Value* operator&()
|
||||
{
|
||||
// Assert if we're empty, on purpose
|
||||
return ref().address();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -1353,13 +1353,6 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
T** Slot() {
|
||||
#ifdef DEBUG
|
||||
inited = true;
|
||||
#endif
|
||||
return &ptr;
|
||||
}
|
||||
|
||||
T* Ptr() {
|
||||
MOZ_ASSERT(inited);
|
||||
MOZ_ASSERT(ptr, "NonNull<T> was set to null");
|
||||
@ -1564,6 +1557,12 @@ public:
|
||||
new (storage.addr()) T();
|
||||
return *storage.addr();
|
||||
}
|
||||
template <typename T1, typename T2>
|
||||
T& SetValue(const T1 &t1, const T2 &t2)
|
||||
{
|
||||
new (storage.addr()) T(t1, t2);
|
||||
return *storage.addr();
|
||||
}
|
||||
const T& Value() const {
|
||||
return *storage.addr();
|
||||
}
|
||||
@ -1572,6 +1571,11 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq);
|
||||
template<typename T>
|
||||
void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq);
|
||||
|
||||
// Class for simple sequence arguments, only used internally by codegen.
|
||||
template<typename T>
|
||||
class AutoSequence : public AutoFallibleTArray<T, 16>
|
||||
@ -1586,6 +1590,222 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// Class used to trace sequences, with specializations for various
|
||||
// sequence types.
|
||||
template<typename T, bool isDictionary=IsBaseOf<DictionaryBase, T>::value>
|
||||
class SequenceTracer
|
||||
{
|
||||
explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
|
||||
};
|
||||
|
||||
// sequence<object> or sequence<object?>
|
||||
template<>
|
||||
class SequenceTracer<JSObject*, false>
|
||||
{
|
||||
explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
|
||||
|
||||
public:
|
||||
static void TraceSequence(JSTracer* trc, JSObject** objp, JSObject** end) {
|
||||
for ( ; objp != end; ++objp) {
|
||||
JS_CallObjectTracer(trc, objp, "sequence<object>");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// sequence<any>
|
||||
template<>
|
||||
class SequenceTracer<JS::Value, false>
|
||||
{
|
||||
explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
|
||||
|
||||
public:
|
||||
static void TraceSequence(JSTracer* trc, JS::Value* valp, JS::Value* end) {
|
||||
for ( ; valp != end; ++valp) {
|
||||
JS_CallValueTracer(trc, valp, "sequence<any>");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// sequence<sequence<T>>
|
||||
template<typename T>
|
||||
class SequenceTracer<Sequence<T>, false>
|
||||
{
|
||||
explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
|
||||
|
||||
public:
|
||||
static void TraceSequence(JSTracer* trc, Sequence<T>* seqp, Sequence<T>* end) {
|
||||
for ( ; seqp != end; ++seqp) {
|
||||
DoTraceSequence(trc, *seqp);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// sequence<sequence<T>> as return value
|
||||
template<typename T>
|
||||
class SequenceTracer<nsTArray<T>, false>
|
||||
{
|
||||
explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
|
||||
|
||||
public:
|
||||
static void TraceSequence(JSTracer* trc, nsTArray<T>* seqp, nsTArray<T>* end) {
|
||||
for ( ; seqp != end; ++seqp) {
|
||||
DoTraceSequence(trc, *seqp);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// sequence<someDictionary>
|
||||
template<typename T>
|
||||
class SequenceTracer<T, true>
|
||||
{
|
||||
explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
|
||||
|
||||
public:
|
||||
static void TraceSequence(JSTracer* trc, T* dictp, T* end) {
|
||||
for ( ; dictp != end; ++dictp) {
|
||||
dictp->TraceDictionary(trc);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// sequence<sequence<T>?>
|
||||
template<typename T>
|
||||
class SequenceTracer<Nullable<Sequence<T> >, false>
|
||||
{
|
||||
explicit SequenceTracer() MOZ_DELETE; // Should never be instantiated
|
||||
|
||||
public:
|
||||
static void TraceSequence(JSTracer* trc, Nullable<Sequence<T> >* seqp,
|
||||
Nullable<Sequence<T> >* end) {
|
||||
for ( ; seqp != end; ++seqp) {
|
||||
if (!seqp->IsNull()) {
|
||||
DoTraceSequence(trc, seqp->Value());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq)
|
||||
{
|
||||
SequenceTracer<T>::TraceSequence(trc, seq.Elements(),
|
||||
seq.Elements() + seq.Length());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq)
|
||||
{
|
||||
SequenceTracer<T>::TraceSequence(trc, seq.Elements(),
|
||||
seq.Elements() + seq.Length());
|
||||
}
|
||||
|
||||
// Rooter class for sequences; this is what we mostly use in the codegen
|
||||
template<typename T>
|
||||
class MOZ_STACK_CLASS SequenceRooter : private JS::CustomAutoRooter
|
||||
{
|
||||
public:
|
||||
explicit SequenceRooter(JSContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
|
||||
mSequenceType(eNone)
|
||||
{
|
||||
}
|
||||
|
||||
void SetSequence(FallibleTArray<T>* aSequence)
|
||||
{
|
||||
mFallibleArray = aSequence;
|
||||
mSequenceType = eFallibleArray;
|
||||
}
|
||||
|
||||
void SetSequence(InfallibleTArray<T>* aSequence)
|
||||
{
|
||||
mInfallibleArray = aSequence;
|
||||
mSequenceType = eInfallibleArray;
|
||||
}
|
||||
|
||||
void SetSequence(Nullable<nsTArray<T>>* aSequence)
|
||||
{
|
||||
mNullableArray = aSequence;
|
||||
mSequenceType = eNullableArray;
|
||||
}
|
||||
|
||||
private:
|
||||
enum SequenceType {
|
||||
eNone,
|
||||
eInfallibleArray,
|
||||
eFallibleArray,
|
||||
eNullableArray
|
||||
};
|
||||
|
||||
virtual void trace(JSTracer *trc) MOZ_OVERRIDE
|
||||
{
|
||||
if (mSequenceType == eFallibleArray) {
|
||||
DoTraceSequence(trc, *mFallibleArray);
|
||||
} else if (mSequenceType == eInfallibleArray) {
|
||||
DoTraceSequence(trc, *mInfallibleArray);
|
||||
} else if (mSequenceType == eNullableArray) {
|
||||
if (!mNullableArray->IsNull()) {
|
||||
DoTraceSequence(trc, mNullableArray->Value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
union {
|
||||
InfallibleTArray<T>* mInfallibleArray;
|
||||
FallibleTArray<T>* mFallibleArray;
|
||||
Nullable<nsTArray<T> >* mNullableArray;
|
||||
};
|
||||
|
||||
SequenceType mSequenceType;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class MOZ_STACK_CLASS DictionaryRooter : JS::CustomAutoRooter
|
||||
{
|
||||
public:
|
||||
explicit DictionaryRooter(JSContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
|
||||
mDictionaryType(eNone)
|
||||
{
|
||||
}
|
||||
|
||||
void SetDictionary(T* aDictionary)
|
||||
{
|
||||
mDictionary = aDictionary;
|
||||
mDictionaryType = eDictionary;
|
||||
}
|
||||
|
||||
void SetDictionary(Nullable<T>* aDictionary)
|
||||
{
|
||||
mNullableDictionary = aDictionary;
|
||||
mDictionaryType = eNullableDictionary;
|
||||
}
|
||||
|
||||
private:
|
||||
enum DictionaryType {
|
||||
eDictionary,
|
||||
eNullableDictionary,
|
||||
eNone
|
||||
};
|
||||
|
||||
virtual void trace(JSTracer *trc) MOZ_OVERRIDE {
|
||||
if (mDictionaryType == eDictionary) {
|
||||
mDictionary->TraceDictionary(trc);
|
||||
} else {
|
||||
MOZ_ASSERT(mDictionaryType == eNullableDictionary);
|
||||
if (!mNullableDictionary->IsNull()) {
|
||||
mNullableDictionary->Value().TraceDictionary(trc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
union {
|
||||
T* mDictionary;
|
||||
Nullable<T>* mNullableDictionary;
|
||||
};
|
||||
|
||||
DictionaryType mDictionaryType;
|
||||
};
|
||||
|
||||
inline bool
|
||||
IdEquals(jsid id, const char* string)
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -137,12 +137,12 @@ public:
|
||||
JSContext*,
|
||||
const DictForConstructor&,
|
||||
JS::Value,
|
||||
JSObject&,
|
||||
JSObject*,
|
||||
JS::Handle<JSObject*>,
|
||||
JS::Handle<JSObject*>,
|
||||
const Sequence<Dict>&,
|
||||
const Optional<LazyRootedValue>&,
|
||||
const Optional<NonNullLazyRootedObject>&,
|
||||
const Optional<LazyRootedObject>&,
|
||||
const Optional<JS::Handle<JS::Value> >&,
|
||||
const Optional<JS::Handle<JSObject*> >&,
|
||||
const Optional<JS::Handle<JSObject*> >&,
|
||||
ErrorResult&);
|
||||
|
||||
// Integer types
|
||||
@ -365,7 +365,11 @@ public:
|
||||
void PassStringSequence(const Sequence<nsString>&);
|
||||
|
||||
void ReceiveAnySequence(JSContext*, nsTArray<JS::Value>&);
|
||||
void ReceiveNullableAnySequence(JSContext*, Nullable<nsTArray<JS::Value> >);
|
||||
void ReceiveNullableAnySequence(JSContext*, Nullable<nsTArray<JS::Value> >&);
|
||||
void ReceiveAnySequenceSequence(JSContext*, nsTArray<nsTArray<JS::Value> >&);
|
||||
|
||||
void ReceiveObjectSequence(JSContext*, nsTArray<JSObject*>&);
|
||||
void ReceiveNullableObjectSequence(JSContext*, nsTArray<JSObject*>&);
|
||||
|
||||
void PassSequenceOfSequences(const Sequence< Sequence<int32_t> >&);
|
||||
void ReceiveSequenceOfSequences(nsTArray< nsTArray<int32_t> >&);
|
||||
@ -428,29 +432,45 @@ public:
|
||||
already_AddRefed<TestTreatAsNullCallback> GetNullableTreatAsNullCallback();
|
||||
|
||||
// Any types
|
||||
void PassAny(JSContext*, JS::Value);
|
||||
void PassOptionalAny(JSContext*, const Optional<LazyRootedValue>&);
|
||||
void PassAnyDefaultNull(JSContext*, JS::Value);
|
||||
void PassAny(JSContext*, JS::Handle<JS::Value>);
|
||||
void PassVariadicAny(JSContext*, const Sequence<JS::Value>&);
|
||||
void PassOptionalAny(JSContext*, const Optional<JS::Handle<JS::Value> >&);
|
||||
void PassAnyDefaultNull(JSContext*, JS::Handle<JS::Value>);
|
||||
void PassSequenceOfAny(JSContext*, const Sequence<JS::Value>&);
|
||||
void PassNullableSequenceOfAny(JSContext*, const Nullable<Sequence<JS::Value> >&);
|
||||
void PassOptionalSequenceOfAny(JSContext*, const Optional<Sequence<JS::Value> >&);
|
||||
void PassOptionalNullableSequenceOfAny(JSContext*, const Optional<Nullable<Sequence<JS::Value> > >&);
|
||||
void PassOptionalSequenceOfAnyWithDefaultValue(JSContext*, const Nullable<Sequence<JS::Value> >&);
|
||||
void PassSequenceOfSequenceOfAny(JSContext*, const Sequence<Sequence<JS::Value> >&);
|
||||
void PassSequenceOfNullableSequenceOfAny(JSContext*, const Sequence<Nullable<Sequence<JS::Value> > >&);
|
||||
void PassNullableSequenceOfNullableSequenceOfAny(JSContext*, const Nullable<Sequence<Nullable<Sequence<JS::Value> > > >&);
|
||||
void PassOptionalNullableSequenceOfNullableSequenceOfAny(JSContext*, const Optional<Nullable<Sequence<Nullable<Sequence<JS::Value> > > > >&);
|
||||
JS::Value ReceiveAny(JSContext*);
|
||||
|
||||
// object types
|
||||
void PassObject(JSContext*, JSObject&);
|
||||
void PassNullableObject(JSContext*, JSObject*);
|
||||
void PassOptionalObject(JSContext*, const Optional<NonNullLazyRootedObject>&);
|
||||
void PassOptionalNullableObject(JSContext*, const Optional<LazyRootedObject>&);
|
||||
void PassOptionalNullableObjectWithDefaultValue(JSContext*, JSObject*);
|
||||
void PassObject(JSContext*, JS::Handle<JSObject*>);
|
||||
void PassVariadicObject(JSContext*, const Sequence<JSObject*>&);
|
||||
void PassNullableObject(JSContext*, JS::Handle<JSObject*>);
|
||||
void PassVariadicNullableObject(JSContext*, const Sequence<JSObject*>&);
|
||||
void PassOptionalObject(JSContext*, const Optional<JS::Handle<JSObject*> >&);
|
||||
void PassOptionalNullableObject(JSContext*, const Optional<JS::Handle<JSObject*> >&);
|
||||
void PassOptionalNullableObjectWithDefaultValue(JSContext*, JS::Handle<JSObject*>);
|
||||
void PassSequenceOfObject(JSContext*, const Sequence<JSObject*>&);
|
||||
void PassSequenceOfNullableObject(JSContext*, const Sequence<JSObject*>&);
|
||||
void PassOptionalNullableSequenceOfNullableSequenceOfObject(JSContext*, const Optional<Nullable<Sequence<Nullable<Sequence<JSObject*> > > > >&);
|
||||
void PassOptionalNullableSequenceOfNullableSequenceOfNullableObject(JSContext*, const Optional<Nullable<Sequence<Nullable<Sequence<JSObject*> > > > >&);
|
||||
JSObject* ReceiveObject(JSContext*);
|
||||
JSObject* ReceiveNullableObject(JSContext*);
|
||||
|
||||
// Union types
|
||||
void PassUnion(JSContext*, const ObjectOrLong& arg);
|
||||
void PassUnionWithNullable(JSContext*, const ObjectOrNullOrLong& arg)
|
||||
void PassUnionWithNullable(JSContext* cx, const ObjectOrNullOrLong& arg)
|
||||
{
|
||||
ObjectOrLong returnValue;
|
||||
if (arg.IsNull()) {
|
||||
} else if (arg.IsObject()) {
|
||||
JSObject& obj = (JSObject&)arg.GetAsObject();
|
||||
JS_GetClass(&obj);
|
||||
JS::Rooted<JSObject*> obj(cx, arg.GetAsObject());
|
||||
JS_GetClass(obj);
|
||||
//returnValue.SetAsObject(&obj);
|
||||
} else {
|
||||
int32_t i = arg.GetAsLong();
|
||||
@ -490,13 +510,14 @@ public:
|
||||
// Dictionary tests
|
||||
void PassDictionary(JSContext*, const Dict&);
|
||||
void ReceiveDictionary(JSContext*, Dict&);
|
||||
void ReceiveNullableDictionary(JSContext*, Nullable<DictInitializer>&);
|
||||
void PassOtherDictionary(const GrandparentDict&);
|
||||
void PassSequenceOfDictionaries(JSContext*, const Sequence<Dict>&);
|
||||
void PassDictionaryOrLong(JSContext*, const Dict&);
|
||||
void PassDictionaryOrLong(int32_t);
|
||||
void PassDictContainingDict(JSContext*, const DictContainingDict&);
|
||||
void PassDictContainingSequence(const DictContainingSequence&);
|
||||
void ReceiveDictContainingSequence(DictContainingSequence&);
|
||||
void PassDictContainingSequence(JSContext*, const DictContainingSequence&);
|
||||
void ReceiveDictContainingSequence(JSContext*, DictContainingSequence&);
|
||||
|
||||
// Typedefs
|
||||
void ExerciseTypedefInterfaces1(TestInterface&);
|
||||
@ -675,6 +696,19 @@ private:
|
||||
void PassSequence(Sequence<int32_t> &) MOZ_DELETE;
|
||||
void PassNullableSequence(Nullable< Sequence<int32_t> >&) MOZ_DELETE;
|
||||
void PassOptionalNullableSequenceWithDefaultValue(Nullable< Sequence<int32_t> >&) MOZ_DELETE;
|
||||
void PassSequenceOfAny(JSContext*, Sequence<JS::Value>&) MOZ_DELETE;
|
||||
void PassNullableSequenceOfAny(JSContext*, Nullable<Sequence<JS::Value> >&) MOZ_DELETE;
|
||||
void PassOptionalSequenceOfAny(JSContext*, Optional<Sequence<JS::Value> >&) MOZ_DELETE;
|
||||
void PassOptionalNullableSequenceOfAny(JSContext*, Optional<Nullable<Sequence<JS::Value> > >&) MOZ_DELETE;
|
||||
void PassOptionalSequenceOfAnyWithDefaultValue(JSContext*, Nullable<Sequence<JS::Value> >&) MOZ_DELETE;
|
||||
void PassSequenceOfSequenceOfAny(JSContext*, Sequence<Sequence<JS::Value> >&) MOZ_DELETE;
|
||||
void PassSequenceOfNullableSequenceOfAny(JSContext*, Sequence<Nullable<Sequence<JS::Value> > >&) MOZ_DELETE;
|
||||
void PassNullableSequenceOfNullableSequenceOfAny(JSContext*, Nullable<Sequence<Nullable<Sequence<JS::Value> > > >&) MOZ_DELETE;
|
||||
void PassOptionalNullableSequenceOfNullableSequenceOfAny(JSContext*, Optional<Nullable<Sequence<Nullable<Sequence<JS::Value> > > > >&) MOZ_DELETE;
|
||||
void PassSequenceOfObject(JSContext*, Sequence<JSObject*>&) MOZ_DELETE;
|
||||
void PassSequenceOfNullableObject(JSContext*, Sequence<JSObject*>&) MOZ_DELETE;
|
||||
void PassOptionalNullableSequenceOfNullableSequenceOfObject(JSContext*, Optional<Nullable<Sequence<Nullable<Sequence<JSObject*> > > > >&) MOZ_DELETE;
|
||||
void PassOptionalNullableSequenceOfNullableSequenceOfNullableObject(JSContext*, Optional<Nullable<Sequence<Nullable<Sequence<JSObject*> > > > >&) MOZ_DELETE;
|
||||
|
||||
// Enforce that only const things are passed for optional
|
||||
void PassOptionalByte(Optional<int8_t>&) MOZ_DELETE;
|
||||
@ -698,9 +732,9 @@ private:
|
||||
void PassOptionalArrayBuffer(Optional<ArrayBuffer>&) MOZ_DELETE;
|
||||
void PassOptionalNullableArrayBuffer(Optional<ArrayBuffer*>&) MOZ_DELETE;
|
||||
void PassOptionalEnum(Optional<TestEnum>&) MOZ_DELETE;
|
||||
void PassOptionalCallback(JSContext*, Optional<JSObject*>&) MOZ_DELETE;
|
||||
void PassOptionalNullableCallback(JSContext*, Optional<JSObject*>&) MOZ_DELETE;
|
||||
void PassOptionalAny(Optional<JS::Value>&) MOZ_DELETE;
|
||||
void PassOptionalCallback(JSContext*, Optional<OwningNonNull<TestCallback> >&) MOZ_DELETE;
|
||||
void PassOptionalNullableCallback(JSContext*, Optional<nsRefPtr<TestCallback> >&) MOZ_DELETE;
|
||||
void PassOptionalAny(Optional<JS::Handle<JS::Value> >&) MOZ_DELETE;
|
||||
|
||||
// And test that string stuff is always const
|
||||
void PassString(nsAString&) MOZ_DELETE;
|
||||
@ -737,6 +771,11 @@ private:
|
||||
void PassOptionalNullableDateWithDefaultValue(Nullable<Date>&) MOZ_DELETE;
|
||||
void PassDateSequence(Sequence<Date>&) MOZ_DELETE;
|
||||
void PassNullableDateSequence(Sequence<Nullable<Date> >&) MOZ_DELETE;
|
||||
|
||||
// Make sure variadics are const as needed
|
||||
void PassVariadicAny(JSContext*, Sequence<JS::Value>&) MOZ_DELETE;
|
||||
void PassVariadicObject(JSContext*, Sequence<JSObject*>&) MOZ_DELETE;
|
||||
void PassVariadicNullableObject(JSContext*, Sequence<JSObject*>&) MOZ_DELETE;
|
||||
};
|
||||
|
||||
class TestIndexedGetterInterface : public nsISupports,
|
||||
|
@ -336,6 +336,10 @@ interface TestInterface {
|
||||
|
||||
sequence<any> receiveAnySequence();
|
||||
sequence<any>? receiveNullableAnySequence();
|
||||
sequence<sequence<any>> receiveAnySequenceSequence();
|
||||
|
||||
sequence<object> receiveObjectSequence();
|
||||
sequence<object?> receiveNullableObjectSequence();
|
||||
|
||||
void passSequenceOfSequences(sequence<sequence<long>> arg);
|
||||
sequence<sequence<long>> receiveSequenceOfSequences();
|
||||
@ -396,16 +400,32 @@ interface TestInterface {
|
||||
|
||||
// Any types
|
||||
void passAny(any arg);
|
||||
void passVariadicAny(any... arg);
|
||||
void passOptionalAny(optional any arg);
|
||||
void passAnyDefaultNull(optional any arg = null);
|
||||
void passSequenceOfAny(sequence<any> arg);
|
||||
void passNullableSequenceOfAny(sequence<any>? arg);
|
||||
void passOptionalSequenceOfAny(optional sequence<any> arg);
|
||||
void passOptionalNullableSequenceOfAny(optional sequence<any>? arg);
|
||||
void passOptionalSequenceOfAnyWithDefaultValue(optional sequence<any>? arg = null);
|
||||
void passSequenceOfSequenceOfAny(sequence<sequence<any>> arg);
|
||||
void passSequenceOfNullableSequenceOfAny(sequence<sequence<any>?> arg);
|
||||
void passNullableSequenceOfNullableSequenceOfAny(sequence<sequence<any>?>? arg);
|
||||
void passOptionalNullableSequenceOfNullableSequenceOfAny(optional sequence<sequence<any>?>? arg);
|
||||
any receiveAny();
|
||||
|
||||
// object types
|
||||
void passObject(object arg);
|
||||
void passVariadicObject(object... arg);
|
||||
void passNullableObject(object? arg);
|
||||
void passVariadicNullableObject(object... arg);
|
||||
void passOptionalObject(optional object arg);
|
||||
void passOptionalNullableObject(optional object? arg);
|
||||
void passOptionalNullableObjectWithDefaultValue(optional object? arg = null);
|
||||
void passSequenceOfObject(sequence<object> arg);
|
||||
void passSequenceOfNullableObject(sequence<object?> arg);
|
||||
void passOptionalNullableSequenceOfNullableSequenceOfObject(optional sequence<sequence<object>?>? arg);
|
||||
void passOptionalNullableSequenceOfNullableSequenceOfNullableObject(optional sequence<sequence<object?>?>? arg);
|
||||
object receiveObject();
|
||||
object? receiveNullableObject();
|
||||
|
||||
@ -447,8 +467,11 @@ interface TestInterface {
|
||||
|
||||
void passDictionary(optional Dict x);
|
||||
Dict receiveDictionary();
|
||||
Dict? receiveNullableDictionary();
|
||||
void passOtherDictionary(optional GrandparentDict x);
|
||||
void passSequenceOfDictionaries(sequence<Dict> x);
|
||||
// No support for nullable dictionaries inside a sequence (nor should there be)
|
||||
// void passSequenceOfNullableDictionaries(sequence<Dict?> x);
|
||||
void passDictionaryOrLong(optional Dict x);
|
||||
void passDictionaryOrLong(long x);
|
||||
|
||||
@ -657,6 +680,13 @@ dictionary DictContainingDict {
|
||||
dictionary DictContainingSequence {
|
||||
sequence<long> ourSequence;
|
||||
sequence<TestInterface> ourSequence2;
|
||||
sequence<any> ourSequence3;
|
||||
sequence<object> ourSequence4;
|
||||
sequence<object?> ourSequence5;
|
||||
sequence<object>? ourSequence6;
|
||||
sequence<object?>? ourSequence7;
|
||||
sequence<object>? ourSequence8 = null;
|
||||
sequence<object?>? ourSequence9 = null;
|
||||
};
|
||||
|
||||
dictionary DictForConstructor {
|
||||
@ -665,7 +695,9 @@ dictionary DictForConstructor {
|
||||
sequence<Dict> seq1;
|
||||
sequence<sequence<Dict>>? seq2;
|
||||
sequence<sequence<Dict>?> seq3;
|
||||
// No support for sequences of "any" or "object" as return values yet.
|
||||
sequence<any> seq4;
|
||||
sequence<any> seq5;
|
||||
sequence<DictContainingSequence> seq6;
|
||||
object obj1;
|
||||
object? obj2;
|
||||
any any1 = null;
|
||||
|
@ -234,6 +234,11 @@ interface TestExampleInterface {
|
||||
|
||||
sequence<any> receiveAnySequence();
|
||||
sequence<any>? receiveNullableAnySequence();
|
||||
//XXXbz No support for sequence of sequence return values yet.
|
||||
//sequence<sequence<any>> receiveAnySequenceSequence();
|
||||
|
||||
sequence<object> receiveObjectSequence();
|
||||
sequence<object?> receiveNullableObjectSequence();
|
||||
|
||||
void passSequenceOfSequences(sequence<sequence<long>> arg);
|
||||
//XXXbz No support for sequence of sequence return values yet.
|
||||
@ -293,16 +298,32 @@ interface TestExampleInterface {
|
||||
|
||||
// Any types
|
||||
void passAny(any arg);
|
||||
void passVariadicAny(any... arg);
|
||||
void passOptionalAny(optional any arg);
|
||||
void passAnyDefaultNull(optional any arg = null);
|
||||
void passSequenceOfAny(sequence<any> arg);
|
||||
void passNullableSequenceOfAny(sequence<any>? arg);
|
||||
void passOptionalSequenceOfAny(optional sequence<any> arg);
|
||||
void passOptionalNullableSequenceOfAny(optional sequence<any>? arg);
|
||||
void passOptionalSequenceOfAnyWithDefaultValue(optional sequence<any>? arg = null);
|
||||
void passSequenceOfSequenceOfAny(sequence<sequence<any>> arg);
|
||||
void passSequenceOfNullableSequenceOfAny(sequence<sequence<any>?> arg);
|
||||
void passNullableSequenceOfNullableSequenceOfAny(sequence<sequence<any>?>? arg);
|
||||
void passOptionalNullableSequenceOfNullableSequenceOfAny(optional sequence<sequence<any>?>? arg);
|
||||
any receiveAny();
|
||||
|
||||
// object types
|
||||
void passObject(object arg);
|
||||
void passVariadicObject(object... arg);
|
||||
void passNullableObject(object? arg);
|
||||
void passVariadicNullableObject(object... arg);
|
||||
void passOptionalObject(optional object arg);
|
||||
void passOptionalNullableObject(optional object? arg);
|
||||
void passOptionalNullableObjectWithDefaultValue(optional object? arg = null);
|
||||
void passSequenceOfObject(sequence<object> arg);
|
||||
void passSequenceOfNullableObject(sequence<object?> arg);
|
||||
void passOptionalNullableSequenceOfNullableSequenceOfObject(optional sequence<sequence<object>?>? arg);
|
||||
void passOptionalNullableSequenceOfNullableSequenceOfNullableObject(optional sequence<sequence<object?>?>? arg);
|
||||
object receiveObject();
|
||||
object? receiveNullableObject();
|
||||
|
||||
@ -343,9 +364,13 @@ interface TestExampleInterface {
|
||||
attribute byte attributeRenamedFrom;
|
||||
|
||||
void passDictionary(optional Dict x);
|
||||
//UNSUPPORTED Dict receiveDictionary();
|
||||
// FIXME: Bug 863949 no dictionary return values in callbacks
|
||||
// Dict receiveDictionary();
|
||||
// Dict? receiveNullableDictionary();
|
||||
void passOtherDictionary(optional GrandparentDict x);
|
||||
void passSequenceOfDictionaries(sequence<Dict> x);
|
||||
// No support for nullable dictionaries inside a sequence (nor should there be)
|
||||
// void passSequenceOfNullableDictionaries(sequence<Dict?> x);
|
||||
void passDictionaryOrLong(optional Dict x);
|
||||
void passDictionaryOrLong(long x);
|
||||
|
||||
|
@ -22,9 +22,9 @@ enum MyTestEnum {
|
||||
[Constructor(DOMString str, unsigned long num, boolean? boolArg,
|
||||
TestInterface? iface, long arg1,
|
||||
DictForConstructor dict, any any1,
|
||||
/* (BUG 856911) object obj1,*/
|
||||
object obj1,
|
||||
object? obj2, sequence<Dict> seq, optional any any2,
|
||||
/* (BUG 856911) optional object obj3, */
|
||||
optional object obj3,
|
||||
optional object? obj4),
|
||||
JSImplementation="@mozilla.org/test-js-impl-interface;1"]
|
||||
interface TestJSImplInterface {
|
||||
@ -252,9 +252,13 @@ interface TestJSImplInterface {
|
||||
sequence<DOMString> receiveStringSequence();
|
||||
// Callback interface problem. See bug 843261.
|
||||
//void passStringSequence(sequence<DOMString> arg);
|
||||
// "Can't handle sequence member 'any'; need to sort out rooting issues"
|
||||
//sequence<any> receiveAnySequence();
|
||||
//sequence<any>? receiveNullableAnySequence();
|
||||
sequence<any> receiveAnySequence();
|
||||
sequence<any>? receiveNullableAnySequence();
|
||||
//XXXbz No support for sequence of sequence return values yet.
|
||||
//sequence<sequence<any>> receiveAnySequenceSequence();
|
||||
|
||||
sequence<object> receiveObjectSequence();
|
||||
sequence<object?> receiveNullableObjectSequence();
|
||||
|
||||
void passSequenceOfSequences(sequence<sequence<long>> arg);
|
||||
//sequence<sequence<long>> receiveSequenceOfSequences();
|
||||
@ -318,18 +322,31 @@ interface TestJSImplInterface {
|
||||
|
||||
// Any types
|
||||
void passAny(any arg);
|
||||
void passVariadicAny(any... arg);
|
||||
void passOptionalAny(optional any arg);
|
||||
void passAnyDefaultNull(optional any arg = null);
|
||||
void passSequenceOfAny(sequence<any> arg);
|
||||
void passNullableSequenceOfAny(sequence<any>? arg);
|
||||
void passOptionalSequenceOfAny(optional sequence<any> arg);
|
||||
void passOptionalNullableSequenceOfAny(optional sequence<any>? arg);
|
||||
void passOptionalSequenceOfAnyWithDefaultValue(optional sequence<any>? arg = null);
|
||||
void passSequenceOfSequenceOfAny(sequence<sequence<any>> arg);
|
||||
void passSequenceOfNullableSequenceOfAny(sequence<sequence<any>?> arg);
|
||||
void passNullableSequenceOfNullableSequenceOfAny(sequence<sequence<any>?>? arg);
|
||||
void passOptionalNullableSequenceOfNullableSequenceOfAny(optional sequence<sequence<any>?>? arg);
|
||||
any receiveAny();
|
||||
|
||||
// object types. Unfortunately, non-nullable object is inconsistently
|
||||
// represented as either JSObject* (for callbacks) or JSObject& (for
|
||||
// non-callbacks), so we can't handle those yet. See bug 856911.
|
||||
//(BUG 856911) void passObject(object arg);
|
||||
void passObject(object arg);
|
||||
void passVariadicObject(object... arg);
|
||||
void passNullableObject(object? arg);
|
||||
//(BUG 856911) void passOptionalObject(optional object arg);
|
||||
void passVariadicNullableObject(object... arg);
|
||||
void passOptionalObject(optional object arg);
|
||||
void passOptionalNullableObject(optional object? arg);
|
||||
void passOptionalNullableObjectWithDefaultValue(optional object? arg = null);
|
||||
void passSequenceOfObject(sequence<object> arg);
|
||||
void passSequenceOfNullableObject(sequence<object?> arg);
|
||||
void passOptionalNullableSequenceOfNullableSequenceOfObject(optional sequence<sequence<object>?>? arg);
|
||||
void passOptionalNullableSequenceOfNullableSequenceOfNullableObject(optional sequence<sequence<object?>?>? arg);
|
||||
object receiveObject();
|
||||
object? receiveNullableObject();
|
||||
|
||||
@ -374,8 +391,11 @@ interface TestJSImplInterface {
|
||||
void passDictionary(optional Dict x);
|
||||
// FIXME: Bug 863949 no dictionary return values
|
||||
// Dict receiveDictionary();
|
||||
// Dict? receiveNullableDictionary();
|
||||
void passOtherDictionary(optional GrandparentDict x);
|
||||
void passSequenceOfDictionaries(sequence<Dict> x);
|
||||
// No support for nullable dictionaries inside a sequence (nor should there be)
|
||||
// void passSequenceOfNullableDictionaries(sequence<Dict?> x);
|
||||
void passDictionaryOrLong(optional Dict x);
|
||||
void passDictionaryOrLong(long x);
|
||||
|
||||
|
@ -1039,6 +1039,18 @@ nsGonkCameraControl::TakePictureComplete(uint8_t* aData, uint32_t aLength)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsGonkCameraControl::TakePictureError()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> takePictureError = new CameraErrorResult(mTakePictureOnErrorCb, NS_LITERAL_STRING("FAILURE"), mWindowId);
|
||||
mTakePictureOnSuccessCb = nullptr;
|
||||
mTakePictureOnErrorCb = nullptr;
|
||||
nsresult rv = NS_DispatchToMainThread(takePictureError);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to dispatch takePicture() onError callback to main thread!");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsGonkCameraControl::SetPreviewSize(uint32_t aWidth, uint32_t aHeight)
|
||||
{
|
||||
@ -1455,6 +1467,12 @@ ReceiveImage(nsGonkCameraControl* gc, uint8_t* aData, uint32_t aLength)
|
||||
gc->TakePictureComplete(aData, aLength);
|
||||
}
|
||||
|
||||
void
|
||||
ReceiveImageError(nsGonkCameraControl* gc)
|
||||
{
|
||||
gc->TakePictureError();
|
||||
}
|
||||
|
||||
void
|
||||
AutoFocusComplete(nsGonkCameraControl* gc, bool aSuccess)
|
||||
{
|
||||
|
@ -65,6 +65,7 @@ public:
|
||||
|
||||
void AutoFocusComplete(bool aSuccess);
|
||||
void TakePictureComplete(uint8_t* aData, uint32_t aLength);
|
||||
void TakePictureError();
|
||||
void HandleRecorderEvent(int msg, int ext1, int ext2);
|
||||
|
||||
protected:
|
||||
@ -127,6 +128,7 @@ private:
|
||||
|
||||
// camera driver callbacks
|
||||
void ReceiveImage(nsGonkCameraControl* gc, uint8_t* aData, uint32_t aLength);
|
||||
void ReceiveImageError(nsGonkCameraControl* gc);
|
||||
void AutoFocusComplete(nsGonkCameraControl* gc, bool aSuccess);
|
||||
void ReceiveFrame(nsGonkCameraControl* gc, layers::GraphicBufferLocked* aBuffer);
|
||||
void OnShutter(nsGonkCameraControl* gc);
|
||||
|
@ -88,7 +88,11 @@ GonkCameraHardware::postData(int32_t aMsgType, const sp<IMemory>& aDataPtr, came
|
||||
break;
|
||||
|
||||
case CAMERA_MSG_COMPRESSED_IMAGE:
|
||||
ReceiveImage(mTarget, (uint8_t*)aDataPtr->pointer(), aDataPtr->size());
|
||||
if (aDataPtr != nullptr) {
|
||||
ReceiveImage(mTarget, (uint8_t*)aDataPtr->pointer(), aDataPtr->size());
|
||||
} else {
|
||||
ReceiveImageError(mTarget);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -11,6 +11,7 @@ relativesrcdir = @relativesrcdir@
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MOCHITEST_FILES = \
|
||||
test_dataChannel_noOffer.html \
|
||||
test_getUserMedia_exceptions.html \
|
||||
test_getUserMedia_basicAudio.html \
|
||||
test_getUserMedia_basicVideo.html \
|
||||
|
33
dom/media/tests/mochitest/test_dataChannel_noOffer.html
Normal file
33
dom/media/tests/mochitest/test_dataChannel_noOffer.html
Normal file
@ -0,0 +1,33 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "856319",
|
||||
title: "Don't offer m=application unless createDataChannel is called first"
|
||||
});
|
||||
|
||||
runTest(function () {
|
||||
var pc = new mozRTCPeerConnection();
|
||||
|
||||
// necessary to circumvent bug 864109
|
||||
var options = { mandatory: { OfferToReceiveAudio: true} };
|
||||
|
||||
pc.createOffer(function (offer) {
|
||||
ok(!offer.sdp.contains("m=application"),
|
||||
"m=application is not contained in the SDP");
|
||||
|
||||
SimpleTest.finish();
|
||||
}, unexpectedCallbackAndFinish(new Error), options);
|
||||
}, true);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -377,9 +377,25 @@ nsPluginTag::GetClicktoplay(bool *aClicktoplay)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPluginTag::GetEnabledState(uint32_t *aEnabledState) {
|
||||
*aEnabledState = Preferences::GetInt(GetStatePrefNameForPlugin(this).get(),
|
||||
ePluginState_Enabled);
|
||||
return NS_OK;
|
||||
int32_t enabledState;
|
||||
nsresult rv = Preferences::GetInt(GetStatePrefNameForPlugin(this).get(),
|
||||
&enabledState);
|
||||
if (NS_SUCCEEDED(rv) &&
|
||||
enabledState >= nsIPluginTag::STATE_DISABLED &&
|
||||
enabledState <= nsIPluginTag::STATE_ENABLED) {
|
||||
*aEnabledState = (uint32_t)enabledState;
|
||||
return rv;
|
||||
}
|
||||
|
||||
enabledState = Preferences::GetInt("plugin.default.state",
|
||||
nsIPluginTag::STATE_ENABLED);
|
||||
if (enabledState >= nsIPluginTag::STATE_DISABLED &&
|
||||
enabledState <= nsIPluginTag::STATE_ENABLED) {
|
||||
*aEnabledState = (uint32_t)enabledState;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -42,16 +42,17 @@ function get_test_plugin() {
|
||||
}
|
||||
|
||||
// Finds the test nsIPluginTag
|
||||
function get_test_plugintag() {
|
||||
function get_test_plugintag(aName) {
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
var name = aName || "Test Plug-in";
|
||||
var host = Cc["@mozilla.org/plugin/host;1"].
|
||||
getService(Ci.nsIPluginHost);
|
||||
var tags = host.getPluginTags();
|
||||
|
||||
for (var i = 0; i < tags.length; i++) {
|
||||
if (tags[i].name == "Test Plug-in")
|
||||
if (tags[i].name == name)
|
||||
return tags[i];
|
||||
}
|
||||
return null;
|
||||
|
30
dom/plugins/test/unit/test_plugin_default_state.js
Normal file
30
dom/plugins/test/unit/test_plugin_default_state.js
Normal file
@ -0,0 +1,30 @@
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function run_test() {
|
||||
let pluginDefaultState = Services.prefs.getIntPref("plugin.default.state");
|
||||
// if this fails, we just have to switch around the values we're testing
|
||||
do_check_neq(pluginDefaultState, Ci.nsIPluginTag.STATE_DISABLED);
|
||||
let nonDefaultState = (pluginDefaultState != Ci.nsIPluginTag.STATE_ENABLED ?
|
||||
Ci.nsIPluginTag.STATE_ENABLED :
|
||||
Ci.nsIPluginTag.STATE_CLICKTOPLAY);
|
||||
let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
|
||||
let testPlugin = get_test_plugintag();
|
||||
// the test plugin should have the default enabledState
|
||||
do_check_eq(testPlugin.enabledState, pluginDefaultState);
|
||||
|
||||
let secondTestPlugin = get_test_plugintag("Second Test Plug-in");
|
||||
// set an enabledState for the second test plugin
|
||||
secondTestPlugin.enabledState = Ci.nsIPluginTag.STATE_DISABLED;
|
||||
// change what the default enabledState is
|
||||
Services.prefs.setIntPref("plugin.default.state", nonDefaultState);
|
||||
// the test plugin should follow the default (it has no individual pref yet)
|
||||
do_check_eq(testPlugin.enabledState, nonDefaultState);
|
||||
// the second test plugin should retain its preferred state
|
||||
do_check_eq(secondTestPlugin.enabledState, Ci.nsIPluginTag.STATE_DISABLED);
|
||||
|
||||
// clean up
|
||||
testPlugin.enabledState = pluginDefaultState;
|
||||
secondTestPlugin.enabledState = pluginDefaultState;
|
||||
Services.prefs.clearUserPref("plugin.default.state");
|
||||
Services.prefs.clearUserPref("plugin.importedState");
|
||||
}
|
@ -16,3 +16,4 @@ fail-if = os == "android"
|
||||
fail-if = os == "android"
|
||||
[test_persist_in_prefs.js]
|
||||
[test_bug854467.js]
|
||||
[test_plugin_default_state.js]
|
||||
|
@ -46,9 +46,9 @@ public:
|
||||
bool aCapture, ErrorResult& aRv);
|
||||
|
||||
bool
|
||||
DispatchEvent(JSObject& aEvent, ErrorResult& aRv) const
|
||||
DispatchEvent(JS::Handle<JSObject*> aEvent, ErrorResult& aRv) const
|
||||
{
|
||||
return mListenerManager.DispatchEvent(GetJSContext(), *this, &aEvent, aRv);
|
||||
return mListenerManager.DispatchEvent(GetJSContext(), *this, aEvent, aRv);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
|
@ -71,10 +71,10 @@ FileReaderSync::Constructor(const WorkerGlobalObject& aGlobal, ErrorResult& aRv)
|
||||
}
|
||||
|
||||
JSObject*
|
||||
FileReaderSync::ReadAsArrayBuffer(JSContext* aCx, JSObject& aBlob,
|
||||
FileReaderSync::ReadAsArrayBuffer(JSContext* aCx, JS::Handle<JSObject*> aBlob,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(&aBlob);
|
||||
nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aBlob);
|
||||
if (!blob) {
|
||||
aRv.Throw(NS_ERROR_INVALID_ARG);
|
||||
return nullptr;
|
||||
@ -117,10 +117,11 @@ FileReaderSync::ReadAsArrayBuffer(JSContext* aCx, JSObject& aBlob,
|
||||
}
|
||||
|
||||
void
|
||||
FileReaderSync::ReadAsBinaryString(JSObject& aBlob, nsAString& aResult,
|
||||
FileReaderSync::ReadAsBinaryString(JS::Handle<JSObject*> aBlob,
|
||||
nsAString& aResult,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(&aBlob);
|
||||
nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aBlob);
|
||||
if (!blob) {
|
||||
aRv.Throw(NS_ERROR_INVALID_ARG);
|
||||
return;
|
||||
@ -152,12 +153,12 @@ FileReaderSync::ReadAsBinaryString(JSObject& aBlob, nsAString& aResult,
|
||||
}
|
||||
|
||||
void
|
||||
FileReaderSync::ReadAsText(JSObject& aBlob,
|
||||
FileReaderSync::ReadAsText(JS::Handle<JSObject*> aBlob,
|
||||
const Optional<nsAString>& aEncoding,
|
||||
nsAString& aResult,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(&aBlob);
|
||||
nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aBlob);
|
||||
if (!blob) {
|
||||
aRv.Throw(NS_ERROR_INVALID_ARG);
|
||||
return;
|
||||
@ -208,10 +209,10 @@ FileReaderSync::ReadAsText(JSObject& aBlob,
|
||||
}
|
||||
|
||||
void
|
||||
FileReaderSync::ReadAsDataURL(JSObject& aBlob, nsAString& aResult,
|
||||
FileReaderSync::ReadAsDataURL(JS::Handle<JSObject*> aBlob, nsAString& aResult,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(&aBlob);
|
||||
nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aBlob);
|
||||
if (!blob) {
|
||||
aRv.Throw(NS_ERROR_INVALID_ARG);
|
||||
return;
|
||||
|
@ -42,13 +42,15 @@ public:
|
||||
|
||||
FileReaderSync(JSContext* aCx);
|
||||
|
||||
JSObject* ReadAsArrayBuffer(JSContext* aCx, JSObject& aBlob,
|
||||
JSObject* ReadAsArrayBuffer(JSContext* aCx, JS::Handle<JSObject*> aBlob,
|
||||
ErrorResult& aRv);
|
||||
void ReadAsBinaryString(JSObject& aBlob, nsAString& aResult,
|
||||
void ReadAsBinaryString(JS::Handle<JSObject*> aBlob, nsAString& aResult,
|
||||
ErrorResult& aRv);
|
||||
void ReadAsText(JSObject& aBlob, const Optional<nsAString>& aEncoding,
|
||||
void ReadAsText(JS::Handle<JSObject*> aBlob,
|
||||
const Optional<nsAString>& aEncoding,
|
||||
nsAString& aResult, ErrorResult& aRv);
|
||||
void ReadAsDataURL(JSObject& aBlob, nsAString& aResult, ErrorResult& aRv);
|
||||
void ReadAsDataURL(JS::Handle<JSObject*> aBlob, nsAString& aResult,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// From nsICharsetDetectionObserver
|
||||
NS_IMETHOD Notify(const char *aCharset, nsDetectionConfident aConf);
|
||||
|
@ -241,7 +241,7 @@ public:
|
||||
}
|
||||
|
||||
JS::Value
|
||||
GetInterface(JSContext* cx, JSObject& aIID, ErrorResult& aRv)
|
||||
GetInterface(JSContext* cx, JS::Handle<JSObject*> aIID, ErrorResult& aRv)
|
||||
{
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return JSVAL_NULL;
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
#include "nsIWindowsRegKey.h"
|
||||
|
||||
#include "harfbuzz/hb.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
#define LOG_FONTLIST(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
|
||||
@ -264,8 +266,8 @@ UsingArabicOrHebrewScriptSystemLocale()
|
||||
}
|
||||
|
||||
nsresult
|
||||
gfxDWriteFontEntry::GetFontTable(uint32_t aTableTag,
|
||||
FallibleTArray<uint8_t> &aBuffer)
|
||||
gfxDWriteFontEntry::CopyFontTable(uint32_t aTableTag,
|
||||
FallibleTArray<uint8_t> &aBuffer)
|
||||
{
|
||||
gfxDWriteFontList *pFontList = gfxDWriteFontList::PlatformFontList();
|
||||
|
||||
@ -301,12 +303,8 @@ gfxDWriteFontEntry::GetFontTable(uint32_t aTableTag,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
nsresult rv;
|
||||
nsRefPtr<IDWriteFontFace> fontFace;
|
||||
|
||||
rv = CreateFontFace(getter_AddRefs(fontFace));
|
||||
|
||||
nsresult rv = CreateFontFace(getter_AddRefs(fontFace));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
@ -315,29 +313,83 @@ gfxDWriteFontEntry::GetFontTable(uint32_t aTableTag,
|
||||
uint32_t len;
|
||||
void *tableContext = NULL;
|
||||
BOOL exists;
|
||||
hr = fontFace->TryGetFontTable(NativeEndian::swapToBigEndian(aTableTag),
|
||||
(const void**)&tableData,
|
||||
&len,
|
||||
&tableContext,
|
||||
&exists);
|
||||
|
||||
HRESULT hr =
|
||||
fontFace->TryGetFontTable(NativeEndian::swapToBigEndian(aTableTag),
|
||||
(const void**)&tableData, &len,
|
||||
&tableContext, &exists);
|
||||
if (FAILED(hr) || !exists) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (!aBuffer.SetLength(len)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
if (aBuffer.SetLength(len)) {
|
||||
memcpy(aBuffer.Elements(), tableData, len);
|
||||
rv = NS_OK;
|
||||
} else {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
memcpy(aBuffer.Elements(), tableData, len);
|
||||
|
||||
if (tableContext) {
|
||||
fontFace->ReleaseFontTable(&tableContext);
|
||||
}
|
||||
return NS_OK;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Access to font tables packaged in hb_blob_t form
|
||||
|
||||
// object attached to the Harfbuzz blob, used to release
|
||||
// the table when the blob is destroyed
|
||||
class FontTableRec {
|
||||
public:
|
||||
FontTableRec(IDWriteFontFace *aFontFace, void *aContext)
|
||||
: mFontFace(aFontFace), mContext(aContext)
|
||||
{ }
|
||||
|
||||
~FontTableRec() {
|
||||
mFontFace->ReleaseFontTable(mContext);
|
||||
}
|
||||
|
||||
private:
|
||||
IDWriteFontFace *mFontFace;
|
||||
void *mContext;
|
||||
};
|
||||
|
||||
static void
|
||||
DestroyBlobFunc(void* aUserData)
|
||||
{
|
||||
FontTableRec *ftr = static_cast<FontTableRec*>(aUserData);
|
||||
delete ftr;
|
||||
}
|
||||
|
||||
hb_blob_t *
|
||||
gfxDWriteFontEntry::GetFontTable(uint32_t aTag)
|
||||
{
|
||||
// try to avoid potentially expensive DWrite call if we haven't actually
|
||||
// created the font face yet, by using the gfxFontEntry method that will
|
||||
// use CopyFontTable and then cache the data
|
||||
if (!mFontFace) {
|
||||
return gfxFontEntry::GetFontTable(aTag);
|
||||
}
|
||||
|
||||
const void *data;
|
||||
UINT32 size;
|
||||
void *context;
|
||||
BOOL exists;
|
||||
HRESULT hr = mFontFace->TryGetFontTable(NativeEndian::swapToBigEndian(aTag),
|
||||
&data, &size, &context, &exists);
|
||||
if (SUCCEEDED(hr) && exists) {
|
||||
FontTableRec *ftr = new FontTableRec(mFontFace, context);
|
||||
return hb_blob_create(static_cast<const char*>(data), size,
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
ftr, DestroyBlobFunc);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
gfxDWriteFontEntry::ReadCMAP()
|
||||
{
|
||||
HRESULT hr;
|
||||
nsresult rv;
|
||||
|
||||
// attempt this once, if errors occur leave a blank cmap
|
||||
@ -347,47 +399,17 @@ gfxDWriteFontEntry::ReadCMAP()
|
||||
|
||||
nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
|
||||
|
||||
// if loading via GDI, just use GetFontTable
|
||||
if (mFont && gfxDWriteFontList::PlatformFontList()->UseGDIFontTableAccess()) {
|
||||
uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
|
||||
|
||||
AutoFallibleTArray<uint8_t,16384> cmap;
|
||||
rv = GetFontTable(kCMAP, cmap);
|
||||
|
||||
uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
|
||||
AutoTable cmapTable(this, kCMAP);
|
||||
if (cmapTable) {
|
||||
bool unicodeFont = false, symbolFont = false; // currently ignored
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(),
|
||||
*charmap, mUVSOffset,
|
||||
unicodeFont, symbolFont);
|
||||
}
|
||||
} else {
|
||||
// loading using dwrite, don't use GetFontTable to avoid copy
|
||||
nsRefPtr<IDWriteFontFace> fontFace;
|
||||
rv = CreateFontFace(getter_AddRefs(fontFace));
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
const uint32_t kCmapTag = DWRITE_MAKE_OPENTYPE_TAG('c', 'm', 'a', 'p');
|
||||
uint8_t *tableData;
|
||||
uint32_t len;
|
||||
void *tableContext = NULL;
|
||||
BOOL exists;
|
||||
hr = fontFace->TryGetFontTable(kCmapTag, (const void**)&tableData,
|
||||
&len, &tableContext, &exists);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
bool isSymbol = fontFace->IsSymbolFont();
|
||||
bool isUnicode = true;
|
||||
if (exists) {
|
||||
rv = gfxFontUtils::ReadCMAP(tableData, len, *charmap,
|
||||
mUVSOffset, isUnicode,
|
||||
isSymbol);
|
||||
}
|
||||
fontFace->ReleaseFontTable(tableContext);
|
||||
} else {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
uint32_t cmapLen;
|
||||
const uint8_t* cmapData =
|
||||
reinterpret_cast<const uint8_t*>(hb_blob_get_data(cmapTable,
|
||||
&cmapLen));
|
||||
rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen,
|
||||
*charmap, mUVSOffset,
|
||||
unicodeFont, symbolFont);
|
||||
}
|
||||
|
||||
mHasCmapTable = NS_SUCCEEDED(rv);
|
||||
@ -426,52 +448,60 @@ nsresult
|
||||
gfxDWriteFontEntry::CreateFontFace(IDWriteFontFace **aFontFace,
|
||||
DWRITE_FONT_SIMULATIONS aSimulations)
|
||||
{
|
||||
HRESULT hr;
|
||||
if (mFont) {
|
||||
hr = mFont->CreateFontFace(aFontFace);
|
||||
if (SUCCEEDED(hr) && (aSimulations & DWRITE_FONT_SIMULATIONS_BOLD) &&
|
||||
!((*aFontFace)->GetSimulations() & DWRITE_FONT_SIMULATIONS_BOLD)) {
|
||||
// need to replace aFontFace with a version that has the Bold
|
||||
// simulation - unfortunately, DWrite doesn't provide a simple API
|
||||
// for this
|
||||
nsRefPtr<IDWriteFontFace> origFace = (*aFontFace);
|
||||
(*aFontFace)->Release();
|
||||
*aFontFace = NULL;
|
||||
UINT32 numberOfFiles = 0;
|
||||
hr = origFace->GetFiles(&numberOfFiles, NULL);
|
||||
if (FAILED(hr)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsAutoTArray<IDWriteFontFile*,1> files;
|
||||
files.AppendElements(numberOfFiles);
|
||||
hr = origFace->GetFiles(&numberOfFiles, files.Elements());
|
||||
if (FAILED(hr)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// initialize mFontFace if this hasn't been done before
|
||||
if (!mFontFace) {
|
||||
HRESULT hr;
|
||||
if (mFont) {
|
||||
hr = mFont->CreateFontFace(getter_AddRefs(mFontFace));
|
||||
} else if (mFontFile) {
|
||||
IDWriteFontFile *fontFile = mFontFile.get();
|
||||
hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
|
||||
CreateFontFace(origFace->GetType(),
|
||||
numberOfFiles,
|
||||
files.Elements(),
|
||||
origFace->GetIndex(),
|
||||
aSimulations,
|
||||
aFontFace);
|
||||
for (UINT32 i = 0; i < numberOfFiles; ++i) {
|
||||
files[i]->Release();
|
||||
}
|
||||
CreateFontFace(mFaceType,
|
||||
1,
|
||||
&fontFile,
|
||||
0,
|
||||
DWRITE_FONT_SIMULATIONS_NONE,
|
||||
getter_AddRefs(mFontFace));
|
||||
} else {
|
||||
NS_NOTREACHED("invalid font entry");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
} else if (mFontFile) {
|
||||
IDWriteFontFile *fontFile = mFontFile.get();
|
||||
hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
|
||||
CreateFontFace(mFaceType,
|
||||
1,
|
||||
&fontFile,
|
||||
0,
|
||||
if (FAILED(hr)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// check whether we need to add a DWrite simulated style
|
||||
if ((aSimulations & DWRITE_FONT_SIMULATIONS_BOLD) &&
|
||||
!(mFontFace->GetSimulations() & DWRITE_FONT_SIMULATIONS_BOLD)) {
|
||||
// if so, we need to return not mFontFace itself but a version that
|
||||
// has the Bold simulation - unfortunately, DWrite doesn't provide
|
||||
// a simple API for this
|
||||
UINT32 numberOfFiles = 0;
|
||||
if (FAILED(mFontFace->GetFiles(&numberOfFiles, NULL))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsAutoTArray<IDWriteFontFile*,1> files;
|
||||
files.AppendElements(numberOfFiles);
|
||||
if (FAILED(mFontFace->GetFiles(&numberOfFiles, files.Elements()))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
HRESULT hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
|
||||
CreateFontFace(mFontFace->GetType(),
|
||||
numberOfFiles,
|
||||
files.Elements(),
|
||||
mFontFace->GetIndex(),
|
||||
aSimulations,
|
||||
aFontFace);
|
||||
for (UINT32 i = 0; i < numberOfFiles; ++i) {
|
||||
files[i]->Release();
|
||||
}
|
||||
return FAILED(hr) ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
if (FAILED(hr)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// no simulation: we can just add a reference to mFontFace and return that
|
||||
*aFontFace = mFontFace;
|
||||
(*aFontFace)->AddRef();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -498,7 +528,7 @@ gfxDWriteFontEntry::IsCJKFont()
|
||||
|
||||
const uint32_t kOS2Tag = TRUETYPE_TAG('O','S','/','2');
|
||||
AutoFallibleTArray<uint8_t,128> buffer;
|
||||
if (GetFontTable(kOS2Tag, buffer) != NS_OK) {
|
||||
if (CopyFontTable(kOS2Tag, buffer) != NS_OK) {
|
||||
return mIsCJK;
|
||||
}
|
||||
|
||||
|
@ -143,8 +143,7 @@ public:
|
||||
|
||||
virtual bool IsSymbolFont();
|
||||
|
||||
virtual nsresult GetFontTable(uint32_t aTableTag,
|
||||
FallibleTArray<uint8_t>& aBuffer);
|
||||
virtual hb_blob_t* GetFontTable(uint32_t aTableTag) MOZ_OVERRIDE;
|
||||
|
||||
nsresult ReadCMAP();
|
||||
|
||||
@ -162,6 +161,9 @@ protected:
|
||||
friend class gfxDWriteFont;
|
||||
friend class gfxDWriteFontList;
|
||||
|
||||
virtual nsresult CopyFontTable(uint32_t aTableTag,
|
||||
FallibleTArray<uint8_t>& aBuffer) MOZ_OVERRIDE;
|
||||
|
||||
virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle,
|
||||
bool aNeedsBold);
|
||||
|
||||
@ -177,6 +179,11 @@ protected:
|
||||
*/
|
||||
nsRefPtr<IDWriteFont> mFont;
|
||||
nsRefPtr<IDWriteFontFile> mFontFile;
|
||||
|
||||
// font face corresponding to the mFont/mFontFile *without* any DWrite
|
||||
// style simulations applied
|
||||
nsRefPtr<IDWriteFontFace> mFontFace;
|
||||
|
||||
DWRITE_FONT_FACE_TYPE mFaceType;
|
||||
|
||||
int8_t mIsCJK;
|
||||
|
@ -19,6 +19,7 @@
|
||||
// Chosen this as to resemble DWrite's own oblique face style.
|
||||
#define OBLIQUE_SKEW_FACTOR 0.3
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
// This is also in gfxGDIFont.cpp. Would be nice to put it somewhere common,
|
||||
@ -229,24 +230,16 @@ gfxDWriteFont::ComputeMetrics(AntialiasOption anAAOption)
|
||||
mMetrics->maxAdvance = mAdjustedSize;
|
||||
|
||||
// try to get the true maxAdvance value from 'hhea'
|
||||
uint8_t *tableData;
|
||||
uint32_t len;
|
||||
void *tableContext = NULL;
|
||||
BOOL exists;
|
||||
HRESULT hr =
|
||||
mFontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('h', 'h', 'e', 'a'),
|
||||
(const void**)&tableData,
|
||||
&len,
|
||||
&tableContext,
|
||||
&exists);
|
||||
if (SUCCEEDED(hr)) {
|
||||
if (exists && len >= sizeof(mozilla::HheaTable)) {
|
||||
const mozilla::HheaTable* hhea =
|
||||
reinterpret_cast<const mozilla::HheaTable*>(tableData);
|
||||
gfxFontEntry::AutoTable hheaTable(GetFontEntry(),
|
||||
TRUETYPE_TAG('h','h','e','a'));
|
||||
if (hheaTable) {
|
||||
uint32_t len;
|
||||
const HheaTable* hhea =
|
||||
reinterpret_cast<const HheaTable*>(hb_blob_get_data(hheaTable, &len));
|
||||
if (len >= sizeof(HheaTable)) {
|
||||
mMetrics->maxAdvance =
|
||||
uint16_t(hhea->advanceWidthMax) * mFUnitsConvFactor;
|
||||
}
|
||||
mFontFace->ReleaseFontTable(tableContext);
|
||||
}
|
||||
|
||||
mMetrics->internalLeading = std::max(mMetrics->maxHeight - mMetrics->emHeight, 0.0);
|
||||
@ -259,22 +252,19 @@ gfxDWriteFont::ComputeMetrics(AntialiasOption anAAOption)
|
||||
// if the table is not available or if using hinted/pixel-snapped widths
|
||||
if (mUseSubpixelPositions) {
|
||||
mMetrics->aveCharWidth = 0;
|
||||
hr = mFontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('O', 'S', '/', '2'),
|
||||
(const void**)&tableData,
|
||||
&len,
|
||||
&tableContext,
|
||||
&exists);
|
||||
if (SUCCEEDED(hr)) {
|
||||
if (exists && len >= 4) {
|
||||
gfxFontEntry::AutoTable os2Table(GetFontEntry(),
|
||||
TRUETYPE_TAG('O','S','/','2'));
|
||||
if (os2Table) {
|
||||
uint32_t len;
|
||||
const OS2Table* os2 =
|
||||
reinterpret_cast<const OS2Table*>(hb_blob_get_data(os2Table, &len));
|
||||
if (len >= 4) {
|
||||
// Not checking against sizeof(mozilla::OS2Table) here because older
|
||||
// versions of the table have different sizes; we only need the first
|
||||
// two 16-bit fields here.
|
||||
const mozilla::OS2Table* os2 =
|
||||
reinterpret_cast<const mozilla::OS2Table*>(tableData);
|
||||
mMetrics->aveCharWidth =
|
||||
int16_t(os2->xAvgCharWidth) * mFUnitsConvFactor;
|
||||
}
|
||||
mFontFace->ReleaseFontTable(tableContext);
|
||||
}
|
||||
}
|
||||
|
||||
@ -601,60 +591,6 @@ gfxDWriteFont::Measure(gfxTextRun *aTextRun,
|
||||
return metrics;
|
||||
}
|
||||
|
||||
// Access to font tables packaged in hb_blob_t form
|
||||
|
||||
// object attached to the Harfbuzz blob, used to release
|
||||
// the table when the blob is destroyed
|
||||
class FontTableRec {
|
||||
public:
|
||||
FontTableRec(IDWriteFontFace *aFontFace, void *aContext)
|
||||
: mFontFace(aFontFace), mContext(aContext)
|
||||
{ }
|
||||
|
||||
~FontTableRec() {
|
||||
mFontFace->ReleaseFontTable(mContext);
|
||||
}
|
||||
|
||||
private:
|
||||
IDWriteFontFace *mFontFace;
|
||||
void *mContext;
|
||||
};
|
||||
|
||||
/*static*/ void
|
||||
gfxDWriteFont::DestroyBlobFunc(void* aUserData)
|
||||
{
|
||||
FontTableRec *ftr = static_cast<FontTableRec*>(aUserData);
|
||||
delete ftr;
|
||||
}
|
||||
|
||||
hb_blob_t *
|
||||
gfxDWriteFont::GetFontTable(uint32_t aTag)
|
||||
{
|
||||
const void *data;
|
||||
UINT32 size;
|
||||
void *context;
|
||||
BOOL exists;
|
||||
HRESULT hr = mFontFace->TryGetFontTable(mozilla::NativeEndian::swapToBigEndian(aTag),
|
||||
&data, &size, &context, &exists);
|
||||
if (SUCCEEDED(hr) && exists) {
|
||||
FontTableRec *ftr = new FontTableRec(mFontFace, context);
|
||||
return hb_blob_create(static_cast<const char*>(data), size,
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
ftr, DestroyBlobFunc);
|
||||
}
|
||||
|
||||
if (mFontEntry->IsUserFont() && !mFontEntry->IsLocalUserFont()) {
|
||||
// for downloaded fonts, there may be layout tables cached in the entry
|
||||
// even though they're absent from the sanitized platform font
|
||||
hb_blob_t *blob;
|
||||
if (mFontEntry->GetExistingFontTable(aTag, &blob)) {
|
||||
return blob;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
gfxDWriteFont::ProvidesGlyphWidths()
|
||||
{
|
||||
|
@ -52,10 +52,6 @@ public:
|
||||
gfxContext *aContextForTightBoundingBox,
|
||||
Spacing *aSpacing);
|
||||
|
||||
// override gfxFont table access function to bypass gfxFontEntry cache,
|
||||
// use DWrite API to get direct access to system font data
|
||||
virtual hb_blob_t *GetFontTable(uint32_t aTag);
|
||||
|
||||
virtual bool ProvidesGlyphWidths();
|
||||
|
||||
virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID);
|
||||
@ -88,8 +84,6 @@ protected:
|
||||
|
||||
gfxFloat MeasureGlyphWidth(uint16_t aGlyph);
|
||||
|
||||
static void DestroyBlobFunc(void* userArg);
|
||||
|
||||
DWRITE_MEASURING_MODE GetMeasuringMode();
|
||||
bool GetForceGDIClassic();
|
||||
|
||||
|
@ -146,22 +146,6 @@ gfxFT2FontBase::GetSpaceGlyph()
|
||||
return mSpaceGlyph;
|
||||
}
|
||||
|
||||
hb_blob_t *
|
||||
gfxFT2FontBase::GetFontTable(uint32_t aTag)
|
||||
{
|
||||
hb_blob_t *blob;
|
||||
if (mFontEntry->GetExistingFontTable(aTag, &blob))
|
||||
return blob;
|
||||
|
||||
FallibleTArray<uint8_t> buffer;
|
||||
bool haveTable = gfxFT2LockedFace(this).GetFontTable(aTag, buffer);
|
||||
|
||||
// Cache even when there is no table to save having to open the FT_Face
|
||||
// again.
|
||||
return mFontEntry->ShareFontTableAndGetBlob(aTag,
|
||||
haveTable ? &buffer : nullptr);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
gfxFT2FontBase::GetGlyph(uint32_t unicode, uint32_t variation_selector)
|
||||
{
|
||||
|
@ -23,7 +23,6 @@ public:
|
||||
cairo_text_extents_t* aExtents);
|
||||
virtual const gfxFont::Metrics& GetMetrics();
|
||||
virtual uint32_t GetSpaceGlyph();
|
||||
virtual hb_blob_t *GetFontTable(uint32_t aTag);
|
||||
virtual bool ProvidesGetGlyph() const { return true; }
|
||||
virtual uint32_t GetGlyph(uint32_t unicode, uint32_t variation_selector);
|
||||
virtual bool ProvidesGlyphWidths() { return true; }
|
||||
|
@ -416,7 +416,7 @@ FT2FontEntry::ReadCMAP()
|
||||
nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
|
||||
|
||||
AutoFallibleTArray<uint8_t,16384> buffer;
|
||||
nsresult rv = GetFontTable(TTAG_cmap, buffer);
|
||||
nsresult rv = CopyFontTable(TTAG_cmap, buffer);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
bool unicodeFont;
|
||||
@ -438,8 +438,8 @@ FT2FontEntry::ReadCMAP()
|
||||
}
|
||||
|
||||
nsresult
|
||||
FT2FontEntry::GetFontTable(uint32_t aTableTag,
|
||||
FallibleTArray<uint8_t>& aBuffer)
|
||||
FT2FontEntry::CopyFontTable(uint32_t aTableTag,
|
||||
FallibleTArray<uint8_t>& aBuffer)
|
||||
{
|
||||
AutoFTFace face(this);
|
||||
if (!face) {
|
||||
|
@ -66,7 +66,9 @@ public:
|
||||
cairo_scaled_font_t *CreateScaledFont(const gfxFontStyle *aStyle);
|
||||
|
||||
nsresult ReadCMAP();
|
||||
nsresult GetFontTable(uint32_t aTableTag, FallibleTArray<uint8_t>& aBuffer);
|
||||
|
||||
virtual nsresult CopyFontTable(uint32_t aTableTag,
|
||||
FallibleTArray<uint8_t>& aBuffer) MOZ_OVERRIDE;
|
||||
|
||||
// Check for various kinds of brokenness, and set flags on the entry
|
||||
// accordingly so that we avoid using bad font tables
|
||||
|
@ -318,31 +318,6 @@ gfxFT2LockedFace::GetUVSGlyph(uint32_t aCharCode, uint32_t aVariantSelector)
|
||||
return (*sGetCharVariantPtr)(mFace, aCharCode, aVariantSelector);
|
||||
}
|
||||
|
||||
bool
|
||||
gfxFT2LockedFace::GetFontTable(uint32_t aTag, FallibleTArray<uint8_t>& aBuffer)
|
||||
{
|
||||
if (!mFace || !FT_IS_SFNT(mFace))
|
||||
return false;
|
||||
|
||||
FT_ULong length = 0;
|
||||
// TRUETYPE_TAG is defined equivalent to FT_MAKE_TAG
|
||||
FT_Error error = FT_Load_Sfnt_Table(mFace, aTag, 0, NULL, &length);
|
||||
if (error != 0)
|
||||
return false;
|
||||
|
||||
if (MOZ_UNLIKELY(length > static_cast<FallibleTArray<uint8_t>::size_type>(-1))
|
||||
|| MOZ_UNLIKELY(!aBuffer.SetLength(length)))
|
||||
return false;
|
||||
|
||||
error = FT_Load_Sfnt_Table(mFace, aTag, 0, aBuffer.Elements(), &length);
|
||||
if (MOZ_UNLIKELY(error != 0)) {
|
||||
aBuffer.Clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
gfxFT2LockedFace::GetCharExtents(char aChar, cairo_text_extents_t* aExtents)
|
||||
{
|
||||
|
@ -48,8 +48,6 @@ public:
|
||||
|
||||
void GetMetrics(gfxFont::Metrics* aMetrics, uint32_t* aSpaceGlyph);
|
||||
|
||||
bool GetFontTable(uint32_t aTag, FallibleTArray<uint8_t>& aBuffer);
|
||||
|
||||
// A scale factor for use in converting horizontal metrics from font units
|
||||
// to pixels.
|
||||
gfxFloat XScale()
|
||||
|
@ -45,6 +45,7 @@
|
||||
|
||||
#include "harfbuzz/hb.h"
|
||||
#include "harfbuzz/hb-ot.h"
|
||||
#include "graphite2/Font.h"
|
||||
|
||||
#include "nsCRT.h"
|
||||
#include "GeckoProfiler.h"
|
||||
@ -95,6 +96,12 @@ gfxFontEntry::~gfxFontEntry()
|
||||
gfxUserFontSet::UserFontCache::ForgetFont(this);
|
||||
}
|
||||
|
||||
// By the time the entry is destroyed, all font instances that were
|
||||
// using it should already have been deleted, and so the HB and/or Gr
|
||||
// face objects should have been released.
|
||||
MOZ_ASSERT(!mHBFace);
|
||||
MOZ_ASSERT(!mGrFaceInitialized);
|
||||
|
||||
if (mSVGGlyphs) {
|
||||
delete mSVGGlyphs;
|
||||
}
|
||||
@ -130,17 +137,19 @@ nsresult gfxFontEntry::InitializeUVSMap()
|
||||
|
||||
if (!mUVSData) {
|
||||
const uint32_t kCmapTag = TRUETYPE_TAG('c','m','a','p');
|
||||
AutoFallibleTArray<uint8_t,16384> buffer;
|
||||
if (GetFontTable(kCmapTag, buffer) != NS_OK) {
|
||||
AutoTable cmapTable(this, kCmapTag);
|
||||
if (!cmapTable) {
|
||||
mUVSOffset = 0; // don't bother to read the table again
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
uint8_t* uvsData;
|
||||
unsigned int cmapLen;
|
||||
const char* cmapData = hb_blob_get_data(cmapTable, &cmapLen);
|
||||
nsresult rv = gfxFontUtils::ReadCMAPTableFormat14(
|
||||
buffer.Elements() + mUVSOffset,
|
||||
buffer.Length() - mUVSOffset,
|
||||
uvsData);
|
||||
(const uint8_t*)cmapData + mUVSOffset,
|
||||
cmapLen - mUVSOffset, uvsData);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
mUVSOffset = 0; // don't bother to read the table again
|
||||
return rv;
|
||||
@ -173,11 +182,10 @@ nsresult gfxFontEntry::ReadCMAP()
|
||||
nsString
|
||||
gfxFontEntry::RealFaceName()
|
||||
{
|
||||
FallibleTArray<uint8_t> nameTable;
|
||||
nsresult rv = GetFontTable(TRUETYPE_TAG('n','a','m','e'), nameTable);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
AutoTable nameTable(this, TRUETYPE_TAG('n','a','m','e'));
|
||||
if (nameTable) {
|
||||
nsAutoString name;
|
||||
rv = gfxFontUtils::GetFullNameFromTable(nameTable, name);
|
||||
nsresult rv = gfxFontUtils::GetFullNameFromTable(nameTable, name);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return name;
|
||||
}
|
||||
@ -241,28 +249,29 @@ gfxFontEntry::RenderSVGGlyph(gfxContext *aContext, uint32_t aGlyphId,
|
||||
bool
|
||||
gfxFontEntry::TryGetSVGData()
|
||||
{
|
||||
if (!gfxPlatform::GetPlatform()->OpenTypeSVGEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mSVGInitialized) {
|
||||
mSVGInitialized = true;
|
||||
|
||||
bool svgEnabled;
|
||||
nsresult rv =
|
||||
Preferences::GetBool("gfx.font_rendering.opentype_svg.enabled",
|
||||
&svgEnabled);
|
||||
|
||||
if (NS_FAILED(rv) || !svgEnabled) {
|
||||
// We don't use AutoTable here because we'll pass ownership of these
|
||||
// blobs to the gfxSVGGlyphs, once we've confirmed the tables exist
|
||||
hb_blob_t *svgTable = GetFontTable(TRUETYPE_TAG('S','V','G',' '));
|
||||
if (!svgTable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FallibleTArray<uint8_t> svgTable;
|
||||
rv = GetFontTable(TRUETYPE_TAG('S', 'V', 'G', ' '), svgTable);
|
||||
if (NS_FAILED(rv)) {
|
||||
hb_blob_t *cmapTable = GetFontTable(TRUETYPE_TAG('c','m','a','p'));
|
||||
if (!cmapTable) {
|
||||
NS_NOTREACHED("using a font with no cmap!");
|
||||
hb_blob_destroy(svgTable);
|
||||
return false;
|
||||
}
|
||||
|
||||
FallibleTArray<uint8_t> cmapTable;
|
||||
rv = GetFontTable(TRUETYPE_TAG('c', 'm', 'a', 'p'), cmapTable);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
// gfxSVGGlyphs will hb_blob_destroy() the tables when it is finished
|
||||
// with them.
|
||||
mSVGGlyphs = new gfxSVGGlyphs(svgTable, cmapTable);
|
||||
}
|
||||
|
||||
@ -432,12 +441,136 @@ gfxFontEntry::ShareFontTableAndGetBlob(uint32_t aTag,
|
||||
return entry->ShareTableAndGetBlob(*aBuffer, &mFontTableCache);
|
||||
}
|
||||
|
||||
hb_blob_t *
|
||||
gfxFontEntry::GetFontTable(uint32_t aTag)
|
||||
{
|
||||
hb_blob_t *blob;
|
||||
if (GetExistingFontTable(aTag, &blob)) {
|
||||
return blob;
|
||||
}
|
||||
|
||||
FallibleTArray<uint8_t> buffer;
|
||||
bool haveTable = NS_SUCCEEDED(CopyFontTable(aTag, buffer));
|
||||
|
||||
return ShareFontTableAndGetBlob(aTag, haveTable ? &buffer : nullptr);
|
||||
}
|
||||
|
||||
// callback for HarfBuzz to get a font table (in hb_blob_t form)
|
||||
// from the font entry (passed as aUserData)
|
||||
/*static*/ hb_blob_t *
|
||||
gfxFontEntry::HBGetTable(hb_face_t *face, uint32_t aTag, void *aUserData)
|
||||
{
|
||||
gfxFontEntry *fontEntry = static_cast<gfxFontEntry*>(aUserData);
|
||||
|
||||
// bug 589682 - ignore the GDEF table in buggy fonts (applies to
|
||||
// Italic and BoldItalic faces of Times New Roman)
|
||||
if (aTag == TRUETYPE_TAG('G','D','E','F') &&
|
||||
fontEntry->IgnoreGDEF()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// bug 721719 - ignore the GSUB table in buggy fonts (applies to Roboto,
|
||||
// at least on some Android ICS devices; set in gfxFT2FontList.cpp)
|
||||
if (aTag == TRUETYPE_TAG('G','S','U','B') &&
|
||||
fontEntry->IgnoreGSUB()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return fontEntry->GetFontTable(aTag);
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
gfxFontEntry::HBFaceDeletedCallback(void *aUserData)
|
||||
{
|
||||
gfxFontEntry *fe = static_cast<gfxFontEntry*>(aUserData);
|
||||
fe->ForgetHBFace();
|
||||
}
|
||||
|
||||
void
|
||||
gfxFontEntry::ForgetHBFace()
|
||||
{
|
||||
mHBFace = nullptr;
|
||||
}
|
||||
|
||||
hb_face_t*
|
||||
gfxFontEntry::GetHBFace()
|
||||
{
|
||||
if (!mHBFace) {
|
||||
mHBFace = hb_face_create_for_tables(HBGetTable, this,
|
||||
HBFaceDeletedCallback);
|
||||
return mHBFace;
|
||||
}
|
||||
return hb_face_reference(mHBFace);
|
||||
}
|
||||
|
||||
/*static*/ const void*
|
||||
gfxFontEntry::GrGetTable(const void *aAppFaceHandle, unsigned int aName,
|
||||
size_t *aLen)
|
||||
{
|
||||
gfxFontEntry *fontEntry =
|
||||
static_cast<gfxFontEntry*>(const_cast<void*>(aAppFaceHandle));
|
||||
hb_blob_t *blob = fontEntry->GetFontTable(aName);
|
||||
if (blob) {
|
||||
unsigned int blobLength;
|
||||
const void *tableData = hb_blob_get_data(blob, &blobLength);
|
||||
fontEntry->mGrTableMap->Put(tableData, blob);
|
||||
*aLen = blobLength;
|
||||
return tableData;
|
||||
}
|
||||
*aLen = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
gfxFontEntry::GrReleaseTable(const void *aAppFaceHandle,
|
||||
const void *aTableBuffer)
|
||||
{
|
||||
gfxFontEntry *fontEntry =
|
||||
static_cast<gfxFontEntry*>(const_cast<void*>(aAppFaceHandle));
|
||||
void *data;
|
||||
if (fontEntry->mGrTableMap->Get(aTableBuffer, &data)) {
|
||||
fontEntry->mGrTableMap->Remove(aTableBuffer);
|
||||
hb_blob_destroy(static_cast<hb_blob_t*>(data));
|
||||
}
|
||||
}
|
||||
|
||||
gr_face*
|
||||
gfxFontEntry::GetGrFace()
|
||||
{
|
||||
if (!mGrFaceInitialized) {
|
||||
gr_face_ops faceOps = {
|
||||
sizeof(gr_face_ops),
|
||||
GrGetTable,
|
||||
GrReleaseTable
|
||||
};
|
||||
mGrTableMap = new nsDataHashtable<nsPtrHashKey<const void>,void*>;
|
||||
mGrTableMap->Init();
|
||||
mGrFace = gr_make_face_with_ops(this, &faceOps, gr_face_default);
|
||||
mGrFaceInitialized = true;
|
||||
}
|
||||
++mGrFaceRefCnt;
|
||||
return mGrFace;
|
||||
}
|
||||
|
||||
void
|
||||
gfxFontEntry::ReleaseGrFace(gr_face *aFace)
|
||||
{
|
||||
MOZ_ASSERT(aFace == mGrFace); // sanity-check
|
||||
MOZ_ASSERT(mGrFaceRefCnt > 0);
|
||||
if (--mGrFaceRefCnt == 0) {
|
||||
gr_face_destroy(mGrFace);
|
||||
mGrFace = nullptr;
|
||||
mGrFaceInitialized = false;
|
||||
delete mGrTableMap;
|
||||
mGrTableMap = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gfxFontEntry::CheckForGraphiteTables()
|
||||
{
|
||||
AutoFallibleTArray<uint8_t,16384> buffer;
|
||||
mHasGraphiteTables =
|
||||
NS_SUCCEEDED(GetFontTable(TRUETYPE_TAG('S','i','l','f'), buffer));
|
||||
AutoTable silfTable(this, TRUETYPE_TAG('S','i','l','f'));
|
||||
mHasGraphiteTables = silfTable && hb_blob_get_length(silfTable) > 0;
|
||||
}
|
||||
|
||||
/* static */ size_t
|
||||
@ -889,11 +1022,11 @@ gfxFontFamily::SearchAllFontsForChar(GlobalFontMatch *aMatchData)
|
||||
// returns true if other names were found, false otherwise
|
||||
bool
|
||||
gfxFontFamily::ReadOtherFamilyNamesForFace(gfxPlatformFontList *aPlatformFontList,
|
||||
FallibleTArray<uint8_t>& aNameTable,
|
||||
bool useFullName)
|
||||
hb_blob_t *aNameTable,
|
||||
bool useFullName)
|
||||
{
|
||||
const uint8_t *nameData = aNameTable.Elements();
|
||||
uint32_t dataLength = aNameTable.Length();
|
||||
uint32_t dataLength;
|
||||
const char *nameData = hb_blob_get_data(aNameTable, &dataLength);
|
||||
const gfxFontUtils::NameHeader *nameHeader =
|
||||
reinterpret_cast<const gfxFontUtils::NameHeader*>(nameData);
|
||||
|
||||
@ -952,18 +1085,18 @@ gfxFontFamily::ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList)
|
||||
// read in other family names for the first face in the list
|
||||
uint32_t i, numFonts = mAvailableFonts.Length();
|
||||
const uint32_t kNAME = TRUETYPE_TAG('n','a','m','e');
|
||||
AutoFallibleTArray<uint8_t,8192> buffer;
|
||||
|
||||
for (i = 0; i < numFonts; ++i) {
|
||||
gfxFontEntry *fe = mAvailableFonts[i];
|
||||
if (!fe)
|
||||
if (!fe) {
|
||||
continue;
|
||||
|
||||
if (fe->GetFontTable(kNAME, buffer) != NS_OK)
|
||||
}
|
||||
gfxFontEntry::AutoTable nameTable(fe, kNAME);
|
||||
if (!nameTable) {
|
||||
continue;
|
||||
|
||||
}
|
||||
mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aPlatformFontList,
|
||||
buffer);
|
||||
nameTable);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -977,13 +1110,14 @@ gfxFontFamily::ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList)
|
||||
// family names for individual weights (e.g. Hiragino Kaku Gothic Pro W6)
|
||||
for ( ; i < numFonts; i++) {
|
||||
gfxFontEntry *fe = mAvailableFonts[i];
|
||||
if (!fe)
|
||||
if (!fe) {
|
||||
continue;
|
||||
|
||||
if (fe->GetFontTable(kNAME, buffer) != NS_OK)
|
||||
}
|
||||
gfxFontEntry::AutoTable nameTable(fe, kNAME);
|
||||
if (!nameTable) {
|
||||
continue;
|
||||
|
||||
ReadOtherFamilyNamesForFace(aPlatformFontList, buffer);
|
||||
}
|
||||
ReadOtherFamilyNamesForFace(aPlatformFontList, nameTable);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1000,48 +1134,49 @@ gfxFontFamily::ReadFaceNames(gfxPlatformFontList *aPlatformFontList,
|
||||
|
||||
uint32_t i, numFonts = mAvailableFonts.Length();
|
||||
const uint32_t kNAME = TRUETYPE_TAG('n','a','m','e');
|
||||
AutoFallibleTArray<uint8_t,8192> buffer;
|
||||
nsAutoString fullname, psname;
|
||||
|
||||
bool firstTime = true, readAllFaces = false;
|
||||
for (i = 0; i < numFonts; ++i) {
|
||||
gfxFontEntry *fe = mAvailableFonts[i];
|
||||
if (!fe)
|
||||
if (!fe) {
|
||||
continue;
|
||||
|
||||
if (fe->GetFontTable(kNAME, buffer) != NS_OK)
|
||||
}
|
||||
gfxFontEntry::AutoTable nameTable(fe, kNAME);
|
||||
if (!nameTable) {
|
||||
continue;
|
||||
|
||||
}
|
||||
if (aNeedFullnamePostscriptNames) {
|
||||
if (gfxFontUtils::ReadCanonicalName(
|
||||
buffer, gfxFontUtils::NAME_ID_FULL, fullname) == NS_OK)
|
||||
nameTable, gfxFontUtils::NAME_ID_FULL, fullname) == NS_OK)
|
||||
{
|
||||
aPlatformFontList->AddFullname(fe, fullname);
|
||||
}
|
||||
|
||||
if (gfxFontUtils::ReadCanonicalName(
|
||||
buffer, gfxFontUtils::NAME_ID_POSTSCRIPT, psname) == NS_OK)
|
||||
nameTable, gfxFontUtils::NAME_ID_POSTSCRIPT, psname) == NS_OK)
|
||||
{
|
||||
aPlatformFontList->AddPostscriptName(fe, psname);
|
||||
}
|
||||
}
|
||||
|
||||
if (!mOtherFamilyNamesInitialized && (firstTime || readAllFaces)) {
|
||||
bool foundOtherName = ReadOtherFamilyNamesForFace(aPlatformFontList,
|
||||
buffer);
|
||||
if (!mOtherFamilyNamesInitialized && (firstTime || readAllFaces)) {
|
||||
bool foundOtherName = ReadOtherFamilyNamesForFace(aPlatformFontList,
|
||||
nameTable);
|
||||
|
||||
// if the first face has a different name, scan all faces, otherwise
|
||||
// assume the family doesn't have other names
|
||||
if (firstTime && foundOtherName) {
|
||||
mHasOtherFamilyNames = true;
|
||||
readAllFaces = true;
|
||||
}
|
||||
firstTime = false;
|
||||
}
|
||||
// if the first face has a different name, scan all faces, otherwise
|
||||
// assume the family doesn't have other names
|
||||
if (firstTime && foundOtherName) {
|
||||
mHasOtherFamilyNames = true;
|
||||
readAllFaces = true;
|
||||
}
|
||||
firstTime = false;
|
||||
}
|
||||
|
||||
// if not reading in any more names, skip other faces
|
||||
if (!readAllFaces && !aNeedFullnamePostscriptNames)
|
||||
break;
|
||||
// if not reading in any more names, skip other faces
|
||||
if (!readAllFaces && !aNeedFullnamePostscriptNames) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mFaceNamesInitialized = true;
|
||||
@ -1579,26 +1714,6 @@ gfxFont::AgeCacheEntry(CacheHashEntry *aEntry, void *aUserData)
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
hb_blob_t *
|
||||
gfxFont::GetFontTable(uint32_t aTag) {
|
||||
hb_blob_t *blob;
|
||||
if (mFontEntry->GetExistingFontTable(aTag, &blob))
|
||||
return blob;
|
||||
|
||||
FallibleTArray<uint8_t> buffer;
|
||||
bool haveTable = NS_SUCCEEDED(mFontEntry->GetFontTable(aTag, buffer));
|
||||
|
||||
return mFontEntry->ShareFontTableAndGetBlob(aTag,
|
||||
haveTable ? &buffer : nullptr);
|
||||
}
|
||||
|
||||
static hb_blob_t *
|
||||
HBGetTable(hb_face_t *face, hb_tag_t aTag, void *aUserData)
|
||||
{
|
||||
gfxFont* font = static_cast<gfxFont*>(aUserData);
|
||||
return font->GetFontTable(aTag);
|
||||
}
|
||||
|
||||
static bool
|
||||
HasLookupRuleWithGlyphByScript(hb_face_t *aFace, hb_tag_t aTableTag,
|
||||
hb_tag_t aScript, uint16_t aGlyph)
|
||||
@ -1762,7 +1877,7 @@ gfxFont::CheckForFeaturesInvolvingSpace()
|
||||
|
||||
bool result = false;
|
||||
|
||||
hb_face_t *face = hb_face_create_for_tables(HBGetTable, this, nullptr);
|
||||
hb_face_t *face = GetFontEntry()->GetHBFace();
|
||||
|
||||
uint32_t i, len, offset;
|
||||
uint32_t spaceGlyph = GetSpaceGlyph();
|
||||
@ -3297,6 +3412,8 @@ gfxFont::SetupGlyphExtents(gfxContext *aContext, uint32_t aGlyphID, bool aNeedTi
|
||||
// Return FALSE if the gfxFontEntry subclass does not
|
||||
// implement GetFontTable(), or for non-sfnt fonts where tables are
|
||||
// not available.
|
||||
// If this returns TRUE without setting the mIsValid flag, then we -did-
|
||||
// apparently find an sfnt, but it was too broken to be used.
|
||||
bool
|
||||
gfxFont::InitMetricsFromSfntTables(Metrics& aMetrics)
|
||||
{
|
||||
@ -3307,16 +3424,21 @@ gfxFont::InitMetricsFromSfntTables(Metrics& aMetrics)
|
||||
const uint32_t kPostTableTag = TRUETYPE_TAG('p','o','s','t');
|
||||
const uint32_t kOS_2TableTag = TRUETYPE_TAG('O','S','/','2');
|
||||
|
||||
uint32_t len;
|
||||
|
||||
if (mFUnitsConvFactor == 0.0) {
|
||||
// If the conversion factor from FUnits is not yet set,
|
||||
// 'head' table is required; otherwise we cannot read any metrics
|
||||
// because we don't know unitsPerEm
|
||||
AutoFallibleTArray<uint8_t,sizeof(HeadTable)> headData;
|
||||
if (NS_FAILED(mFontEntry->GetFontTable(kHeadTableTag, headData)) ||
|
||||
headData.Length() < sizeof(HeadTable)) {
|
||||
return false; // no 'head' table -> not an sfnt
|
||||
gfxFontEntry::AutoTable headTable(mFontEntry, kHeadTableTag);
|
||||
if (!headTable) {
|
||||
return false;
|
||||
}
|
||||
const HeadTable* head =
|
||||
reinterpret_cast<const HeadTable*>(hb_blob_get_data(headTable, &len));
|
||||
if (len < sizeof(HeadTable)) {
|
||||
return false;
|
||||
}
|
||||
HeadTable *head = reinterpret_cast<HeadTable*>(headData.Elements());
|
||||
uint32_t unitsPerEm = head->unitsPerEm;
|
||||
if (!unitsPerEm) {
|
||||
return true; // is an sfnt, but not valid
|
||||
@ -3325,12 +3447,15 @@ gfxFont::InitMetricsFromSfntTables(Metrics& aMetrics)
|
||||
}
|
||||
|
||||
// 'hhea' table is required to get vertical extents
|
||||
AutoFallibleTArray<uint8_t,sizeof(HheaTable)> hheaData;
|
||||
if (NS_FAILED(mFontEntry->GetFontTable(kHheaTableTag, hheaData)) ||
|
||||
hheaData.Length() < sizeof(HheaTable)) {
|
||||
gfxFontEntry::AutoTable hheaTable(mFontEntry, kHheaTableTag);
|
||||
if (!hheaTable) {
|
||||
return false; // no 'hhea' table -> not an sfnt
|
||||
}
|
||||
HheaTable *hhea = reinterpret_cast<HheaTable*>(hheaData.Elements());
|
||||
const HheaTable* hhea =
|
||||
reinterpret_cast<const HheaTable*>(hb_blob_get_data(hheaTable, &len));
|
||||
if (len < sizeof(HheaTable)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#define SET_UNSIGNED(field,src) aMetrics.field = uint16_t(src) * mFUnitsConvFactor
|
||||
#define SET_SIGNED(field,src) aMetrics.field = int16_t(src) * mFUnitsConvFactor
|
||||
@ -3341,27 +3466,26 @@ gfxFont::InitMetricsFromSfntTables(Metrics& aMetrics)
|
||||
SET_SIGNED(externalLeading, hhea->lineGap);
|
||||
|
||||
// 'post' table is required for underline metrics
|
||||
AutoFallibleTArray<uint8_t,sizeof(PostTable)> postData;
|
||||
if (NS_FAILED(mFontEntry->GetFontTable(kPostTableTag, postData))) {
|
||||
gfxFontEntry::AutoTable postTable(mFontEntry, kPostTableTag);
|
||||
if (!postTable) {
|
||||
return true; // no 'post' table -> sfnt is not valid
|
||||
}
|
||||
if (postData.Length() <
|
||||
offsetof(PostTable, underlineThickness) + sizeof(uint16_t)) {
|
||||
const PostTable *post =
|
||||
reinterpret_cast<const PostTable*>(hb_blob_get_data(postTable, &len));
|
||||
if (len < offsetof(PostTable, underlineThickness) + sizeof(uint16_t)) {
|
||||
return true; // bad post table -> sfnt is not valid
|
||||
}
|
||||
PostTable *post = reinterpret_cast<PostTable*>(postData.Elements());
|
||||
|
||||
SET_SIGNED(underlineOffset, post->underlinePosition);
|
||||
SET_UNSIGNED(underlineSize, post->underlineThickness);
|
||||
|
||||
// 'OS/2' table is optional, if not found we'll estimate xHeight
|
||||
// and aveCharWidth by measuring glyphs
|
||||
AutoFallibleTArray<uint8_t,sizeof(OS2Table)> os2data;
|
||||
if (NS_SUCCEEDED(mFontEntry->GetFontTable(kOS_2TableTag, os2data))) {
|
||||
OS2Table *os2 = reinterpret_cast<OS2Table*>(os2data.Elements());
|
||||
|
||||
if (os2data.Length() >= offsetof(OS2Table, sxHeight) +
|
||||
sizeof(int16_t) &&
|
||||
gfxFontEntry::AutoTable os2Table(mFontEntry, kOS_2TableTag);
|
||||
if (os2Table) {
|
||||
const OS2Table *os2 =
|
||||
reinterpret_cast<const OS2Table*>(hb_blob_get_data(os2Table, &len));
|
||||
if (len >= offsetof(OS2Table, sxHeight) + sizeof(int16_t) &&
|
||||
uint16_t(os2->version) >= 2) {
|
||||
// version 2 and later includes the x-height field
|
||||
SET_SIGNED(xHeight, os2->sxHeight);
|
||||
@ -3369,8 +3493,7 @@ gfxFont::InitMetricsFromSfntTables(Metrics& aMetrics)
|
||||
aMetrics.xHeight = Abs(aMetrics.xHeight);
|
||||
}
|
||||
// this should always be present
|
||||
if (os2data.Length() >= offsetof(OS2Table, yStrikeoutPosition) +
|
||||
sizeof(int16_t)) {
|
||||
if (len >= offsetof(OS2Table, yStrikeoutPosition) + sizeof(int16_t)) {
|
||||
SET_SIGNED(aveCharWidth, os2->xAvgCharWidth);
|
||||
SET_SIGNED(subscriptOffset, os2->ySubscriptYOffset);
|
||||
SET_SIGNED(superscriptOffset, os2->ySuperscriptYOffset);
|
||||
|
@ -29,8 +29,10 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include <algorithm>
|
||||
#include "nsUnicodeProperties.h"
|
||||
#include "harfbuzz/hb.h"
|
||||
|
||||
typedef struct _cairo_scaled_font cairo_scaled_font_t;
|
||||
typedef struct gr_face gr_face;
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
@ -50,8 +52,6 @@ class gfxTextObjectPaint;
|
||||
|
||||
class nsILanguageAtomService;
|
||||
|
||||
typedef struct hb_blob_t hb_blob_t;
|
||||
|
||||
#define FONT_MAX_SIZE 2000.0
|
||||
|
||||
#define NO_FONT_LANGUAGE_OVERRIDE 0
|
||||
@ -237,13 +237,17 @@ public:
|
||||
mHasSpaceFeaturesKerning(false),
|
||||
mHasSpaceFeaturesNonKerning(false),
|
||||
mHasSpaceFeaturesSubDefault(false),
|
||||
mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
|
||||
mCheckedForGraphiteTables(false),
|
||||
mHasCmapTable(false),
|
||||
mGrFaceInitialized(false),
|
||||
mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
|
||||
mUVSOffset(0), mUVSData(nullptr),
|
||||
mUserFontData(nullptr),
|
||||
mSVGGlyphs(nullptr),
|
||||
mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE)
|
||||
mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
|
||||
mHBFace(nullptr),
|
||||
mGrFace(nullptr),
|
||||
mGrFaceRefCnt(0)
|
||||
{
|
||||
memset(&mHasSpaceFeaturesSub, 0, sizeof(mHasSpaceFeaturesSub));
|
||||
}
|
||||
@ -322,9 +326,46 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual nsresult GetFontTable(uint32_t aTableTag, FallibleTArray<uint8_t>& aBuffer) {
|
||||
return NS_ERROR_FAILURE; // all platform subclasses should reimplement this!
|
||||
}
|
||||
// Access to raw font table data (needed for Harfbuzz):
|
||||
// returns a pointer to data owned by the fontEntry or the OS,
|
||||
// which will remain valid until the blob is destroyed.
|
||||
// The data MUST be treated as read-only; we may be getting a
|
||||
// reference to a shared system font cache.
|
||||
//
|
||||
// The default implementation uses CopyFontTable to get the data
|
||||
// into a byte array, and maintains a cache of loaded tables.
|
||||
//
|
||||
// Subclasses should override this if they can provide more efficient
|
||||
// access than copying table data into our own buffers.
|
||||
//
|
||||
// Get blob that encapsulates a specific font table, or NULL if
|
||||
// the table doesn't exist in the font.
|
||||
//
|
||||
// Caller is responsible to call hb_blob_destroy() on the returned blob
|
||||
// (if non-NULL) when no longer required. For transient access to a table,
|
||||
// use of AutoTable (below) is generally preferred.
|
||||
virtual hb_blob_t *GetFontTable(uint32_t aTag);
|
||||
|
||||
// Stack-based utility to return a specified table, automatically releasing
|
||||
// the blob when the AutoTable goes out of scope.
|
||||
class AutoTable {
|
||||
public:
|
||||
AutoTable(gfxFontEntry* aFontEntry, uint32_t aTag)
|
||||
{
|
||||
mBlob = aFontEntry->GetFontTable(aTag);
|
||||
}
|
||||
~AutoTable() {
|
||||
if (mBlob) {
|
||||
hb_blob_destroy(mBlob);
|
||||
}
|
||||
}
|
||||
operator hb_blob_t*() const { return mBlob; }
|
||||
private:
|
||||
hb_blob_t* mBlob;
|
||||
// not implemented:
|
||||
AutoTable(const AutoTable&) MOZ_DELETE;
|
||||
AutoTable& operator=(const AutoTable&) MOZ_DELETE;
|
||||
};
|
||||
|
||||
already_AddRefed<gfxFont> FindOrMakeFont(const gfxFontStyle *aStyle,
|
||||
bool aNeedsBold);
|
||||
@ -347,6 +388,21 @@ public:
|
||||
hb_blob_t *ShareFontTableAndGetBlob(uint32_t aTag,
|
||||
FallibleTArray<uint8_t>* aTable);
|
||||
|
||||
// Shaper face accessors:
|
||||
// NOTE that harfbuzz and graphite handle ownership/lifetime of the face
|
||||
// object in completely different ways.
|
||||
|
||||
// Get HarfBuzz face corresponding to this font file.
|
||||
// Caller must release with hb_face_destroy() when finished with it,
|
||||
// and the font entry will be notified via ForgetHBFace.
|
||||
hb_face_t* GetHBFace();
|
||||
virtual void ForgetHBFace();
|
||||
|
||||
// Get Graphite face corresponding to this font file.
|
||||
// Caller must call gfxFontEntry::ReleaseGrFace when finished with it.
|
||||
gr_face* GetGrFace();
|
||||
virtual void ReleaseGrFace(gr_face* aFace);
|
||||
|
||||
// For memory reporting
|
||||
virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
|
||||
FontListSizes* aSizes) const;
|
||||
@ -373,6 +429,10 @@ public:
|
||||
bool mHasSpaceFeaturesKerning : 1;
|
||||
bool mHasSpaceFeaturesNonKerning : 1;
|
||||
bool mHasSpaceFeaturesSubDefault : 1;
|
||||
bool mHasGraphiteTables : 1;
|
||||
bool mCheckedForGraphiteTables : 1;
|
||||
bool mHasCmapTable : 1;
|
||||
bool mGrFaceInitialized : 1;
|
||||
|
||||
// bitvector of substitution space features per script
|
||||
uint32_t mHasSpaceFeaturesSub[(MOZ_NUM_SCRIPT_CODES + 31) / 32];
|
||||
@ -380,9 +440,6 @@ public:
|
||||
uint16_t mWeight;
|
||||
int16_t mStretch;
|
||||
|
||||
bool mHasGraphiteTables;
|
||||
bool mCheckedForGraphiteTables;
|
||||
bool mHasCmapTable;
|
||||
nsRefPtr<gfxCharacterMap> mCharacterMap;
|
||||
uint32_t mUVSOffset;
|
||||
nsAutoArrayPtr<uint8_t> mUVSData;
|
||||
@ -415,13 +472,17 @@ protected:
|
||||
mHasSpaceFeaturesKerning(false),
|
||||
mHasSpaceFeaturesNonKerning(false),
|
||||
mHasSpaceFeaturesSubDefault(false),
|
||||
mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
|
||||
mCheckedForGraphiteTables(false),
|
||||
mHasCmapTable(false),
|
||||
mGrFaceInitialized(false),
|
||||
mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
|
||||
mUVSOffset(0), mUVSData(nullptr),
|
||||
mUserFontData(nullptr),
|
||||
mSVGGlyphs(nullptr),
|
||||
mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE)
|
||||
mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
|
||||
mHBFace(nullptr),
|
||||
mGrFace(nullptr),
|
||||
mGrFaceRefCnt(0)
|
||||
{ }
|
||||
|
||||
virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold) {
|
||||
@ -431,8 +492,52 @@ protected:
|
||||
|
||||
virtual void CheckForGraphiteTables();
|
||||
|
||||
private:
|
||||
// Copy a font table into aBuffer.
|
||||
// The caller will be responsible for ownership of the data.
|
||||
virtual nsresult CopyFontTable(uint32_t aTableTag,
|
||||
FallibleTArray<uint8_t>& aBuffer) {
|
||||
NS_NOTREACHED("forgot to override either GetFontTable or CopyFontTable?");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Shaper-specific face objects, shared by all instantiations of the same
|
||||
// physical font, regardless of size.
|
||||
// Usually, only one of these will actually be created for any given font
|
||||
// entry, depending on the font tables that are present.
|
||||
|
||||
// hb_face_t is refcounted internally, so each shaper that's using it will
|
||||
// bump the ref count when it acquires the face, and "destroy" (release) it
|
||||
// in its destructor. The font entry has only this non-owning reference to
|
||||
// the face; when the face is deleted, it will tell the font entry to forget
|
||||
// it, so that a new face will be created next time it is needed.
|
||||
hb_face_t* mHBFace;
|
||||
|
||||
static hb_blob_t* HBGetTable(hb_face_t *face, uint32_t aTag, void *aUserData);
|
||||
|
||||
// Callback that the hb_face will use to tell us when it is being deleted.
|
||||
static void HBFaceDeletedCallback(void *aUserData);
|
||||
|
||||
// gr_face is -not- refcounted, so it will be owned directly by the font
|
||||
// entry, and we'll keep a count of how many references we've handed out;
|
||||
// each shaper is responsible to call ReleaseGrFace on its entry when
|
||||
// finished with it, so that we know when it can be deleted.
|
||||
gr_face* mGrFace;
|
||||
|
||||
// hashtable to map raw table data ptr back to its owning blob, for use by
|
||||
// graphite table-release callback
|
||||
nsDataHashtable<nsPtrHashKey<const void>,void*>* mGrTableMap;
|
||||
|
||||
// number of current users of this entry's mGrFace
|
||||
nsrefcnt mGrFaceRefCnt;
|
||||
|
||||
static const void* GrGetTable(const void *aAppFaceHandle,
|
||||
unsigned int aName,
|
||||
size_t *aLen);
|
||||
static void GrReleaseTable(const void *aAppFaceHandle,
|
||||
const void *aTableBuffer);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Font table hashtable, to support GetFontTable for harfbuzz.
|
||||
*
|
||||
@ -692,8 +797,8 @@ protected:
|
||||
bool anItalic, int16_t aStretch);
|
||||
|
||||
bool ReadOtherFamilyNamesForFace(gfxPlatformFontList *aPlatformFontList,
|
||||
FallibleTArray<uint8_t>& aNameTable,
|
||||
bool useFullName = false);
|
||||
hb_blob_t *aNameTable,
|
||||
bool useFullName = false);
|
||||
|
||||
// set whether this font family is in "bad" underline offset blacklist.
|
||||
void SetBadUnderlineFonts() {
|
||||
@ -1307,21 +1412,6 @@ public:
|
||||
return mFontEntry->HasGraphiteTables();
|
||||
}
|
||||
|
||||
// Access to raw font table data (needed for Harfbuzz):
|
||||
// returns a pointer to data owned by the fontEntry or the OS,
|
||||
// which will remain valid until released.
|
||||
//
|
||||
// Default implementations forward to the font entry,
|
||||
// and maintain a shared table.
|
||||
//
|
||||
// Subclasses should override this if they can provide more efficient
|
||||
// access than getting tables with mFontEntry->GetFontTable() and sharing
|
||||
// them via the entry.
|
||||
//
|
||||
// Get pointer to a specific font table, or NULL if
|
||||
// the table doesn't exist in the font
|
||||
virtual hb_blob_t *GetFontTable(uint32_t aTag);
|
||||
|
||||
// Subclasses may choose to look up glyph ids for characters.
|
||||
// If they do not override this, gfxHarfBuzzShaper will fetch the cmap
|
||||
// table and use that.
|
||||
|
@ -20,6 +20,8 @@
|
||||
#include "nsMemory.h"
|
||||
#include "nsICharsetConverterManager.h"
|
||||
|
||||
#include "harfbuzz/hb.h"
|
||||
|
||||
#include "plbase64.h"
|
||||
#include "prlog.h"
|
||||
|
||||
@ -1215,17 +1217,18 @@ gfxFontUtils::GetFullNameFromSFNT(const uint8_t* aFontData, uint32_t aLength,
|
||||
uint32_t len = dirEntry->length;
|
||||
NS_ENSURE_TRUE(aLength > len && aLength - len >= dirEntry->offset,
|
||||
NS_ERROR_UNEXPECTED);
|
||||
FallibleTArray<uint8_t> nameTable;
|
||||
if (!nameTable.SetLength(len)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
memcpy(nameTable.Elements(), aFontData + dirEntry->offset, len);
|
||||
|
||||
return GetFullNameFromTable(nameTable, aFullName);
|
||||
hb_blob_t *nameBlob =
|
||||
hb_blob_create((const char*)aFontData + dirEntry->offset, len,
|
||||
HB_MEMORY_MODE_READONLY, nullptr, nullptr);
|
||||
nsresult rv = GetFullNameFromTable(nameBlob, aFullName);
|
||||
hb_blob_destroy(nameBlob);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
gfxFontUtils::GetFullNameFromTable(FallibleTArray<uint8_t>& aNameTable,
|
||||
gfxFontUtils::GetFullNameFromTable(hb_blob_t *aNameTable,
|
||||
nsAString& aFullName)
|
||||
{
|
||||
nsAutoString name;
|
||||
@ -1257,7 +1260,7 @@ gfxFontUtils::GetFullNameFromTable(FallibleTArray<uint8_t>& aNameTable,
|
||||
}
|
||||
|
||||
nsresult
|
||||
gfxFontUtils::GetFamilyNameFromTable(FallibleTArray<uint8_t>& aNameTable,
|
||||
gfxFontUtils::GetFamilyNameFromTable(hb_blob_t *aNameTable,
|
||||
nsAString& aFullName)
|
||||
{
|
||||
nsAutoString name;
|
||||
@ -1283,14 +1286,14 @@ enum {
|
||||
};
|
||||
|
||||
nsresult
|
||||
gfxFontUtils::ReadNames(FallibleTArray<uint8_t>& aNameTable, uint32_t aNameID,
|
||||
gfxFontUtils::ReadNames(hb_blob_t *aNameTable, uint32_t aNameID,
|
||||
int32_t aPlatformID, nsTArray<nsString>& aNames)
|
||||
{
|
||||
return ReadNames(aNameTable, aNameID, LANG_ALL, aPlatformID, aNames);
|
||||
}
|
||||
|
||||
nsresult
|
||||
gfxFontUtils::ReadCanonicalName(FallibleTArray<uint8_t>& aNameTable, uint32_t aNameID,
|
||||
gfxFontUtils::ReadCanonicalName(hb_blob_t *aNameTable, uint32_t aNameID,
|
||||
nsString& aName)
|
||||
{
|
||||
nsresult rv;
|
||||
@ -1458,7 +1461,7 @@ gfxFontUtils::GetCharsetForFontName(uint16_t aPlatform, uint16_t aScript, uint16
|
||||
// convert a raw name from the name table to an nsString, if possible;
|
||||
// return value indicates whether conversion succeeded
|
||||
bool
|
||||
gfxFontUtils::DecodeFontName(const uint8_t *aNameData, int32_t aByteLen,
|
||||
gfxFontUtils::DecodeFontName(const char *aNameData, int32_t aByteLen,
|
||||
uint32_t aPlatformCode, uint32_t aScriptCode,
|
||||
uint32_t aLangCode, nsAString& aName)
|
||||
{
|
||||
@ -1508,7 +1511,7 @@ gfxFontUtils::DecodeFontName(const uint8_t *aNameData, int32_t aByteLen,
|
||||
}
|
||||
|
||||
int32_t destLength;
|
||||
rv = decoder->GetMaxLength(reinterpret_cast<const char*>(aNameData), aByteLen, &destLength);
|
||||
rv = decoder->GetMaxLength(aNameData, aByteLen, &destLength);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("decoder->GetMaxLength failed, invalid font name?");
|
||||
return false;
|
||||
@ -1516,7 +1519,7 @@ gfxFontUtils::DecodeFontName(const uint8_t *aNameData, int32_t aByteLen,
|
||||
|
||||
// make space for the converted string
|
||||
aName.SetLength(destLength);
|
||||
rv = decoder->Convert(reinterpret_cast<const char*>(aNameData), &aByteLen,
|
||||
rv = decoder->Convert(aNameData, &aByteLen,
|
||||
aName.BeginWriting(), &destLength);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("decoder->Convert failed, invalid font name?");
|
||||
@ -1528,17 +1531,17 @@ gfxFontUtils::DecodeFontName(const uint8_t *aNameData, int32_t aByteLen,
|
||||
}
|
||||
|
||||
nsresult
|
||||
gfxFontUtils::ReadNames(FallibleTArray<uint8_t>& aNameTable, uint32_t aNameID,
|
||||
gfxFontUtils::ReadNames(hb_blob_t *aNameTable, uint32_t aNameID,
|
||||
int32_t aLangID, int32_t aPlatformID,
|
||||
nsTArray<nsString>& aNames)
|
||||
{
|
||||
uint32_t nameTableLen = aNameTable.Length();
|
||||
uint32_t nameTableLen;
|
||||
const char *nameTable = hb_blob_get_data(aNameTable, &nameTableLen);
|
||||
NS_ASSERTION(nameTableLen != 0, "null name table");
|
||||
|
||||
if (nameTableLen == 0)
|
||||
if (!nameTableLen) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
uint8_t *nameTable = aNameTable.Elements();
|
||||
}
|
||||
|
||||
// -- name table data
|
||||
const NameHeader *nameHeader = reinterpret_cast<const NameHeader*>(nameTable);
|
||||
|
@ -33,6 +33,8 @@
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
typedef struct hb_blob_t hb_blob_t;
|
||||
|
||||
class gfxSparseBitSet {
|
||||
private:
|
||||
enum { BLOCK_SIZE = 32 }; // ==> 256 codepoints per block
|
||||
@ -829,12 +831,12 @@ public:
|
||||
// helper to get fullname from name table, constructing from family+style
|
||||
// if no explicit fullname is present
|
||||
static nsresult
|
||||
GetFullNameFromTable(FallibleTArray<uint8_t>& aNameTable,
|
||||
GetFullNameFromTable(hb_blob_t *aNameTable,
|
||||
nsAString& aFullName);
|
||||
|
||||
// helper to get family name from name table
|
||||
static nsresult
|
||||
GetFamilyNameFromTable(FallibleTArray<uint8_t>& aNameTable,
|
||||
GetFamilyNameFromTable(hb_blob_t *aNameTable,
|
||||
nsAString& aFamilyName);
|
||||
|
||||
// create a new name table and build a new font with that name table
|
||||
@ -845,20 +847,20 @@ public:
|
||||
|
||||
// read all names matching aNameID, returning in aNames array
|
||||
static nsresult
|
||||
ReadNames(FallibleTArray<uint8_t>& aNameTable, uint32_t aNameID,
|
||||
ReadNames(hb_blob_t *aNameTable, uint32_t aNameID,
|
||||
int32_t aPlatformID, nsTArray<nsString>& aNames);
|
||||
|
||||
// reads English or first name matching aNameID, returning in aName
|
||||
// platform based on OS
|
||||
static nsresult
|
||||
ReadCanonicalName(FallibleTArray<uint8_t>& aNameTable, uint32_t aNameID,
|
||||
ReadCanonicalName(hb_blob_t *aNameTable, uint32_t aNameID,
|
||||
nsString& aName);
|
||||
|
||||
// convert a name from the raw name table data into an nsString,
|
||||
// provided we know how; return true if successful, or false
|
||||
// if we can't handle the encoding
|
||||
static bool
|
||||
DecodeFontName(const uint8_t *aBuf, int32_t aLength,
|
||||
DecodeFontName(const char *aBuf, int32_t aLength,
|
||||
uint32_t aPlatformCode, uint32_t aScriptCode,
|
||||
uint32_t aLangCode, nsAString& dest);
|
||||
|
||||
@ -934,7 +936,7 @@ public:
|
||||
|
||||
protected:
|
||||
static nsresult
|
||||
ReadNames(FallibleTArray<uint8_t>& aNameTable, uint32_t aNameID,
|
||||
ReadNames(hb_blob_t *aNameTable, uint32_t aNameID,
|
||||
int32_t aLangID, int32_t aPlatformID, nsTArray<nsString>& aNames);
|
||||
|
||||
// convert opentype name-table platform/encoding/language values to a charset name
|
||||
|
@ -199,7 +199,7 @@ GDIFontEntry::ReadCMAP()
|
||||
nsresult rv;
|
||||
|
||||
AutoFallibleTArray<uint8_t,16384> cmap;
|
||||
rv = GetFontTable(kCMAP, cmap);
|
||||
rv = CopyFontTable(kCMAP, cmap);
|
||||
|
||||
bool unicodeFont = false, symbolFont = false; // currently ignored
|
||||
|
||||
@ -263,8 +263,8 @@ GDIFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle, bool aNeedsBold
|
||||
}
|
||||
|
||||
nsresult
|
||||
GDIFontEntry::GetFontTable(uint32_t aTableTag,
|
||||
FallibleTArray<uint8_t>& aBuffer)
|
||||
GDIFontEntry::CopyFontTable(uint32_t aTableTag,
|
||||
FallibleTArray<uint8_t>& aBuffer)
|
||||
{
|
||||
if (!IsTrueType()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -280,8 +280,8 @@ protected:
|
||||
|
||||
virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold);
|
||||
|
||||
virtual nsresult GetFontTable(uint32_t aTableTag,
|
||||
FallibleTArray<uint8_t>& aBuffer);
|
||||
virtual nsresult CopyFontTable(uint32_t aTableTag,
|
||||
FallibleTArray<uint8_t>& aBuffer) MOZ_OVERRIDE;
|
||||
|
||||
LOGFONTW mLogFont;
|
||||
};
|
||||
|
@ -40,69 +40,26 @@ using namespace mozilla; // for AutoSwap_* types
|
||||
|
||||
gfxGraphiteShaper::gfxGraphiteShaper(gfxFont *aFont)
|
||||
: gfxFontShaper(aFont),
|
||||
mGrFace(nullptr),
|
||||
mGrFace(mFont->GetFontEntry()->GetGrFace()),
|
||||
mGrFont(nullptr)
|
||||
{
|
||||
mTables.Init();
|
||||
mCallbackData.mFont = aFont;
|
||||
mCallbackData.mShaper = this;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
ReleaseTableFunc(const uint32_t& /* aKey */,
|
||||
gfxGraphiteShaper::TableRec& aData,
|
||||
void* /* aUserArg */)
|
||||
{
|
||||
hb_blob_destroy(aData.mBlob);
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
gfxGraphiteShaper::~gfxGraphiteShaper()
|
||||
{
|
||||
if (mGrFont) {
|
||||
gr_font_destroy(mGrFont);
|
||||
}
|
||||
if (mGrFace) {
|
||||
gr_face_destroy(mGrFace);
|
||||
}
|
||||
mTables.Enumerate(ReleaseTableFunc, nullptr);
|
||||
mFont->GetFontEntry()->ReleaseGrFace(mGrFace);
|
||||
}
|
||||
|
||||
static const void*
|
||||
GrGetTable(const void* appFaceHandle, unsigned int name, size_t *len)
|
||||
/*static*/ float
|
||||
gfxGraphiteShaper::GrGetAdvance(const void* appFontHandle, uint16_t glyphid)
|
||||
{
|
||||
const gfxGraphiteShaper::CallbackData *cb =
|
||||
static_cast<const gfxGraphiteShaper::CallbackData*>(appFaceHandle);
|
||||
return cb->mShaper->GetTable(name, len);
|
||||
}
|
||||
|
||||
const void*
|
||||
gfxGraphiteShaper::GetTable(uint32_t aTag, size_t *aLength)
|
||||
{
|
||||
TableRec tableRec;
|
||||
|
||||
if (!mTables.Get(aTag, &tableRec)) {
|
||||
hb_blob_t *blob = mFont->GetFontTable(aTag);
|
||||
if (blob) {
|
||||
// mFont->GetFontTable() gives us a reference to the blob.
|
||||
// We will destroy (release) it in our destructor.
|
||||
tableRec.mBlob = blob;
|
||||
tableRec.mData = hb_blob_get_data(blob, &tableRec.mLength);
|
||||
mTables.Put(aTag, tableRec);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
*aLength = tableRec.mLength;
|
||||
return tableRec.mData;
|
||||
}
|
||||
|
||||
static float
|
||||
GrGetAdvance(const void* appFontHandle, gr_uint16 glyphid)
|
||||
{
|
||||
const gfxGraphiteShaper::CallbackData *cb =
|
||||
static_cast<const gfxGraphiteShaper::CallbackData*>(appFontHandle);
|
||||
const CallbackData *cb =
|
||||
static_cast<const CallbackData*>(appFontHandle);
|
||||
return FixedToFloat(cb->mFont->GetGlyphWidth(cb->mContext, glyphid));
|
||||
}
|
||||
|
||||
@ -152,7 +109,6 @@ gfxGraphiteShaper::ShapeText(gfxContext *aContext,
|
||||
mCallbackData.mContext = aContext;
|
||||
|
||||
if (!mGrFont) {
|
||||
mGrFace = gr_make_face(&mCallbackData, GrGetTable, gr_face_default);
|
||||
if (!mGrFace) {
|
||||
return false;
|
||||
}
|
||||
@ -170,8 +126,6 @@ gfxGraphiteShaper::ShapeText(gfxContext *aContext,
|
||||
}
|
||||
|
||||
if (!mGrFont) {
|
||||
gr_face_destroy(mGrFace);
|
||||
mGrFace = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -27,22 +27,8 @@ public:
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText);
|
||||
|
||||
const void* GetTable(uint32_t aTag, size_t *aLength);
|
||||
|
||||
static void Shutdown();
|
||||
|
||||
struct CallbackData {
|
||||
gfxFont *mFont;
|
||||
gfxGraphiteShaper *mShaper;
|
||||
gfxContext *mContext;
|
||||
};
|
||||
|
||||
struct TableRec {
|
||||
hb_blob_t *mBlob;
|
||||
const void *mData;
|
||||
uint32_t mLength;
|
||||
};
|
||||
|
||||
protected:
|
||||
nsresult SetGlyphsFromSegment(gfxContext *aContext,
|
||||
gfxShapedText *aShapedText,
|
||||
@ -51,13 +37,20 @@ protected:
|
||||
const PRUnichar *aText,
|
||||
gr_segment *aSegment);
|
||||
|
||||
gr_face *mGrFace;
|
||||
gr_font *mGrFont;
|
||||
static float GrGetAdvance(const void* appFontHandle, uint16_t glyphid);
|
||||
|
||||
gr_face *mGrFace; // owned by the font entry; shaper must call
|
||||
// gfxFontEntry::ReleaseGrFace when finished with it
|
||||
gr_font *mGrFont; // owned by the shaper itself
|
||||
|
||||
struct CallbackData {
|
||||
gfxFont *mFont;
|
||||
gfxGraphiteShaper *mShaper;
|
||||
gfxContext *mContext;
|
||||
};
|
||||
|
||||
CallbackData mCallbackData;
|
||||
|
||||
nsDataHashtable<nsUint32HashKey,TableRec> mTables;
|
||||
|
||||
// Convert HTML 'lang' (BCP47) to Graphite language code
|
||||
static uint32_t GetGraphiteTagForLang(const nsCString& aLang);
|
||||
static nsTHashtable<nsUint32HashKey> sLanguageTags;
|
||||
|
@ -43,7 +43,8 @@ using namespace mozilla::unicode; // for Unicode property lookup
|
||||
|
||||
gfxHarfBuzzShaper::gfxHarfBuzzShaper(gfxFont *aFont)
|
||||
: gfxFontShaper(aFont),
|
||||
mHBFace(nullptr),
|
||||
mHBFace(aFont->GetFontEntry()->GetHBFace()),
|
||||
mHBFont(nullptr),
|
||||
mKernTable(nullptr),
|
||||
mHmtxTable(nullptr),
|
||||
mNumLongMetrics(0),
|
||||
@ -52,63 +53,30 @@ gfxHarfBuzzShaper::gfxHarfBuzzShaper(gfxFont *aFont)
|
||||
mSubtableOffset(0),
|
||||
mUVSTableOffset(0),
|
||||
mUseFontGetGlyph(aFont->ProvidesGetGlyph()),
|
||||
mUseFontGlyphWidths(false)
|
||||
mUseFontGlyphWidths(false),
|
||||
mInitialized(false)
|
||||
{
|
||||
}
|
||||
|
||||
gfxHarfBuzzShaper::~gfxHarfBuzzShaper()
|
||||
{
|
||||
hb_blob_destroy(mCmapTable);
|
||||
hb_blob_destroy(mHmtxTable);
|
||||
hb_blob_destroy(mKernTable);
|
||||
hb_face_destroy(mHBFace);
|
||||
}
|
||||
|
||||
/*
|
||||
* HarfBuzz callback access to font table data
|
||||
*/
|
||||
|
||||
// callback for HarfBuzz to get a font table (in hb_blob_t form)
|
||||
// from the shaper (passed as aUserData)
|
||||
static hb_blob_t *
|
||||
HBGetTable(hb_face_t *face, hb_tag_t aTag, void *aUserData)
|
||||
{
|
||||
gfxHarfBuzzShaper *shaper = static_cast<gfxHarfBuzzShaper*>(aUserData);
|
||||
gfxFont *font = shaper->GetFont();
|
||||
|
||||
// bug 589682 - ignore the GDEF table in buggy fonts (applies to
|
||||
// Italic and BoldItalic faces of Times New Roman)
|
||||
if (aTag == TRUETYPE_TAG('G','D','E','F') &&
|
||||
font->GetFontEntry()->IgnoreGDEF()) {
|
||||
return nullptr;
|
||||
if (mCmapTable) {
|
||||
hb_blob_destroy(mCmapTable);
|
||||
}
|
||||
|
||||
// bug 721719 - ignore the GSUB table in buggy fonts (applies to Roboto,
|
||||
// at least on some Android ICS devices; set in gfxFT2FontList.cpp)
|
||||
if (aTag == TRUETYPE_TAG('G','S','U','B') &&
|
||||
font->GetFontEntry()->IgnoreGSUB()) {
|
||||
return nullptr;
|
||||
if (mHmtxTable) {
|
||||
hb_blob_destroy(mHmtxTable);
|
||||
}
|
||||
if (mKernTable) {
|
||||
hb_blob_destroy(mKernTable);
|
||||
}
|
||||
if (mHBFont) {
|
||||
hb_font_destroy(mHBFont);
|
||||
}
|
||||
if (mHBFace) {
|
||||
hb_face_destroy(mHBFace);
|
||||
}
|
||||
|
||||
return font->GetFontTable(aTag);
|
||||
}
|
||||
|
||||
/*
|
||||
* HarfBuzz font callback functions; font_data is a ptr to a
|
||||
* FontCallbackData struct
|
||||
*/
|
||||
|
||||
struct FontCallbackData {
|
||||
FontCallbackData(gfxHarfBuzzShaper *aShaper, gfxContext *aContext,
|
||||
bool aKerning)
|
||||
: mShaper(aShaper), mContext(aContext), mKerning(aKerning)
|
||||
{ }
|
||||
|
||||
gfxHarfBuzzShaper *mShaper;
|
||||
gfxContext *mContext;
|
||||
bool mKerning;
|
||||
};
|
||||
|
||||
#define UNICODE_BMP_LIMIT 0x10000
|
||||
|
||||
hb_codepoint_t
|
||||
@ -175,8 +143,8 @@ HBGetGlyph(hb_font_t *font, void *font_data,
|
||||
hb_codepoint_t *glyph,
|
||||
void *user_data)
|
||||
{
|
||||
const FontCallbackData *fcd =
|
||||
static_cast<const FontCallbackData*>(font_data);
|
||||
const gfxHarfBuzzShaper::FontCallbackData *fcd =
|
||||
static_cast<const gfxHarfBuzzShaper::FontCallbackData*>(font_data);
|
||||
*glyph = fcd->mShaper->GetGlyph(unicode, variation_selector);
|
||||
return *glyph != 0;
|
||||
}
|
||||
@ -240,8 +208,8 @@ static hb_position_t
|
||||
HBGetGlyphHAdvance(hb_font_t *font, void *font_data,
|
||||
hb_codepoint_t glyph, void *user_data)
|
||||
{
|
||||
const FontCallbackData *fcd =
|
||||
static_cast<const FontCallbackData*>(font_data);
|
||||
const gfxHarfBuzzShaper::FontCallbackData *fcd =
|
||||
static_cast<const gfxHarfBuzzShaper::FontCallbackData*>(font_data);
|
||||
return fcd->mShaper->GetGlyphHAdvance(fcd->mContext, glyph);
|
||||
}
|
||||
|
||||
@ -500,7 +468,7 @@ gfxHarfBuzzShaper::GetHKerning(uint16_t aFirstGlyph,
|
||||
}
|
||||
|
||||
if (!mKernTable) {
|
||||
mKernTable = mFont->GetFontTable(TRUETYPE_TAG('k','e','r','n'));
|
||||
mKernTable = mFont->GetFontEntry()->GetFontTable(TRUETYPE_TAG('k','e','r','n'));
|
||||
if (!mKernTable) {
|
||||
mKernTable = hb_blob_get_empty();
|
||||
}
|
||||
@ -644,15 +612,9 @@ HBGetHKerning(hb_font_t *font, void *font_data,
|
||||
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
|
||||
void *user_data)
|
||||
{
|
||||
const FontCallbackData *fcd =
|
||||
static_cast<const FontCallbackData*>(font_data);
|
||||
|
||||
// return 0 if kerning is explicitly disabled
|
||||
if (fcd->mKerning) {
|
||||
return fcd->mShaper->GetHKerning(first_glyph, second_glyph);
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
const gfxHarfBuzzShaper::FontCallbackData *fcd =
|
||||
static_cast<const gfxHarfBuzzShaper::FontCallbackData*>(font_data);
|
||||
return fcd->mShaper->GetHKerning(first_glyph, second_glyph);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -859,12 +821,15 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mHBFace) {
|
||||
mCallbackData.mContext = aContext;
|
||||
gfxFontEntry *entry = mFont->GetFontEntry();
|
||||
|
||||
if (!mInitialized) {
|
||||
mInitialized = true;
|
||||
mCallbackData.mShaper = this;
|
||||
|
||||
mUseFontGlyphWidths = mFont->ProvidesGlyphWidths();
|
||||
|
||||
// set up the harfbuzz face etc the first time we use the font
|
||||
|
||||
if (!sHBFontFuncs) {
|
||||
// static function callback pointers, initialized by the first
|
||||
// harfbuzz shaper used
|
||||
@ -905,11 +870,9 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
|
||||
nullptr, nullptr);
|
||||
}
|
||||
|
||||
mHBFace = hb_face_create_for_tables(HBGetTable, this, nullptr);
|
||||
|
||||
if (!mUseFontGetGlyph) {
|
||||
// get the cmap table and find offset to our subtable
|
||||
mCmapTable = mFont->GetFontTable(TRUETYPE_TAG('c','m','a','p'));
|
||||
mCmapTable = entry->GetFontTable(TRUETYPE_TAG('c','m','a','p'));
|
||||
if (!mCmapTable) {
|
||||
NS_WARNING("failed to load cmap, glyphs will be missing");
|
||||
return false;
|
||||
@ -928,8 +891,7 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
|
||||
// the hmtx table directly;
|
||||
// read mNumLongMetrics from hhea table without caching its blob,
|
||||
// and preload/cache the hmtx table
|
||||
hb_blob_t *hheaTable =
|
||||
mFont->GetFontTable(TRUETYPE_TAG('h','h','e','a'));
|
||||
gfxFontEntry::AutoTable hheaTable(entry, TRUETYPE_TAG('h','h','e','a'));
|
||||
if (hheaTable) {
|
||||
uint32_t len;
|
||||
const HMetricsHeader* hhea =
|
||||
@ -943,7 +905,7 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
|
||||
// in that case, we won't be able to use this font
|
||||
// (this method will return FALSE below if mHmtx is null)
|
||||
mHmtxTable =
|
||||
mFont->GetFontTable(TRUETYPE_TAG('h','m','t','x'));
|
||||
entry->GetFontTable(TRUETYPE_TAG('h','m','t','x'));
|
||||
if (hb_blob_get_length(mHmtxTable) <
|
||||
mNumLongMetrics * sizeof(HLongMetric)) {
|
||||
// hmtx table is not large enough for the claimed
|
||||
@ -954,8 +916,13 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
|
||||
}
|
||||
}
|
||||
}
|
||||
hb_blob_destroy(hheaTable);
|
||||
}
|
||||
|
||||
mHBFont = hb_font_create(mHBFace);
|
||||
hb_font_set_funcs(mHBFont, sHBFontFuncs, &mCallbackData, nullptr);
|
||||
hb_font_set_ppem(mHBFont, mFont->GetAdjustedSize(), mFont->GetAdjustedSize());
|
||||
uint32_t scale = FloatToFixed(mFont->GetAdjustedSize()); // 16.16 fixed-point
|
||||
hb_font_set_scale(mHBFont, scale, scale);
|
||||
}
|
||||
|
||||
if ((!mUseFontGetGlyph && mCmapFormat <= 0) ||
|
||||
@ -965,24 +932,14 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
|
||||
}
|
||||
|
||||
const gfxFontStyle *style = mFont->GetStyle();
|
||||
// kerning is enabled *except* when explicitly disabled (font-kerning: none)
|
||||
FontCallbackData fcd(this, aContext, !mFont->KerningDisabled());
|
||||
hb_font_t *font = hb_font_create(mHBFace);
|
||||
hb_font_set_funcs(font, sHBFontFuncs, &fcd, nullptr);
|
||||
hb_font_set_ppem(font, mFont->GetAdjustedSize(), mFont->GetAdjustedSize());
|
||||
uint32_t scale = FloatToFixed(mFont->GetAdjustedSize()); // 16.16 fixed-point
|
||||
hb_font_set_scale(font, scale, scale);
|
||||
|
||||
nsAutoTArray<hb_feature_t,20> features;
|
||||
|
||||
gfxFontEntry *entry = mFont->GetFontEntry();
|
||||
|
||||
nsDataHashtable<nsUint32HashKey,uint32_t> mergedFeatures;
|
||||
|
||||
if (MergeFontFeatures(style,
|
||||
mFont->GetFontEntry()->mFeatureSettings,
|
||||
entry->mFeatureSettings,
|
||||
aShapedText->DisableLigatures(),
|
||||
mFont->GetFontEntry()->FamilyName(),
|
||||
entry->FamilyName(),
|
||||
mergedFeatures))
|
||||
{
|
||||
// enumerate result and insert into hb_feature array
|
||||
@ -1020,7 +977,7 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
|
||||
reinterpret_cast<const uint16_t*>(aText),
|
||||
length, 0, length);
|
||||
|
||||
hb_shape(font, buffer, features.Elements(), features.Length());
|
||||
hb_shape(mHBFont, buffer, features.Elements(), features.Length());
|
||||
|
||||
if (isRightToLeft) {
|
||||
hb_buffer_reverse(buffer);
|
||||
@ -1031,7 +988,6 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
|
||||
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "failed to store glyphs into gfxShapedWord");
|
||||
hb_buffer_destroy(buffer);
|
||||
hb_font_destroy(font);
|
||||
|
||||
return NS_SUCCEEDED(rv);
|
||||
}
|
||||
|
@ -18,6 +18,15 @@ public:
|
||||
gfxHarfBuzzShaper(gfxFont *aFont);
|
||||
virtual ~gfxHarfBuzzShaper();
|
||||
|
||||
/*
|
||||
* For HarfBuzz font callback functions, font_data is a ptr to a
|
||||
* FontCallbackData struct
|
||||
*/
|
||||
struct FontCallbackData {
|
||||
gfxHarfBuzzShaper *mShaper;
|
||||
gfxContext *mContext;
|
||||
};
|
||||
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const PRUnichar *aText,
|
||||
uint32_t aOffset,
|
||||
@ -54,9 +63,15 @@ protected:
|
||||
nsTArray<nsPoint>& aPositions,
|
||||
uint32_t aAppUnitsPerDevUnit);
|
||||
|
||||
// harfbuzz face object, created on first use (caches font tables)
|
||||
// harfbuzz face object: we acquire a reference from the font entry
|
||||
// on shaper creation, and release it in our destructor
|
||||
hb_face_t *mHBFace;
|
||||
|
||||
// size-specific font object, owned by the gfxHarfBuzzShaper
|
||||
hb_font_t *mHBFont;
|
||||
|
||||
FontCallbackData mCallbackData;
|
||||
|
||||
// Following table references etc are declared "mutable" because the
|
||||
// harfbuzz callback functions take a const ptr to the shaper, but
|
||||
// wish to cache tables here to avoid repeatedly looking them up
|
||||
@ -87,6 +102,8 @@ protected:
|
||||
// Whether the font implements GetGlyphWidth, or we should read tables
|
||||
// directly to get ideal widths
|
||||
bool mUseFontGlyphWidths;
|
||||
|
||||
bool mInitialized;
|
||||
};
|
||||
|
||||
#endif /* GFX_HARFBUZZSHAPER_H */
|
||||
|
@ -189,13 +189,17 @@ gfxMacFont::InitMetrics()
|
||||
// return the true value for OpenType/CFF fonts (it normalizes to 1000,
|
||||
// which then leads to metrics errors when we read the 'hmtx' table to
|
||||
// get glyph advances for HarfBuzz, see bug 580863)
|
||||
const uint32_t kHeadTableTag = TRUETYPE_TAG('h','e','a','d');
|
||||
AutoFallibleTArray<uint8_t,sizeof(HeadTable)> headData;
|
||||
if (NS_SUCCEEDED(mFontEntry->GetFontTable(kHeadTableTag, headData)) &&
|
||||
headData.Length() >= sizeof(HeadTable)) {
|
||||
HeadTable *head = reinterpret_cast<HeadTable*>(headData.Elements());
|
||||
upem = head->unitsPerEm;
|
||||
} else {
|
||||
CFDataRef headData =
|
||||
::CGFontCopyTableForTag(mCGFont, TRUETYPE_TAG('h','e','a','d'));
|
||||
if (headData) {
|
||||
if (size_t(::CFDataGetLength(headData)) >= sizeof(HeadTable)) {
|
||||
const HeadTable *head =
|
||||
reinterpret_cast<const HeadTable*>(::CFDataGetBytePtr(headData));
|
||||
upem = head->unitsPerEm;
|
||||
}
|
||||
::CFRelease(headData);
|
||||
}
|
||||
if (!upem) {
|
||||
upem = ::CGFontGetUnitsPerEm(mCGFont);
|
||||
}
|
||||
|
||||
@ -348,35 +352,6 @@ gfxMacFont::GetCharWidth(CFDataRef aCmap, PRUnichar aUniChar,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
gfxMacFont::DestroyBlobFunc(void* aUserData)
|
||||
{
|
||||
::CFRelease((CFDataRef)aUserData);
|
||||
}
|
||||
|
||||
hb_blob_t *
|
||||
gfxMacFont::GetFontTable(uint32_t aTag)
|
||||
{
|
||||
CFDataRef dataRef = ::CGFontCopyTableForTag(mCGFont, aTag);
|
||||
if (dataRef) {
|
||||
return hb_blob_create((const char*)::CFDataGetBytePtr(dataRef),
|
||||
::CFDataGetLength(dataRef),
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
(void*)dataRef, DestroyBlobFunc);
|
||||
}
|
||||
|
||||
if (mFontEntry->IsUserFont() && !mFontEntry->IsLocalUserFont()) {
|
||||
// for downloaded fonts, there may be layout tables cached in the entry
|
||||
// even though they're absent from the sanitized platform font
|
||||
hb_blob_t *blob;
|
||||
if (mFontEntry->GetExistingFontTable(aTag, &blob)) {
|
||||
return blob;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Try to initialize font metrics via platform APIs (CG/CT),
|
||||
// and set mIsValid = TRUE on success.
|
||||
// We ONLY call this for local (platform) fonts that are not sfnt format;
|
||||
|
@ -40,10 +40,6 @@ public:
|
||||
gfxContext *aContextForTightBoundingBox,
|
||||
Spacing *aSpacing);
|
||||
|
||||
// override gfxFont table access function to bypass gfxFontEntry cache,
|
||||
// use CGFontRef API to get direct access to system font data
|
||||
virtual hb_blob_t *GetFontTable(uint32_t aTag);
|
||||
|
||||
virtual mozilla::TemporaryRef<mozilla::gfx::ScaledFont> GetScaledFont(mozilla::gfx::DrawTarget *aTarget);
|
||||
|
||||
virtual void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
|
||||
@ -73,8 +69,6 @@ protected:
|
||||
gfxFloat GetCharWidth(CFDataRef aCmap, PRUnichar aUniChar,
|
||||
uint32_t *aGlyphID, gfxFloat aConvFactor);
|
||||
|
||||
static void DestroyBlobFunc(void* aUserData);
|
||||
|
||||
// a weak reference to the CoreGraphics font: this is owned by the
|
||||
// MacOSFontEntry, it is not retained or released by gfxMacFont
|
||||
CGFontRef mCGFont;
|
||||
|
@ -40,8 +40,9 @@ public:
|
||||
|
||||
virtual CGFontRef GetFontRef();
|
||||
|
||||
virtual nsresult GetFontTable(uint32_t aTableTag,
|
||||
FallibleTArray<uint8_t>& aBuffer);
|
||||
// override gfxFontEntry table access function to bypass table cache,
|
||||
// use CGFontRef API to get direct access to system font data
|
||||
virtual hb_blob_t *GetFontTable(uint32_t aTag) MOZ_OVERRIDE;
|
||||
|
||||
virtual void SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf,
|
||||
FontListSizes* aSizes) const;
|
||||
@ -57,6 +58,8 @@ protected:
|
||||
|
||||
virtual bool HasFontTable(uint32_t aTableTag);
|
||||
|
||||
static void DestroyBlobFunc(void* aUserData);
|
||||
|
||||
CGFontRef mFontRef; // owning reference to the CGFont, released on destruction
|
||||
|
||||
bool mFontRefInitialized;
|
||||
|
@ -201,41 +201,21 @@ static const ScriptRange sComplexScripts[] = {
|
||||
// Thai seems to be "renderable" without AAT morphing tables
|
||||
};
|
||||
|
||||
static void
|
||||
DestroyBlobFunc(void* aUserData)
|
||||
{
|
||||
FallibleTArray<uint8_t>* data = static_cast<FallibleTArray<uint8_t>*>(aUserData);
|
||||
delete data;
|
||||
}
|
||||
|
||||
// This is only used via MacOSFontEntry::ReadCMAP when checking for layout
|
||||
// support; it does not respect the mIgnore* flags on font entries, as those
|
||||
// are not relevant here at present.
|
||||
static hb_blob_t *
|
||||
GetTableForHarfBuzz(hb_face_t *aFace, hb_tag_t aTag, void *aUserData)
|
||||
{
|
||||
gfxFontEntry *fe = static_cast<gfxFontEntry*>(aUserData);
|
||||
FallibleTArray<uint8_t>* table = new FallibleTArray<uint8_t>;
|
||||
nsresult rv = fe->GetFontTable(aTag, *table);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return hb_blob_create((const char*)table->Elements(), table->Length(),
|
||||
HB_MEMORY_MODE_READONLY, table, DestroyBlobFunc);
|
||||
}
|
||||
delete table;
|
||||
return hb_blob_get_empty();
|
||||
}
|
||||
|
||||
static bool
|
||||
SupportsScriptInGSUB(gfxFontEntry* aFontEntry, const hb_tag_t* aScriptTags)
|
||||
{
|
||||
hb_face_t *face = hb_face_create_for_tables(GetTableForHarfBuzz,
|
||||
aFontEntry, nullptr);
|
||||
hb_face_t *face = aFontEntry->GetHBFace();
|
||||
if (!face) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int index;
|
||||
hb_tag_t chosenScript;
|
||||
bool found =
|
||||
hb_ot_layout_table_choose_script(face, TRUETYPE_TAG('G','S','U','B'),
|
||||
aScriptTags, &index, &chosenScript);
|
||||
hb_face_destroy(face);
|
||||
|
||||
return found && chosenScript != TRUETYPE_TAG('D','F','L','T');
|
||||
}
|
||||
|
||||
@ -250,18 +230,19 @@ MacOSFontEntry::ReadCMAP()
|
||||
nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
|
||||
|
||||
uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
|
||||
nsresult rv;
|
||||
|
||||
AutoFallibleTArray<uint8_t,16384> cmap;
|
||||
rv = GetFontTable(kCMAP, cmap);
|
||||
AutoTable cmapTable(this, kCMAP);
|
||||
if (!cmapTable) {
|
||||
return NS_OK; // leave it empty
|
||||
}
|
||||
|
||||
bool unicodeFont = false, symbolFont = false; // currently ignored
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(),
|
||||
*charmap, mUVSOffset,
|
||||
unicodeFont, symbolFont);
|
||||
}
|
||||
uint32_t cmapLen;
|
||||
const char* cmapData = hb_blob_get_data(cmapTable, &cmapLen);
|
||||
nsresult rv = gfxFontUtils::ReadCMAP((const uint8_t*)cmapData, cmapLen,
|
||||
*charmap, mUVSOffset,
|
||||
unicodeFont, symbolFont);
|
||||
|
||||
if (NS_SUCCEEDED(rv) && !HasGraphiteTables()) {
|
||||
// We assume a Graphite font knows what it's doing,
|
||||
@ -395,33 +376,29 @@ MacOSFontEntry::GetFontRef()
|
||||
return mFontRef;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MacOSFontEntry::GetFontTable(uint32_t aTableTag,
|
||||
FallibleTArray<uint8_t>& aBuffer)
|
||||
/*static*/ void
|
||||
MacOSFontEntry::DestroyBlobFunc(void* aUserData)
|
||||
{
|
||||
nsAutoreleasePool localPool;
|
||||
::CFRelease((CFDataRef)aUserData);
|
||||
}
|
||||
|
||||
hb_blob_t *
|
||||
MacOSFontEntry::GetFontTable(uint32_t aTag)
|
||||
{
|
||||
CGFontRef fontRef = GetFontRef();
|
||||
if (!fontRef) {
|
||||
return NS_ERROR_FAILURE;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CFDataRef tableData = ::CGFontCopyTableForTag(fontRef, aTableTag);
|
||||
if (!tableData) {
|
||||
return NS_ERROR_FAILURE;
|
||||
CFDataRef dataRef = ::CGFontCopyTableForTag(fontRef, aTag);
|
||||
if (dataRef) {
|
||||
return hb_blob_create((const char*)::CFDataGetBytePtr(dataRef),
|
||||
::CFDataGetLength(dataRef),
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
(void*)dataRef, DestroyBlobFunc);
|
||||
}
|
||||
|
||||
nsresult rval = NS_OK;
|
||||
CFIndex dataLength = ::CFDataGetLength(tableData);
|
||||
if (aBuffer.AppendElements(dataLength)) {
|
||||
::CFDataGetBytes(tableData, ::CFRangeMake(0, dataLength),
|
||||
aBuffer.Elements());
|
||||
} else {
|
||||
rval = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
::CFRelease(tableData);
|
||||
|
||||
return rval;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -640,22 +617,26 @@ gfxSingleFaceMacFontFamily::LocalizedName(nsAString& aLocalizedName)
|
||||
void
|
||||
gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList)
|
||||
{
|
||||
if (mOtherFamilyNamesInitialized)
|
||||
if (mOtherFamilyNamesInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
gfxFontEntry *fe = mAvailableFonts[0];
|
||||
if (!fe)
|
||||
if (!fe) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t kNAME = TRUETYPE_TAG('n','a','m','e');
|
||||
AutoFallibleTArray<uint8_t,8192> buffer;
|
||||
|
||||
if (fe->GetFontTable(kNAME, buffer) != NS_OK)
|
||||
gfxFontEntry::AutoTable nameTable(fe, kNAME);
|
||||
if (!nameTable) {
|
||||
return;
|
||||
}
|
||||
|
||||
mHasOtherFamilyNames = ReadOtherFamilyNamesForFace(aPlatformFontList,
|
||||
buffer,
|
||||
nameTable,
|
||||
true);
|
||||
|
||||
mOtherFamilyNamesInitialized = true;
|
||||
}
|
||||
|
||||
|
@ -315,7 +315,8 @@ public:
|
||||
gfxSystemFcFontEntry(cairo_font_face_t *aFontFace,
|
||||
FcPattern *aFontPattern,
|
||||
const nsAString& aName)
|
||||
: gfxFcFontEntry(aName), mFontFace(aFontFace)
|
||||
: gfxFcFontEntry(aName), mFontFace(aFontFace),
|
||||
mFTFace(nullptr), mFTFaceInitialized(false)
|
||||
{
|
||||
cairo_font_face_reference(mFontFace);
|
||||
cairo_font_face_set_user_data(mFontFace, &sFontEntryKey, this, NULL);
|
||||
@ -336,10 +337,89 @@ public:
|
||||
cairo_font_face_set_user_data(mFontFace, &sFontEntryKey, NULL, NULL);
|
||||
cairo_font_face_destroy(mFontFace);
|
||||
}
|
||||
|
||||
virtual void ForgetHBFace();
|
||||
virtual void ReleaseGrFace(gr_face* aFace);
|
||||
|
||||
protected:
|
||||
virtual nsresult
|
||||
CopyFontTable(uint32_t aTableTag, FallibleTArray<uint8_t>& aBuffer) MOZ_OVERRIDE;
|
||||
|
||||
void MaybeReleaseFTFace();
|
||||
|
||||
private:
|
||||
cairo_font_face_t *mFontFace;
|
||||
FT_Face mFTFace;
|
||||
bool mFTFaceInitialized;
|
||||
};
|
||||
|
||||
nsresult
|
||||
gfxSystemFcFontEntry::CopyFontTable(uint32_t aTableTag,
|
||||
FallibleTArray<uint8_t>& aBuffer)
|
||||
{
|
||||
if (!mFTFaceInitialized) {
|
||||
mFTFaceInitialized = true;
|
||||
FcChar8 *filename;
|
||||
if (FcPatternGetString(mPatterns[0], FC_FILE, 0, &filename) != FcResultMatch) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
int index;
|
||||
if (FcPatternGetInteger(mPatterns[0], FC_INDEX, 0, &index) != FcResultMatch) {
|
||||
index = 0; // default to 0 if not found in pattern
|
||||
}
|
||||
if (FT_New_Face(gfxPangoFontGroup::GetFTLibrary(),
|
||||
(const char*)filename, index, &mFTFace) != 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mFTFace) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
FT_ULong length = 0;
|
||||
if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, nullptr, &length) != 0) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
if (!aBuffer.SetLength(length)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, aBuffer.Elements(), &length) != 0) {
|
||||
aBuffer.Clear();
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
gfxSystemFcFontEntry::MaybeReleaseFTFace()
|
||||
{
|
||||
// don't release if either HB or Gr face still exists
|
||||
if (mHBFace || mGrFace) {
|
||||
return;
|
||||
}
|
||||
if (mFTFace) {
|
||||
FT_Done_Face(mFTFace);
|
||||
mFTFace = nullptr;
|
||||
}
|
||||
mFTFaceInitialized = false;
|
||||
}
|
||||
|
||||
void
|
||||
gfxSystemFcFontEntry::ForgetHBFace()
|
||||
{
|
||||
gfxFontEntry::ForgetHBFace();
|
||||
MaybeReleaseFTFace();
|
||||
}
|
||||
|
||||
void
|
||||
gfxSystemFcFontEntry::ReleaseGrFace(gr_face* aFace)
|
||||
{
|
||||
gfxFontEntry::ReleaseGrFace(aFace);
|
||||
MaybeReleaseFTFace();
|
||||
}
|
||||
|
||||
// A namespace for @font-face family names in FcPatterns so that fontconfig
|
||||
// aliases do not pick up families from @font-face rules and so that
|
||||
// fontconfig rules can distinguish between web fonts and platform fonts.
|
||||
@ -514,8 +594,7 @@ public:
|
||||
// lifetime of the FontEntry.
|
||||
PangoCoverage *GetPangoCoverage();
|
||||
|
||||
virtual nsresult
|
||||
GetFontTable(uint32_t aTableTag, FallibleTArray<uint8_t>& aBuffer) MOZ_OVERRIDE;
|
||||
virtual hb_blob_t* GetFontTable(uint32_t aTableTag) MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
void InitPattern();
|
||||
@ -732,27 +811,33 @@ gfxDownloadedFcFontEntry::GetPangoCoverage()
|
||||
return mPangoCoverage;
|
||||
}
|
||||
|
||||
nsresult
|
||||
gfxDownloadedFcFontEntry::GetFontTable(uint32_t aTableTag,
|
||||
FallibleTArray<uint8_t>& aBuffer)
|
||||
static int
|
||||
DirEntryCmp(const void* aKey, const void* aItem)
|
||||
{
|
||||
FT_ULong length = 0;
|
||||
FT_Error error = FT_Load_Sfnt_Table(mFace, aTableTag, 0, nullptr, &length);
|
||||
if (error) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
int32_t tag = *static_cast<const int32_t*>(aKey);
|
||||
const TableDirEntry* entry = static_cast<const TableDirEntry*>(aItem);
|
||||
return tag - int32_t(entry->tag);
|
||||
}
|
||||
|
||||
if (!aBuffer.SetLength(length)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
hb_blob_t *
|
||||
gfxDownloadedFcFontEntry::GetFontTable(uint32_t aTableTag)
|
||||
{
|
||||
// The entry already owns the (sanitized) sfnt data in mFontData,
|
||||
// so we can just return a blob that "wraps" the appropriate chunk of it.
|
||||
// The blob should not attempt to free its data, as the entire sfnt data
|
||||
// will be freed when the font entry is deleted.
|
||||
const SFNTHeader* header = reinterpret_cast<const SFNTHeader*>(mFontData);
|
||||
const TableDirEntry* dir = reinterpret_cast<const TableDirEntry*>(header + 1);
|
||||
dir = static_cast<const TableDirEntry*>
|
||||
(bsearch(&aTableTag, dir, header->numTables, sizeof(TableDirEntry),
|
||||
DirEntryCmp));
|
||||
if (dir) {
|
||||
return hb_blob_create(reinterpret_cast<const char*>(mFontData) +
|
||||
dir->offset, dir->length,
|
||||
HB_MEMORY_MODE_READONLY, nullptr, nullptr);
|
||||
|
||||
error = FT_Load_Sfnt_Table(mFace, aTableTag, 0, aBuffer.Elements(), &length);
|
||||
if (error) {
|
||||
aBuffer.Clear();
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -95,6 +95,7 @@ private:
|
||||
return mSizeAdjustFactor;
|
||||
}
|
||||
|
||||
friend class gfxSystemFcFontEntry;
|
||||
static FT_Library GetFTLibrary();
|
||||
};
|
||||
|
||||
|
@ -246,6 +246,7 @@ gfxPlatform::gfxPlatform()
|
||||
mFallbackUsesCmaps = UNINITIALIZED_VALUE;
|
||||
|
||||
mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
|
||||
mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
|
||||
mBidiNumeralOption = UNINITIALIZED_VALUE;
|
||||
|
||||
uint32_t canvasMask = (1 << BACKEND_CAIRO) | (1 << BACKEND_SKIA);
|
||||
@ -875,6 +876,17 @@ gfxPlatform::UseCmapsDuringSystemFallback()
|
||||
return mFallbackUsesCmaps;
|
||||
}
|
||||
|
||||
bool
|
||||
gfxPlatform::OpenTypeSVGEnabled()
|
||||
{
|
||||
if (mOpenTypeSVGEnabled == UNINITIALIZED_VALUE) {
|
||||
mOpenTypeSVGEnabled =
|
||||
Preferences::GetBool(GFX_PREF_OPENTYPE_SVG, false);
|
||||
}
|
||||
|
||||
return mOpenTypeSVGEnabled > 0;
|
||||
}
|
||||
|
||||
bool
|
||||
gfxPlatform::UseGraphiteShaping()
|
||||
{
|
||||
@ -1674,6 +1686,7 @@ gfxPlatform::FontsPrefsChanged(const char *aPref)
|
||||
} else if (!strcmp(BIDI_NUMERAL_PREF, aPref)) {
|
||||
mBidiNumeralOption = UNINITIALIZED_VALUE;
|
||||
} else if (!strcmp(GFX_PREF_OPENTYPE_SVG, aPref)) {
|
||||
mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
|
||||
gfxFontCache::GetCache()->AgeAllGenerations();
|
||||
}
|
||||
}
|
||||
|
@ -364,6 +364,11 @@ public:
|
||||
*/
|
||||
bool UseCmapsDuringSystemFallback();
|
||||
|
||||
/**
|
||||
* Whether to render SVG glyphs within an OpenType font wrapper
|
||||
*/
|
||||
bool OpenTypeSVGEnabled();
|
||||
|
||||
/**
|
||||
* Whether to use the SIL Graphite rendering engine
|
||||
* (for fonts that include Graphite tables)
|
||||
@ -588,6 +593,7 @@ protected:
|
||||
|
||||
int8_t mAllowDownloadableFonts;
|
||||
int8_t mGraphiteShapingEnabled;
|
||||
int8_t mOpenTypeSVGEnabled;
|
||||
|
||||
int8_t mBidiNumeralOption;
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user