Merge the last PGO-green inbound changeset to m-c.

This commit is contained in:
Ryan VanderMeulen 2012-10-23 22:28:33 -04:00
commit 12d8547592
200 changed files with 4133 additions and 1794 deletions

View File

@ -83,6 +83,8 @@ const kDiscBulletText = String.fromCharCode(0x2022) + " ";
const kCircleBulletText = String.fromCharCode(0x25e6) + " ";
const kSquareBulletText = String.fromCharCode(0x25aa) + " ";
const MAX_TRIM_LENGTH = 100;
/**
* nsIAccessibleRetrieval service.
*/
@ -607,7 +609,7 @@ function prettyName(aIdentifier)
try {
msg += ", role: " + roleToString(acc.role);
if (acc.name)
msg += ", name: '" + acc.name + "'";
msg += ", name: '" + shortenString(acc.name) + "'";
} catch (e) {
msg += "defunct";
}
@ -625,6 +627,21 @@ function prettyName(aIdentifier)
return " '" + aIdentifier + "' ";
}
/**
* Shorten a long string if it exceeds MAX_TRIM_LENGTH.
* @param aString the string to shorten.
* @returns the shortened string.
*/
function shortenString(aString, aMaxLength)
{
if (aString.length <= MAX_TRIM_LENGTH)
return aString;
// Trim the string if its length is > MAX_TRIM_LENGTH characters.
var trimOffset = MAX_TRIM_LENGTH / 2;
return aString.substring(0, trimOffset - 1) + "..." +
aString.substring(aString.length - trimOffset, aString.length);
}
////////////////////////////////////////////////////////////////////////////////
// Private

View File

@ -56,8 +56,9 @@
this.getID = function changeText_getID()
{
return "change text '" + this.textData + "' -> " + this.textNode.data +
"for " + prettyName(this.containerNode);
return "change text '" + shortenString(this.textData) + "' -> '" +
shortenString(this.textNode.data) + "' for " +
prettyName(this.containerNode);
}
}

View File

@ -19,7 +19,6 @@ Cu.import('resource://gre/modules/DOMFMRadioParent.jsm');
Cu.import('resource://gre/modules/AlarmService.jsm');
Cu.import('resource://gre/modules/ActivitiesService.jsm');
Cu.import('resource://gre/modules/PermissionPromptHelper.jsm');
Cu.import('resource://gre/modules/PermissionSettings.jsm');
Cu.import('resource://gre/modules/ObjectWrapper.jsm');
Cu.import('resource://gre/modules/accessibility/AccessFu.jsm');
Cu.import('resource://gre/modules/Payment.jsm');

View File

@ -44,8 +44,53 @@ XPCOMUtils.defineLazyServiceGetter(Services, "settings",
"@mozilla.org/settingsService;1",
"nsISettingsService");
function UpdateCheckListener(updatePrompt) {
this._updatePrompt = updatePrompt;
}
UpdateCheckListener.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdateCheckListener]),
_updatePrompt: null,
onCheckComplete: function UCL_onCheckComplete(request, updates, updateCount) {
if (Services.um.activeUpdate) {
return;
}
if (updateCount == 0) {
this._updatePrompt.setUpdateStatus("no-updates");
return;
}
let update = Services.aus.selectUpdate(updates, updateCount);
if (!update) {
this._updatePrompt.setUpdateStatus("already-latest-version");
return;
}
this._updatePrompt.setUpdateStatus("check-complete");
this._updatePrompt.showUpdateAvailable(update);
},
onError: function UCL_onError(request, update) {
if (update.errorCode == NETWORK_ERROR_OFFLINE) {
this._updatePrompt.setUpdateStatus("retry-when-online");
}
Services.aus.QueryInterface(Ci.nsIUpdateCheckListener);
Services.aus.onError(request, update);
},
onProgress: function UCL_onProgress(request, position, totalSize) {
Services.aus.QueryInterface(Ci.nsIUpdateCheckListener);
Services.aus.onProgress(request, position, totalSize);
}
};
function UpdatePrompt() {
this.wrappedJSObject = this;
this._updateCheckListener = new UpdateCheckListener(this);
}
UpdatePrompt.prototype = {
@ -60,6 +105,7 @@ UpdatePrompt.prototype = {
_update: null,
_applyPromptTimer: null,
_waitingForIdle: false,
_updateCheckListner: null,
// nsIUpdatePrompt
@ -107,42 +153,6 @@ UpdatePrompt.prototype = {
showUpdateHistory: function UP_showUpdateHistory(aParent) { },
showUpdateInstalled: function UP_showUpdateInstalled() { },
// nsIUpdateCheckListener
onCheckComplete: function UP_onCheckComplete(request, updates, updateCount) {
if (Services.um.activeUpdate) {
return;
}
if (updateCount == 0) {
this.setUpdateStatus("no-updates");
return;
}
let update = Services.aus.selectUpdate(updates, updateCount);
if (!update) {
this.setUpdateStatus("already-latest-version");
return;
}
this.setUpdateStatus("check-complete");
this.showUpdateAvailable(update);
},
onError: function UP_onError(request, update) {
if (update.errorCode == NETWORK_ERROR_OFFLINE) {
this.setUpdateStatus("retry-when-online");
}
Services.aus.QueryInterface(Ci.nsIUpdateCheckListener);
Services.aus.onError(request, update);
},
onProgress: function UP_onProgress(request, position, totalSize) {
Services.aus.QueryInterface(Ci.nsIUpdateCheckListener);
Services.aus.onProgress(request, position, totalSize);
},
// Custom functions
waitForIdle: function UP_waitForIdle() {
@ -320,7 +330,7 @@ UpdatePrompt.prototype = {
let checker = Cc["@mozilla.org/updates/update-checker;1"]
.createInstance(Ci.nsIUpdateChecker);
checker.checkForUpdates(this, true);
checker.checkForUpdates(this._updateCheckListener, true);
},
handleEvent: function UP_handleEvent(evt) {

View File

@ -482,9 +482,7 @@
accesskey="&toolsMenu.accesskey;">
<menupopup id="menu_ToolsPopup"
#ifdef MOZ_SERVICES_SYNC
onpopupshowing="gSyncUI.updateUI(); SocialMenu.populate();"
#else
onpopupshowing="SocialMenu.populate();"
onpopupshowing="gSyncUI.updateUI();"
#endif
>
<menuitem id="menu_search"
@ -510,9 +508,23 @@
autocheck="false"
command="Social:Toggle"/>
<menu id="menu_socialAmbientMenu"
class="show-only-for-keyboard"
command="Social:Toggle">
<menupopup id="menu_socialAmbientMenuPopup"/>
class="show-only-for-keyboard">
<menupopup id="menu_socialAmbientMenuPopup">
<menuseparator id="socialAmbientMenuSeparator"
hidden="true"/>
<menuitem id="social-toggle-sidebar-keyboardmenuitem"
type="checkbox"
autocheck="false"
command="Social:ToggleSidebar"
label="&social.toggleSidebar.label;"
accesskey="&social.toggleSidebar.accesskey;"/>
<menuitem id="social-toggle-notifications-keyboardmenuitem"
type="checkbox"
autocheck="false"
command="Social:ToggleNotifications"
label="&social.toggleNotifications.label;"
accesskey="&social.toggleNotifications.accesskey;"/>
</menupopup>
</menu>
#ifdef MOZ_SERVICES_SYNC
<!-- only one of sync-setup or sync-menu will be showing at once -->

View File

@ -62,7 +62,7 @@ let SocialUI = {
break;
case "social:ambient-notification-changed":
SocialToolbar.updateButton();
SocialMenu.updateMenu();
SocialMenu.populate();
break;
case "social:profile-changed":
SocialToolbar.updateProfile();
@ -72,6 +72,8 @@ let SocialUI = {
case "nsPref:changed":
SocialSidebar.updateSidebar();
SocialToolbar.updateButton();
SocialMenu.populate();
break;
}
},
@ -99,25 +101,14 @@ let SocialUI = {
SocialToolbar.init();
SocialShareButton.init();
SocialSidebar.init();
SocialMenu.populate();
},
updateToggleCommand: function SocialUI_updateToggleCommand() {
let toggleCommand = this.toggleCommand;
// We only need to update the command itself - all our menu items use it.
toggleCommand.setAttribute("checked", Services.prefs.getBoolPref("social.enabled"));
// FIXME: bug 772808: menu items don't inherit the "hidden" state properly,
// need to update them manually.
// This should just be: toggleCommand.hidden = !Social.active;
for (let id of ["appmenu_socialToggle", "menu_socialToggle", "menu_socialAmbientMenu"]) {
let el = document.getElementById(id);
if (!el)
continue;
if (Social.active)
el.removeAttribute("hidden");
else
el.setAttribute("hidden", "true");
}
toggleCommand.setAttribute("hidden", Social.active ? "false" : "true");
},
// This handles "ActivateSocialFeature" events fired against content documents
@ -610,24 +601,28 @@ var SocialMenu = {
populate: function SocialMenu_populate() {
// This menu is only accessible through keyboard navigation.
let submenu = document.getElementById("menu_socialAmbientMenuPopup");
while (submenu.hasChildNodes())
submenu.removeChild(submenu.firstChild);
let ambientMenuItems = submenu.getElementsByClassName("ambient-menuitem");
for (let ambientMenuItem of ambientMenuItems)
submenu.removeChild(ambientMenuItem);
let provider = Social.provider;
if (Social.active && provider) {
let iconNames = Object.keys(provider.ambientNotificationIcons);
let separator = document.getElementById("socialAmbientMenuSeparator");
for (let name of iconNames) {
let icon = provider.ambientNotificationIcons[name];
if (!icon.label || !icon.menuURL)
continue;
let menuitem = document.createElement("menuitem");
menuitem.setAttribute("label", icon.label);
menuitem.classList.add("ambient-menuitem");
menuitem.addEventListener("command", function() {
openUILinkIn(icon.menuURL, "tab");
}, false);
submenu.appendChild(menuitem);
submenu.insertBefore(menuitem, separator);
}
separator.hidden = !iconNames.length;
}
document.getElementById("menu_socialAmbientMenu").hidden = !submenu.querySelector("menuitem");
document.getElementById("menu_socialAmbientMenu").hidden = !Social.enabled;
}
};
@ -692,11 +687,12 @@ var SocialToolbar = {
const CACHE_PREF_NAME = "social.cached.notificationIcons";
// provider.profile == undefined means no response yet from the provider
// to tell us whether the user is logged in or not.
if (!SocialUI.haveLoggedInUser() && provider.profile !== undefined) {
// The provider has responded with a profile and the user isn't logged
// in. The icons etc have already been removed by
// updateButtonHiddenState, so we want to nuke any cached icons we
// have and get out of here!
if (!Social.provider || !Social.provider.enabled ||
(!SocialUI.haveLoggedInUser() && provider.profile !== undefined)) {
// Either no enabled provider, or there is a provider and it has
// responded with a profile and the user isn't loggedin. The icons
// etc have already been removed by updateButtonHiddenState, so we want
// to nuke any cached icons we have and get out of here!
Services.prefs.clearUserPref(CACHE_PREF_NAME);
return;
}
@ -923,7 +919,7 @@ var SocialSidebar = {
updateSidebar: function SocialSidebar_updateSidebar() {
// Hide the toggle menu item if the sidebar cannot appear
let command = document.getElementById("Social:ToggleSidebar");
command.hidden = !this.canShow;
command.setAttribute("hidden", this.canShow ? "false" : "true");
// Hide the sidebar if it cannot appear, or has been toggled off.
// Also set the command "checked" state accordingly.

View File

@ -46,7 +46,8 @@ var tests = {
toolsPopup.removeEventListener("popupshown", ontoolspopupshownNoAmbient);
let socialToggleMore = document.getElementById("menu_socialAmbientMenu");
ok(socialToggleMore, "Keyboard accessible social menu should exist");
is(socialToggleMore.hidden, true, "Menu should be hidden when no ambient notifications.");
is(socialToggleMore.querySelectorAll("menuitem").length, 2, "The minimum number of menuitems is two when there are no ambient notifications.");
is(socialToggleMore.hidden, false, "Menu should be visible since we show some non-ambient notifications in the menu.");
toolsPopup.hidePopup();
next();
}, false);
@ -85,6 +86,7 @@ var tests = {
toolsPopup.removeEventListener("popupshown", ontoolspopupshownAmbient);
let socialToggleMore = document.getElementById("menu_socialAmbientMenu");
ok(socialToggleMore, "Keyboard accessible social menu should exist");
is(socialToggleMore.querySelectorAll("menuitem").length, 3, "The number of menuitems is minimum plus one ambient notification menuitem.");
is(socialToggleMore.hidden, false, "Menu is visible when ambient notifications have label & menuURL");
let menuitem = socialToggleMore.querySelector("menuitem");
is(menuitem.getAttribute("label"), "Test Ambient 1", "Keyboard accessible ambient menuitem should have specified label");
@ -109,11 +111,15 @@ var tests = {
testShowSidebarMenuitemExists: function(next) {
let toggleSidebarMenuitem = document.getElementById("social-toggle-sidebar-menuitem");
ok(toggleSidebarMenuitem, "Toggle Sidebar menuitem exists");
let toggleSidebarKeyboardMenuitem = document.getElementById("social-toggle-sidebar-keyboardmenuitem");
ok(toggleSidebarKeyboardMenuitem, "Toggle Sidebar keyboard menuitem exists");
next();
},
testShowDesktopNotificationsMenuitemExists: function(next) {
let toggleDesktopNotificationsMenuitem = document.getElementById("social-toggle-notifications-menuitem");
ok(toggleDesktopNotificationsMenuitem, "Toggle notifications menuitem exists");
let toggleDesktopNotificationsKeyboardMenuitem = document.getElementById("social-toggle-notifications-keyboardmenuitem");
ok(toggleDesktopNotificationsKeyboardMenuitem, "Toggle notifications keyboard menuitem exists");
next();
}
}

View File

@ -1,3 +1,3 @@
%filter substitution
%define primaryToolbarButtons #back-button, #forward-button, #reload-button, #stop-button, #home-button, #print-button, #downloads-button, #history-button, #bookmarks-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #cut-button, #copy-button, #paste-button, #fullscreen-button, #zoom-out-button, #zoom-in-button, #sync-button, #feed-button, #alltabs-button, #tabview-button
%define primaryToolbarButtons #back-button, #forward-button, #reload-button, #stop-button, #home-button, #print-button, #downloads-button, #downloads-indicator, #history-button, #bookmarks-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #cut-button, #copy-button, #paste-button, #fullscreen-button, #zoom-out-button, #zoom-in-button, #sync-button, #feed-button, #alltabs-button, #tabview-button

View File

@ -2734,6 +2734,7 @@ html|*#gcli-output-frame {
.chat-titlebar {
background-color: #d9d9d9;
background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0));
height: 20px;
min-height: 20px;
width: 100%;
@ -2754,7 +2755,10 @@ html|*#gcli-output-frame {
}
.chat-titlebar[activity] {
background-color: #ceeaff;
background-image: radial-gradient(ellipse closest-side at center, rgb(255,255,255), rgba(255,255,255,0));
background-repeat: no-repeat;
background-size: 100% 20px;
background-position: 0 -10px;
}
.chat-frame {
@ -2764,6 +2768,7 @@ html|*#gcli-output-frame {
}
.chatbar-button {
-moz-appearance: none;
background-color: #d9d9d9;
list-style-image: url("chrome://browser/skin/social/social.png");
border: none;
@ -2775,8 +2780,16 @@ html|*#gcli-output-frame {
-moz-border-end: 1px solid #ccc;
}
.chatbar-button[open="true"],
.chatbar-button:active:hover {
.chatbar-button > .toolbarbutton-icon {
opacity: .6;
-moz-margin-end: 0;
}
.chatbar-button:hover > .toolbarbutton-icon,
.chatbar-button[open="true"] > .toolbarbutton-icon {
opacity: 1;
}
.chatbar-button[open="true"] {
background-color: #f0f0f0;
box-shadow: inset 0 2px 5px rgba(0,0,0,0.6), 0 1px rgba(255,255,255,0.2);
}
@ -2787,7 +2800,7 @@ html|*#gcli-output-frame {
}
.chatbar-button[activity] {
background-color: #ceeaff;
background-image: radial-gradient(circle farthest-corner at center 3px, rgb(233,242,252) 3%, rgba(172,206,255,0.75) 40%, rgba(87,151,201,0.5) 80%, rgba(87,151,201,0));
}
.chatbar-button > menupopup > menuitem[activity] {
@ -2811,6 +2824,8 @@ chatbox {
background-color: white;
border: 1px solid #ccc;
border-bottom: none;
border-top-left-radius: 2.5px;
border-top-right-radius: 2.5px;
}
chatbox[minimized="true"] {

View File

@ -61,7 +61,6 @@ richlistitem[type="download"]:last-child {
#downloadsListBox:-moz-focusring > richlistitem[type="download"][selected] {
outline: 1px -moz-dialogtext dotted;
outline-offset: -1px;
-moz-outline-radius: 3px;
}
.downloadTypeIcon {

View File

@ -4156,6 +4156,7 @@ html|*#gcli-output-frame {
.chat-titlebar {
background-color: #d9d9d9;
background-image: linear-gradient(rgba(255,255,255,.43), rgba(255,255,255,0));
height: 20px;
min-height: 20px;
width: 100%;
@ -4172,7 +4173,10 @@ html|*#gcli-output-frame {
}
.chat-titlebar[activity] {
background-color: #ceeaff;
background-image: radial-gradient(ellipse closest-side at center, rgb(255,255,255), rgba(255,255,255,0));
background-repeat: no-repeat;
background-size: 100% 20px;
background-position: 0 -10px;
}
.chat-titlebar[selected] {
@ -4197,8 +4201,15 @@ html|*#gcli-output-frame {
-moz-border-end: 1px solid #ccc;
}
.chatbar-button[open="true"],
.chatbar-button:active:hover {
.chatbar-button > .toolbarbutton-icon {
opacity: .6;
}
.chatbar-button:hover > .toolbarbutton-icon,
.chatbar-button[open="true"] > .toolbarbutton-icon {
opacity: 1;
}
.chatbar-button[open="true"] {
background-color: #f0f0f0;
box-shadow: inset 0 2px 5px rgba(0,0,0,0.6), 0 1px rgba(255,255,255,0.2);
}
@ -4209,7 +4220,7 @@ html|*#gcli-output-frame {
}
.chatbar-button[activity] {
background-color: #ceeaff;
background-image: radial-gradient(circle farthest-corner at center 2px, rgb(254,254,255) 3%, rgba(210,235,255,0.9) 12%, rgba(148,205,253,0.6) 30%, rgba(148,205,253,0.2) 70%);
}
.chatbar-button > menupopup > menuitem[activity] {
@ -4218,7 +4229,7 @@ html|*#gcli-output-frame {
.chatbar-innerbox {
background: transparent;
margin: -285px -1px 0 -1px;
margin: -285px 0 0;
overflow: hidden;
}
@ -4233,6 +4244,8 @@ chatbox {
background-color: white;
border: 1px solid #ccc;
border-bottom: none;
border-top-left-radius: @toolbarbuttonCornerRadius@;
border-top-right-radius: @toolbarbuttonCornerRadius@;
}
chatbox[minimized="true"] {

View File

@ -77,7 +77,6 @@ richlistitem[type="download"]:last-child {
#downloadsListBox:-moz-focusring > richlistitem[type="download"][selected] {
outline: 1px -moz-dialogtext dotted;
outline-offset: -1px;
-moz-outline-radius: 3px;
}
.downloadTypeIcon {

View File

@ -3438,6 +3438,7 @@ html|*#gcli-output-frame {
.chat-titlebar {
background-color: #c4cfde;
background-image: linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,0));
height: 20px;
min-height: 20px;
width: 100%;
@ -3458,7 +3459,10 @@ html|*#gcli-output-frame {
}
.chat-titlebar[activity] {
background-color: #ceeaff;
background-image: radial-gradient(ellipse closest-side at center, rgb(255,255,255), rgba(255,255,255,0));
background-repeat: no-repeat;
background-size: 100% 20px;
background-position: 0 -10px;
}
.chat-frame {
@ -3487,9 +3491,16 @@ html|*#gcli-output-frame {
padding: 2px;
}
.chatbar-button[open="true"],
.chatbar-button:hover,
.chatbar-button:active:hover {
.chatbar-button > .toolbarbutton-icon {
opacity: .6;
-moz-margin-end: 0;
}
.chatbar-button:hover > .toolbarbutton-icon,
.chatbar-button[open="true"] > .toolbarbutton-icon {
opacity: 1;
}
.chatbar-button[open="true"] {
background-color: #dae3f0;
box-shadow: inset 0 2px 5px rgba(0,0,0,0.6), 0 1px rgba(255,255,255,0.2);
}
@ -3499,8 +3510,8 @@ html|*#gcli-output-frame {
display: none;
}
.chatbar-button[activity] {
background-color: #ceeaff;
.chatbar-button[activity]:not([open="true"]) {
background-image: radial-gradient(circle farthest-corner at center 3px, rgb(255,255,255) 3%, rgba(186,221,251,0.75) 40%, rgba(127,179,255,0.5) 80%, rgba(127,179,255,0.25));
}
.chatbar-button > menupopup > menuitem[activity] {
@ -3509,7 +3520,7 @@ html|*#gcli-output-frame {
.chatbar-innerbox {
background: transparent;
margin: -285px -1px 0 -1px;
margin: -285px 0 0;
overflow: hidden;
}
@ -3524,6 +3535,8 @@ chatbox {
background-color: white;
border: 1px solid #ccc;
border-bottom: none;
border-top-left-radius: 2.5px;
border-top-right-radius: 2.5px;
}
chatbox[minimized="true"] {

View File

@ -72,7 +72,6 @@ richlistitem[type="download"]:first-child {
#downloadsListBox:-moz-focusring > richlistitem[type="download"][selected] {
outline: 1px -moz-dialogtext dotted;
outline-offset: -1px;
-moz-outline-radius: 3px;
}
.downloadTypeIcon {

View File

@ -21,7 +21,7 @@ interface nsIContentSecurityPolicy;
[ptr] native JSPrincipals(JSPrincipals);
[ptr] native PrincipalArray(nsTArray<nsCOMPtr<nsIPrincipal> >);
[scriptable, uuid(96a92f0c-adcb-44ac-a034-37627647ec97)]
[scriptable, uuid(3a283dc9-f733-4618-a36f-e2b68c280ab7)]
interface nsIPrincipal : nsISerializable
{
/**
@ -195,6 +195,12 @@ interface nsIPrincipal : nsISerializable
* appId everywhere where we construct principals.
*/
readonly attribute boolean unknownAppId;
/**
* Returns true iff this principal is a null principal (corresponding to an
* unknown, hence assumed minimally privileged, security context).
*/
readonly attribute boolean isNullPrincipal;
};
/**
@ -217,4 +223,4 @@ interface nsIExpandedPrincipal : nsISupports
* should not be changed and should only be used ephemerally.
*/
[noscript] readonly attribute PrincipalArray whiteList;
};
};

View File

@ -71,6 +71,7 @@ public:
NS_IMETHOD GetAppId(uint32_t* aAppStatus);
NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement);
NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId);
NS_IMETHOD GetIsNullPrincipal(bool* aIsNullPrincipal);
#ifdef DEBUG
virtual void dumpImpl();
#endif
@ -152,6 +153,7 @@ public:
NS_IMETHOD GetAppId(uint32_t* aAppStatus);
NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement);
NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId);
NS_IMETHOD GetIsNullPrincipal(bool* aIsNullPrincipal);
#ifdef DEBUG
virtual void dumpImpl();
#endif

View File

@ -291,6 +291,13 @@ nsNullPrincipal::GetUnknownAppId(bool* aUnknownAppId)
return NS_OK;
}
NS_IMETHODIMP
nsNullPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal)
{
*aIsNullPrincipal = true;
return NS_OK;
}
/**
* nsISerializable implementation
*/

View File

@ -541,6 +541,13 @@ nsPrincipal::GetUnknownAppId(bool* aUnknownAppId)
return NS_OK;
}
NS_IMETHODIMP
nsPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal)
{
*aIsNullPrincipal = false;
return NS_OK;
}
NS_IMETHODIMP
nsPrincipal::Read(nsIObjectInputStream* aStream)
{
@ -852,6 +859,13 @@ nsExpandedPrincipal::GetUnknownAppId(bool* aUnknownAppId)
return NS_OK;
}
NS_IMETHODIMP
nsExpandedPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal)
{
*aIsNullPrincipal = false;
return NS_OK;
}
void
nsExpandedPrincipal::GetScriptLocation(nsACString& aStr)
{

View File

@ -2992,11 +2992,13 @@ GetExtendedOrigin(nsIURI* aURI, uint32_t aAppId, bool aInMozBrowser,
return;
}
// aExtendedOrigin = appId + "+" + origin + "+" + { 't', 'f' }
// aExtendedOrigin = appId + "+" + { 't', 'f' } "+" + origin;
aExtendedOrigin.Truncate();
aExtendedOrigin.AppendInt(aAppId);
aExtendedOrigin.Append(NS_LITERAL_CSTRING("+") + origin + NS_LITERAL_CSTRING("+"));
aExtendedOrigin.Append('+');
aExtendedOrigin.Append(aInMozBrowser ? 't' : 'f');
aExtendedOrigin.Append('+');
aExtendedOrigin.Append(origin);
return;
}

View File

@ -198,6 +198,13 @@ nsSystemPrincipal::GetUnknownAppId(bool* aUnknownAppId)
return NS_OK;
}
NS_IMETHODIMP
nsSystemPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal)
{
*aIsNullPrincipal = false;
return NS_OK;
}
//////////////////////////////////////////
// Methods implementing nsISerializable //
//////////////////////////////////////////

View File

@ -1202,15 +1202,15 @@ WebGLContext::DummyFramebufferOperation(const char *info)
// are met.
// At a bare minimum, from context lost to context restores, it would take 3
// full timer iterations: detection, webglcontextlost, webglcontextrestored.
NS_IMETHODIMP
WebGLContext::Notify(nsITimer* timer)
void
WebGLContext::RobustnessTimerCallback(nsITimer* timer)
{
TerminateContextLossTimer();
if (!mCanvasElement) {
// the canvas is gone. That happens when the page was closed before we got
// this timer event. In this case, there's nothing to do here, just don't crash.
return NS_OK;
return;
}
// If the context has been lost and we're waiting for it to be restored, do
@ -1243,7 +1243,7 @@ WebGLContext::Notify(nsITimer* timer)
// Try to restore the context. If it fails, try again later.
if (NS_FAILED(SetDimensions(mWidth, mHeight))) {
SetupContextLossTimer();
return NS_OK;
return;
}
mContextStatus = ContextStable;
nsContentUtils::DispatchTrustedEvent(mCanvasElement->OwnerDoc(),
@ -1258,7 +1258,7 @@ WebGLContext::Notify(nsITimer* timer)
}
MaybeRestoreContext();
return NS_OK;
return;
}
void
@ -1408,7 +1408,6 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLContext)
NS_INTERFACE_MAP_ENTRY(nsIDOMWebGLRenderingContext)
NS_INTERFACE_MAP_ENTRY(nsICanvasRenderingContextInternal)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
// If the exact way we cast to nsISupports here ever changes, fix our
// PreCreate hook!
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports,

View File

@ -473,7 +473,6 @@ class WebGLContext :
public nsIDOMWebGLRenderingContext,
public nsICanvasRenderingContextInternal,
public nsSupportsWeakReference,
public nsITimerCallback,
public WebGLRectangleObject,
public nsWrapperCache
{
@ -510,8 +509,6 @@ public:
NS_DECL_NSIDOMWEBGLRENDERINGCONTEXT
NS_DECL_NSITIMERCALLBACK
// nsICanvasRenderingContextInternal
NS_IMETHOD SetDimensions(int32_t width, int32_t height);
NS_IMETHOD InitializeWithSurface(nsIDocShell *docShell, gfxASurface *surface, int32_t width, int32_t height)
@ -607,6 +604,12 @@ public:
return mMinCapability;
}
void RobustnessTimerCallback(nsITimer* timer);
static void RobustnessTimerCallbackStatic(nsITimer* timer, void *thisPointer) {
static_cast<WebGLContext*>(thisPointer)->RobustnessTimerCallback(timer);
}
void SetupContextLossTimer() {
// If the timer was already running, don't restart it here. Instead,
// wait until the previous call is done, then fire it one more time.
@ -616,10 +619,11 @@ public:
mDrawSinceContextLossTimerSet = true;
return;
}
mContextRestorer->InitWithCallback(static_cast<nsITimerCallback*>(this),
PR_MillisecondsToInterval(1000),
nsITimer::TYPE_ONE_SHOT);
mContextRestorer->InitWithFuncCallback(RobustnessTimerCallbackStatic,
static_cast<void*>(this),
PR_MillisecondsToInterval(1000),
nsITimer::TYPE_ONE_SHOT);
mContextLossTimerRunning = true;
mDrawSinceContextLossTimerSet = false;
}

