Merge inbound to m-c.

This commit is contained in:
Ryan VanderMeulen 2013-05-16 20:29:40 -04:00
commit 0a63e25ce6
164 changed files with 3462 additions and 2440 deletions

View File

@ -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);
}
});
});

View File

@ -1,6 +1,6 @@
[{
"size": 659020310,
"digest": "8201020a5214337cf19d43bb3fde8c4624d7a7a71f04a4522a34783194694fe5e66f8087acf6fe7080d7bf787b8311dd9ed8facfbac39198d0121f817b8eef32",
"size": 677339898,
"digest": "af1d883664bf4f02637060855d76026cceffd28a796ab3d65e16f1b0b6d1a8d5bb634388152ba63ecbfa2fbb1bd59317c0cfd508e163eaf950923b6b999369bc",
"algorithm": "sha512",
"filename": "emulator.zip"
}]

View File

@ -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"

View File

@ -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 = "";
},
};

View File

@ -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();
}
},

View File

@ -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>

View File

@ -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;

View File

@ -44,6 +44,7 @@ let Elements = {};
["toolbar", "toolbar"],
["browsers", "browsers"],
["appbar", "appbar"],
["contextappbar", "contextappbar"],
["contentViewport", "content-viewport"],
["progress", "progress-control"],
["progressContainer", "progress-container"],

View File

@ -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;

View File

@ -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')"/>

View File

@ -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)

View File

@ -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);

View File

@ -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 = "";

View File

@ -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];

View File

@ -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>

View File

@ -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>

View File

@ -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;

View File

@ -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 />

View File

@ -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",

View File

@ -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 />

View File

@ -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",

View File

@ -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";

View File

@ -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) {

View File

@ -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@;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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);

View File

@ -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.

View File

@ -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();

View File

@ -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, &currentTransform_);
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, &currentTransform_);
EnsureTarget();
if (!IsTargetValid()) {
error.Throw(NS_ERROR_FAILURE);

View File

@ -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)

View File

@ -196,6 +196,8 @@ WebGLContext::WebGLContext()
mMinInUseAttribArrayLength = 0;
mIsScreenCleared = false;
mDisableFragHighP = false;
}
WebGLContext::~WebGLContext()

View File

@ -857,6 +857,7 @@ protected:
bool mCanLoseContextInForeground;
bool mShouldPresent;
bool mIsScreenCleared;
bool mDisableFragHighP;
template<typename WebGLObjectType>
void DeleteWebGLObjectsArray(nsTArray<WebGLObjectType>& array);

View File

@ -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);

View File

@ -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;

View File

@ -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()

View File

@ -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*

View File

@ -167,8 +167,6 @@ public:
return nsDocument::GetElementById(aElementId);
}
virtual nsXPCClassInfo* GetClassInfo();
virtual void DocSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const;
// DocSizeOfIncludingThis is inherited from nsIDocument.

View File

@ -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

View File

@ -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

View File

@ -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;
};

View File

@ -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

View File

@ -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

View File

@ -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";

View File

@ -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

View File

@ -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);
}
};

View File

@ -38,9 +38,6 @@ DOMCI_CLASS(DeviceMotionEvent)
DOMCI_CLASS(DeviceAcceleration)
DOMCI_CLASS(DeviceRotationRate)
// HTML classes
DOMCI_CLASS(HTMLDocument)
// HTML element classes
DOMCI_CLASS(HTMLFormElement)

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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)
{

View File

@ -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);

View File

@ -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:

View File

@ -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 \

View 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>

View File

@ -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

View File

@ -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;

View 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");
}

View File

@ -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]

View File

@ -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*

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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()
{

View File

@ -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();

View File

@ -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)
{

View File

@ -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; }

View File

@ -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) {

View File

@ -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

View File

@ -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)
{

View File

@ -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()

View File

@ -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);

View File

@ -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.

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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;
};

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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 */

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}
/*

View File

@ -95,6 +95,7 @@ private:
return mSizeAdjustFactor;
}
friend class gfxSystemFcFontEntry;
static FT_Library GetFTLibrary();
};

View File

@ -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();
}
}

View File

@ -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