View File

@ -64,12 +64,6 @@ CPPSRCS = \
TextComposition.cpp \
$(NULL)
ifdef MOZ_B2G_RIL
CPPSRCS += \
nsDOMWifiEvent.cpp \
$(NULL)
endif
# we don't want the shared lib, but we want to force the creation of a static lib.
FORCE_STATIC_LIB = 1

View File

@ -1,179 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsDOMWifiEvent.h"
#include "nsContentUtils.h"
#include "DictionaryHelpers.h"
#include "nsDOMClassInfoID.h"
// nsDOMMozWifiStatusChangeEvent
DOMCI_DATA(MozWifiStatusChangeEvent, nsDOMMozWifiStatusChangeEvent)
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMMozWifiStatusChangeEvent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMMozWifiStatusChangeEvent, nsDOMEvent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mNetwork)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMMozWifiStatusChangeEvent, nsDOMEvent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNetwork)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN(nsDOMMozWifiStatusChangeEvent)
NS_INTERFACE_MAP_ENTRY(nsIDOMMozWifiStatusChangeEvent)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozWifiStatusChangeEvent)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
NS_IMPL_ADDREF_INHERITED(nsDOMMozWifiStatusChangeEvent, nsDOMEvent)
NS_IMPL_RELEASE_INHERITED(nsDOMMozWifiStatusChangeEvent, nsDOMEvent)
NS_IMETHODIMP
nsDOMMozWifiStatusChangeEvent::GetNetwork(nsIVariant** aNetwork)
{
NS_IF_ADDREF(*aNetwork = mNetwork);
return NS_OK;
}
NS_IMETHODIMP
nsDOMMozWifiStatusChangeEvent::GetStatus(nsAString& aStatus)
{
aStatus = mStatus;
return NS_OK;
}
NS_IMETHODIMP
nsDOMMozWifiStatusChangeEvent::InitMozWifiStatusChangeEvent(const nsAString& aType,
bool aCanBubble,
bool aCancelable,
nsIVariant* aNetwork,
const nsAString& aStatus)
{
nsresult rv = nsDOMEvent::InitEvent(aType, aCanBubble, aCancelable);
NS_ENSURE_SUCCESS(rv, rv);
mNetwork = aNetwork;
mStatus = aStatus;
return NS_OK;
}
nsresult
nsDOMMozWifiStatusChangeEvent::InitFromCtor(const nsAString& aType,
JSContext* aCx, jsval* aVal)
{
mozilla::dom::MozWifiStatusChangeEventInit d;
nsresult rv = d.Init(aCx, aVal);
NS_ENSURE_SUCCESS(rv, rv);
return InitMozWifiStatusChangeEvent(aType, d.bubbles, d.cancelable, d.network, d.status);
}
nsresult
NS_NewDOMMozWifiStatusChangeEvent(nsIDOMEvent** aInstancePtrResult,
nsPresContext* aPresContext,
nsEvent* aEvent)
{
nsDOMMozWifiStatusChangeEvent* e = new nsDOMMozWifiStatusChangeEvent(aPresContext, aEvent);
return CallQueryInterface(e, aInstancePtrResult);
}
// nsDOMMozWifiConnectionInfoEvent
DOMCI_DATA(MozWifiConnectionInfoEvent, nsDOMMozWifiConnectionInfoEvent)
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMMozWifiConnectionInfoEvent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMMozWifiConnectionInfoEvent, nsDOMEvent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mNetwork)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMMozWifiConnectionInfoEvent, nsDOMEvent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNetwork)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN(nsDOMMozWifiConnectionInfoEvent)
NS_INTERFACE_MAP_ENTRY(nsIDOMMozWifiConnectionInfoEvent)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozWifiConnectionInfoEvent)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
NS_IMPL_ADDREF_INHERITED(nsDOMMozWifiConnectionInfoEvent, nsDOMEvent)
NS_IMPL_RELEASE_INHERITED(nsDOMMozWifiConnectionInfoEvent, nsDOMEvent)
NS_IMETHODIMP
nsDOMMozWifiConnectionInfoEvent::GetNetwork(nsIVariant** aNetwork)
{
NS_IF_ADDREF(*aNetwork = mNetwork);
return NS_OK;
}
NS_IMETHODIMP
nsDOMMozWifiConnectionInfoEvent::GetSignalStrength(int16_t* aSignalStrength)
{
*aSignalStrength = mSignalStrength;
return NS_OK;
}
NS_IMETHODIMP
nsDOMMozWifiConnectionInfoEvent::GetRelSignalStrength(int16_t* aRelSignalStrength)
{
*aRelSignalStrength = mRelSignalStrength;
return NS_OK;
}
NS_IMETHODIMP
nsDOMMozWifiConnectionInfoEvent::GetLinkSpeed(int32_t* aLinkSpeed)
{
*aLinkSpeed = mLinkSpeed;
return NS_OK;
}
NS_IMETHODIMP
nsDOMMozWifiConnectionInfoEvent::GetIpAddress(nsAString& aIpAddress)
{
aIpAddress = mIpAddress;
return NS_OK;
}
NS_IMETHODIMP
nsDOMMozWifiConnectionInfoEvent::InitMozWifiConnectionInfoEvent(const nsAString& aType,
bool aCanBubble,
bool aCancelable,
nsIVariant *aNetwork,
int16_t aSignalStrength,
int16_t aRelSignalStrength,
int32_t aLinkSpeed,
const nsAString &aIpAddress)
{
nsresult rv = nsDOMEvent::InitEvent(aType, aCanBubble, aCancelable);
NS_ENSURE_SUCCESS(rv, rv);
mNetwork = aNetwork;
mSignalStrength = aSignalStrength;
mRelSignalStrength = aRelSignalStrength;
mLinkSpeed = aLinkSpeed;
mIpAddress = aIpAddress;
return NS_OK;
}
nsresult
nsDOMMozWifiConnectionInfoEvent::InitFromCtor(const nsAString& aType,
JSContext* aCx, jsval* aVal)
{
mozilla::dom::MozWifiConnectionInfoEventInit d;
nsresult rv = d.Init(aCx, aVal);
NS_ENSURE_SUCCESS(rv, rv);
return InitMozWifiConnectionInfoEvent(aType, d.bubbles, d.cancelable, d.network,
d.signalStrength, d.relSignalStrength, d.linkSpeed,
d.ipAddress);
}
nsresult
NS_NewDOMMozWifiConnectionInfoEvent(nsIDOMEvent** aInstancePtrResult,
nsPresContext* aPresContext,
nsEvent* aEvent)
{
nsDOMMozWifiConnectionInfoEvent* e = new nsDOMMozWifiConnectionInfoEvent(aPresContext, aEvent);
return CallQueryInterface(e, aInstancePtrResult);
}

View File

@ -1,58 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsDOMWifiEvent_h__
#define nsDOMWifiEvent_h__
#include "nsIWifi.h"
#include "nsIWifiEventInits.h"
#include "nsDOMEvent.h"
class nsDOMMozWifiStatusChangeEvent : public nsDOMEvent,
public nsIDOMMozWifiStatusChangeEvent
{
public:
nsDOMMozWifiStatusChangeEvent(nsPresContext* aPresContext, nsEvent* aEvent)
: nsDOMEvent(aPresContext, aEvent) {}
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMMozWifiStatusChangeEvent, nsDOMEvent)
// Forward to base class
NS_FORWARD_TO_NSDOMEVENT
NS_DECL_NSIDOMMOZWIFISTATUSCHANGEEVENT
virtual nsresult InitFromCtor(const nsAString& aType,
JSContext* aCx, jsval* aVal);
private:
nsCOMPtr<nsIVariant> mNetwork;
nsString mStatus;
};
class nsDOMMozWifiConnectionInfoEvent : public nsDOMEvent,
public nsIDOMMozWifiConnectionInfoEvent
{
public:
nsDOMMozWifiConnectionInfoEvent(nsPresContext* aPresContext, nsEvent* aEvent)
: nsDOMEvent(aPresContext, aEvent) {}
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMMozWifiConnectionInfoEvent, nsDOMEvent)
// Forward to base class
NS_FORWARD_TO_NSDOMEVENT
NS_DECL_NSIDOMMOZWIFICONNECTIONINFOEVENT
virtual nsresult InitFromCtor(const nsAString& aType,
JSContext* aCx, jsval* aVal);
private:
nsCOMPtr<nsIVariant> mNetwork;
int16_t mSignalStrength;
int16_t mRelSignalStrength;
int32_t mLinkSpeed;
nsString mIpAddress;
};
#endif // nsDOMWifiEvent_h__

View File

@ -167,7 +167,9 @@ nsSVGSVGElement::nsSVGSVGElement(already_AddRefed<nsINodeInfo> aNodeInfo,
mCurrentScale(1.0f),
mPreviousTranslate(0.0f, 0.0f),
mPreviousScale(1.0f),
mStartAnimationOnBindToTree(!aFromParser),
mStartAnimationOnBindToTree(aFromParser == NOT_FROM_PARSER ||
aFromParser == FROM_PARSER_FRAGMENT ||
aFromParser == FROM_PARSER_XSLT),
mImageNeedsTransformInvalidation(false),
mIsPaintingSVGImageElement(false),
mHasChildrenOnlyTransform(false),

View File

@ -19,20 +19,20 @@ AlarmHalService::Init()
if (!mAlarmEnabled) {
return;
}
RegisterSystemTimeChangeObserver(this);
RegisterSystemTimezoneChangeObserver(this);
}
/* virtual */ AlarmHalService::~AlarmHalService()
{
if (mAlarmEnabled) {
UnregisterTheOneAlarmObserver();
UnregisterSystemTimeChangeObserver(this);
UnregisterSystemTimezoneChangeObserver(this);
}
}
/* static */ StaticRefPtr<AlarmHalService> AlarmHalService::sSingleton;
/* static */ already_AddRefed<nsIAlarmHalService>
/* static */ already_AddRefed<AlarmHalService>
AlarmHalService::GetInstance()
{
if (!sSingleton) {
@ -41,7 +41,7 @@ AlarmHalService::GetInstance()
ClearOnShutdown(&sSingleton);
}
nsCOMPtr<nsIAlarmHalService> service(do_QueryInterface(sSingleton));
nsRefPtr<AlarmHalService> service = sSingleton.get();
return service.forget();
}
@ -76,7 +76,7 @@ AlarmHalService::SetTimezoneChangedCb(nsITimezoneChangedCb* aTimeZoneChangedCb)
}
void
AlarmHalService::Notify(const mozilla::void_t& aVoid)
AlarmHalService::Notify(const void_t& aVoid)
{
if (!mAlarmFiredCb) {
return;
@ -85,26 +85,14 @@ AlarmHalService::Notify(const mozilla::void_t& aVoid)
}
void
AlarmHalService::Notify(const SystemTimeChange& aReason)
AlarmHalService::Notify(
const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
{
if (aReason != SYS_TIME_CHANGE_TZ || !mTimezoneChangedCb) {
if (!mTimezoneChangedCb) {
return;
}
mTimezoneChangedCb->OnTimezoneChanged(GetTimezoneOffset(false));
}
int32_t
AlarmHalService::GetTimezoneOffset(bool aIgnoreDST)
{
PRExplodedTime prTime;
PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &prTime);
int32_t offset = prTime.tm_params.tp_gmt_offset;
if (!aIgnoreDST) {
offset += prTime.tm_params.tp_dst_offset;
}
return -(offset / 60);
mTimezoneChangedCb->OnTimezoneChanged(
aSystemTimezoneChangeInfo.newTimezoneOffsetMinutes());
}
} // alarm

View File

@ -13,17 +13,17 @@
#include "nsIAlarmHalService.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "prtime.h"
namespace mozilla {
namespace dom {
namespace alarm {
using namespace hal;
typedef Observer<void_t> AlarmObserver;
typedef Observer<hal::SystemTimezoneChangeInformation> SystemTimezoneChangeObserver;
class AlarmHalService : public nsIAlarmHalService,
public AlarmObserver,
public SystemTimeObserver
public SystemTimezoneChangeObserver
{
public:
NS_DECL_ISUPPORTS
@ -32,13 +32,13 @@ public:
void Init();
virtual ~AlarmHalService();
static already_AddRefed<nsIAlarmHalService> GetInstance();
static already_AddRefed<AlarmHalService> GetInstance();
// Implementing hal::AlarmObserver
void Notify(const mozilla::void_t& aVoid);
void Notify(const void_t& aVoid);
// Implementing hal::SystemTimeObserver
void Notify(const SystemTimeChange& aReason);
// Implementing hal::SystemTimezoneChangeObserver
void Notify(const hal::SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo);
private:
bool mAlarmEnabled;
@ -46,8 +46,6 @@ private:
nsCOMPtr<nsIAlarmFiredCb> mAlarmFiredCb;
nsCOMPtr<nsITimezoneChangedCb> mTimezoneChangedCb;
int32_t GetTimezoneOffset(bool aIgnoreDST);
};
} // namespace alarm

View File

@ -26,6 +26,7 @@ EXTRA_PP_JS_MODULES += \
EXTRA_JS_MODULES += \
AppsServiceChild.jsm \
AppsUtils.jsm \
OfflineCacheInstaller.jsm \
PermissionsInstaller.jsm \
$(NULL)

View File

@ -0,0 +1,174 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;
const CC = Components.Constructor;
let EXPORTED_SYMBOLS = ["OfflineCacheInstaller"];
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/AppsUtils.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
let Namespace = CC('@mozilla.org/network/application-cache-namespace;1',
'nsIApplicationCacheNamespace',
'init');
let makeFile = CC('@mozilla.org/file/local;1',
'nsIFile',
'initWithPath');
const nsICache = Ci.nsICache;
const nsIApplicationCache = Ci.nsIApplicationCache;
const applicationCacheService =
Cc['@mozilla.org/network/application-cache-service;1']
.getService(Ci.nsIApplicationCacheService);
function debug(aMsg) {
//dump("-*-*- OfflineCacheInstaller.jsm : " + aMsg + "\n");
}
function enableOfflineCacheForApp(origin, appId) {
let originURI = Services.io.newURI(origin, null, null);
let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(
originURI, appId, false);
Services.perms.addFromPrincipal(principal, 'offline-app',
Ci.nsIPermissionManager.ALLOW_ACTION);
// Prevent cache from being evicted:
Services.perms.addFromPrincipal(principal, 'pin-app',
Ci.nsIPermissionManager.ALLOW_ACTION);
}
function storeCache(applicationCache, url, file, itemType) {
let session = Services.cache.createSession(applicationCache.clientID,
nsICache.STORE_OFFLINE, true);
session.asyncOpenCacheEntry(url, nsICache.ACCESS_WRITE, {
onCacheEntryAvailable: function (cacheEntry, accessGranted, status) {
cacheEntry.setMetaDataElement('request-method', 'GET');
cacheEntry.setMetaDataElement('response-head', 'HTTP/1.1 200 OK\r\n');
let outputStream = cacheEntry.openOutputStream(0);
// Input-Output stream machinery in order to push nsIFile content into cache
let inputStream = Cc['@mozilla.org/network/file-input-stream;1']
.createInstance(Ci.nsIFileInputStream);
inputStream.init(file, 1, -1, null);
let bufferedOutputStream = Cc['@mozilla.org/network/buffered-output-stream;1']
.createInstance(Ci.nsIBufferedOutputStream);
bufferedOutputStream.init(outputStream, 1024);
bufferedOutputStream.writeFrom(inputStream, inputStream.available());
bufferedOutputStream.flush();
bufferedOutputStream.close();
outputStream.close();
inputStream.close();
cacheEntry.markValid();
debug (file.path + ' -> ' + url + ' (' + itemType + ')');
applicationCache.markEntry(url, itemType);
cacheEntry.close();
}
});
}
function readFile(aFile, aCallback) {
let channel = NetUtil.newChannel(aFile);
channel.contentType = "pain/text";
NetUtil.asyncFetch(channel, function(aStream, aResult) {
if (!Components.isSuccessCode(aResult)) {
Cu.reportError("OfflineCacheInstaller: Could not read file " + aFile.path);
if (aCallback)
aCallback(null);
return;
}
// Obtain a converter to read from a UTF-8 encoded input stream.
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
let data = NetUtil.readInputStreamToString(aStream,
aStream.available());
aCallback(converter.ConvertToUnicode(data));
});
}
const OfflineCacheInstaller = {
installCache: function installCache(app) {
let cacheDir = makeFile(app.basePath)
cacheDir.append(app.appId);
cacheDir.append("cache");
if (!cacheDir.exists())
return;
let cacheManifest = cacheDir.clone();
cacheManifest.append("manifest.appcache");
if (!cacheManifest.exists())
return;
enableOfflineCacheForApp(app.origin, app.localId);
// Get the url for the manifest.
let appcacheURL = app.origin + "cache/manifest.appcache";
// The group ID contains application id and 'f' for not being hosted in
// a browser element, but a mozbrowser iframe.
// See netwerk/cache/nsDiskCacheDeviceSQL.cpp: AppendJARIdentifier
let groupID = appcacheURL + '#' + app.localId+ '+f';
let applicationCache = applicationCacheService.createApplicationCache(groupID);
applicationCache.activate();
readFile(cacheManifest, function (content) {
let lines = content.split(/\r?\n/);
// Process each manifest line, read only CACHE entries
// (ignore NETWORK entries) and compute absolute URL for each entry
let urls = [];
for(let i = 0; i < lines.length; i++) {
let line = lines[i];
// Ignore comments
if (/^#/.test(line) || !line.length)
continue;
if (line == 'CACHE MANIFEST')
continue;
if (line == 'CACHE:')
continue;
// Ignore network entries and everything that comes after
if (line == 'NETWORK:')
break;
// Prepend webapp origin in case of absolute path
if (line[0] == '/') {
urls.push(app.origin + line.substring(1));
// Just pass along the url, if we have one
} else if (line.substr(0, 4) == 'http') {
urls.push(line);
} else {
throw new Error('Invalid line in appcache manifest:\n' + line +
'\nFrom: ' + cacheManifest.path);
}
}
urls.forEach(function processCachedFile(url) {
// Get this nsIFile from cache folder for this URL
let path = url.replace(/https?:\/\//, '');
let file = cacheDir.clone();
let paths = path.split('/');
paths.forEach(file.append);
if (!file.exists()) {
let msg = 'File ' + file.path + ' exists in the manifest but does ' +
'not points to a real file.';
throw new Error(msg);
}
let itemType = nsIApplicationCache.ITEM_EXPLICIT;
storeCache(applicationCache, url, file, itemType);
});
});
}
};

View File

@ -9,6 +9,7 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/AppsUtils.jsm");
Cu.import("resource://gre/modules/PermissionSettings.jsm");
var EXPORTED_SYMBOLS = ["PermissionsInstaller"];
@ -25,16 +26,6 @@ const READWRITE = "readwrite";
const PERM_TO_STRING = ["unknown", "allow", "deny", "prompt"];
XPCOMUtils.defineLazyServiceGetter(this,
"PermSettings",
"@mozilla.org/permissionSettings;1",
"nsIDOMPermissionSettings");
XPCOMUtils.defineLazyServiceGetter(this,
"permissionManager",
"@mozilla.org/permissionmanager;1",
"nsIPermissionManager");
function debug(aMsg) {
//dump("-*-*- PermissionsInstaller.jsm : " + aMsg + "\n");
}
@ -344,7 +335,7 @@ let PermissionsInstaller = {
let index = newPerms.indexOf(AllPossiblePermissions[idx]);
if (index == -1) {
// See if the permission was installed previously
let _perm = PermSettings.get(AllPossiblePermissions[idx],
let _perm = PermissionSettingsModule.getPermission(AllPossiblePermissions[idx],
aApp.manifestURL,
aApp.origin,
false);
@ -415,13 +406,25 @@ let PermissionsInstaller = {
**/
_setPermission: function setPermission(aPerm, aValue, aApp) {
if (aPerm != "storage") {
PermSettings.set(aPerm, aValue, aApp.manifestURL, aApp.origin, false);
PermissionSettingsModule.addPermission({
type: aPerm,
origin: aApp.origin,
manifestURL: aApp.manifestURL,
value: aValue,
browserFlag: false
});
return;
}
["indexedDB-unlimited", "offline-app", "pin-app"].forEach(
function(aName) {
PermSettings.set(aName, aValue, aApp.manifestURL, aApp.origin, false);
PermissionSettingsModule.addPermission({
type: aName,
origin: aApp.origin,
manifestURL: aApp.manifestURL,
value: aValue,
browserFlag: false
});
}
);
}

View File

@ -17,6 +17,7 @@ Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import('resource://gre/modules/ActivitiesService.jsm');
Cu.import("resource://gre/modules/AppsUtils.jsm");
Cu.import("resource://gre/modules/PermissionsInstaller.jsm");
Cu.import("resource://gre/modules/OfflineCacheInstaller.jsm");
function debug(aMsg) {
//dump("-*-*- Webapps.jsm : " + aMsg + "\n");
@ -92,7 +93,7 @@ let DOMApplicationRegistry = {
// aNext() is called after we load the current webapps list.
loadCurrentRegistry: function loadCurrentRegistry(aNext) {
let file = FileUtils.getFile(DIRECTORY_NAME, ["webapps", "webapps.json"], false);
if (file && file.exists) {
if (file && file.exists()) {
this._loadJSONAsync(file, (function loadRegistry(aData) {
if (aData) {
this.webapps = aData;
@ -175,89 +176,99 @@ let DOMApplicationRegistry = {
}).bind(this));
},
updateOfflineCacheForApp: function updateOfflineCacheForApp(aId) {
let app = this.webapps[aId];
OfflineCacheInstaller.installCache({
basePath: app.basePath,
appId: aId,
origin: app.origin,
localId: app.localId
});
},
// Implements the core of bug 787439
// 1. load the apps from the current registry.
// 2. if at first run, go through these steps:
// if at first run, go through these steps:
// a. load the core apps registry.
// b. uninstall any core app from the current registry but not in the
// new core apps registry.
// c. for all apps in the new core registry, install them if they are not
// yet in the current registry, and run installPermissions()
installSystemApps: function installSystemApps(aNext) {
let file;
try {
file = FileUtils.getFile("coreAppsDir", ["webapps", "webapps.json"], false);
} catch(e) { }
if (file && file.exists()) {
// a
this._loadJSONAsync(file, (function loadCoreRegistry(aData) {
if (!aData) {
aNext();
return;
}
// b : core apps are not removable.
for (let id in this.webapps) {
if (id in aData || this.webapps[id].removable)
continue;
delete this.webapps[id];
// Remove the permissions, cookies and private data for this app.
let localId = this.webapps[id].localId;
let permMgr = Cc["@mozilla.org/permissionmanager;1"]
.getService(Ci.nsIPermissionManager);
permMgr.RemovePermissionsForApp(localId);
Services.cookies.removeCookiesForApp(localId, false);
this._clearPrivateData(localId, false);
}
let appDir = FileUtils.getDir("coreAppsDir", ["webapps"], false);
// c
for (let id in aData) {
// Core apps have ids matching their domain name (eg: dialer.gaiamobile.org)
// Use that property to check if they are new or not.
if (!(id in this.webapps)) {
this.webapps[id] = aData[id];
this.webapps[id].basePath = appDir.path;
// Create a new localId.
this.webapps[id].localId = this._nextLocalId();
// Core apps are not removable.
if (this.webapps[id].removable === undefined) {
this.webapps[id].removable = false;
}
}
}
aNext();
}).bind(this));
} else {
aNext();
}
},
loadAndUpdateApps: function loadAndUpdateApps() {
let runUpdate = AppsUtils.isFirstRun(Services.prefs);
// 1.
this.loadCurrentRegistry((function() {
#ifdef MOZ_WIDGET_GONK
// if first run, merge the system apps.
if (runUpdate) {
let file;
try {
file = FileUtils.getFile("coreAppsDir", ["webapps", "webapps.json"], false);
} catch(e) { }
if (file && file.exists) {
// 2.a
this._loadJSONAsync(file, (function loadCoreRegistry(aData) {
if (!aData) {
this.registerAppsHandlers();
return;
}
// 2.b : core apps are not removable.
for (let id in this.webapps) {
if (id in aData || this.webapps[id].removable)
continue;
delete this.webapps[id];
// Remove the permissions, cookies and private data for this app.
let localId = this.webapps[id].localId;
let permMgr = Cc["@mozilla.org/permissionmanager;1"]
.getService(Ci.nsIPermissionManager);
permMgr.RemovePermissionsForApp(localId);
Services.cookies.removeCookiesForApp(localId, false);
this._clearPrivateData(localId, false);
}
let appDir = FileUtils.getDir("coreAppsDir", ["webapps"], false);
// 2.c
for (let id in aData) {
// Core apps have ids matching their domain name (eg: dialer.gaiamobile.org)
// Use that property to check if they are new or not.
if (!(id in this.webapps)) {
this.webapps[id] = aData[id];
this.webapps[id].basePath = appDir.path;
// Create a new localId.
this.webapps[id].localId = this._nextLocalId();
// Core apps are not removable.
if (this.webapps[id].removable === undefined) {
this.webapps[id].removable = false;
}
}
this.updatePermissionsForApp(id);
}
this.registerAppsHandlers();
}).bind(this));
} else {
// At first run, set up the permissions for eng builds.
let onAppsLoaded = (function onAppsLoaded() {
if (runUpdate) {
// At first run, set up the permissions
for (let id in this.webapps) {
this.updatePermissionsForApp(id);
this.updateOfflineCacheForApp(id);
}
this.registerAppsHandlers();
}
} else {
this.registerAppsHandlers();
}
}).bind(this);
this.loadCurrentRegistry((function() {
#ifdef MOZ_WIDGET_GONK
// if first run, merge the system apps.
if (runUpdate)
this.installSystemApps(onAppsLoaded);
else
onAppsLoaded();
#else
if (runUpdate) {
// At first run, set up the permissions for desktop builds.
for (let id in this.webapps) {
this.updatePermissionsForApp(id);
}
}
this.registerAppsHandlers();
onAppsLoaded();
#endif
}).bind(this));
},
@ -475,14 +486,14 @@ let DOMApplicationRegistry = {
aCallback(data);
} catch (ex) {
Cu.reportError("DOMApplicationRegistry: Could not parse JSON: " +
aFile.path + " " + ex);
aFile.path + " " + ex + "\n" + ex.stack);
if (aCallback)
aCallback(null);
}
});
} catch (ex) {
Cu.reportError("DOMApplicationRegistry: Could not read from " +
aFile.path + " : " + ex);
aFile.path + " : " + ex + "\n" + ex.stack);
if (aCallback)
aCallback(null);
}
@ -1725,6 +1736,10 @@ let DOMApplicationRegistry = {
switch (message.name) {
case "Webapps:ClearBrowserData":
this._clearPrivateData(appId, true);
// XXXbent This is a hack until bug 802366 is fixed. Currently all data
// loaded in mozbrowser frames within an app believe that their
// appId is 0.
this._clearPrivateData(0, true);
break;
}
},

View File

@ -179,7 +179,6 @@
#ifdef MOZ_B2G_RIL
#include "nsIWifi.h"
#include "nsIWifiEventInits.h"
#endif
// includes needed for the prototype chain interfaces
@ -1619,10 +1618,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
DOM_DEFAULT_SCRIPTABLE_FLAGS)
#ifdef MOZ_B2G_RIL
NS_DEFINE_CLASSINFO_DATA(MozWifiStatusChangeEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(MozWifiConnectionInfoEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(Telephony, nsEventTargetSH,
EVENTTARGET_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(TelephonyCall, nsEventTargetSH,
@ -1733,10 +1728,6 @@ NS_DEFINE_EVENT_CTOR(Event)
NS_DEFINE_EVENT_CTOR(UIEvent)
NS_DEFINE_EVENT_CTOR(MouseEvent)
NS_DEFINE_EVENT_CTOR(WheelEvent)
#ifdef MOZ_B2G_RIL
NS_DEFINE_EVENT_CTOR(MozWifiStatusChangeEvent)
NS_DEFINE_EVENT_CTOR(MozWifiConnectionInfoEvent)
#endif
#define MOZ_GENERATED_EVENT_LIST
#define MOZ_GENERATED_EVENT(_event_interface) \

View File

@ -488,8 +488,6 @@ DOMCI_CLASS(MutationObserver)
DOMCI_CLASS(MutationRecord)
#ifdef MOZ_B2G_RIL
DOMCI_CLASS(MozWifiStatusChangeEvent)
DOMCI_CLASS(MozWifiConnectionInfoEvent)
DOMCI_CLASS(Telephony)
DOMCI_CLASS(TelephonyCall)
DOMCI_CLASS(CallEvent)

View File

@ -181,31 +181,6 @@ DatabaseInfo::Remove(nsIAtom* aId)
}
}
PLDHashOperator
EnumerateDatabasesRemoveOrigin(nsISupports* aId,
DatabaseInfo*& aDatabaseInfo,
void* aUserArg)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
const nsACString* origin = static_cast<const nsACString*>(aUserArg);
return aDatabaseInfo->origin.Equals(*origin) ?
PL_DHASH_REMOVE :
PL_DHASH_NEXT;
}
// static
void
DatabaseInfo::RemoveAllForOrigin(const nsACString& aOrigin)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (gDatabaseHash) {
gDatabaseHash->Enumerate(EnumerateDatabasesRemoveOrigin,
const_cast<nsACString*>(&aOrigin));
}
}
bool
DatabaseInfo::GetObjectStoreNames(nsTArray<nsString>& aNames)
{

View File

@ -62,8 +62,6 @@ struct DatabaseInfo : public DatabaseInfoGuts
static void Remove(nsIAtom* aId);
static void RemoveAllForOrigin(const nsACString& aOrigin);
bool GetObjectStoreNames(nsTArray<nsString>& aNames);
bool ContainsStoreName(const nsAString& aName);

View File

@ -10,6 +10,7 @@
#include "mozilla/Mutex.h"
#include "mozilla/storage.h"
#include "mozilla/unused.h"
#include "mozilla/dom/ContentParent.h"
#include "nsDOMClassInfo.h"
#include "nsDOMLists.h"
@ -33,6 +34,7 @@
#include "nsContentUtils.h"
#include "ipc/IndexedDBChild.h"
#include "ipc/IndexedDBParent.h"
USING_INDEXEDDB_NAMESPACE
using mozilla::dom::ContentParent;
@ -269,12 +271,14 @@ IDBDatabase::Invalidate()
if (owner) {
IndexedDatabaseManager::CancelPromptsForWindow(owner);
}
}
bool
IDBDatabase::IsInvalidated()
{
return mInvalidated;
DatabaseInfo::Remove(mDatabaseId);
// And let the child process know as well.
if (mActorParent) {
NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
mozilla::unused << mActorParent->SendInvalidate();
}
}
void
@ -299,8 +303,9 @@ IDBDatabase::DisconnectFromActor()
}
bool
IDBDatabase::IsDisconnectedFromActor()
IDBDatabase::IsDisconnectedFromActor() const
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
return mDisconnected;
}
@ -330,7 +335,7 @@ IDBDatabase::CloseInternal(bool aIsDead)
}
// And let the parent process know as well.
if (mActorChild) {
if (mActorChild && !IsInvalidated()) {
NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
mActorChild->SendClose(aIsDead);
}
@ -338,7 +343,7 @@ IDBDatabase::CloseInternal(bool aIsDead)
}
bool
IDBDatabase::IsClosed()
IDBDatabase::IsClosed() const
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
return mClosed;

View File

@ -74,12 +74,12 @@ public:
return mDatabaseInfo;
}
const nsString& Name()
const nsString& Name() const
{
return mName;
}
const nsString& FilePath()
const nsString& FilePath() const
{
return mFilePath;
}
@ -95,7 +95,7 @@ public:
return doc.forget();
}
nsCString& Origin()
const nsCString& Origin() const
{
return mASCIIOrigin;
}
@ -103,20 +103,24 @@ public:
void Invalidate();
// Whether or not the database has been invalidated. If it has then no further
// transactions for this database will be allowed to run.
bool IsInvalidated();
// transactions for this database will be allowed to run. This function may be
// called on any thread.
bool IsInvalidated() const
{
return mInvalidated;
}
void DisconnectFromActor();
// Whether or not the database has been disconnected from its actor. If true
// it is not safe to send any IPC messages to the actor representing this db
// or any of its subactors.
bool IsDisconnectedFromActor();
bool IsDisconnectedFromActor() const;
void CloseInternal(bool aIsDead);
// Whether or not the database has had Close called on it.
bool IsClosed();
bool IsClosed() const;
void EnterSetVersionTransaction();
void ExitSetVersionTransaction();

View File

@ -541,8 +541,9 @@ IDBFactory::OpenCommon(const nsAString& aName,
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
NS_ASSERTION(mgr, "This should never be null!");
rv =
mgr->WaitForOpenAllowed(mASCIIOrigin, openHelper->Id(), permissionHelper);
rv =
mgr->WaitForOpenAllowed(OriginOrPatternString::FromOrigin(mASCIIOrigin),
openHelper->Id(), permissionHelper);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
}
else if (aDeleting) {

View File

@ -175,6 +175,44 @@ struct SerializedStructuredCloneWriteInfo
uint64_t offsetToKeyProp;
};
class OriginOrPatternString : public nsCString
{
public:
static OriginOrPatternString
FromOrigin(const nsACString& aOrigin)
{
return OriginOrPatternString(aOrigin, true);
}
static OriginOrPatternString
FromPattern(const nsACString& aPattern)
{
return OriginOrPatternString(aPattern, false);
}
bool
IsOrigin() const
{
return mIsOrigin;
}
bool
IsPattern() const
{
return !mIsOrigin;
}
private:
OriginOrPatternString(const nsACString& aOriginOrPattern, bool aIsOrigin)
: nsCString(aOriginOrPattern), mIsOrigin(aIsOrigin)
{ }
bool
operator==(const OriginOrPatternString& aOther) MOZ_DELETE;
bool mIsOrigin;
};
END_INDEXEDDB_NAMESPACE
#endif // mozilla_dom_indexeddb_indexeddatabase_h__

View File

@ -5,14 +5,15 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "IndexedDatabaseManager.h"
#include "DatabaseInfo.h"
#include "mozIApplicationClearPrivateDataParams.h"
#include "nsIAtom.h"
#include "nsIConsoleService.h"
#include "nsIDOMScriptObjectFactory.h"
#include "nsIFile.h"
#include "nsIFileStorage.h"
#include "nsIObserverService.h"
#include "nsIPrincipal.h"
#include "nsIScriptError.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsIScriptSecurityManager.h"
@ -27,8 +28,10 @@
#include "mozilla/storage.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsContentUtils.h"
#include "nsCRTGlue.h"
#include "nsDirectoryServiceUtils.h"
#include "nsEventDispatcher.h"
#include "nsScriptSecurityManager.h"
#include "nsThreadUtils.h"
#include "nsXPCOM.h"
#include "nsXPCOMPrivate.h"
@ -133,34 +136,247 @@ EnumerateToTArray(const nsACString& aKey,
NS_ASSERTION(aValue, "Null pointer!");
NS_ASSERTION(aUserArg, "Null pointer!");
nsTArray<T>* array =
static_cast<nsTArray<T>*>(aUserArg);
if (!array->AppendElements(*aValue)) {
NS_WARNING("Out of memory!");
return PL_DHASH_STOP;
}
static_cast<nsTArray<T>*>(aUserArg)->AppendElements(*aValue);
return PL_DHASH_NEXT;
}
bool
PatternMatchesOrigin(const nsACString& aPatternString, const nsACString& aOrigin)
{
// Aren't we smart!
return StringBeginsWith(aOrigin, aPatternString);
}
enum MozBrowserPatternFlag
{
MozBrowser = 0,
NotMozBrowser,
IgnoreMozBrowser
};
// Use one of the friendly overloads below.
void
GetOriginPatternString(uint32_t aAppId, MozBrowserPatternFlag aBrowserFlag,
const nsACString& aOrigin, nsAutoCString& _retval)
{
NS_ASSERTION(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
"Bad appId!");
NS_ASSERTION(aOrigin.IsEmpty() || aBrowserFlag != IgnoreMozBrowser,
"Bad args!");
if (aOrigin.IsEmpty()) {
_retval.Truncate();
_retval.AppendInt(aAppId);
_retval.Append('+');
if (aBrowserFlag != IgnoreMozBrowser) {
if (aBrowserFlag == MozBrowser) {
_retval.Append('t');
}
else {
_retval.Append('f');
}
_retval.Append('+');
}
return;
}
#ifdef DEBUG
if (aAppId != nsIScriptSecurityManager::NO_APP_ID ||
aBrowserFlag == MozBrowser) {
nsAutoCString pattern;
GetOriginPatternString(aAppId, aBrowserFlag, EmptyCString(), pattern);
NS_ASSERTION(PatternMatchesOrigin(pattern, aOrigin),
"Origin doesn't match parameters!");
}
#endif
_retval = aOrigin;
}
void
GetOriginPatternString(uint32_t aAppId, nsAutoCString& _retval)
{
return GetOriginPatternString(aAppId, IgnoreMozBrowser, EmptyCString(),
_retval);
}
void
GetOriginPatternString(uint32_t aAppId, bool aBrowserOnly,
nsAutoCString& _retval)
{
return GetOriginPatternString(aAppId,
aBrowserOnly ? MozBrowser : NotMozBrowser,
EmptyCString(), _retval);
}
void
GetOriginPatternString(uint32_t aAppId, bool aBrowserOnly,
const nsACString& aOrigin, nsAutoCString& _retval)
{
return GetOriginPatternString(aAppId,
aBrowserOnly ? MozBrowser : NotMozBrowser,
aOrigin, _retval);
}
void
GetOriginPatternStringMaybeIgnoreBrowser(uint32_t aAppId, bool aBrowserOnly,
nsAutoCString& _retval)
{
return GetOriginPatternString(aAppId,
aBrowserOnly ? MozBrowser : IgnoreMozBrowser,
EmptyCString(), _retval);
}
template <class ValueType>
class PatternMatchArray : public nsAutoTArray<ValueType, 20>
{
typedef PatternMatchArray<ValueType> SelfType;
struct Closure
{
Closure(SelfType& aSelf, const nsACString& aPattern)
: mSelf(aSelf), mPattern(aPattern)
{ }
SelfType& mSelf;
const nsACString& mPattern;
};
public:
template <class T>
void
Find(const T& aHashtable,
const nsACString& aPattern)
{
SelfType::Clear();
Closure closure(*this, aPattern);
aHashtable.EnumerateRead(SelfType::Enumerate, &closure);
}
private:
static PLDHashOperator
Enumerate(const nsACString& aKey,
nsTArray<ValueType>* aValue,
void* aUserArg)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!aKey.IsEmpty(), "Empty key!");
NS_ASSERTION(aValue, "Null pointer!");
NS_ASSERTION(aUserArg, "Null pointer!");
Closure* closure = static_cast<Closure*>(aUserArg);
if (PatternMatchesOrigin(closure->mPattern, aKey)) {
closure->mSelf.AppendElements(*aValue);
}
return PL_DHASH_NEXT;
}
};
typedef PatternMatchArray<IDBDatabase*> DatabasePatternMatchArray;
PLDHashOperator
InvalidateAllFileManagers(const nsACString& aKey,
nsTArray<nsRefPtr<FileManager> >* aValue,
void* aUserArg)
InvalidateAndRemoveFileManagers(
const nsACString& aKey,
nsAutoPtr<nsTArray<nsRefPtr<FileManager> > >& aValue,
void* aUserArg)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!aKey.IsEmpty(), "Empty key!");
NS_ASSERTION(aValue, "Null pointer!");
for (uint32_t i = 0; i < aValue->Length(); i++) {
nsRefPtr<FileManager> fileManager = aValue->ElementAt(i);
fileManager->Invalidate();
const nsACString* pattern =
static_cast<const nsACString*>(aUserArg);
if (!pattern || PatternMatchesOrigin(*pattern, aKey)) {
for (uint32_t i = 0; i < aValue->Length(); i++) {
nsRefPtr<FileManager>& fileManager = aValue->ElementAt(i);
fileManager->Invalidate();
}
return PL_DHASH_REMOVE;
}
return PL_DHASH_NEXT;
}
void
SanitizeOriginString(nsCString& aOrigin)
{
// We want profiles to be platform-independent so we always need to replace
// the same characters on every platform. Windows has the most extensive set
// of illegal characters so we use its FILE_ILLEGAL_CHARACTERS and
// FILE_PATH_SEPARATOR.
static const char kReplaceChars[] = CONTROL_CHARACTERS "/:*?\"<>|\\";
#ifdef XP_WIN
NS_ASSERTION(!strcmp(kReplaceChars,
FILE_ILLEGAL_CHARACTERS FILE_PATH_SEPARATOR),
"Illegal file characters have changed!");
#endif
aOrigin.ReplaceChar(kReplaceChars, '+');
}
nsresult
GetASCIIOriginFromURI(nsIURI* aURI,
uint32_t aAppId,
bool aInMozBrowser,
nsACString& aOrigin)
{
NS_ASSERTION(aURI, "Null uri!");
nsCString origin;
mozilla::GetExtendedOrigin(aURI, aAppId, aInMozBrowser, origin);
if (origin.IsEmpty()) {
NS_WARNING("GetExtendedOrigin returned empty string!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
aOrigin.Assign(origin);
return NS_OK;
}
nsresult
GetASCIIOriginFromPrincipal(nsIPrincipal* aPrincipal,
nsACString& aOrigin)
{
NS_ASSERTION(aPrincipal, "Don't hand me a null principal!");
static const char kChromeOrigin[] = "chrome";
nsCString origin;
if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
origin.AssignLiteral(kChromeOrigin);
}
else {
bool isNullPrincipal;
nsresult rv = aPrincipal->GetIsNullPrincipal(&isNullPrincipal);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (isNullPrincipal) {
NS_WARNING("IndexedDB not supported from this principal!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
rv = aPrincipal->GetExtendedOrigin(origin);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (origin.EqualsLiteral(kChromeOrigin)) {
NS_WARNING("Non-chrome principal can't use chrome origin!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
}
aOrigin.Assign(origin);
return NS_OK;
}
} // anonymous namespace
IndexedDatabaseManager::IndexedDatabaseManager()
@ -297,10 +513,10 @@ IndexedDatabaseManager::GetDirectoryForOrigin(const nsACString& aASCIIOrigin,
rv = directory->InitWithPath(GetBaseDirectory());
NS_ENSURE_SUCCESS(rv, rv);
NS_ConvertASCIItoUTF16 originSanitized(aASCIIOrigin);
originSanitized.ReplaceChar(":/", '+');
nsAutoCString originSanitized(aASCIIOrigin);
SanitizeOriginString(originSanitized);
rv = directory->Append(originSanitized);
rv = directory->Append(NS_ConvertASCIItoUTF16(originSanitized));
NS_ENSURE_SUCCESS(rv, rv);
directory.forget(aDirectory);
@ -406,6 +622,37 @@ IndexedDatabaseManager::FireWindowOnError(nsPIDOMWindow* aOwner,
return consoleService->LogMessage(scriptError);
}
// static
bool
IndexedDatabaseManager::OriginMatchesApp(const nsACString& aOrigin,
uint32_t aAppId)
{
NS_ASSERTION(!aOrigin.IsEmpty(), "Empty origin!");
NS_ASSERTION(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
"Bad appId!");
nsAutoCString pattern;
GetOriginPatternString(aAppId, pattern);
return PatternMatchesOrigin(pattern, aOrigin);
}
// static
bool
IndexedDatabaseManager::OriginMatchesApp(const nsACString& aOrigin,
uint32_t aAppId,
bool aInMozBrowser)
{
NS_ASSERTION(!aOrigin.IsEmpty(), "Empty origin!");
NS_ASSERTION(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
"Bad appId!");
nsAutoCString pattern;
GetOriginPatternString(aAppId, aInMozBrowser, pattern);
return PatternMatchesOrigin(pattern, aOrigin);
}
bool
IndexedDatabaseManager::RegisterDatabase(IDBDatabase* aDatabase)
{
@ -466,15 +713,16 @@ IndexedDatabaseManager::OnUsageCheckComplete(AsyncUsageRunnable* aRunnable)
}
nsresult
IndexedDatabaseManager::WaitForOpenAllowed(const nsACString& aOrigin,
nsIAtom* aId,
nsIRunnable* aRunnable)
IndexedDatabaseManager::WaitForOpenAllowed(
const OriginOrPatternString& aOriginOrPattern,
nsIAtom* aId,
nsIRunnable* aRunnable)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!aOrigin.IsEmpty(), "Empty origin!");
NS_ASSERTION(!aOriginOrPattern.IsEmpty(), "Empty pattern!");
NS_ASSERTION(aRunnable, "Null pointer!");
nsAutoPtr<SynchronizedOp> op(new SynchronizedOp(aOrigin, aId));
nsAutoPtr<SynchronizedOp> op(new SynchronizedOp(aOriginOrPattern, aId));
// See if this runnable needs to wait.
bool delayed = false;
@ -501,16 +749,18 @@ IndexedDatabaseManager::WaitForOpenAllowed(const nsACString& aOrigin,
}
void
IndexedDatabaseManager::AllowNextSynchronizedOp(const nsACString& aOrigin,
nsIAtom* aId)
IndexedDatabaseManager::AllowNextSynchronizedOp(
const OriginOrPatternString& aOriginOrPattern,
nsIAtom* aId)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!aOrigin.IsEmpty(), "Empty origin!");
NS_ASSERTION(!aOriginOrPattern.IsEmpty(), "Empty origin/pattern!");
uint32_t count = mSynchronizedOps.Length();
for (uint32_t index = 0; index < count; index++) {
nsAutoPtr<SynchronizedOp>& op = mSynchronizedOps[index];
if (op->mOrigin.Equals(aOrigin)) {
if (op->mOriginOrPattern.IsOrigin() == aOriginOrPattern.IsOrigin() &&
op->mOriginOrPattern == aOriginOrPattern) {
if (op->mId == aId) {
NS_ASSERTION(op->mDatabases.IsEmpty(), "How did this happen?");
@ -531,7 +781,7 @@ IndexedDatabaseManager::AllowNextSynchronizedOp(const nsACString& aOrigin,
nsresult
IndexedDatabaseManager::AcquireExclusiveAccess(
const nsACString& aOrigin,
const nsACString& aPattern,
IDBDatabase* aDatabase,
AsyncConnectionHelper* aHelper,
nsIRunnable* aRunnable,
@ -544,26 +794,26 @@ IndexedDatabaseManager::AcquireExclusiveAccess(
// Find the right SynchronizedOp.
SynchronizedOp* op =
FindSynchronizedOp(aOrigin, aDatabase ? aDatabase->Id() : nullptr);
FindSynchronizedOp(aPattern, aDatabase ? aDatabase->Id() : nullptr);
NS_ASSERTION(op, "We didn't find a SynchronizedOp?");
NS_ASSERTION(!op->mHelper, "SynchronizedOp already has a helper?!?");
NS_ASSERTION(!op->mRunnable, "SynchronizedOp already has a runnable?!?");
nsTArray<IDBDatabase*>* array;
mLiveDatabases.Get(aOrigin, &array);
DatabasePatternMatchArray matches;
matches.Find(mLiveDatabases, aPattern);
// We need to wait for the databases to go away.
// Hold on to all database objects that represent the same database file
// (except the one that is requesting this version change).
nsTArray<nsRefPtr<IDBDatabase> > liveDatabases;
if (array) {
if (!matches.IsEmpty()) {
if (aDatabase) {
// Grab all databases that are not yet closed but whose database id match
// the one we're looking for.
for (uint32_t index = 0; index < array->Length(); index++) {
IDBDatabase*& database = array->ElementAt(index);
for (uint32_t index = 0; index < matches.Length(); index++) {
IDBDatabase*& database = matches[index];
if (!database->IsClosed() &&
database != aDatabase &&
database->Id() == aDatabase->Id()) {
@ -574,7 +824,7 @@ IndexedDatabaseManager::AcquireExclusiveAccess(
else {
// We want *all* databases, even those that are closed, if we're going to
// clear the origin.
liveDatabases.AppendElements(*array);
liveDatabases.AppendElements(matches);
}
}
@ -986,18 +1236,8 @@ IndexedDatabaseManager::GetASCIIOriginFromWindow(nsPIDOMWindow* aWindow,
nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
NS_ENSURE_TRUE(principal, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (nsContentUtils::IsSystemPrincipal(principal)) {
aASCIIOrigin.AssignLiteral("chrome");
}
else {
nsresult rv = principal->GetExtendedOrigin(aASCIIOrigin);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (aASCIIOrigin.EqualsLiteral("null")) {
NS_WARNING("IndexedDB databases not allowed for this principal!");
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
}
nsresult rv = GetASCIIOriginFromPrincipal(principal, aASCIIOrigin);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
@ -1053,17 +1293,12 @@ IndexedDatabaseManager::AddFileManager(const nsACString& aOrigin,
}
void
IndexedDatabaseManager::InvalidateFileManagersForOrigin(
const nsACString& aOrigin)
IndexedDatabaseManager::InvalidateFileManagersForPattern(
const nsACString& aPattern)
{
nsTArray<nsRefPtr<FileManager> >* array;
if (mFileManagers.Get(aOrigin, &array)) {
for (uint32_t i = 0; i < array->Length(); i++) {
nsRefPtr<FileManager> fileManager = array->ElementAt(i);
fileManager->Invalidate();
}
mFileManagers.Remove(aOrigin);
}
NS_ASSERTION(!aPattern.IsEmpty(), "Empty pattern!");
mFileManagers.Enumerate(InvalidateAndRemoveFileManagers,
const_cast<nsACString*>(&aPattern));
}
void
@ -1173,39 +1408,103 @@ IndexedDatabaseManager::RunSynchronizedOp(IDBDatabase* aDatabase,
return NS_OK;
}
IndexedDatabaseManager::SynchronizedOp*
IndexedDatabaseManager::FindSynchronizedOp(const nsACString& aPattern,
nsIAtom* aId)
{
for (uint32_t index = 0; index < mSynchronizedOps.Length(); index++) {
const nsAutoPtr<SynchronizedOp>& currentOp = mSynchronizedOps[index];
if (PatternMatchesOrigin(aPattern, currentOp->mOriginOrPattern) &&
(!currentOp->mId || currentOp->mId == aId)) {
return currentOp;
}
}
return nullptr;
}
nsresult
IndexedDatabaseManager::ClearDatabasesForApp(uint32_t aAppId, bool aBrowserOnly)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
"Bad appId!");
// This only works from the main process.
NS_ENSURE_TRUE(IsMainProcess(), NS_ERROR_NOT_AVAILABLE);
nsAutoCString pattern;
GetOriginPatternStringMaybeIgnoreBrowser(aAppId, aBrowserOnly, pattern);
// If there is a pending or running clear operation for this app, return
// immediately.
if (IsClearOriginPending(pattern)) {
return NS_OK;
}
OriginOrPatternString oops = OriginOrPatternString::FromPattern(pattern);
// Queue up the origin clear runnable.
nsRefPtr<OriginClearRunnable> runnable = new OriginClearRunnable(oops);
nsresult rv = WaitForOpenAllowed(oops, nullptr, runnable);
NS_ENSURE_SUCCESS(rv, rv);
runnable->AdvanceState();
// Give the runnable some help by invalidating any databases in the way.
DatabasePatternMatchArray matches;
matches.Find(mLiveDatabases, pattern);
for (uint32_t index = 0; index < matches.Length(); index++) {
// We need to grab references here to prevent the database from dying while
// we invalidate it.
nsRefPtr<IDBDatabase> database = matches[index];
database->Invalidate();
}
return NS_OK;
}
NS_IMPL_ISUPPORTS2(IndexedDatabaseManager, nsIIndexedDatabaseManager,
nsIObserver)
NS_IMETHODIMP
IndexedDatabaseManager::GetUsageForURI(
nsIURI* aURI,
nsIIndexedDatabaseUsageCallback* aCallback)
nsIIndexedDatabaseUsageCallback* aCallback,
uint32_t aAppId,
bool aInMozBrowserOnly,
uint8_t aOptionalArgCount)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aURI);
NS_ENSURE_ARG_POINTER(aCallback);
// This only works from the main process.
NS_ENSURE_TRUE(IsMainProcess(), NS_ERROR_NOT_AVAILABLE);
if (!aOptionalArgCount) {
aAppId = nsIScriptSecurityManager::NO_APP_ID;
}
// Figure out which origin we're dealing with.
nsCString origin;
nsresult rv = nsContentUtils::GetASCIIOrigin(aURI, origin);
nsresult rv = GetASCIIOriginFromURI(aURI, aAppId, aInMozBrowserOnly, origin);
NS_ENSURE_SUCCESS(rv, rv);
OriginOrPatternString oops = OriginOrPatternString::FromOrigin(origin);
nsRefPtr<AsyncUsageRunnable> runnable =
new AsyncUsageRunnable(aURI, origin, aCallback);
new AsyncUsageRunnable(aAppId, aInMozBrowserOnly, oops, aURI, aCallback);
nsRefPtr<AsyncUsageRunnable>* newRunnable =
mUsageRunnables.AppendElement(runnable);
NS_ENSURE_TRUE(newRunnable, NS_ERROR_OUT_OF_MEMORY);
// Non-standard URIs can't create databases anyway so fire the callback
// immediately.
if (origin.EqualsLiteral("null")) {
return runnable->TakeShortcut();
}
// Otherwise put the computation runnable in the queue.
rv = WaitForOpenAllowed(origin, nullptr, runnable);
rv = WaitForOpenAllowed(oops, nullptr, runnable);
NS_ENSURE_SUCCESS(rv, rv);
runnable->AdvanceState();
@ -1216,77 +1515,95 @@ IndexedDatabaseManager::GetUsageForURI(
NS_IMETHODIMP
IndexedDatabaseManager::CancelGetUsageForURI(
nsIURI* aURI,
nsIIndexedDatabaseUsageCallback* aCallback)
nsIIndexedDatabaseUsageCallback* aCallback,
uint32_t aAppId,
bool aInMozBrowserOnly,
uint8_t aOptionalArgCount)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aURI);
NS_ENSURE_ARG_POINTER(aCallback);
// This only works from the main process.
NS_ENSURE_TRUE(IsMainProcess(), NS_ERROR_NOT_AVAILABLE);
if (!aOptionalArgCount) {
aAppId = nsIScriptSecurityManager::NO_APP_ID;
}
// See if one of our pending callbacks matches both the URI and the callback
// given. Cancel an remove it if so.
for (uint32_t index = 0; index < mUsageRunnables.Length(); index++) {
nsRefPtr<AsyncUsageRunnable>& runnable = mUsageRunnables[index];
bool equals;
nsresult rv = runnable->mURI->Equals(aURI, &equals);
NS_ENSURE_SUCCESS(rv, rv);
if (runnable->mAppId == aAppId &&
runnable->mInMozBrowserOnly == aInMozBrowserOnly) {
bool equals;
nsresult rv = runnable->mURI->Equals(aURI, &equals);
NS_ENSURE_SUCCESS(rv, rv);
if (equals && SameCOMIdentity(aCallback, runnable->mCallback)) {
runnable->Cancel();
break;
if (equals && SameCOMIdentity(aCallback, runnable->mCallback)) {
runnable->Cancel();
break;
}
}
}
return NS_OK;
}
NS_IMETHODIMP
IndexedDatabaseManager::ClearDatabasesForURI(nsIURI* aURI)
IndexedDatabaseManager::ClearDatabasesForURI(nsIURI* aURI,
uint32_t aAppId,
bool aInMozBrowserOnly,
uint8_t aOptionalArgCount)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aURI);
// This only works from the main process.
NS_ENSURE_TRUE(IsMainProcess(), NS_ERROR_NOT_AVAILABLE);
if (!aOptionalArgCount) {
aAppId = nsIScriptSecurityManager::NO_APP_ID;
}
// Figure out which origin we're dealing with.
nsCString origin;
nsresult rv = nsContentUtils::GetASCIIOrigin(aURI, origin);
nsresult rv = GetASCIIOriginFromURI(aURI, aAppId, aInMozBrowserOnly, origin);
NS_ENSURE_SUCCESS(rv, rv);
// Non-standard URIs can't create databases anyway, so return immediately.
if (origin.EqualsLiteral("null")) {
return NS_OK;
}
nsAutoCString pattern;
GetOriginPatternString(aAppId, aInMozBrowserOnly, origin, pattern);
// If there is a pending or running clear operation for this origin, return
// immediately.
if (IsClearOriginPending(origin)) {
if (IsClearOriginPending(pattern)) {
return NS_OK;
}
// Queue up the origin clear runnable.
nsRefPtr<OriginClearRunnable> runnable = new OriginClearRunnable(origin);
OriginOrPatternString oops = OriginOrPatternString::FromPattern(pattern);
rv = WaitForOpenAllowed(origin, nullptr, runnable);
// Queue up the origin clear runnable.
nsRefPtr<OriginClearRunnable> runnable = new OriginClearRunnable(oops);
rv = WaitForOpenAllowed(oops, nullptr, runnable);
NS_ENSURE_SUCCESS(rv, rv);
runnable->AdvanceState();
// Give the runnable some help by invalidating any databases in the way. We
// need to grab references to any live databases here to prevent them from
// dying while we invalidate them.
nsTArray<nsRefPtr<IDBDatabase> > liveDatabases;
// Give the runnable some help by invalidating any databases in the way.
DatabasePatternMatchArray matches;
matches.Find(mLiveDatabases, pattern);
nsTArray<IDBDatabase*>* array;
if (mLiveDatabases.Get(origin, &array)) {
liveDatabases.AppendElements(*array);
for (uint32_t index = 0; index < matches.Length(); index++) {
// We need to grab references to any live databases here to prevent them
// from dying while we invalidate them.
nsRefPtr<IDBDatabase> database = matches[index];
database->Invalidate();
}
for (uint32_t index = 0; index < liveDatabases.Length(); index++) {
liveDatabases[index]->Invalidate();
}
DatabaseInfo::RemoveAllForOrigin(origin);
// After everything has been invalidated the helper should be dispatched to
// the end of the event queue.
return NS_OK;
@ -1361,7 +1678,7 @@ IndexedDatabaseManager::Observe(nsISupports* aSubject,
}
}
mFileManagers.EnumerateRead(InvalidateAllFileManagers, nullptr);
mFileManagers.Enumerate(InvalidateAndRemoveFileManagers, nullptr);
if (PR_ATOMIC_SET(&gClosed, 1)) {
NS_ERROR("Close more than once?!");
@ -1392,6 +1709,25 @@ IndexedDatabaseManager::Observe(nsISupports* aSubject,
return NS_OK;
}
if (!strcmp(aTopic, TOPIC_WEB_APP_CLEAR_DATA)) {
nsCOMPtr<mozIApplicationClearPrivateDataParams> params =
do_QueryInterface(aSubject);
NS_ENSURE_TRUE(params, NS_ERROR_UNEXPECTED);
uint32_t appId;
nsresult rv = params->GetAppId(&appId);
NS_ENSURE_SUCCESS(rv, rv);
bool browserOnly;
rv = params->GetBrowserOnly(&browserOnly);
NS_ENSURE_SUCCESS(rv, rv);
rv = ClearDatabasesForApp(appId, browserOnly);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_NOTREACHED("Unknown topic!");
return NS_ERROR_UNEXPECTED;
}
@ -1408,16 +1744,75 @@ OriginClearRunnable::InvalidateOpenedDatabases(
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
OriginClearRunnable* self = static_cast<OriginClearRunnable*>(aClosure);
nsTArray<nsRefPtr<IDBDatabase> > databases;
databases.SwapElements(aDatabases);
for (uint32_t index = 0; index < databases.Length(); index++) {
databases[index]->Invalidate();
}
}
DatabaseInfo::RemoveAllForOrigin(self->mOrigin);
void
IndexedDatabaseManager::
OriginClearRunnable::DeleteFiles(IndexedDatabaseManager* aManager)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aManager, "Don't pass me null!");
nsresult rv;
nsCOMPtr<nsIFile> directory =
do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS_VOID(rv);
rv = directory->InitWithPath(aManager->GetBaseDirectory());
NS_ENSURE_SUCCESS_VOID(rv);
nsCOMPtr<nsISimpleEnumerator> entries;
rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
NS_ENSURE_SUCCESS_VOID(rv);
if (!entries) {
return;
}
nsCString originSanitized(mOriginOrPattern);
SanitizeOriginString(originSanitized);
bool hasMore;
while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
nsCOMPtr<nsISupports> entry;
rv = entries->GetNext(getter_AddRefs(entry));
NS_ENSURE_SUCCESS_VOID(rv);
nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
NS_ASSERTION(file, "Don't know what this is!");
bool isDirectory;
rv = file->IsDirectory(&isDirectory);
NS_ENSURE_SUCCESS_VOID(rv);
if (!isDirectory) {
NS_WARNING("Something in the IndexedDB directory that doesn't belong!");
continue;
}
nsString leafName;
rv = file->GetLeafName(leafName);
NS_ENSURE_SUCCESS_VOID(rv);
// Skip databases for other apps.
if (!PatternMatchesOrigin(originSanitized,
NS_ConvertUTF16toUTF8(leafName))) {
continue;
}
if (NS_FAILED(file->Remove(true))) {
// This should never fail if we've closed all database connections
// correctly...
NS_ERROR("Failed to remove directory!");
}
}
}
NS_IMETHODIMP
@ -1439,9 +1834,9 @@ IndexedDatabaseManager::OriginClearRunnable::Run()
// Now we have to wait until the thread pool is done with all of the
// databases we care about.
nsresult rv =
mgr->AcquireExclusiveAccess(mOrigin, this, InvalidateOpenedDatabases,
this);
nsresult rv = mgr->AcquireExclusiveAccess(mOriginOrPattern, this,
InvalidateOpenedDatabases,
nullptr);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
@ -1452,24 +1847,7 @@ IndexedDatabaseManager::OriginClearRunnable::Run()
AdvanceState();
// Remove the directory that contains all our databases.
nsCOMPtr<nsIFile> directory;
nsresult rv =
mgr->GetDirectoryForOrigin(mOrigin, getter_AddRefs(directory));
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to get directory to remove!");
if (NS_SUCCEEDED(rv)) {
bool exists;
rv = directory->Exists(&exists);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"Failed to check that the directory exists!");
if (NS_SUCCEEDED(rv) && exists && NS_FAILED(directory->Remove(true))) {
// This should never fail if we've closed all database connections
// correctly...
NS_ERROR("Failed to remove directory!");
}
}
DeleteFiles(mgr);
// Now dispatch back to the main thread.
if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
@ -1483,10 +1861,10 @@ IndexedDatabaseManager::OriginClearRunnable::Run()
case Complete: {
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
mgr->InvalidateFileManagersForOrigin(mOrigin);
mgr->InvalidateFileManagersForPattern(mOriginOrPattern);
// Tell the IndexedDatabaseManager that we're done.
mgr->AllowNextSynchronizedOp(mOrigin, nullptr);
mgr->AllowNextSynchronizedOp(mOriginOrPattern, nullptr);
return NS_OK;
}
@ -1501,19 +1879,24 @@ IndexedDatabaseManager::OriginClearRunnable::Run()
}
IndexedDatabaseManager::AsyncUsageRunnable::AsyncUsageRunnable(
uint32_t aAppId,
bool aInMozBrowserOnly,
const OriginOrPatternString& aOrigin,
nsIURI* aURI,
const nsACString& aOrigin,
nsIIndexedDatabaseUsageCallback* aCallback)
: mURI(aURI),
mOrigin(aOrigin),
mCallback(aCallback),
mUsage(0),
mFileUsage(0),
mAppId(aAppId),
mCanceled(0),
mCallbackState(Pending)
mOrigin(aOrigin),
mCallbackState(Pending),
mInMozBrowserOnly(aInMozBrowserOnly)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aURI, "Null pointer!");
NS_ASSERTION(aOrigin.IsOrigin(), "Expect origin only here!");
NS_ASSERTION(!aOrigin.IsEmpty(), "Empty origin!");
NS_ASSERTION(aCallback, "Null pointer!");
}
@ -1612,7 +1995,8 @@ IndexedDatabaseManager::AsyncUsageRunnable::RunInternal()
if (!mCanceled) {
uint64_t usage = mUsage;
IncrementUsage(&usage, mFileUsage);
mCallback->OnUsageResult(mURI, usage, mFileUsage);
mCallback->OnUsageResult(mURI, usage, mFileUsage, mAppId,
mInMozBrowserOnly);
}
// Clean up.
@ -1779,9 +2163,9 @@ IndexedDatabaseManager::WaitForLockedFilesToFinishRunnable::Run()
}
IndexedDatabaseManager::
SynchronizedOp::SynchronizedOp(const nsACString& aOrigin,
SynchronizedOp::SynchronizedOp(const OriginOrPatternString& aOriginOrPattern,
nsIAtom* aId)
: mOrigin(aOrigin), mId(aId)
: mOriginOrPattern(aOriginOrPattern), mId(aId)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
MOZ_COUNT_CTOR(IndexedDatabaseManager::SynchronizedOp);
@ -1794,24 +2178,42 @@ IndexedDatabaseManager::SynchronizedOp::~SynchronizedOp()
}
bool
IndexedDatabaseManager::SynchronizedOp::MustWaitFor(const SynchronizedOp& aRhs)
const
IndexedDatabaseManager::
SynchronizedOp::MustWaitFor(const SynchronizedOp& aExistingOp)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
bool match;
if (aExistingOp.mOriginOrPattern.IsOrigin()) {
if (mOriginOrPattern.IsOrigin()) {
match = aExistingOp.mOriginOrPattern.Equals(mOriginOrPattern);
}
else {
match = PatternMatchesOrigin(mOriginOrPattern, aExistingOp.mOriginOrPattern);
}
}
else if (mOriginOrPattern.IsOrigin()) {
match = PatternMatchesOrigin(aExistingOp.mOriginOrPattern, mOriginOrPattern);
}
else {
match = PatternMatchesOrigin(mOriginOrPattern, aExistingOp.mOriginOrPattern) ||
PatternMatchesOrigin(aExistingOp.mOriginOrPattern, mOriginOrPattern);
}
// If the origins don't match, the second can proceed.
if (!aRhs.mOrigin.Equals(mOrigin)) {
if (!match) {
return false;
}
// If the origins and the ids match, the second must wait.
if (aRhs.mId == mId) {
if (aExistingOp.mId == mId) {
return true;
}
// Waiting is required if either one corresponds to an origin clearing
// (a null Id).
if (!aRhs.mId || !mId) {
if (!aExistingOp.mId || !mId) {
return true;
}

View File

@ -57,11 +57,11 @@ public:
// Waits for databases to be cleared and for version change transactions to
// complete before dispatching the given runnable.
nsresult WaitForOpenAllowed(const nsACString& aOrigin,
nsresult WaitForOpenAllowed(const OriginOrPatternString& aOriginOrPattern,
nsIAtom* aId,
nsIRunnable* aRunnable);
void AllowNextSynchronizedOp(const nsACString& aOrigin,
void AllowNextSynchronizedOp(const OriginOrPatternString& aOriginOrPattern,
nsIAtom* aId);
nsIThread* IOThread()
@ -169,7 +169,7 @@ public:
const nsAString& aDatabaseName,
FileManager* aFileManager);
void InvalidateFileManagersForOrigin(const nsACString& aOrigin);
void InvalidateFileManagersForPattern(const nsACString& aPattern);
void InvalidateFileManager(const nsACString& aOrigin,
const nsAString& aDatabaseName);
@ -200,7 +200,18 @@ public:
const nsAString& aName);
static nsresult
FireWindowOnError(nsPIDOMWindow* aOwner, nsEventChainPostVisitor& aVisitor);
FireWindowOnError(nsPIDOMWindow* aOwner,
nsEventChainPostVisitor& aVisitor);
static bool
OriginMatchesApp(const nsACString& aOrigin,
uint32_t aAppId);
static bool
OriginMatchesApp(const nsACString& aOrigin,
uint32_t aAppId,
bool aInMozBrowser);
private:
IndexedDatabaseManager();
~IndexedDatabaseManager();
@ -225,6 +236,8 @@ private:
// Called when a database has been closed.
void OnDatabaseClosed(IDBDatabase* aDatabase);
nsresult ClearDatabasesForApp(uint32_t aAppId, bool aBrowserOnly);
// Responsible for clearing the database files for a particular origin on the
// IO thread. Created when nsIIDBIndexedDatabaseManager::ClearDatabasesForURI
// is called. Runs three times, first on the main thread, next on the IO
@ -253,8 +266,8 @@ private:
NS_DECL_ISUPPORTS
NS_DECL_NSIRUNNABLE
OriginClearRunnable(const nsACString& aOrigin)
: mOrigin(aOrigin),
OriginClearRunnable(const OriginOrPatternString& aOriginOrPattern)
: mOriginOrPattern(aOriginOrPattern),
mCallbackState(Pending)
{ }
@ -279,8 +292,10 @@ private:
nsTArray<nsRefPtr<IDBDatabase> >& aDatabases,
void* aClosure);
void DeleteFiles(IndexedDatabaseManager* aManager);
private:
nsCString mOrigin;
OriginOrPatternString mOriginOrPattern;
CallbackState mCallbackState;
};
@ -311,12 +326,15 @@ private:
// Running on the main thread after skipping the work
Shortcut
};
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIRUNNABLE
AsyncUsageRunnable(nsIURI* aURI,
const nsACString& aOrigin,
AsyncUsageRunnable(uint32_t aAppId,
bool aInMozBrowserOnly,
const OriginOrPatternString& aOrigin,
nsIURI* aURI,
nsIIndexedDatabaseUsageCallback* aCallback);
// Sets the canceled flag so that the callback is never called.
@ -349,13 +367,14 @@ private:
uint64_t* aUsage);
nsCOMPtr<nsIURI> mURI;
nsCString mOrigin;
nsCOMPtr<nsIIndexedDatabaseUsageCallback> mCallback;
uint64_t mUsage;
uint64_t mFileUsage;
uint32_t mAppId;
int32_t mCanceled;
OriginOrPatternString mOrigin;
CallbackState mCallbackState;
bool mInMozBrowserOnly;
};
// Called when AsyncUsageRunnable has finished its Run() method.
@ -366,16 +385,17 @@ private:
// clearing dbs for an origin, etc).
struct SynchronizedOp
{
SynchronizedOp(const nsACString& aOrigin, nsIAtom* aId);
SynchronizedOp(const OriginOrPatternString& aOriginOrPattern,
nsIAtom* aId);
~SynchronizedOp();
// Test whether the second SynchronizedOp needs to get behind this one.
bool MustWaitFor(const SynchronizedOp& aRhs) const;
// Test whether this SynchronizedOp needs to wait for the given op.
bool MustWaitFor(const SynchronizedOp& aOp);
void DelayRunnable(nsIRunnable* aRunnable);
void DispatchDelayedRunnables();
const nsCString mOrigin;
const OriginOrPatternString mOriginOrPattern;
nsCOMPtr<nsIAtom> mId;
nsRefPtr<AsyncConnectionHelper> mHelper;
nsCOMPtr<nsIRunnable> mRunnable;
@ -442,22 +462,12 @@ private:
static nsresult RunSynchronizedOp(IDBDatabase* aDatabase,
SynchronizedOp* aOp);
SynchronizedOp* FindSynchronizedOp(const nsACString& aOrigin,
nsIAtom* aId)
{
for (uint32_t index = 0; index < mSynchronizedOps.Length(); index++) {
const nsAutoPtr<SynchronizedOp>& currentOp = mSynchronizedOps[index];
if (currentOp->mOrigin == aOrigin &&
(!currentOp->mId || currentOp->mId == aId)) {
return currentOp;
}
}
return nullptr;
}
SynchronizedOp* FindSynchronizedOp(const nsACString& aPattern,
nsIAtom* aId);
bool IsClearOriginPending(const nsACString& aOrigin)
bool IsClearOriginPending(const nsACString& aPattern)
{
return !!FindSynchronizedOp(aOrigin, nullptr);
return !!FindSynchronizedOp(aPattern, nullptr);
}
// Maintains a list of live databases per origin.

View File

@ -66,12 +66,13 @@ EXPORTS_mozilla/dom/indexedDB = \
$(NULL)
LOCAL_INCLUDES = \
-I$(topsrcdir)/db/sqlite3/src \
-I$(topsrcdir)/xpcom/build \
-I$(topsrcdir)/dom/base \
-I$(topsrcdir)/dom/src/storage \
-I$(topsrcdir)/caps/include \
-I$(topsrcdir)/content/base/src \
-I$(topsrcdir)/content/events/src \
-I$(topsrcdir)/db/sqlite3/src \
-I$(topsrcdir)/dom/base \
-I$(topsrcdir)/dom/src/storage \
-I$(topsrcdir)/xpcom/build \
$(NULL)
DEFINES += -D_IMPL_NS_LAYOUT

View File

@ -2018,7 +2018,9 @@ OpenDatabaseHelper::Run()
IndexedDatabaseManager* manager = IndexedDatabaseManager::Get();
NS_ASSERTION(manager, "This should never be null!");
manager->AllowNextSynchronizedOp(mASCIIOrigin, mDatabaseId);
manager->AllowNextSynchronizedOp(
OriginOrPatternString::FromOrigin(mASCIIOrigin),
mDatabaseId);
ReleaseMainThreadObjects();

View File

@ -434,6 +434,15 @@ IndexedDBDatabaseChild::RecvVersionChange(const uint64_t& aOldVersion,
return true;
}
bool
IndexedDBDatabaseChild::RecvInvalidate()
{
if (mDatabase) {
mDatabase->Invalidate();
}
return true;
}
bool
IndexedDBDatabaseChild::RecvPIndexedDBTransactionConstructor(
PIndexedDBTransactionChild* aActor,
@ -584,9 +593,30 @@ IndexedDBTransactionChild::ActorDestroy(ActorDestroyReason aWhy)
}
bool
IndexedDBTransactionChild::RecvComplete(const nsresult& aRv)
IndexedDBTransactionChild::RecvComplete(const CompleteParams& aParams)
{
FireCompleteEvent(aRv);
MOZ_ASSERT(mTransaction);
MOZ_ASSERT(mStrongTransaction);
nsresult resultCode;
switch (aParams.type()) {
case CompleteParams::TCompleteResult:
resultCode = NS_OK;
break;
case CompleteParams::TAbortResult:
resultCode = aParams.get_AbortResult().errorCode();
if (NS_SUCCEEDED(resultCode)) {
resultCode = NS_ERROR_DOM_INDEXEDDB_ABORT_ERR;
}
break;
default:
MOZ_NOT_REACHED("Unknown union type!");
return false;
}
FireCompleteEvent(resultCode);
return true;
}

View File

@ -119,6 +119,9 @@ protected:
RecvVersionChange(const uint64_t& aOldVersion, const uint64_t& aNewVersion)
MOZ_OVERRIDE;
virtual bool
RecvInvalidate() MOZ_OVERRIDE;
virtual bool
RecvPIndexedDBTransactionConstructor(PIndexedDBTransactionChild* aActor,
const TransactionParams& aParams)
@ -163,7 +166,7 @@ protected:
ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
virtual bool
RecvComplete(const nsresult& aRv) MOZ_OVERRIDE;
RecvComplete(const CompleteParams& aParams) MOZ_OVERRIDE;
virtual PIndexedDBObjectStoreChild*
AllocPIndexedDBObjectStore(const ObjectStoreConstructorParams& aParams)

View File

@ -355,7 +355,11 @@ IndexedDBDatabaseParent::HandleRequestEvent(nsIDOMEvent* aEvent,
}
MOZ_ASSERT(!mDatabase || mDatabase == databaseConcrete);
mDatabase = databaseConcrete;
if (!mDatabase) {
databaseConcrete->SetActor(this);
mDatabase = databaseConcrete;
}
return NS_OK;
}
@ -390,6 +394,7 @@ IndexedDBDatabaseParent::HandleRequestEvent(nsIDOMEvent* aEvent,
return NS_ERROR_FAILURE;
}
databaseConcrete->SetActor(this);
mDatabase = databaseConcrete;
return NS_OK;
@ -555,10 +560,10 @@ IndexedDBTransactionParent::HandleEvent(nsIDOMEvent* aEvent)
nsresult rv = aEvent->GetType(type);
NS_ENSURE_SUCCESS(rv, rv);
nsresult transactionResult;
CompleteParams params;
if (type.EqualsLiteral(COMPLETE_EVT_STR)) {
transactionResult = NS_OK;
params = CompleteResult();
}
else if (type.EqualsLiteral(ABORT_EVT_STR)) {
#ifdef DEBUG
@ -573,15 +578,14 @@ IndexedDBTransactionParent::HandleEvent(nsIDOMEvent* aEvent)
}
}
#endif
MOZ_ASSERT(NS_FAILED(mTransaction->GetAbortCode()));
transactionResult = mTransaction->GetAbortCode();
params = AbortResult(mTransaction->GetAbortCode());
}
else {
NS_WARNING("Unknown message type!");
return NS_ERROR_UNEXPECTED;
}
if (!SendComplete(transactionResult)) {
if (!SendComplete(params)) {
return NS_ERROR_FAILURE;
}

View File

@ -58,6 +58,8 @@ child:
VersionChange(uint64_t oldVersion, uint64_t newVersion);
Invalidate();
both:
PIndexedDBTransaction(TransactionParams params);
};

View File

@ -31,6 +31,20 @@ union ObjectStoreConstructorParams
GetObjectStoreParams;
};
struct CompleteResult
{ };
struct AbortResult
{
nsresult errorCode;
};
union CompleteParams
{
CompleteResult;
AbortResult;
};
} // namespace ipc
protocol PIndexedDBTransaction
@ -51,7 +65,7 @@ parent:
DeleteObjectStore(nsString name);
child:
Complete(nsresult rv);
Complete(CompleteParams params);
};
} // namespace indexedDB

View File

@ -8,18 +8,17 @@
interface nsIURI;
[scriptable, function, uuid(ef1795ec-7050-4658-b80f-0e48cbe1d64b)]
[scriptable, function, uuid(38f15cc7-2df0-4a90-8b7f-1606b2243522)]
interface nsIIndexedDatabaseUsageCallback : nsISupports
{
/**
*
*/
void onUsageResult(in nsIURI aURI,
in unsigned long long aUsage,
in unsigned long long aFileUsage);
in unsigned long long aFileUsage,
in unsigned long aAppId,
in boolean aInMozBrowserOnly);
};
[scriptable, builtinclass, uuid(02256aa7-70d8-473f-bf3b-8cb35d28fd75)]
[scriptable, builtinclass, uuid(e5168115-baff-4559-887e-7c0405cc9e63)]
interface nsIIndexedDatabaseManager : nsISupports
{
/**
@ -31,8 +30,11 @@ interface nsIIndexedDatabaseManager : nsISupports
* @param aCallback
* The callback that will be called when the usage is available.
*/
[optional_argc]
void getUsageForURI(in nsIURI aURI,
in nsIIndexedDatabaseUsageCallback aCallback);
in nsIIndexedDatabaseUsageCallback aCallback,
[optional] in unsigned long aAppId,
[optional] in boolean aInMozBrowserOnly);
/**
* Cancels an asynchronous usage check initiated by a previous call to
@ -43,9 +45,11 @@ interface nsIIndexedDatabaseManager : nsISupports
* @param aCallback
* The callback that will be called when the usage is available.
*/
[optional_argc]
void cancelGetUsageForURI(in nsIURI aURI,
in nsIIndexedDatabaseUsageCallback aCallback);
in nsIIndexedDatabaseUsageCallback aCallback,
[optional] in unsigned long aAppId,
[optional] in boolean aInMozBrowserOnly);
/**
* Removes all databases stored for the given URI. The files may not be
@ -54,7 +58,10 @@ interface nsIIndexedDatabaseManager : nsISupports
* @param aURI
* The URI whose databases are to be cleared.
*/
void clearDatabasesForURI(in nsIURI aURI);
[optional_argc]
void clearDatabasesForURI(in nsIURI aURI,
[optional] in unsigned long aAppId,
[optional] in boolean aInMozBrowserOnly);
/**
* Defines indexedDB and IDBKeyrange with its static functions on

View File

@ -21,6 +21,8 @@ MOCHITEST_FILES = \
event_propagation_iframe.html \
exceptions_in_events_iframe.html \
file.js \
file_app_isolation.html \
file_app_isolation.js \
helpers.js \
leaving_page_iframe.html \
test_add_put.html \
@ -100,12 +102,13 @@ MOCHITEST_FILES = \
test_setVersion_events.html \
test_setVersion_exclusion.html \
test_unique_index_update.html \
test_webapp_clearBrowserData.html \
third_party_iframe1.html \
third_party_iframe2.html \
test_app_isolation_inproc.html \
test_app_isolation_oop.html \
file_app_isolation.html \
file_app_isolation.js \
webapp_clearBrowserData_appFrame.html \
webapp_clearBrowserData_browserFrame.html \
$(NULL)
# test_writer_starvation.html disabled for infinite loops, bug 595368

View File

@ -0,0 +1,137 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>Indexed Database Clear Browser Data Test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript;version=1.7">
"use strict";
const appDomain = "example.org";
const manifestURL =
location.protocol + "//" + appDomain + "/manifest.webapp";
function testSteps()
{
const objectStoreName = "foo";
const testKey = 1;
const testValue = objectStoreName;
let request = indexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = unexpectedSuccessHandler;
let event = yield;
let db = event.target.result;
db.onerror = errorHandler;
db.onversionchange = function(event) {
event.target.close();
}
let objectStore = db.createObjectStore(objectStoreName);
objectStore.add(testValue, testKey);
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let srcURL =
location.protocol + "//" + appDomain +
location.pathname.replace("test_webapp_clearBrowserData.html",
"webapp_clearBrowserData_appFrame.html");
let iframe = document.createElement("iframe");
iframe.setAttribute("mozbrowser", "");
iframe.setAttribute("mozapp", manifestURL);
iframe.setAttribute("src", srcURL);
iframe.setAttribute("remote", "true");
iframe.addEventListener("mozbrowsershowmodalprompt", function(event) {
let message = JSON.parse(event.detail.message);
switch (message.type) {
case "info":
case "ok":
window[message.type].apply(window, message.args);
break;
case "done":
continueToNextStepSync();
break;
default:
throw "unknown message";
}
});
info("loading app frame");
document.body.appendChild(iframe);
yield;
request = indexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onupgradeneeded = unexpectedSuccessHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
db = event.target.result;
db.onerror = errorHandler;
objectStore =
db.transaction(objectStoreName).objectStore(objectStoreName);
objectStore.get(testKey).onsuccess = grabEventAndContinueHandler;
event = yield;
ok(testValue == event.target.result, "data still exists");
finishTest();
yield;
}
function start()
{
if (!SpecialPowers.isMainProcess()) {
todo(false, "Test disabled in child processes, for now");
SimpleTest.finish();
return;
}
SpecialPowers.addPermission("browser", true, document);
SpecialPowers.addPermission("browser", true, { manifestURL: manifestURL,
isInBrowserElement: false });
SpecialPowers.addPermission("embed-apps", true, document);
let Webapps = {};
SpecialPowers.wrap(Components)
.utils.import("resource://gre/modules/Webapps.jsm", Webapps);
let appRegistry = SpecialPowers.wrap(Webapps.DOMApplicationRegistry);
let originalAllAppsLaunchable = appRegistry.allAppsLaunchable;
appRegistry.allAppsLaunchable = true;
window.addEventListener("unload", function cleanup(event) {
if (event.target == document) {
window.removeEventListener("unload", cleanup, false);
SpecialPowers.removePermission("browser", location.href);
SpecialPowers.removePermission("browser",
location.protocol + "//" + appDomain);
SpecialPowers.removePermission("embed-apps", location.href);
appRegistry.allAppsLaunchable = originalAllAppsLaunchable;
}
}, false);
SpecialPowers.pushPrefEnv({
"set": [["dom.mozBrowserFramesEnabled", true]]
}, runTest);
}
</script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>
<body onload="start();"></body>
</html>

View File

@ -0,0 +1,126 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>Indexed Database Clear Browser Data Test</title>
<script type="text/javascript;version=1.7">
"use strict";
function ok(cond, message)
{
alert(JSON.stringify({ type: "ok",
args: [!!cond, "appFrame: " + message] }));
}
function info(message)
{
alert(JSON.stringify({ type: "info",
args: ["appFrame: " + message] }));
}
function finish()
{
alert(JSON.stringify({ type: "done" }));
}
window.onerror = ok.bind(window, false);
function testSteps()
{
const objectStoreName = "foo";
const testKey = 1;
const testValue = objectStoreName;
let request = indexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = unexpectedSuccessHandler;
let event = yield;
let db = event.target.result;
db.onerror = errorHandler;
db.onversionchange = function(event) {
event.target.close();
}
let objectStore = db.createObjectStore(objectStoreName);
objectStore.add(testValue, testKey);
request.onsuccess = grabEventAndContinueHandler;
event = yield;
ok(db === event.target.result, "created database");
objectStore =
db.transaction(objectStoreName).objectStore(objectStoreName);
objectStore.get(testKey).onsuccess = grabEventAndContinueHandler;
event = yield;
ok(testValue == event.target.result, "data exists");
let iframe = document.createElement("iframe");
iframe.setAttribute("mozbrowser", "");
iframe.setAttribute("src", "webapp_clearBrowserData_browserFrame.html");
iframe.addEventListener("mozbrowsershowmodalprompt", function(event) {
let message = JSON.parse(event.detail.message);
switch (message.type) {
case "block":
info("blocking browserFrame");
event.preventDefault();
let request = navigator.mozApps.getSelf();
request.onsuccess = function() {
let app = request.result;
ok(app, "got app");
info("clearing browser data");
app.clearBrowserData();
info("unblocking browserFrame");
event.detail.unblock();
}
break;
case "done":
continueToNextStepSync();
break;
default:
alert(event.detail.message);
}
});
info("loading browser frame");
document.body.appendChild(iframe);
yield;
request = indexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onupgradeneeded = unexpectedSuccessHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
db = event.target.result;
db.onerror = errorHandler;
objectStore =
db.transaction(objectStoreName).objectStore(objectStoreName);
objectStore.get(testKey).onsuccess = grabEventAndContinueHandler;
event = yield;
ok(testValue == event.target.result, "data still exists");
finish();
yield;
}
</script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>
<body onload="testGenerator.next();"></body>
</html>

View File

@ -0,0 +1,103 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>Indexed Database Clear Browser Data Test</title>
<script type="text/javascript;version=1.7">
"use strict";
function ok(cond, message)
{
alert(JSON.stringify({ type: "ok",
args: [!!cond, "browserFrame: " + message] }));
}
function info(message)
{
alert(JSON.stringify({ type: "info",
args: ["browserFrame: " + message] }));
}
function block()
{
info("about to block");
// This will block until the parent has cleared our database.
alert(JSON.stringify({ type: "block" }));
info("unblocked");
}
function finish()
{
alert(JSON.stringify({ type: "done" }));
}
window.onerror = ok.bind(window, false);
function testSteps()
{
const objectStoreName = "foo";
const testKey = 1;
const testValue = objectStoreName;
let request = indexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = unexpectedSuccessHandler;
let event = yield;
let db = event.target.result;
db.onerror = errorHandler;
db.onversionchange = function(event) {
event.target.close();
}
let objectStore = db.createObjectStore(objectStoreName);
objectStore.add(testValue, testKey);
request.onsuccess = grabEventAndContinueHandler;
event = yield;
ok(db === event.target.result, "created database");
objectStore =
db.transaction(objectStoreName).objectStore(objectStoreName);
objectStore.get(testKey).onsuccess = grabEventAndContinueHandler;
event = yield;
ok(testValue == event.target.result, "data exists");
block();
request = indexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = unexpectedSuccessHandler;
event = yield;
ok(event.type == "upgradeneeded", "db doesn't exist");
request.onsuccess = grabEventAndContinueHandler;
event = yield;
db = event.target.result;
info(db.objectStoreNames.length);
ok(!db.objectStoreNames.length, "no object stores");
finish();
yield;
}
</script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>
<body onload="testGenerator.next();"></body>
</html>

View File

@ -13,3 +13,7 @@ interface mozIApplicationClearPrivateDataParams : nsISupports
readonly attribute unsigned long appId;
readonly attribute boolean browserOnly;
};
%{C++
#define TOPIC_WEB_APP_CLEAR_DATA "webapps-clear-data"
%}

View File

@ -57,7 +57,6 @@ XPIDLSRCS = \
nsIDOMCustomEvent.idl \
nsIDOMCompositionEvent.idl \
nsIDOMWheelEvent.idl \
nsIWifiEventInits.idl \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -329,9 +329,5 @@ NS_NewDOMSmsEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext,
nsresult
NS_NewDOMMozSettingsEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);
nsresult
NS_NewDOMMozWifiStatusChangeEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);
nsresult
NS_NewDOMMozWifiConnectionInfoEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);
nsresult
NS_NewDOMMozApplicationEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent);
%}

View File

@ -1,24 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
#include "nsIDOMEventTarget.idl"
#include "nsIDOMEvent.idl"
interface nsIVariant;
dictionary MozWifiStatusChangeEventInit : EventInit
{
nsIVariant network;
DOMString status;
};
dictionary MozWifiConnectionInfoEventInit : EventInit
{
nsIVariant network;
short signalStrength;
short relSignalStrength;
long linkSpeed;
DOMString ipAddress;
};

View File

@ -884,6 +884,23 @@ TabParent::RecvPIndexedDBConstructor(PIndexedDBParent* aActor,
NS_RUNTIMEABORT("Not supported yet!");
}
nsresult rv;
// XXXbent Need to make sure we have a whitelist for chrome databases!
// Verify the appID in the origin first.
if (mApp && !aASCIIOrigin.EqualsLiteral("chrome")) {
uint32_t appId;
rv = mApp->GetLocalId(&appId);
NS_ENSURE_SUCCESS(rv, false);
if (!IndexedDatabaseManager::OriginMatchesApp(aASCIIOrigin, appId)) {
NS_WARNING("App attempted to open databases that it does not have "
"permission to access!");
return false;
}
}
nsCOMPtr<nsINode> node = do_QueryInterface(GetOwnerElement());
NS_ENSURE_TRUE(node, false);
@ -897,9 +914,8 @@ TabParent::RecvPIndexedDBConstructor(PIndexedDBParent* aActor,
NS_ASSERTION(contentParent, "Null manager?!");
nsRefPtr<IDBFactory> factory;
nsresult rv =
IDBFactory::Create(window, aASCIIOrigin, contentParent,
getter_AddRefs(factory));
rv = IDBFactory::Create(window, aASCIIOrigin, contentParent,
getter_AddRefs(factory));
NS_ENSURE_SUCCESS(rv, false);
if (!factory) {

View File

@ -0,0 +1,29 @@
<!DOCTYPE HTML>
<html class="reftest-wait">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=791330
-->
<head>
<meta charset="utf-8">
<title>PeerConnection test - operate on closed connection</title>
<script type="application/javascript">
function finish() {
document.documentElement.removeAttribute("class");
}
function runTest() {
var pc = mozRTCPeerConnection();
pc.close();
navigator.mozGetUserMedia({audio: true, fake: true}, function (stream) {
pc.addStream(stream);
pc.createOffer(function (offer) {
}, finish);
}, function () {});
}
</script>
</head>
<body onload="setTimeout(runTest, 100)">
</body>
</html>

View File

@ -1,3 +1,4 @@
pref(media.peerconnection.enabled,true) load 780790.html
pref(media.peerconnection.enabled,true) load 791270.html
pref(media.peerconnection.enabled,true) load 791278.html
pref(media.peerconnection.enabled,true) load 791330.html

View File

@ -5,7 +5,7 @@
"use strict";
function debug(aMsg) {
// dump("-*- PermissionSettings.js: " + aMsg + "\n");
//dump("-*- PermissionSettings.js: " + aMsg + "\n");
}
const Cc = Components.classes;
@ -28,9 +28,20 @@ function PermissionSettings()
debug("Constructor");
}
var permissionManager = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
var secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
var appsService = Cc["@mozilla.org/AppsService;1"].getService(Ci.nsIAppsService);
XPCOMUtils.defineLazyServiceGetter(this,
"permissionManager",
"@mozilla.org/permissionmanager;1",
"nsIPermissionManager");
XPCOMUtils.defineLazyServiceGetter(this,
"secMan",
"@mozilla.org/scriptsecuritymanager;1",
"nsIScriptSecurityManager");
XPCOMUtils.defineLazyServiceGetter(this,
"appsService",
"@mozilla.org/AppsService;1",
"nsIAppsService");
PermissionSettings.prototype = {
get: function get(aPermission, aManifestURL, aOrigin, aBrowserFlag) {

View File

@ -4,11 +4,9 @@
"use strict";
let DEBUG = 0;
if (DEBUG)
debug = function (s) { dump("-*- PermissionSettings Module: " + s + "\n"); }
else
debug = function (s) {}
function debug(s) {
//dump("-*- PermissionSettings Module: " + s + "\n");
}
const Cu = Components.utils;
const Cc = Components.classes;
@ -23,9 +21,20 @@ XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
"@mozilla.org/parentprocessmessagemanager;1",
"nsIMessageListenerManager");
var permissionManager = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
var secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
var appsService = Cc["@mozilla.org/AppsService;1"].getService(Ci.nsIAppsService);
XPCOMUtils.defineLazyServiceGetter(this,
"permissionManager",
"@mozilla.org/permissionmanager;1",
"nsIPermissionManager");
XPCOMUtils.defineLazyServiceGetter(this,
"secMan",
"@mozilla.org/scriptsecuritymanager;1",
"nsIScriptSecurityManager");
XPCOMUtils.defineLazyServiceGetter(this,
"appsService",
"@mozilla.org/AppsService;1",
"nsIAppsService");
let PermissionSettingsModule = {
init: function() {
@ -62,6 +71,29 @@ let PermissionSettingsModule = {
permissionManager.addFromPrincipal(principal, aData.type, action);
},
getPermission: function getPermission(aPermission, aManifestURL, aOrigin, aBrowserFlag) {
debug("getPermission: " + aPermission + ", " + aManifestURL + ", " + aOrigin);
let uri = Services.io.newURI(aOrigin, null, null);
let appID = appsService.getAppLocalIdByManifestURL(aManifestURL);
let principal = secMan.getAppCodebasePrincipal(uri, appID, aBrowserFlag);
let result = permissionManager.testExactPermissionFromPrincipal(principal, aPermission);
switch (result)
{
case Ci.nsIPermissionManager.UNKNOWN_ACTION:
return "unknown";
case Ci.nsIPermissionManager.ALLOW_ACTION:
return "allow";
case Ci.nsIPermissionManager.DENY_ACTION:
return "deny";
case Ci.nsIPermissionManager.PROMPT_ACTION:
return "prompt";
default:
dump("Unsupported PermissionSettings Action!\n");
return "unknown";
}
},
observe: function(aSubject, aTopic, aData) {
ppmm.removeMessageListener("PermissionSettings:AddPermission", this);
Services.obs.removeObserver(this, "profile-before-change");

View File

@ -331,7 +331,7 @@ nsDOMStorageManager::Observe(nsISupports *aSubject,
rv = params->GetBrowserOnly(&browserOnly);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(appId != nsIScriptSecurityManager::NO_APP_ID);
MOZ_ASSERT(appId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
return DOMStorageImpl::gStorageDB->RemoveAllForApp(appId, browserOnly);
}

View File

@ -21,6 +21,7 @@
#include "mozIStorageFunction.h"
#include "nsNetUtil.h"
#include "mozilla/Attributes.h"
#include "mozilla/Telemetry.h"
#include "sampler.h"
@ -226,6 +227,8 @@ nsDOMStoragePersistentDB::EnsureLoadTemporaryTableForStorage(DOMStorageImpl* aSt
if (!mTempTableLoads.Get(aStorage->GetScopeDBKey(), &timeStamp)) {
nsresult rv;
Telemetry::AutoTimer<Telemetry::LOCALDOMSTORAGE_FETCH_DOMAIN_MS> timer;
rv = MaybeCommitInsertTransaction();
NS_ENSURE_SUCCESS(rv, rv);
@ -307,8 +310,23 @@ nsDOMStoragePersistentDB::FlushTemporaryTable(nsCStringHashKey::KeyType aKey,
nsresult
nsDOMStoragePersistentDB::FlushTemporaryTables(bool force)
{
mozStorageTransaction trans(mConnection, false);
nsCOMPtr<mozIStorageStatement> stmt =
mStatements.GetCachedStatement(
"SELECT COUNT(*) FROM webappsstore2_temp WHERE modified = 1"
);
mozStorageStatementScoper scope(stmt);
TimeStamp startTime;
bool exists;
int32_t dirtyCount;
if (stmt &&
NS_SUCCEEDED(stmt->ExecuteStep(&exists)) && exists &&
NS_SUCCEEDED(stmt->GetInt32(0, &dirtyCount)) && dirtyCount > 0) {
// Time the operation if dirty entries will be flushed
startTime = TimeStamp::Now();
}
mozStorageTransaction trans(mConnection, false);
nsresult rv;
FlushTemporaryTableData data;
@ -325,6 +343,10 @@ nsDOMStoragePersistentDB::FlushTemporaryTables(bool force)
rv = MaybeCommitInsertTransaction();
NS_ENSURE_SUCCESS(rv, rv);
if (!startTime.IsNull()) {
Telemetry::AutoTimer<Telemetry::LOCALDOMSTORAGE_TIMER_FLUSH_MS> timer(startTime);
}
return NS_OK;
}
@ -332,6 +354,7 @@ nsresult
nsDOMStoragePersistentDB::GetAllKeys(DOMStorageImpl* aStorage,
nsTHashtable<nsSessionStorageEntry>* aKeys)
{
Telemetry::AutoTimer<Telemetry::LOCALDOMSTORAGE_GETALLKEYS_MS> timer;
nsresult rv;
rv = MaybeCommitInsertTransaction();
@ -384,6 +407,7 @@ nsDOMStoragePersistentDB::GetKeyValue(DOMStorageImpl* aStorage,
nsAString& aValue,
bool* aSecure)
{
Telemetry::AutoTimer<Telemetry::LOCALDOMSTORAGE_GETVALUE_MS> timer;
SAMPLE_LABEL("nsDOMStoragePersistentDB", "GetKeyValue");
nsresult rv;
@ -435,6 +459,8 @@ nsDOMStoragePersistentDB::SetKey(DOMStorageImpl* aStorage,
const nsAString& aValue,
bool aSecure)
{
Telemetry::AutoTimer<Telemetry::LOCALDOMSTORAGE_SETVALUE_MS> timer;
nsresult rv;
rv = EnsureLoadTemporaryTableForStorage(aStorage);
@ -541,6 +567,7 @@ nsresult
nsDOMStoragePersistentDB::RemoveKey(DOMStorageImpl* aStorage,
const nsAString& aKey)
{
Telemetry::AutoTimer<Telemetry::LOCALDOMSTORAGE_REMOVEKEY_MS> timer;
nsresult rv;
rv = MaybeCommitInsertTransaction();
@ -645,6 +672,7 @@ nsDOMStoragePersistentDB::RemoveOwner(const nsACString& aOwner)
nsresult
nsDOMStoragePersistentDB::RemoveAll()
{
Telemetry::AutoTimer<Telemetry::LOCALDOMSTORAGE_REMOVEALL_MS> timer;
nsresult rv;
rv = MaybeCommitInsertTransaction();
@ -726,6 +754,8 @@ nsDOMStoragePersistentDB::GetUsageInternal(const nsACString& aQuotaDBKey,
return NS_OK;
}
Telemetry::AutoTimer<Telemetry::LOCALDOMSTORAGE_FETCH_QUOTA_USE_MS> timer;
nsresult rv;
rv = MaybeCommitInsertTransaction();

View File

@ -40,6 +40,7 @@ const kSmsSentObserverTopic = "sms-sent";
const kSmsDeliveredObserverTopic = "sms-delivered";
const kMozSettingsChangedObserverTopic = "mozsettings-changed";
const kSysMsgListenerReadyObserverTopic = "system-message-listener-ready";
const kSysClockChangeObserverTopic = "system-clock-change";
const kTimeNitzAutomaticUpdateEnabled = "time.nitz.automatic-update.enabled";
const DOM_SMS_DELIVERY_RECEIVED = "received";
const DOM_SMS_DELIVERY_SENT = "sent";
@ -274,6 +275,7 @@ function RadioInterfaceLayer() {
Services.obs.addObserver(this, "xpcom-shutdown", false);
Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false);
Services.obs.addObserver(this, kSysMsgListenerReadyObserverTopic, false);
Services.obs.addObserver(this, kSysClockChangeObserverTopic, false);
this._sentSmsEnvelopes = {};
@ -1366,12 +1368,9 @@ RadioInterfaceLayer.prototype = {
},
/**
* Handle the NITZ message.
* Set the NITZ message in our system time.
*/
handleNitzTime: function handleNitzTime(message) {
if (!this._nitzAutomaticUpdateEnabled) {
return;
}
setNitzTime: function setNitzTime(message) {
// To set the system clock time. Note that there could be a time diff
// between when the NITZ was received and when the time is actually set.
gTimeService.set(
@ -1394,6 +1393,19 @@ RadioInterfaceLayer.prototype = {
}
},
/**
* Handle the NITZ message.
*/
handleNitzTime: function handleNitzTime(message) {
// Cache the latest NITZ message whenever receiving it.
this._lastNitzMessage = message;
// Set the received NITZ time if the setting is enabled.
if (this._nitzAutomaticUpdateEnabled) {
this.setNitzTime(message);
}
},
handleICCInfoChange: function handleICCInfoChange(message) {
let oldIcc = this.rilContext.icc;
this.rilContext.icc = message;
@ -1418,7 +1430,7 @@ RadioInterfaceLayer.prototype = {
handleUSSDReceived: function handleUSSDReceived(ussd) {
debug("handleUSSDReceived " + JSON.stringify(ussd));
this._sendMobileConnectionMessage("RIL:UssdReceived", ussd);
this._sendMobileConnectionMessage("RIL:USSDReceived", ussd);
},
handleSendMMI: function handleSendMMI(message) {
@ -1472,6 +1484,12 @@ RadioInterfaceLayer.prototype = {
ppmm = null;
Services.obs.removeObserver(this, "xpcom-shutdown");
Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic);
Services.obs.removeObserver(this, kSysClockChangeObserverTopic);
break;
case kSysClockChangeObserverTopic:
if (this._lastNitzMessage) {
this._lastNitzMessage.receiveTimeInMS += parseInt(data, 10);
}
break;
}
},
@ -1504,6 +1522,10 @@ RadioInterfaceLayer.prototype = {
// 'time.nitz.automatic-update.enabled' setting from the UI.
_nitzAutomaticUpdateEnabled: null,
// Remember the last NITZ message so that we can set the time based on
// the network immediately when users enable network-based time.
_lastNitzMessage: null,
// nsISettingsServiceCallback
handle: function handle(aName, aResult) {
switch(aName) {
@ -1559,6 +1581,11 @@ RadioInterfaceLayer.prototype = {
break;
case kTimeNitzAutomaticUpdateEnabled:
this._nitzAutomaticUpdateEnabled = aResult;
// Set the latest cached NITZ time if the setting is enabled.
if (this._nitzAutomaticUpdateEnabled && this._lastNitzMessage) {
this.setNitzTime(this._lastNitzMessage);
}
break;
};
},

View File

@ -16,24 +16,20 @@ namespace mozilla {
namespace dom {
namespace time {
class DateCacheCleaner : public SystemTimeChangeObserver
class DateCacheCleaner : public SystemTimezoneChangeObserver
{
public:
DateCacheCleaner()
{
RegisterSystemTimeChangeObserver(this);
RegisterSystemTimezoneChangeObserver(this);
}
~DateCacheCleaner()
{
UnregisterSystemTimeChangeObserver(this);
UnregisterSystemTimezoneChangeObserver(this);
}
void Notify(const SystemTimeChange& aReason)
void Notify(const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
{
if (aReason == SYS_TIME_CHANGE_CLOCK) {
return;
}
nsCOMPtr<nsIThreadJSContextStack> stack =
do_GetService("@mozilla.org/js/xpc/ContextStack;1");
if (!stack) {

View File

@ -9,9 +9,11 @@
#include "nsPIDOMWindow.h"
#include "nsDOMEvent.h"
#include "nsContentUtils.h"
#include "nsIObserverService.h"
using namespace mozilla::hal;
using namespace mozilla;
using namespace mozilla::hal;
using namespace mozilla::services;
StaticAutoPtr<nsSystemTimeChangeObserver> sObserver;
@ -27,11 +29,12 @@ nsSystemTimeChangeObserver* nsSystemTimeChangeObserver::GetInstance()
nsSystemTimeChangeObserver::~nsSystemTimeChangeObserver()
{
mWindowListeners.Clear();
UnregisterSystemTimeChangeObserver(this);
UnregisterSystemClockChangeObserver(this);
UnregisterSystemTimezoneChangeObserver(this);
}
void
nsSystemTimeChangeObserver::Notify(const SystemTimeChange& aReason)
nsSystemTimeChangeObserver::FireMozTimeChangeEvent()
{
//Copy mWindowListeners and iterate over windowListeners instead because
//mWindowListeners may be modified while we loop.
@ -58,6 +61,28 @@ nsSystemTimeChangeObserver::Notify(const SystemTimeChange& aReason)
}
}
void
nsSystemTimeChangeObserver::Notify(const int64_t& aClockDeltaMS)
{
// Notify observers that the system clock has been adjusted.
nsCOMPtr<nsIObserverService> observerService = GetObserverService();
if (observerService) {
nsString dataStr;
dataStr.AppendFloat(static_cast<double>(aClockDeltaMS));
observerService->NotifyObservers(
nullptr, "system-clock-change", dataStr.get());
}
FireMozTimeChangeEvent();
}
void
nsSystemTimeChangeObserver::Notify(
const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
{
FireMozTimeChangeEvent();
}
nsresult
nsSystemTimeChangeObserver::AddWindowListener(nsIDOMWindow* aWindow)
{
@ -80,7 +105,8 @@ nsSystemTimeChangeObserver::AddWindowListenerImpl(nsIDOMWindow* aWindow)
}
if (mWindowListeners.Length() == 0) {
RegisterSystemTimeChangeObserver(sObserver);
RegisterSystemClockChangeObserver(sObserver);
RegisterSystemTimezoneChangeObserver(sObserver);
}
mWindowListeners.AppendElement(windowWeakRef);
@ -103,7 +129,8 @@ nsSystemTimeChangeObserver::RemoveWindowListenerImpl(nsIDOMWindow* aWindow)
mWindowListeners.RemoveElement(NS_GetWeakReference(aWindow));
if (mWindowListeners.Length() == 0) {
UnregisterSystemTimeChangeObserver(sObserver);
UnregisterSystemClockChangeObserver(sObserver);
UnregisterSystemTimezoneChangeObserver(sObserver);
}
return NS_OK;

View File

@ -12,14 +12,23 @@
#include "nsPIDOMWindow.h"
#include "nsWeakPtr.h"
typedef mozilla::Observer<mozilla::hal::SystemTimeChange> SystemTimeChangeObserver;
typedef mozilla::Observer<int64_t> SystemClockChangeObserver;
typedef mozilla::Observer<mozilla::hal::SystemTimezoneChangeInformation> SystemTimezoneChangeObserver;
class nsSystemTimeChangeObserver : public SystemTimeChangeObserver
class nsSystemTimeChangeObserver : public SystemClockChangeObserver,
public SystemTimezoneChangeObserver
{
public:
static nsSystemTimeChangeObserver* GetInstance();
virtual ~nsSystemTimeChangeObserver();
void Notify(const mozilla::hal::SystemTimeChange& aReason);
// Implementing hal::SystemClockChangeObserver::Notify()
void Notify(const int64_t& aClockDeltaMS);
// Implementing hal::SystemTimezoneChangeObserver::Notify()
void Notify(
const mozilla::hal::SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo);
static nsresult AddWindowListener(nsIDOMWindow* aWindow);
static nsresult RemoveWindowListener(nsIDOMWindow* aWindow);
private:
@ -27,6 +36,7 @@ private:
nsresult RemoveWindowListenerImpl(nsIDOMWindow* aWindow);
nsSystemTimeChangeObserver() { };
nsTArray<nsWeakPtr> mWindowListeners;
void FireMozTimeChangeEvent();
};
#endif //_mozilla_time_change_observer_h_

View File

@ -19,6 +19,8 @@ include $(topsrcdir)/dom/dom-config.mk
XPIDLSRCS = \
nsIWifi.idl \
nsIDOMMozWifiStatusChangeEvent.idl \
nsIDOMMozWifiConnectionInfoEvent.idl \
$(NULL)
EXTRA_COMPONENTS = \

View File

@ -0,0 +1,55 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIDOMEvent.idl"
interface nsIVariant;
[scriptable, builtinclass, uuid(1717f9d9-5fd8-43d8-a098-55924c6d37de)]
interface nsIDOMMozWifiConnectionInfoEvent : nsIDOMEvent
{
/**
* Network object with an SSID field.
*/
readonly attribute nsIVariant network;
/**
* Strength of the signal to network, in dBm between -55 and -100 dBm.
*/
readonly attribute short signalStrength;
/**
* Relative signal strength between 0 and 100.
*/
readonly attribute short relSignalStrength;
/**
* Link speed in Mb/s.
*/
readonly attribute long linkSpeed;
/**
* IP address in the dotted quad format.
*/
readonly attribute DOMString ipAddress;
[noscript] void initMozWifiConnectionInfoEvent(in DOMString aType,
in boolean aCanBubble,
in boolean aCancelable,
in nsIVariant aNetwork,
in short signalStrength,
in short relSignalStrength,
in long linkSpeed,
in DOMString ipAddress);
};
dictionary MozWifiConnectionInfoEventInit : EventInit
{
nsIVariant network;
short signalStrength;
short relSignalStrength;
long linkSpeed;
DOMString ipAddress;
};

View File

@ -0,0 +1,35 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIDOMEvent.idl"
interface nsIVariant;
[scriptable, builtinclass, uuid(f3ef70b0-b2d3-4eb5-8ea4-008f8d330cd6)]
interface nsIDOMMozWifiStatusChangeEvent : nsIDOMEvent
{
/**
* Network object with a SSID field describing the network affected by
* this change. This might be null.
*/
readonly attribute nsIVariant network;
/**
* String describing the current status of the wifi manager. See above for
* the possible values.
*/
readonly attribute DOMString status;
[noscript] void initMozWifiStatusChangeEvent(in DOMString aType,
in boolean aCanBubble,
in boolean aCancelable,
in nsIVariant aNetwork,
in DOMString aStatus);
};
dictionary MozWifiStatusChangeEventInit : EventInit
{
nsIVariant network;
DOMString status;
};

View File

@ -186,63 +186,3 @@ interface nsIDOMWifiManager : nsISupports
attribute nsIDOMEventListener onenabled;
attribute nsIDOMEventListener ondisabled;
};
[scriptable, builtinclass, uuid(f3ef70b0-b2d3-4eb5-8ea4-008f8d330cd6)]
interface nsIDOMMozWifiStatusChangeEvent : nsIDOMEvent
{
/**
* Network object with a SSID field describing the network affected by
* this change. This might be null.
*/
readonly attribute nsIVariant network;
/**
* String describing the current status of the wifi manager. See above for
* the possible values.
*/
readonly attribute DOMString status;
[noscript] void initMozWifiStatusChangeEvent(in DOMString aType,
in boolean aCanBubble,
in boolean aCancelable,
in nsIVariant aNetwork,
in DOMString status);
};
[scriptable, builtinclass, uuid(1717f9d9-5fd8-43d8-a098-55924c6d37de)]
interface nsIDOMMozWifiConnectionInfoEvent : nsIDOMEvent
{
/**
* Network object with an SSID field.
*/
readonly attribute nsIVariant network;
/**
* Strength of the signal to network, in dBm between -55 and -100 dBm.
*/
readonly attribute short signalStrength;
/**
* Relative signal strength between 0 and 100.
*/
readonly attribute short relSignalStrength;
/**
* Link speed in Mb/s.
*/
readonly attribute long linkSpeed;
/**
* IP address in the dotted quad format.
*/
readonly attribute DOMString ipAddress;
[noscript] void initMozWifiConnectionInfoEvent(in DOMString aType,
in boolean aCanBubble,
in boolean aCancelable,
in nsIVariant aNetwork,
in short signalStrength,
in short relSignalStrength,
in long linkSpeed,
in DOMString ipAddress);
};

View File

@ -701,9 +701,7 @@ DrawTargetCG::FillGlyphs(ScaledFont *aFont, const GlyphBuffer &aBuffer, const Pa
CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform));
ScaledFontMac* cgFont = static_cast<ScaledFontMac*>(aFont);
CGContextSetFont(cg, cgFont->mFont);
CGContextSetFontSize(cg, cgFont->mSize);
ScaledFontMac* macFont = static_cast<ScaledFontMac*>(aFont);
//XXX: we should use a stack vector here when we have a class like that
std::vector<CGGlyph> glyphs;
@ -729,14 +727,32 @@ DrawTargetCG::FillGlyphs(ScaledFont *aFont, const GlyphBuffer &aBuffer, const Pa
//XXX: CGContextShowGlyphsAtPositions is 10.5+ for older versions use CGContextShowGlyphsWithAdvances
if (isGradient(aPattern)) {
CGContextSetTextDrawingMode(cg, kCGTextClip);
CGContextShowGlyphsAtPositions(cg, &glyphs.front(), &positions.front(), aBuffer.mNumGlyphs);
if (ScaledFontMac::CTFontDrawGlyphsPtr != nullptr) {
ScaledFontMac::CTFontDrawGlyphsPtr(macFont->mCTFont, &glyphs.front(),
&positions.front(),
aBuffer.mNumGlyphs, cg);
} else {
CGContextSetFont(cg, macFont->mFont);
CGContextSetFontSize(cg, macFont->mSize);
CGContextShowGlyphsAtPositions(cg, &glyphs.front(), &positions.front(),
aBuffer.mNumGlyphs);
}
DrawGradient(cg, aPattern);
} else {
//XXX: with CoreGraphics we can stroke text directly instead of going
// through GetPath. It would be nice to add support for using that
CGContextSetTextDrawingMode(cg, kCGTextFill);
SetFillFromPattern(cg, mColorSpace, aPattern);
CGContextShowGlyphsAtPositions(cg, &glyphs.front(), &positions.front(), aBuffer.mNumGlyphs);
if (ScaledFontMac::CTFontDrawGlyphsPtr != nullptr) {
ScaledFontMac::CTFontDrawGlyphsPtr(macFont->mCTFont, &glyphs.front(),
&positions.front(),
aBuffer.mNumGlyphs, cg);
} else {
CGContextSetFont(cg, macFont->mFont);
CGContextSetFontSize(cg, macFont->mSize);
CGContextShowGlyphsAtPositions(cg, &glyphs.front(), &positions.front(),
aBuffer.mNumGlyphs);
}
}
fixer.Fix(mCg);

View File

@ -12,6 +12,7 @@
#endif
#include "DrawTargetCG.h"
#include <vector>
#include <dlfcn.h>
// prototype for private API
extern "C" {
@ -22,15 +23,33 @@ CGPathRef CGFontGetGlyphPath(CGFontRef fontRef, CGAffineTransform *textTransform
namespace mozilla {
namespace gfx {
ScaledFontMac::CTFontDrawGlyphsFuncT* ScaledFontMac::CTFontDrawGlyphsPtr = nullptr;
bool ScaledFontMac::sSymbolLookupDone = false;
ScaledFontMac::ScaledFontMac(CGFontRef aFont, Float aSize)
: ScaledFontBase(aSize)
{
if (!sSymbolLookupDone) {
CTFontDrawGlyphsPtr =
(CTFontDrawGlyphsFuncT*)dlsym(RTLD_DEFAULT, "CTFontDrawGlyphs");
sSymbolLookupDone = true;
}
// XXX: should we be taking a reference
mFont = CGFontRetain(aFont);
if (CTFontDrawGlyphsPtr != nullptr) {
// only create mCTFont if we're going to be using the CTFontDrawGlyphs API
mCTFont = CTFontCreateWithGraphicsFont(aFont, aSize, nullptr, nullptr);
} else {
mCTFont = nullptr;
}
}
ScaledFontMac::~ScaledFontMac()
{
if (mCTFont) {
CFRelease(mCTFont);
}
CGFontRelease(mFont);
}
@ -38,9 +57,13 @@ ScaledFontMac::~ScaledFontMac()
SkTypeface* ScaledFontMac::GetSkTypeface()
{
if (!mTypeface) {
CTFontRef fontFace = CTFontCreateWithGraphicsFont(mFont, mSize, nullptr, nullptr);
mTypeface = SkCreateTypefaceFromCTFont(fontFace);
CFRelease(fontFace);
if (mCTFont) {
mTypeface = SkCreateTypefaceFromCTFont(mCTFont);
} else {
CTFontRef fontFace = CTFontCreateWithGraphicsFont(mFont, mSize, nullptr, nullptr);
mTypeface = SkCreateTypefaceFromCTFont(fontFace);
CFRelease(fontFace);
}
}
return mTypeface;
}

View File

@ -25,9 +25,23 @@ public:
virtual SkTypeface* GetSkTypeface();
#endif
virtual TemporaryRef<Path> GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget);
private:
friend class DrawTargetCG;
CGFontRef mFont;
CTFontRef mCTFont; // only created if CTFontDrawGlyphs is available, otherwise null
typedef void (CTFontDrawGlyphsFuncT)(CTFontRef,
const CGGlyph[], const CGPoint[],
size_t, CGContextRef);
static bool sSymbolLookupDone;
public:
// function pointer for CTFontDrawGlyphs, if available;
// initialized the first time a ScaledFontMac is created,
// so it will be valid by the time DrawTargetCG wants to use it
static CTFontDrawGlyphsFuncT* CTFontDrawGlyphsPtr;
};
}

View File

@ -216,6 +216,10 @@ pixman-16-bit-pipeline.patch: 16 bit pipeline for dithering
pixman-dither.patch: Add dithering of 16 bit gradients
quartz-support-color-emoji-font.patch: support Apple Color Emoji font in cairo-quartz backend
use-show-text-glyphs-if-glyph-path-fails.patch: fall back to show_text_glyphs even at huge sizes if scaled_font_glyph_path didn't work
==== disable printing patch ====
disable-printing.patch: allows us to use NS_PRINTING to disable printing.

View File

@ -2007,13 +2007,24 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
transformed_glyphs, num_glyphs,
&path);
if (status == CAIRO_STATUS_SUCCESS) {
if (status == CAIRO_STATUS_SUCCESS && !_cairo_path_fixed_fill_is_empty (&path)) {
status = _cairo_surface_fill (gstate->target, op, pattern,
&path,
CAIRO_FILL_RULE_WINDING,
gstate->tolerance,
gstate->scaled_font->options.antialias,
_gstate_get_clip (gstate, &clip));
} else {
/* if _cairo_scaled_font_glyph_path() failed, maybe the font doesn't support
* returning paths, so try the _cairo_surface_show_text_glyphs() option
*/
status = _cairo_surface_show_text_glyphs (gstate->target, op, pattern,
utf8, utf8_len,
transformed_glyphs, num_glyphs,
transformed_clusters, num_clusters,
cluster_flags,
gstate->scaled_font,
_gstate_get_clip (gstate, &clip));
}
_cairo_path_fixed_fini (&path);

View File

@ -90,6 +90,10 @@ static int (*CGFontGetAscentPtr) (CGFontRef fontRef) = NULL;
static int (*CGFontGetDescentPtr) (CGFontRef fontRef) = NULL;
static int (*CGFontGetLeadingPtr) (CGFontRef fontRef) = NULL;
/* CTFontCreateWithGraphicsFont is not public until 10.5. */
typedef const struct __CTFontDescriptor *CTFontDescriptorRef;
static CTFontRef (*CTFontCreateWithGraphicsFontPtr) (CGFontRef, CGFloat, const CGAffineTransform *, CTFontDescriptorRef) = NULL;
static cairo_bool_t _cairo_quartz_font_symbol_lookup_done = FALSE;
static cairo_bool_t _cairo_quartz_font_symbols_present = FALSE;
@ -127,6 +131,8 @@ quartz_font_ensure_symbols(void)
CGContextGetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
CTFontCreateWithGraphicsFontPtr = dlsym(RTLD_DEFAULT, "CTFontCreateWithGraphicsFont");
if ((CGFontCreateWithFontNamePtr || CGFontCreateWithNamePtr) &&
CGFontGetGlyphBBoxesPtr &&
CGFontGetGlyphsForUnicharsPtr &&
@ -150,6 +156,7 @@ struct _cairo_quartz_font_face {
cairo_font_face_t base;
CGFontRef cgFont;
CTFontRef ctFont;
};
/*
@ -234,6 +241,10 @@ _cairo_quartz_font_face_destroy (void *abstract_face)
{
cairo_quartz_font_face_t *font_face = (cairo_quartz_font_face_t*) abstract_face;
if (font_face->ctFont) {
CFRelease (font_face->ctFont);
}
CGFontRelease (font_face->cgFont);
}
@ -358,6 +369,12 @@ cairo_quartz_font_face_create_for_cgfont (CGFontRef font)
font_face->cgFont = CGFontRetain (font);
if (CTFontCreateWithGraphicsFontPtr) {
font_face->ctFont = CTFontCreateWithGraphicsFontPtr (font, 1.0, NULL, NULL);
} else {
font_face->ctFont = NULL;
}
_cairo_font_face_init (&font_face->base, &_cairo_quartz_font_face_backend);
return &font_face->base;
@ -777,6 +794,14 @@ _cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *abstract_font)
return ffont->cgFont;
}
CTFontRef
_cairo_quartz_scaled_font_get_ct_font_ref (cairo_scaled_font_t *abstract_font)
{
cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(abstract_font);
return ffont->ctFont;
}
#ifndef __LP64__
/*
* compat with old ATSUI backend

View File

@ -50,6 +50,9 @@ typedef CGFloat cairo_quartz_float_t;
typedef float cairo_quartz_float_t;
#endif
/* define CTFontRef for pre-10.5 SDKs */
typedef const struct __CTFont *CTFontRef;
typedef struct cairo_quartz_surface {
cairo_surface_t base;
@ -104,6 +107,9 @@ _cairo_quartz_create_cgimage (cairo_format_t format,
CGFontRef
_cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *sfont);
CTFontRef
_cairo_quartz_scaled_font_get_ct_font_ref (cairo_scaled_font_t *sfont);
#else
# error Cairo was not compiled with support for the quartz backend

View File

@ -135,6 +135,9 @@ static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL;
static CGPathRef (*CGContextCopyPathPtr) (CGContextRef) = NULL;
static CGFloat (*CGContextGetAlphaPtr) (CGContextRef) = NULL;
/* CTFontDrawGlyphs is not available until 10.7 */
static void (*CTFontDrawGlyphsPtr) (CTFontRef, const CGGlyph[], const CGPoint[], size_t, CGContextRef) = NULL;
static SInt32 _cairo_quartz_osx_version = 0x0;
static cairo_bool_t _cairo_quartz_symbol_lookup_done = FALSE;
@ -172,6 +175,8 @@ static void quartz_ensure_symbols(void)
CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
CGContextGetAlphaPtr = dlsym(RTLD_DEFAULT, "CGContextGetAlpha");
CTFontDrawGlyphsPtr = dlsym(RTLD_DEFAULT, "CTFontDrawGlyphs");
if (Gestalt(gestaltSystemVersion, &_cairo_quartz_osx_version) != noErr) {
// assume 10.5
_cairo_quartz_osx_version = 0x1050;
@ -610,10 +615,13 @@ _cairo_quartz_cairo_matrix_to_quartz (const cairo_matrix_t *src,
typedef struct {
bool isClipping;
CGGlyph *cg_glyphs;
CGSize *cg_advances;
union {
CGSize *cg_advances;
CGPoint *cg_positions;
} u;
size_t nglyphs;
CGAffineTransform textTransform;
CGFontRef font;
cairo_scaled_font_t *scaled_font;
CGPoint origin;
} unbounded_show_glyphs_t;
@ -691,12 +699,6 @@ _cairo_quartz_fixup_unbounded_operation (cairo_quartz_surface_t *surface,
else
CGContextEOFillPath (cgc);
} else if (op->op == UNBOUNDED_SHOW_GLYPHS) {
CGContextSetFont (cgc, op->u.show_glyphs.font);
CGContextSetFontSize (cgc, 1.0);
CGContextSetTextMatrix (cgc, CGAffineTransformIdentity);
CGContextTranslateCTM (cgc, op->u.show_glyphs.origin.x, op->u.show_glyphs.origin.y);
CGContextConcatCTM (cgc, op->u.show_glyphs.textTransform);
if (op->u.show_glyphs.isClipping) {
/* Note that the comment in show_glyphs about kCGTextClip
* and the text transform still applies here; however, the
@ -705,12 +707,25 @@ _cairo_quartz_fixup_unbounded_operation (cairo_quartz_surface_t *surface,
CGContextSetTextDrawingMode (cgc, kCGTextClip);
CGContextSaveGState (cgc);
}
CGContextTranslateCTM (cgc, op->u.show_glyphs.origin.x, op->u.show_glyphs.origin.y);
CGContextConcatCTM (cgc, op->u.show_glyphs.textTransform);
if (CTFontDrawGlyphsPtr) {
CTFontDrawGlyphsPtr (_cairo_quartz_scaled_font_get_ct_font_ref (op->u.show_glyphs.scaled_font),
op->u.show_glyphs.cg_glyphs,
op->u.show_glyphs.u.cg_positions,
op->u.show_glyphs.nglyphs,
cgc);
} else {
CGContextSetFont (cgc, _cairo_quartz_scaled_font_get_cg_font_ref (op->u.show_glyphs.scaled_font));
CGContextSetFontSize (cgc, 1.0);
CGContextSetTextMatrix (cgc, CGAffineTransformIdentity);
CGContextShowGlyphsWithAdvances (cgc,
op->u.show_glyphs.cg_glyphs,
op->u.show_glyphs.cg_advances,
op->u.show_glyphs.nglyphs);
CGContextShowGlyphsWithAdvances (cgc,
op->u.show_glyphs.cg_glyphs,
op->u.show_glyphs.u.cg_advances,
op->u.show_glyphs.nglyphs);
}
if (op->u.show_glyphs.isClipping) {
CGContextClearRect (cgc, clipBoxRound);
CGContextRestoreGState (cgc);
@ -2689,6 +2704,9 @@ _cairo_quartz_surface_show_glyphs_cg (void *abstract_surface,
CGGlyph glyphs_static[STATIC_BUF_SIZE];
CGSize cg_advances_static[STATIC_BUF_SIZE];
CGGlyph *cg_glyphs = &glyphs_static[0];
/* We'll use the cg_advances array for either advances or positions,
depending which API we're using to actually draw. The types involved
have the same size, so this is safe. */
CGSize *cg_advances = &cg_advances_static[0];
cairo_rectangle_int_t glyph_extents;
@ -2801,31 +2819,52 @@ _cairo_quartz_surface_show_glyphs_cg (void *abstract_surface,
CGContextSetTextMatrix (state.context, CGAffineTransformIdentity);
/* Convert our glyph positions to glyph advances. We need n-1 advances,
* since the advance at index 0 is applied after glyph 0. */
xprev = glyphs[0].x;
yprev = glyphs[0].y;
cg_glyphs[0] = glyphs[0].index;
for (i = 1; i < num_glyphs; i++) {
cairo_quartz_float_t xf = glyphs[i].x;
cairo_quartz_float_t yf = glyphs[i].y;
cg_glyphs[i] = glyphs[i].index;
cg_advances[i - 1] = CGSizeApplyAffineTransform(CGSizeMake (xf - xprev, yf - yprev), invTextTransform);
xprev = xf;
yprev = yf;
}
/* Translate to the first glyph's position before drawing */
ctm = CGContextGetCTM (state.context);
CGContextTranslateCTM (state.context, glyphs[0].x, glyphs[0].y);
CGContextConcatCTM (state.context, textTransform);
CGContextShowGlyphsWithAdvances (state.context,
cg_glyphs,
cg_advances,
num_glyphs);
if (CTFontDrawGlyphsPtr) {
/* If CTFontDrawGlyphs is available (i.e. OS X 10.7 or later), we want to use
* that in preference to CGContextShowGlyphsWithAdvances so that colored-bitmap
* fonts like Apple Color Emoji will render properly.
* For this, we need to convert our glyph positions to Core Graphics's CGPoint.
* We borrow the cg_advances array, as CGPoint and CGSize are the same size. */
CGPoint *cg_positions = (CGPoint*) cg_advances;
cairo_quartz_float_t origin_x = glyphs[0].x;
cairo_quartz_float_t origin_y = glyphs[0].y;
for (i = 0; i < num_glyphs; i++) {
CGPoint pt = CGPointMake (glyphs[i].x - origin_x, glyphs[i].y - origin_y);
cg_positions[i] = CGPointApplyAffineTransform (pt, invTextTransform);
cg_glyphs[i] = glyphs[i].index;
}
CTFontDrawGlyphsPtr (_cairo_quartz_scaled_font_get_ct_font_ref (scaled_font),
cg_glyphs, cg_positions, num_glyphs, state.context);
} else {
/* Convert our glyph positions to glyph advances. We need n-1 advances,
* since the advance at index 0 is applied after glyph 0. */
xprev = glyphs[0].x;
yprev = glyphs[0].y;
cg_glyphs[0] = glyphs[0].index;
for (i = 1; i < num_glyphs; i++) {
cairo_quartz_float_t xf = glyphs[i].x;
cairo_quartz_float_t yf = glyphs[i].y;
cg_glyphs[i] = glyphs[i].index;
cg_advances[i - 1] = CGSizeApplyAffineTransform(CGSizeMake (xf - xprev, yf - yprev), invTextTransform);
xprev = xf;
yprev = yf;
}
CGContextShowGlyphsWithAdvances (state.context,
cg_glyphs,
cg_advances,
num_glyphs);
}
CGContextSetCTM (state.context, ctm);
@ -2852,10 +2891,17 @@ BAIL:
ub.u.show_glyphs.isClipping = isClipping;
ub.u.show_glyphs.cg_glyphs = cg_glyphs;
ub.u.show_glyphs.cg_advances = cg_advances;
if (CTFontDrawGlyphsPtr) {
/* we're using Core Text API: the cg_advances array was
reused (above) for glyph positions */
CGPoint *cg_positions = (CGPoint*) cg_advances;
ub.u.show_glyphs.u.cg_positions = cg_positions;
} else {
ub.u.show_glyphs.u.cg_advances = cg_advances;
}
ub.u.show_glyphs.nglyphs = num_glyphs;
ub.u.show_glyphs.textTransform = textTransform;
ub.u.show_glyphs.font = cgfref;
ub.u.show_glyphs.scaled_font = scaled_font;
ub.u.show_glyphs.origin = CGPointMake (glyphs[0].x, glyphs[0].y);
_cairo_quartz_fixup_unbounded_operation (surface, &ub, scaled_font->options.antialias);

View File

@ -0,0 +1,432 @@
From: Jonathan Kew <jkew@mozilla.com>
bug 715798 pt 1 - support Apple Color Emoji font in cairo-quartz backend. r=jrmuizel
diff --git a/gfx/cairo/cairo/src/cairo-quartz-font.c b/gfx/cairo/cairo/src/cairo-quartz-font.c
--- a/gfx/cairo/cairo/src/cairo-quartz-font.c
+++ b/gfx/cairo/cairo/src/cairo-quartz-font.c
@@ -85,16 +85,20 @@ typedef struct {
int descent;
int leading;
} quartz_CGFontMetrics;
static quartz_CGFontMetrics* (*CGFontGetHMetricsPtr) (CGFontRef fontRef) = NULL;
static int (*CGFontGetAscentPtr) (CGFontRef fontRef) = NULL;
static int (*CGFontGetDescentPtr) (CGFontRef fontRef) = NULL;
static int (*CGFontGetLeadingPtr) (CGFontRef fontRef) = NULL;
+/* CTFontCreateWithGraphicsFont is not public until 10.5. */
+typedef const struct __CTFontDescriptor *CTFontDescriptorRef;
+static CTFontRef (*CTFontCreateWithGraphicsFontPtr) (CGFontRef, CGFloat, const CGAffineTransform *, CTFontDescriptorRef) = NULL;
+
static cairo_bool_t _cairo_quartz_font_symbol_lookup_done = FALSE;
static cairo_bool_t _cairo_quartz_font_symbols_present = FALSE;
static void
quartz_font_ensure_symbols(void)
{
if (_cairo_quartz_font_symbol_lookup_done)
return;
@@ -122,16 +126,18 @@ quartz_font_ensure_symbols(void)
CGFontGetHMetricsPtr = dlsym(RTLD_DEFAULT, "CGFontGetHMetrics");
CGFontGetAscentPtr = dlsym(RTLD_DEFAULT, "CGFontGetAscent");
CGFontGetDescentPtr = dlsym(RTLD_DEFAULT, "CGFontGetDescent");
CGFontGetLeadingPtr = dlsym(RTLD_DEFAULT, "CGFontGetLeading");
CGContextGetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
+ CTFontCreateWithGraphicsFontPtr = dlsym(RTLD_DEFAULT, "CTFontCreateWithGraphicsFont");
+
if ((CGFontCreateWithFontNamePtr || CGFontCreateWithNamePtr) &&
CGFontGetGlyphBBoxesPtr &&
CGFontGetGlyphsForUnicharsPtr &&
CGFontGetUnitsPerEmPtr &&
CGFontGetGlyphAdvancesPtr &&
CGFontGetGlyphPathPtr &&
(CGFontGetHMetricsPtr || (CGFontGetAscentPtr && CGFontGetDescentPtr && CGFontGetLeadingPtr)))
_cairo_quartz_font_symbols_present = TRUE;
@@ -145,16 +151,17 @@ typedef struct _cairo_quartz_scaled_font
struct _cairo_quartz_scaled_font {
cairo_scaled_font_t base;
};
struct _cairo_quartz_font_face {
cairo_font_face_t base;
CGFontRef cgFont;
+ CTFontRef ctFont;
};
/*
* font face backend
*/
static cairo_status_t
_cairo_quartz_font_face_create_for_toy (cairo_toy_font_face_t *toy_face,
@@ -229,16 +236,20 @@ static cairo_status_t
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_quartz_font_face_destroy (void *abstract_face)
{
cairo_quartz_font_face_t *font_face = (cairo_quartz_font_face_t*) abstract_face;
+ if (font_face->ctFont) {
+ CFRelease (font_face->ctFont);
+ }
+
CGFontRelease (font_face->cgFont);
}
static const cairo_scaled_font_backend_t _cairo_quartz_scaled_font_backend;
static cairo_status_t
_cairo_quartz_font_face_scaled_font_create (void *abstract_face,
const cairo_matrix_t *font_matrix,
@@ -353,16 +364,22 @@ cairo_quartz_font_face_create_for_cgfont
if (!font_face) {
cairo_status_t ignore_status;
ignore_status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return (cairo_font_face_t *)&_cairo_font_face_nil;
}
font_face->cgFont = CGFontRetain (font);
+ if (CTFontCreateWithGraphicsFontPtr) {
+ font_face->ctFont = CTFontCreateWithGraphicsFontPtr (font, 1.0, NULL, NULL);
+ } else {
+ font_face->ctFont = NULL;
+ }
+
_cairo_font_face_init (&font_face->base, &_cairo_quartz_font_face_backend);
return &font_face->base;
}
/*
* scaled font backend
*/
@@ -772,16 +789,24 @@ static const cairo_scaled_font_backend_t
CGFontRef
_cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *abstract_font)
{
cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(abstract_font);
return ffont->cgFont;
}
+CTFontRef
+_cairo_quartz_scaled_font_get_ct_font_ref (cairo_scaled_font_t *abstract_font)
+{
+ cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(abstract_font);
+
+ return ffont->ctFont;
+}
+
#ifndef __LP64__
/*
* compat with old ATSUI backend
*/
/**
* cairo_quartz_font_face_create_for_atsu_font_id
* @font_id: an ATSUFontID for the font.
diff --git a/gfx/cairo/cairo/src/cairo-quartz-private.h b/gfx/cairo/cairo/src/cairo-quartz-private.h
--- a/gfx/cairo/cairo/src/cairo-quartz-private.h
+++ b/gfx/cairo/cairo/src/cairo-quartz-private.h
@@ -45,16 +45,19 @@
#include "cairo-surface-clipper-private.h"
#ifdef CGFLOAT_DEFINED
typedef CGFloat cairo_quartz_float_t;
#else
typedef float cairo_quartz_float_t;
#endif
+/* define CTFontRef for pre-10.5 SDKs */
+typedef const struct __CTFont *CTFontRef;
+
typedef struct cairo_quartz_surface {
cairo_surface_t base;
CGContextRef cgContext;
CGAffineTransform cgContextBaseCTM;
void *imageData;
cairo_surface_t *imageSurfaceEquiv;
@@ -99,15 +102,18 @@ CGImageRef
cairo_bool_t interpolate,
CGColorSpaceRef colorSpaceOverride,
CGDataProviderReleaseDataCallback releaseCallback,
void *releaseInfo);
CGFontRef
_cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *sfont);
+CTFontRef
+_cairo_quartz_scaled_font_get_ct_font_ref (cairo_scaled_font_t *sfont);
+
#else
# error Cairo was not compiled with support for the quartz backend
#endif /* CAIRO_HAS_QUARTZ_SURFACE */
#endif /* CAIRO_QUARTZ_PRIVATE_H */
diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c
--- a/gfx/cairo/cairo/src/cairo-quartz-surface.c
+++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c
@@ -130,16 +130,19 @@ static void (*CGContextClipToMaskPtr) (C
static void (*CGContextDrawTiledImagePtr) (CGContextRef, CGRect, CGImageRef) = NULL;
static unsigned int (*CGContextGetTypePtr) (CGContextRef) = NULL;
static void (*CGContextSetShouldAntialiasFontsPtr) (CGContextRef, bool) = NULL;
static void (*CGContextSetAllowsFontSmoothingPtr) (CGContextRef, bool) = NULL;
static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL;
static CGPathRef (*CGContextCopyPathPtr) (CGContextRef) = NULL;
static CGFloat (*CGContextGetAlphaPtr) (CGContextRef) = NULL;
+/* CTFontDrawGlyphs is not available until 10.7 */
+static void (*CTFontDrawGlyphsPtr) (CTFontRef, const CGGlyph[], const CGPoint[], size_t, CGContextRef) = NULL;
+
static SInt32 _cairo_quartz_osx_version = 0x0;
static cairo_bool_t _cairo_quartz_symbol_lookup_done = FALSE;
/*
* Utility functions
*/
@@ -167,16 +170,18 @@ static void quartz_ensure_symbols(void)
CGContextDrawTiledImagePtr = dlsym(RTLD_DEFAULT, "CGContextDrawTiledImage");
CGContextGetTypePtr = dlsym(RTLD_DEFAULT, "CGContextGetType");
CGContextSetShouldAntialiasFontsPtr = dlsym(RTLD_DEFAULT, "CGContextSetShouldAntialiasFonts");
CGContextCopyPathPtr = dlsym(RTLD_DEFAULT, "CGContextCopyPath");
CGContextGetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
CGContextGetAlphaPtr = dlsym(RTLD_DEFAULT, "CGContextGetAlpha");
+ CTFontDrawGlyphsPtr = dlsym(RTLD_DEFAULT, "CTFontDrawGlyphs");
+
if (Gestalt(gestaltSystemVersion, &_cairo_quartz_osx_version) != noErr) {
// assume 10.5
_cairo_quartz_osx_version = 0x1050;
}
_cairo_quartz_symbol_lookup_done = TRUE;
}
@@ -605,20 +610,23 @@ static inline void
dst->d = src->yy;
dst->tx = src->x0;
dst->ty = src->y0;
}
typedef struct {
bool isClipping;
CGGlyph *cg_glyphs;
- CGSize *cg_advances;
+ union {
+ CGSize *cg_advances;
+ CGPoint *cg_positions;
+ } u;
size_t nglyphs;
CGAffineTransform textTransform;
- CGFontRef font;
+ cairo_scaled_font_t *scaled_font;
CGPoint origin;
} unbounded_show_glyphs_t;
typedef struct {
CGPathRef cgPath;
cairo_fill_rule_t fill_rule;
} unbounded_stroke_fill_t;
@@ -686,36 +694,43 @@ static void
CGContextBeginPath (cgc);
CGContextAddPath (cgc, op->u.stroke_fill.cgPath);
if (op->u.stroke_fill.fill_rule == CAIRO_FILL_RULE_WINDING)
CGContextFillPath (cgc);
else
CGContextEOFillPath (cgc);
} else if (op->op == UNBOUNDED_SHOW_GLYPHS) {
- CGContextSetFont (cgc, op->u.show_glyphs.font);
- CGContextSetFontSize (cgc, 1.0);
- CGContextSetTextMatrix (cgc, CGAffineTransformIdentity);
- CGContextTranslateCTM (cgc, op->u.show_glyphs.origin.x, op->u.show_glyphs.origin.y);
- CGContextConcatCTM (cgc, op->u.show_glyphs.textTransform);
-
if (op->u.show_glyphs.isClipping) {
/* Note that the comment in show_glyphs about kCGTextClip
* and the text transform still applies here; however, the
* cg_advances we have were already transformed, so we
* don't have to do anything. */
CGContextSetTextDrawingMode (cgc, kCGTextClip);
CGContextSaveGState (cgc);
}
-
- CGContextShowGlyphsWithAdvances (cgc,
- op->u.show_glyphs.cg_glyphs,
- op->u.show_glyphs.cg_advances,
- op->u.show_glyphs.nglyphs);
-
+ CGContextTranslateCTM (cgc, op->u.show_glyphs.origin.x, op->u.show_glyphs.origin.y);
+ CGContextConcatCTM (cgc, op->u.show_glyphs.textTransform);
+ if (CTFontDrawGlyphsPtr) {
+ CTFontDrawGlyphsPtr (_cairo_quartz_scaled_font_get_ct_font_ref (op->u.show_glyphs.scaled_font),
+ op->u.show_glyphs.cg_glyphs,
+ op->u.show_glyphs.u.cg_positions,
+ op->u.show_glyphs.nglyphs,
+ cgc);
+ } else {
+ CGContextSetFont (cgc, _cairo_quartz_scaled_font_get_cg_font_ref (op->u.show_glyphs.scaled_font));
+ CGContextSetFontSize (cgc, 1.0);
+ CGContextSetTextMatrix (cgc, CGAffineTransformIdentity);
+
+ CGContextShowGlyphsWithAdvances (cgc,
+ op->u.show_glyphs.cg_glyphs,
+ op->u.show_glyphs.u.cg_advances,
+ op->u.show_glyphs.nglyphs);
+
+ }
if (op->u.show_glyphs.isClipping) {
CGContextClearRect (cgc, clipBoxRound);
CGContextRestoreGState (cgc);
}
} else if (op->op == UNBOUNDED_MASK) {
CGAffineTransform ctm = CGContextGetCTM (cgc);
CGContextSaveGState (cgc);
CGContextConcatCTM (cgc, op->u.mask.maskTransform);
@@ -2684,16 +2699,19 @@ static cairo_int_status_t
cairo_clip_t *clip,
int *remaining_glyphs)
{
CGAffineTransform textTransform, ctm, invTextTransform;
#define STATIC_BUF_SIZE 64
CGGlyph glyphs_static[STATIC_BUF_SIZE];
CGSize cg_advances_static[STATIC_BUF_SIZE];
CGGlyph *cg_glyphs = &glyphs_static[0];
+ /* We'll use the cg_advances array for either advances or positions,
+ depending which API we're using to actually draw. The types involved
+ have the same size, so this is safe. */
CGSize *cg_advances = &cg_advances_static[0];
cairo_rectangle_int_t glyph_extents;
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
cairo_quartz_drawing_state_t state;
cairo_quartz_float_t xprev, yprev;
int i;
@@ -2796,41 +2814,62 @@ static cairo_int_status_t
invTextTransform = CGAffineTransformMake (scaled_font->scale_inverse.xx,
-scaled_font->scale_inverse.yx,
scaled_font->scale_inverse.xy,
-scaled_font->scale_inverse.yy,
0.0, 0.0);
CGContextSetTextMatrix (state.context, CGAffineTransformIdentity);
- /* Convert our glyph positions to glyph advances. We need n-1 advances,
- * since the advance at index 0 is applied after glyph 0. */
- xprev = glyphs[0].x;
- yprev = glyphs[0].y;
-
- cg_glyphs[0] = glyphs[0].index;
-
- for (i = 1; i < num_glyphs; i++) {
- cairo_quartz_float_t xf = glyphs[i].x;
- cairo_quartz_float_t yf = glyphs[i].y;
- cg_glyphs[i] = glyphs[i].index;
- cg_advances[i - 1] = CGSizeApplyAffineTransform(CGSizeMake (xf - xprev, yf - yprev), invTextTransform);
- xprev = xf;
- yprev = yf;
- }
-
/* Translate to the first glyph's position before drawing */
ctm = CGContextGetCTM (state.context);
CGContextTranslateCTM (state.context, glyphs[0].x, glyphs[0].y);
CGContextConcatCTM (state.context, textTransform);
- CGContextShowGlyphsWithAdvances (state.context,
- cg_glyphs,
- cg_advances,
- num_glyphs);
+ if (CTFontDrawGlyphsPtr) {
+ /* If CTFontDrawGlyphs is available (i.e. OS X 10.7 or later), we want to use
+ * that in preference to CGContextShowGlyphsWithAdvances so that colored-bitmap
+ * fonts like Apple Color Emoji will render properly.
+ * For this, we need to convert our glyph positions to Core Graphics's CGPoint.
+ * We borrow the cg_advances array, as CGPoint and CGSize are the same size. */
+
+ CGPoint *cg_positions = (CGPoint*) cg_advances;
+ cairo_quartz_float_t origin_x = glyphs[0].x;
+ cairo_quartz_float_t origin_y = glyphs[0].y;
+
+ for (i = 0; i < num_glyphs; i++) {
+ CGPoint pt = CGPointMake (glyphs[i].x - origin_x, glyphs[i].y - origin_y);
+ cg_positions[i] = CGPointApplyAffineTransform (pt, invTextTransform);
+ cg_glyphs[i] = glyphs[i].index;
+ }
+
+ CTFontDrawGlyphsPtr (_cairo_quartz_scaled_font_get_ct_font_ref (scaled_font),
+ cg_glyphs, cg_positions, num_glyphs, state.context);
+ } else {
+ /* Convert our glyph positions to glyph advances. We need n-1 advances,
+ * since the advance at index 0 is applied after glyph 0. */
+ xprev = glyphs[0].x;
+ yprev = glyphs[0].y;
+
+ cg_glyphs[0] = glyphs[0].index;
+
+ for (i = 1; i < num_glyphs; i++) {
+ cairo_quartz_float_t xf = glyphs[i].x;
+ cairo_quartz_float_t yf = glyphs[i].y;
+ cg_glyphs[i] = glyphs[i].index;
+ cg_advances[i - 1] = CGSizeApplyAffineTransform(CGSizeMake (xf - xprev, yf - yprev), invTextTransform);
+ xprev = xf;
+ yprev = yf;
+ }
+
+ CGContextShowGlyphsWithAdvances (state.context,
+ cg_glyphs,
+ cg_advances,
+ num_glyphs);
+ }
CGContextSetCTM (state.context, ctm);
if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE ||
state.action == DO_LAYER) {
_cairo_quartz_draw_image (&state, op);
} else if (state.action == DO_SHADING) {
CGContextConcatCTM (state.context, state.transform);
@@ -2847,20 +2886,27 @@ BAIL:
cgfref &&
!_cairo_operator_bounded_by_mask (op))
{
unbounded_op_data_t ub;
ub.op = UNBOUNDED_SHOW_GLYPHS;
ub.u.show_glyphs.isClipping = isClipping;
ub.u.show_glyphs.cg_glyphs = cg_glyphs;
- ub.u.show_glyphs.cg_advances = cg_advances;
+ if (CTFontDrawGlyphsPtr) {
+ /* we're using Core Text API: the cg_advances array was
+ reused (above) for glyph positions */
+ CGPoint *cg_positions = (CGPoint*) cg_advances;
+ ub.u.show_glyphs.u.cg_positions = cg_positions;
+ } else {
+ ub.u.show_glyphs.u.cg_advances = cg_advances;
+ }
ub.u.show_glyphs.nglyphs = num_glyphs;
ub.u.show_glyphs.textTransform = textTransform;
- ub.u.show_glyphs.font = cgfref;
+ ub.u.show_glyphs.scaled_font = scaled_font;
ub.u.show_glyphs.origin = CGPointMake (glyphs[0].x, glyphs[0].y);
_cairo_quartz_fixup_unbounded_operation (surface, &ub, scaled_font->options.antialias);
}
if (cg_advances != &cg_advances_static[0]) {
free (cg_advances);

View File

@ -0,0 +1,42 @@
From: Jonathan Kew <jkew@mozilla.com>
bug 715798 pt 2 - fall back to show_text_glyphs even at huge sizes if scaled_font_glyph_path didn't work. r=jrmuizel
diff --git a/gfx/cairo/cairo/src/cairo-gstate.c b/gfx/cairo/cairo/src/cairo-gstate.c
--- a/gfx/cairo/cairo/src/cairo-gstate.c
+++ b/gfx/cairo/cairo/src/cairo-gstate.c
@@ -2002,23 +2002,34 @@ cairo_status_t
cairo_path_fixed_t path;
_cairo_path_fixed_init (&path);
status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
transformed_glyphs, num_glyphs,
&path);
- if (status == CAIRO_STATUS_SUCCESS) {
+ if (status == CAIRO_STATUS_SUCCESS && !_cairo_path_fixed_fill_is_empty (&path)) {
status = _cairo_surface_fill (gstate->target, op, pattern,
&path,
CAIRO_FILL_RULE_WINDING,
gstate->tolerance,
gstate->scaled_font->options.antialias,
_gstate_get_clip (gstate, &clip));
+ } else {
+ /* if _cairo_scaled_font_glyph_path() failed, maybe the font doesn't support
+ * returning paths, so try the _cairo_surface_show_text_glyphs() option
+ */
+ status = _cairo_surface_show_text_glyphs (gstate->target, op, pattern,
+ utf8, utf8_len,
+ transformed_glyphs, num_glyphs,
+ transformed_clusters, num_clusters,
+ cluster_flags,
+ gstate->scaled_font,
+ _gstate_get_clip (gstate, &clip));
}
_cairo_path_fixed_fini (&path);
}
_cairo_clip_fini (&clip);
CLEANUP_GLYPHS:

View File

@ -410,7 +410,10 @@ BasicTiledThebesLayer::PaintThebes(gfxContext* aContext,
transform.Invert();
// Store the old valid region, then clear it before painting.
// We clip the old valid region to the visible region, as it only gets
// used to decide stale content (currently valid and previously visible)
nsIntRegion oldValidRegion = mTiledBuffer.GetValidRegion();
oldValidRegion.And(oldValidRegion, mVisibleRegion);
mTiledBuffer.ClearPaintedRegion();
// Make sure that tiles that fall outside of the visible region are
@ -453,8 +456,14 @@ BasicTiledThebesLayer::PaintThebes(gfxContext* aContext,
// Keep track of what we're about to refresh.
mValidRegion.Or(mValidRegion, regionToPaint);
// mValidRegion would have been altered by InvalidateRegion, but we still
// want to display stale content until it gets progressively updated.
// Create a region that includes stale content.
nsIntRegion validOrStale;
validOrStale.Or(mValidRegion, oldValidRegion);
// Paint the computed region and subtract it from the invalid region.
mTiledBuffer.PaintThebes(this, mValidRegion, regionToPaint, aCallback, aCallbackData);
mTiledBuffer.PaintThebes(this, validOrStale, regionToPaint, aCallback, aCallbackData);
invalidRegion.Sub(invalidRegion, regionToPaint);
} while (repeat);
} else {

View File

@ -444,22 +444,6 @@ inline nscoord NSIntPixelsToAppUnits(int32_t aPixels, int32_t aAppUnitsPerPixel)
{
// The cast to nscoord makes sure we don't overflow if we ever change
// nscoord to float
#ifndef NS_COORD_IS_FLOAT
const int pixels_MAX = nscoord_MAX / aAppUnitsPerPixel;
// Bounds-check before converting out of float, to avoid overflow
NS_WARN_IF_FALSE(aPixels <= pixels_MAX,
"Overflowed nscoord_MAX in conversion to nscoord");
if (aPixels >= pixels_MAX) {
aPixels = pixels_MAX;
} else {
const int pixels_MIN = nscoord_MIN / aAppUnitsPerPixel;
NS_WARN_IF_FALSE(aPixels >= pixels_MIN,
"Overflowed nscoord_MIN in conversion to nscoord");
if (aPixels <= pixels_MIN) {
aPixels = pixels_MIN;
}
}
#endif
nscoord r = aPixels * (nscoord)aAppUnitsPerPixel;
VERIFY_COORD(r);
return r;

View File

@ -405,52 +405,86 @@ void SetScreenBrightness(double brightness)
PROXY_IF_SANDBOXED(SetScreenBrightness(clamped(brightness, 0.0, 1.0)));
}
bool SetLight(LightType light, const hal::LightConfiguration& aConfig)
bool SetLight(LightType light, const LightConfiguration& aConfig)
{
AssertMainThread();
RETURN_PROXY_IF_SANDBOXED(SetLight(light, aConfig), false);
}
bool GetLight(LightType light, hal::LightConfiguration* aConfig)
bool GetLight(LightType light, LightConfiguration* aConfig)
{
AssertMainThread();
RETURN_PROXY_IF_SANDBOXED(GetLight(light, aConfig), false);
}
class SystemTimeObserversManager : public ObserversManager<SystemTimeChange>
class SystemClockChangeObserversManager : public ObserversManager<int64_t>
{
protected:
void EnableNotifications() {
PROXY_IF_SANDBOXED(EnableSystemTimeChangeNotifications());
PROXY_IF_SANDBOXED(EnableSystemClockChangeNotifications());
}
void DisableNotifications() {
PROXY_IF_SANDBOXED(DisableSystemTimeChangeNotifications());
PROXY_IF_SANDBOXED(DisableSystemClockChangeNotifications());
}
};
static SystemTimeObserversManager sSystemTimeObservers;
static SystemClockChangeObserversManager sSystemClockChangeObservers;
void
RegisterSystemTimeChangeObserver(SystemTimeObserver *aObserver)
RegisterSystemClockChangeObserver(SystemClockChangeObserver* aObserver)
{
AssertMainThread();
sSystemTimeObservers.AddObserver(aObserver);
sSystemClockChangeObservers.AddObserver(aObserver);
}
void
UnregisterSystemTimeChangeObserver(SystemTimeObserver *aObserver)
UnregisterSystemClockChangeObserver(SystemClockChangeObserver* aObserver)
{
AssertMainThread();
sSystemTimeObservers.RemoveObserver(aObserver);
sSystemClockChangeObservers.RemoveObserver(aObserver);
}
void
NotifySystemTimeChange(const hal::SystemTimeChange& aReason)
NotifySystemClockChange(const int64_t& aClockDeltaMS)
{
sSystemTimeObservers.BroadcastInformation(aReason);
sSystemClockChangeObservers.BroadcastInformation(aClockDeltaMS);
}
class SystemTimezoneChangeObserversManager : public ObserversManager<SystemTimezoneChangeInformation>
{
protected:
void EnableNotifications() {
PROXY_IF_SANDBOXED(EnableSystemTimezoneChangeNotifications());
}
void DisableNotifications() {
PROXY_IF_SANDBOXED(DisableSystemTimezoneChangeNotifications());
}
};
static SystemTimezoneChangeObserversManager sSystemTimezoneChangeObservers;
void
RegisterSystemTimezoneChangeObserver(SystemTimezoneChangeObserver* aObserver)
{
AssertMainThread();
sSystemTimezoneChangeObservers.AddObserver(aObserver);
}
void
UnregisterSystemTimezoneChangeObserver(SystemTimezoneChangeObserver* aObserver)
{
AssertMainThread();
sSystemTimezoneChangeObservers.RemoveObserver(aObserver);
}
void
NotifySystemTimezoneChange(const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
{
sSystemTimezoneChangeObservers.BroadcastInformation(aSystemTimezoneChangeInfo);
}
void
AdjustSystemClock(int64_t aDeltaMilliseconds)
{
@ -607,8 +641,8 @@ UnregisterWakeLockObserver(WakeLockObserver* aObserver)
void
ModifyWakeLock(const nsAString &aTopic,
hal::WakeLockControl aLockAdjust,
hal::WakeLockControl aHiddenAdjust)
WakeLockControl aLockAdjust,
WakeLockControl aHiddenAdjust)
{
AssertMainThread();
PROXY_IF_SANDBOXED(ModifyWakeLock(aTopic, aLockAdjust, aHiddenAdjust));
@ -671,18 +705,18 @@ UnlockScreenOrientation()
}
void
EnableSwitchNotifications(hal::SwitchDevice aDevice) {
EnableSwitchNotifications(SwitchDevice aDevice) {
AssertMainThread();
PROXY_IF_SANDBOXED(EnableSwitchNotifications(aDevice));
}
void
DisableSwitchNotifications(hal::SwitchDevice aDevice) {
DisableSwitchNotifications(SwitchDevice aDevice) {
AssertMainThread();
PROXY_IF_SANDBOXED(DisableSwitchNotifications(aDevice));
}
hal::SwitchState GetCurrentSwitchState(hal::SwitchDevice aDevice)
SwitchState GetCurrentSwitchState(SwitchDevice aDevice)
{
AssertMainThread();
RETURN_PROXY_IF_SANDBOXED(GetCurrentSwitchState(aDevice), SWITCH_STATE_UNKNOWN);
@ -693,7 +727,7 @@ typedef mozilla::ObserverList<SwitchEvent> SwitchObserverList;
static SwitchObserverList *sSwitchObserverLists = NULL;
static SwitchObserverList&
GetSwitchObserverList(hal::SwitchDevice aDevice) {
GetSwitchObserverList(SwitchDevice aDevice) {
MOZ_ASSERT(0 <= aDevice && aDevice < NUM_SWITCH_DEVICE);
if (sSwitchObserverLists == NULL) {
sSwitchObserverLists = new SwitchObserverList[NUM_SWITCH_DEVICE];
@ -714,7 +748,7 @@ ReleaseObserversIfNeeded() {
}
void
RegisterSwitchObserver(hal::SwitchDevice aDevice, hal::SwitchObserver *aObserver)
RegisterSwitchObserver(SwitchDevice aDevice, SwitchObserver *aObserver)
{
AssertMainThread();
SwitchObserverList& observer = GetSwitchObserverList(aDevice);
@ -725,7 +759,7 @@ RegisterSwitchObserver(hal::SwitchDevice aDevice, hal::SwitchObserver *aObserver
}
void
UnregisterSwitchObserver(hal::SwitchDevice aDevice, hal::SwitchObserver *aObserver)
UnregisterSwitchObserver(SwitchDevice aDevice, SwitchObserver *aObserver)
{
AssertMainThread();
@ -743,7 +777,7 @@ UnregisterSwitchObserver(hal::SwitchDevice aDevice, hal::SwitchObserver *aObserv
}
void
NotifySwitchChange(const hal::SwitchEvent& aEvent)
NotifySwitchChange(const SwitchEvent& aEvent)
{
// When callback this notification, main thread may call unregister function
// first. We should check if this pointer is valid.

View File

@ -50,7 +50,8 @@ class WindowIdentifier;
extern PRLogModuleInfo *sHalLog;
#define HAL_LOG(msg) PR_LOG(mozilla::hal::sHalLog, PR_LOG_DEBUG, msg)
typedef Observer<SystemTimeChange> SystemTimeObserver;
typedef Observer<int64_t> SystemClockChangeObserver;
typedef Observer<SystemTimezoneChangeInformation> SystemTimezoneChangeObserver;
} // namespace hal
@ -258,22 +259,45 @@ void SetTimezone(const nsCString& aTimezoneSpec);
nsCString GetTimezone();
/**
* Register observer for system time changed notification.
* Register observer for system clock changed notification.
* @param aObserver The observer that should be added.
*/
void RegisterSystemTimeChangeObserver(hal::SystemTimeObserver* aObserver);
void RegisterSystemClockChangeObserver(
hal::SystemClockChangeObserver* aObserver);
/**
* Unregister the observer for system time changed.
* Unregister the observer for system clock changed.
* @param aObserver The observer that should be removed.
*/
void UnregisterSystemTimeChangeObserver(hal::SystemTimeObserver* aObserver);
void UnregisterSystemClockChangeObserver(
hal::SystemClockChangeObserver* aObserver);
/**
* Notify of a change in the system cloeck or time zone.
* @param aReason
* Notify of a change in the system clock.
* @param aClockDeltaMS
*/
void NotifySystemTimeChange(const hal::SystemTimeChange& aReason);
void NotifySystemClockChange(const int64_t& aClockDeltaMS);
/**
* Register observer for system timezone changed notification.
* @param aObserver The observer that should be added.
*/
void RegisterSystemTimezoneChangeObserver(
hal::SystemTimezoneChangeObserver* aObserver);
/**
* Unregister the observer for system timezone changed.
* @param aObserver The observer that should be removed.
*/
void UnregisterSystemTimezoneChangeObserver(
hal::SystemTimezoneChangeObserver* aObserver);
/**
* Notify of a change in the system timezone.
* @param aSystemTimezoneChangeInfo
*/
void NotifySystemTimezoneChange(
const hal::SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo);
/**
* Reboot the device.

View File

@ -75,14 +75,24 @@ bool EnableAlarm();
void DisableAlarm();
/**
* Enable system time change notifications from the backend.
* Enable system clock change notifications from the backend.
*/
void EnableSystemTimeChangeNotifications();
void EnableSystemClockChangeNotifications();
/**
* Disable system time change notifications from the backend.
* Disable system clock change notifications from the backend.
*/
void DisableSystemTimeChangeNotifications();
void DisableSystemClockChangeNotifications();
/**
* Enable system timezone change notifications from the backend.
*/
void EnableSystemTimezoneChangeNotifications();
/**
* Disable system timezone change notifications from the backend.
*/
void DisableSystemTimezoneChangeNotifications();
bool IsHalChildLive();
} // namespace MOZ_HAL_NAMESPACE

View File

@ -84,13 +84,6 @@ enum WakeLockControl {
NUM_WAKE_LOCK
};
enum SystemTimeChange {
SYS_TIME_CHANGE_UNKNOWN = -1,
SYS_TIME_CHANGE_CLOCK,
SYS_TIME_CHANGE_TZ,
SYS_TIME_CHANGE_GUARD
};
class FMRadioOperationInformation;
enum FMRadioOperation {
@ -167,7 +160,6 @@ enum FMRadioCountry {
};
typedef Observer<FMRadioOperationInformation> FMRadioObserver;
typedef Observer<SystemTimeChange> SystemTimeChangeObserver;
} // namespace hal
} // namespace mozilla
@ -250,16 +242,6 @@ struct ParamTraits<mozilla::hal::ProcessPriority>:
mozilla::hal::NUM_PROCESS_PRIORITY> {
};
/**
* SystemTimeChange serializer.
*/
template <>
struct ParamTraits<mozilla::hal::SystemTimeChange>
: public EnumSerializer<mozilla::hal::SystemTimeChange,
mozilla::hal::SYS_TIME_CHANGE_UNKNOWN,
mozilla::hal::SYS_TIME_CHANGE_GUARD>
{};
/**
* Serializer for FMRadioOperation
*/

View File

@ -25,13 +25,24 @@ GetTimezone()
}
void
EnableSystemTimeChangeNotifications()
EnableSystemClockChangeNotifications()
{
}
void
DisableSystemTimeChangeNotifications()
DisableSystemClockChangeNotifications()
{
}
void
EnableSystemTimezoneChangeNotifications()
{
}
void
DisableSystemTimezoneChangeNotifications()
{
}
} // namespace hal_impl
} // namespace mozilla

View File

@ -83,6 +83,13 @@
#define OOM_SCORE_ADJ_MAX 1000
#endif
#ifndef BATTERY_CHARGING_ARGB
#define BATTERY_CHARGING_ARGB 0x00FF0000
#endif
#ifndef BATTERY_FULL_ARGB
#define BATTERY_FULL_ARGB 0x0000FF00
#endif
using namespace mozilla;
using namespace mozilla::hal;
@ -250,6 +257,26 @@ public:
{
hal::BatteryInformation info;
hal_impl::GetCurrentBatteryInformation(&info);
// Control the battery indicator (led light) here using BatteryInformation
// we just retrieved.
uint32_t color = 0; // Format: 0x00rrggbb.
if (info.charging() && (info.level() == 1)) {
// Charging and battery full.
color = BATTERY_FULL_ARGB;
} else if (info.charging() && (info.level() < 1)) {
// Charging but not full.
color = BATTERY_CHARGING_ARGB;
} // else turn off battery indicator.
hal::LightConfiguration aConfig(hal::eHalLightID_Battery,
hal::eHalLightMode_User,
hal::eHalLightFlash_None,
0,
0,
color);
hal_impl::SetLight(hal::eHalLightID_Battery, aConfig);
hal::NotifyBatteryChange(info);
return NS_OK;
}
@ -643,7 +670,21 @@ AdjustSystemClock(int64_t aDeltaMilliseconds)
return;
}
hal::NotifySystemTimeChange(hal::SYS_TIME_CHANGE_CLOCK);
hal::NotifySystemClockChange(aDeltaMilliseconds);
}
static int32_t
GetTimezoneOffset()
{
PRExplodedTime prTime;
PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &prTime);
// Daylight saving time (DST) will be taken into account.
int32_t offset = prTime.tm_params.tp_gmt_offset;
offset += prTime.tm_params.tp_dst_offset;
// Returns the timezone offset relative to UTC in minutes.
return -(offset / 60);
}
void
@ -653,11 +694,15 @@ SetTimezone(const nsCString& aTimezoneSpec)
return;
}
int32_t oldTimezoneOffsetMinutes = GetTimezoneOffset();
property_set("persist.sys.timezone", aTimezoneSpec.get());
// this function is automatically called by the other time conversion
// functions that depend on the timezone. To be safe, we call it manually.
tzset();
hal::NotifySystemTimeChange(hal::SYS_TIME_CHANGE_TZ);
int32_t newTimezoneOffsetMinutes = GetTimezoneOffset();
hal::NotifySystemTimezoneChange(
hal::SystemTimezoneChangeInformation(
oldTimezoneOffsetMinutes, newTimezoneOffsetMinutes));
}
nsCString
@ -669,12 +714,22 @@ GetTimezone()
}
void
EnableSystemTimeChangeNotifications()
EnableSystemClockChangeNotifications()
{
}
void
DisableSystemTimeChangeNotifications()
DisableSystemClockChangeNotifications()
{
}
void
EnableSystemTimezoneChangeNotifications()
{
}
void
DisableSystemTimezoneChangeNotifications()
{
}

View File

@ -24,7 +24,6 @@ using mozilla::hal::SwitchDevice;
using mozilla::hal::ProcessPriority;
using nsIntRect;
using PRTime;
using mozilla::hal::SystemTimeChange;
using mozilla::hal::FMRadioCountry;
using mozilla::hal::FMRadioOperation;
using mozilla::hal::FMRadioOperationStatus;
@ -92,6 +91,13 @@ struct FMRadioSettings {
uint32_t preEmphasis;
};
struct SystemTimezoneChangeInformation {
// These timezone offsets are relative to UTC in minutes and
// have already taken daylight saving time (DST) into account.
int32_t oldTimezoneOffsetMinutes;
int32_t newTimezoneOffsetMinutes;
};
} // namespace hal
namespace hal_sandbox {
@ -105,7 +111,8 @@ child:
NotifyWakeLockChange(WakeLockInformation aWakeLockInfo);
NotifyScreenConfigurationChange(ScreenConfiguration aScreenOrientation);
NotifySwitchChange(SwitchEvent aEvent);
NotifySystemTimeChange(SystemTimeChange aReason);
NotifySystemClockChange(int64_t aClockDeltaMS);
NotifySystemTimezoneChange(SystemTimezoneChangeInformation aSystemTimezoneChangeInfo);
NotifyFMRadioStatus(FMRadioOperationInformation aInfo);
parent:
@ -135,8 +142,10 @@ parent:
SetTimezone(nsCString aTimezoneSpec);
sync GetTimezone()
returns (nsCString aTimezoneSpec);
EnableSystemTimeChangeNotifications();
DisableSystemTimeChangeNotifications();
EnableSystemClockChangeNotifications();
DisableSystemClockChangeNotifications();
EnableSystemTimezoneChangeNotifications();
DisableSystemTimezoneChangeNotifications();
sync SetLight(LightType light, LightConfiguration aConfig)
returns (bool status);

View File

@ -212,15 +212,27 @@ GetTimezone()
}
void
EnableSystemTimeChangeNotifications()
EnableSystemClockChangeNotifications()
{
Hal()->SendEnableSystemTimeChangeNotifications();
Hal()->SendEnableSystemClockChangeNotifications();
}
void
DisableSystemTimeChangeNotifications()
DisableSystemClockChangeNotifications()
{
Hal()->SendDisableSystemTimeChangeNotifications();
Hal()->SendDisableSystemClockChangeNotifications();
}
void
EnableSystemTimezoneChangeNotifications()
{
Hal()->SendEnableSystemTimezoneChangeNotifications();
}
void
DisableSystemTimezoneChangeNotifications()
{
Hal()->SendDisableSystemTimezoneChangeNotifications();
}
void
@ -394,7 +406,8 @@ class HalParent : public PHalParent
, public WakeLockObserver
, public ScreenConfigurationObserver
, public SwitchObserver
, public SystemTimeObserver
, public SystemClockChangeObserver
, public SystemTimezoneChangeObserver
{
public:
virtual void
@ -410,7 +423,8 @@ public:
hal::UnregisterSensorObserver(SensorType(sensor), this);
}
hal::UnregisterWakeLockObserver(this);
hal::UnregisterSystemTimeChangeObserver(this);
hal::UnregisterSystemClockChangeObserver(this);
hal::UnregisterSystemTimezoneChangeObserver(this);
}
virtual bool
@ -643,16 +657,30 @@ public:
}
virtual bool
RecvEnableSystemTimeChangeNotifications() MOZ_OVERRIDE
RecvEnableSystemClockChangeNotifications() MOZ_OVERRIDE
{
hal::RegisterSystemTimeChangeObserver(this);
hal::RegisterSystemClockChangeObserver(this);
return true;
}
virtual bool
RecvDisableSystemTimeChangeNotifications() MOZ_OVERRIDE
RecvDisableSystemClockChangeNotifications() MOZ_OVERRIDE
{
hal::UnregisterSystemTimeChangeObserver(this);
hal::UnregisterSystemClockChangeObserver(this);
return true;
}
virtual bool
RecvEnableSystemTimezoneChangeNotifications() MOZ_OVERRIDE
{
hal::RegisterSystemTimezoneChangeObserver(this);
return true;
}
virtual bool
RecvDisableSystemTimezoneChangeNotifications() MOZ_OVERRIDE
{
hal::UnregisterSystemTimezoneChangeObserver(this);
return true;
}
@ -749,9 +777,14 @@ public:
return true;
}
void Notify(const SystemTimeChange& aReason)
void Notify(const int64_t& aClockDeltaMS)
{
unused << SendNotifySystemTimeChange(aReason);
unused << SendNotifySystemClockChange(aClockDeltaMS);
}
void Notify(const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
{
unused << SendNotifySystemTimezoneChange(aSystemTimezoneChangeInfo);
}
virtual bool
@ -902,8 +935,15 @@ public:
}
virtual bool
RecvNotifySystemTimeChange(const SystemTimeChange& aReason) {
hal::NotifySystemTimeChange(aReason);
RecvNotifySystemClockChange(const int64_t& aClockDeltaMS) {
hal::NotifySystemClockChange(aClockDeltaMS);
return true;
}
virtual bool
RecvNotifySystemTimezoneChange(
const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo) {
hal::NotifySystemTimezoneChange(aSystemTimezoneChangeInfo);
return true;
}

View File

@ -36,7 +36,7 @@ static const uint8_t gASCIIToLower [128] = {
// We want ToLowerCase(uint32_t) and ToLowerCaseASCII(uint32_t) to be fast
// when they're called from within the case-insensitive comparators, so we
// define inlined versions.
static NS_ALWAYS_INLINE uint32_t
static MOZ_ALWAYS_INLINE uint32_t
ToLowerCase_inline(uint32_t aChar)
{
if (IS_ASCII(aChar)) {
@ -46,7 +46,7 @@ ToLowerCase_inline(uint32_t aChar)
return mozilla::unicode::GetLowercase(aChar);
}
static NS_ALWAYS_INLINE uint32_t
static MOZ_ALWAYS_INLINE uint32_t
ToLowerCaseASCII_inline(const uint32_t aChar)
{
if (IS_ASCII(aChar)) {
@ -271,7 +271,7 @@ CaseInsensitiveCompare(const PRUnichar *a,
// the end of the string (as marked by aEnd), returns -1 and does not set
// aNext. Note that this function doesn't check that aStr < aEnd -- it assumes
// you've done that already.
static NS_ALWAYS_INLINE uint32_t
static MOZ_ALWAYS_INLINE uint32_t
GetLowerUTF8Codepoint(const char* aStr, const char* aEnd, const char **aNext)
{
// Convert to unsigned char so that stuffing chars into PRUint32s doesn't

View File

@ -0,0 +1,25 @@
// |jit-test| error:ReferenceError
function e() {
try {} catch (e) {
return (actual = "FAIL");
a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
a.x + a.x + a.x + a.x + a.x + a.x + a.x + a.x
}
while (t) continue;
}
e();

View File

@ -0,0 +1,9 @@
mjitChunkLimit(42);
Function("\
switch (/x/) {\
case 8:\
break;\
t(function(){})\
}\
while (false)(function(){})\
")()

View File

@ -0,0 +1,10 @@
mjitChunkLimit(10);
function e() {
try {
var t = undefined;
} catch (e) { }
while (t)
continue;
}
for (var i = 0; i < 20; i++)
e();

View File

@ -2603,7 +2603,7 @@ MarkRuntime(JSTracer *trc, bool useSavedRoots = false)
mjit::ExpandInlineFrames(c);
#endif
rt->stackSpace.markAndClobber(trc);
rt->stackSpace.mark(trc);
rt->debugScopes->mark(trc);
#ifdef JS_ION
@ -3851,13 +3851,6 @@ BeginSweepPhase(JSRuntime *rt)
{
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_COMPARTMENTS);
/*
* Eliminate any garbage values from the VM stack that may have been
* left by the JIT in between incremental GC slices. We need to do this
* before discarding analysis data during JSCompartment::sweep.
*/
rt->stackSpace.markAndClobber(NULL);
bool releaseTypes = ReleaseObservedTypes(rt);
for (CompartmentsIter c(rt); !c.done(); c.next()) {
gcstats::AutoSCC scc(rt->gcStats, partition.getSCC(c));

View File

@ -748,12 +748,7 @@ void
StackTypeSet::addPropagateThis(JSContext *cx, HandleScript script, jsbytecode *pc,
Type type, StackTypeSet *types)
{
/* Don't add constraints when the call will be 'new' (see addCallProperty). */
jsbytecode *callpc = script->analysis()->getCallPC(pc);
if (JSOp(*callpc) == JSOP_NEW)
return;
add(cx, cx->analysisLifoAlloc().new_<TypeConstraintPropagateThis>(script, callpc, type, types));
add(cx, cx->analysisLifoAlloc().new_<TypeConstraintPropagateThis>(script, pc, type, types));
}
/* Subset constraint which filters out primitive types. */
@ -1207,7 +1202,6 @@ TypeConstraintCallProp<access>::newType(JSContext *cx, TypeSet *source, Type typ
return;
if (!types->hasPropagatedProperty())
object->getFromPrototypes(cx, id, types);
/* Bypass addPropagateThis, we already have the callpc. */
if (access == PROPERTY_READ) {
types->add(cx, cx->typeLifoAlloc().new_<TypeConstraintPropagateThis>(
script_, callpc, type, (StackTypeSet *) NULL));
@ -3579,16 +3573,6 @@ GetInitializerType(JSContext *cx, HandleScript script, jsbytecode *pc)
return TypeScript::InitObject(cx, script, pc, key);
}
static inline Type
GetCalleeThisType(jsbytecode *pc)
{
pc += GetBytecodeLength(pc);
if (*pc == JSOP_UNDEFINED)
return Type::UndefinedType();
JS_ASSERT(*pc == JSOP_IMPLICITTHIS);
return Type::UnknownType();
}
/* Analyze type information for a single bytecode. */
bool
ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferenceState &state)
@ -3823,9 +3807,6 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen
PropertyAccess<PROPERTY_READ_EXISTING>(cx, script, pc, global, seen, id);
else
PropertyAccess<PROPERTY_READ>(cx, script, pc, global, seen, id);
if (op == JSOP_CALLGNAME)
pushed[0].addPropagateThis(cx, script, pc, GetCalleeThisType(pc));
break;
}
@ -3836,8 +3817,6 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen
StackTypeSet *seen = bytecodeTypes(pc);
addTypeBarrier(cx, pc, seen, Type::UnknownType());
seen->addSubset(cx, &pushed[0]);
if (op == JSOP_CALLNAME || op == JSOP_CALLINTRINSIC)
pushed[0].addPropagateThis(cx, script, pc, GetCalleeThisType(pc));
break;
}
@ -3885,8 +3864,6 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen
/* Local 'let' variable. Punt on types for these, for now. */
pushed[0].addType(cx, Type::UnknownType());
}
if (op == JSOP_CALLARG || op == JSOP_CALLLOCAL)
pushed[0].addPropagateThis(cx, script, pc, Type::UndefinedType());
break;
}
@ -3917,8 +3894,6 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen
* variable. Instead, we monitor/barrier all reads unconditionally.
*/
bytecodeTypes(pc)->addSubset(cx, &pushed[0]);
if (op == JSOP_CALLALIASEDVAR)
pushed[0].addPropagateThis(cx, script, pc, Type::UnknownType());
break;
case JSOP_SETALIASEDVAR:
@ -4035,8 +4010,6 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen
}
seen->addSubset(cx, &pushed[0]);
if (op == JSOP_CALLELEM)
pushed[0].addPropagateThis(cx, script, pc, Type::UndefinedType(), poppedTypes(pc, 1));
break;
}
@ -4133,7 +4106,24 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferen
if (op == JSOP_FUNCALL || op == JSOP_FUNAPPLY)
cx->compartment->types.monitorBytecode(cx, script, pc - script_->code);
poppedTypes(pc, argCount + 1)->addCall(cx, callsite);
StackTypeSet *calleeTypes = poppedTypes(pc, argCount + 1);
/*
* Propagate possible 'this' types to the callee except when the call
* came through JSOP_CALLPROP (which uses TypeConstraintCallProperty)
* or for JSOP_NEW (where the callee will construct the 'this' object).
*/
SSAValue calleeValue = poppedValue(pc, argCount + 1);
if (*pc != JSOP_NEW &&
(calleeValue.kind() != SSAValue::PUSHED ||
script->code[calleeValue.pushedOffset()] != JSOP_CALLPROP))
{
HandleScript script_ = script;
calleeTypes->add(cx, cx->analysisLifoAlloc().new_<TypeConstraintPropagateThis>
(script_, pc, Type::UndefinedType(), callsite->thisTypes));
}
calleeTypes->addCall(cx, callsite);
break;
}

View File

@ -704,7 +704,7 @@ MakeJITScript(JSContext *cx, JSScript *script)
Bytecode *code = analysis->maybeCode(offset);
if (!code)
continue;
op = JSOP_NOP; /* Ignore edges from unreachable opcodes. */
/* Whether this should be the last opcode in the chunk. */
bool finishChunk = false;
@ -1292,17 +1292,7 @@ mjit::Compiler::markUndefinedLocal(uint32_t offset, uint32_t i)
uint32_t depth = ssa.getFrame(a->inlineIndex).depth;
uint32_t slot = LocalSlot(script_, i);
Address local(JSFrameReg, sizeof(StackFrame) + (depth + i) * sizeof(Value));
if (!cx->typeInferenceEnabled() || !analysis->trackSlot(slot)) {
masm.storeValue(UndefinedValue(), local);
} else {
Lifetime *lifetime = analysis->liveness(slot).live(offset);
if (lifetime)
masm.storeValue(UndefinedValue(), local);
#ifdef DEBUG
else
masm.storeValue(ObjectValueCrashOnTouch(), local);
#endif
}
masm.storeValue(UndefinedValue(), local);
}
void

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