зеркало из https://github.com/mozilla/pjs.git
Merge last PGO green changeset on inbound to m-c.
This commit is contained in:
Коммит
6d2ef14f81
|
@ -632,9 +632,9 @@ ApplicationAccessibleWrap::Init()
|
|||
if (NS_SUCCEEDED(rv)) {
|
||||
// init atk-bridge
|
||||
(*sAtkBridge.init)();
|
||||
}
|
||||
else
|
||||
} else {
|
||||
MAI_LOG_DEBUG(("Fail to load lib: %s\n", sAtkBridge.libName));
|
||||
}
|
||||
|
||||
if (!sToplevel_event_hook_added) {
|
||||
sToplevel_event_hook_added = true;
|
||||
|
|
|
@ -1382,10 +1382,11 @@ nsresult
|
|||
nsAccessibleWrap::FireAtkShowHideEvent(AccEvent* aEvent,
|
||||
AtkObject *aObject, bool aIsAdded)
|
||||
{
|
||||
if (aIsAdded)
|
||||
if (aIsAdded) {
|
||||
MAI_LOG_DEBUG(("\n\nReceived: Show event\n"));
|
||||
else
|
||||
} else {
|
||||
MAI_LOG_DEBUG(("\n\nReceived: Hide event\n"));
|
||||
}
|
||||
|
||||
PRInt32 indexInParent = getIndexInParentCB(aObject);
|
||||
AtkObject *parentObject = getParentCB(aObject);
|
||||
|
|
|
@ -280,7 +280,7 @@ XULDescriptionIterator::Next()
|
|||
IDRefsIterator::
|
||||
IDRefsIterator(nsDocAccessible* aDoc, nsIContent* aContent,
|
||||
nsIAtom* aIDRefsAttr) :
|
||||
mCurrIdx(0), mContent(aContent), mDoc(aDoc)
|
||||
mContent(aContent), mDoc(aDoc), mCurrIdx(0)
|
||||
{
|
||||
if (mContent->IsInDoc())
|
||||
mContent->GetAttr(kNameSpaceID_None, aIDRefsAttr, mIDs);
|
||||
|
|
|
@ -63,8 +63,8 @@ public:
|
|||
* Constructor. Used to expose default text attributes.
|
||||
*/
|
||||
TextAttrsMgr(nsHyperTextAccessible* aHyperTextAcc) :
|
||||
mHyperTextAcc(aHyperTextAcc), mIncludeDefAttrs(true),
|
||||
mOffsetAcc(nsnull), mOffsetAccIdx(-1) { }
|
||||
mOffsetAcc(nsnull), mHyperTextAcc(aHyperTextAcc),
|
||||
mOffsetAccIdx(-1), mIncludeDefAttrs(true) { }
|
||||
|
||||
/**
|
||||
* Constructor. Used to expose text attributes at the given offset.
|
||||
|
@ -82,8 +82,8 @@ public:
|
|||
bool aIncludeDefAttrs,
|
||||
nsAccessible* aOffsetAcc,
|
||||
PRInt32 aOffsetAccIdx) :
|
||||
mHyperTextAcc(aHyperTextAcc), mIncludeDefAttrs(aIncludeDefAttrs),
|
||||
mOffsetAcc(aOffsetAcc), mOffsetAccIdx(aOffsetAccIdx) { }
|
||||
mOffsetAcc(aOffsetAcc), mHyperTextAcc(aHyperTextAcc),
|
||||
mOffsetAccIdx(aOffsetAccIdx), mIncludeDefAttrs(aIncludeDefAttrs) { }
|
||||
|
||||
/*
|
||||
* Return text attributes and hyper text offsets where these attributes are
|
||||
|
@ -118,8 +118,8 @@ protected:
|
|||
private:
|
||||
nsAccessible* mOffsetAcc;
|
||||
nsHyperTextAccessible* mHyperTextAcc;
|
||||
PRInt32 mOffsetAccIdx;
|
||||
bool mIncludeDefAttrs;
|
||||
PRInt32 mOffsetAccIdx;
|
||||
bool mIncludeDefAttrs;
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -301,8 +301,8 @@
|
|||
; JavaScript components
|
||||
@BINPATH@/components/ConsoleAPI.manifest
|
||||
@BINPATH@/components/ConsoleAPI.js
|
||||
@BINPATH@/components/BrowserElementAPI.manifest
|
||||
@BINPATH@/components/BrowserElementAPI.js
|
||||
@BINPATH@/components/BrowserElementParent.manifest
|
||||
@BINPATH@/components/BrowserElementParent.js
|
||||
@BINPATH@/components/ContactManager.js
|
||||
@BINPATH@/components/ContactManager.manifest
|
||||
@BINPATH@/components/FeedProcessor.manifest
|
||||
|
|
|
@ -1147,9 +1147,14 @@ pref("browser.newtab.url", "about:newtab");
|
|||
// Toggles the content of 'about:newtab'. Shows the grid when enabled.
|
||||
pref("browser.newtabpage.enabled", true);
|
||||
|
||||
// Enable the DOM full-screen API.
|
||||
// Enable the DOM fullscreen API.
|
||||
pref("full-screen-api.enabled", true);
|
||||
|
||||
// True if the fullscreen API requires approval upon a domain entering fullscreen.
|
||||
// Domains that have already had fullscreen permission granted won't re-request
|
||||
// approval.
|
||||
pref("full-screen-api.approval-required", true);
|
||||
|
||||
// Startup Crash Tracking
|
||||
// number of startup crashes that can occur before starting into safe mode automatically
|
||||
// (this pref has no effect if more than 6 hours have passed since the last crash)
|
||||
|
|
|
@ -372,6 +372,16 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
|
|||
|
||||
#full-screen-warning-message {
|
||||
pointer-events: auto;
|
||||
/* We must specify a max-width, otherwise word-wrap:break-word doesn't
|
||||
work in descendant <description> and <label> elements. Bug 630864. */
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
#full-screen-domain-text,
|
||||
#full-screen-remember-decision > .checkbox-label-box > .checkbox-label {
|
||||
word-wrap: break-word;
|
||||
/* We must specify a min-width, otherwise word-wrap:break-word doesn't work. Bug 630864. */
|
||||
min-width: 1px;
|
||||
}
|
||||
|
||||
#nav-bar[mode="text"] > #window-controls > toolbarbutton > .toolbarbutton-icon {
|
||||
|
|
|
@ -434,7 +434,7 @@ function findChildShell(aDocument, aDocShell, aSoughtURI) {
|
|||
|
||||
var gPopupBlockerObserver = {
|
||||
_reportButton: null,
|
||||
|
||||
|
||||
onReportButtonClick: function (aEvent)
|
||||
{
|
||||
if (aEvent.button != 0 || aEvent.target != this._reportButton)
|
||||
|
@ -564,7 +564,7 @@ var gPopupBlockerObserver = {
|
|||
if (pageReport) {
|
||||
for (var i = 0; i < pageReport.length; ++i) {
|
||||
// popupWindowURI will be null if the file picker popup is blocked.
|
||||
// xxxdz this should make the option say "Show file picker" and do it (Bug 590306)
|
||||
// xxxdz this should make the option say "Show file picker" and do it (Bug 590306)
|
||||
if (!pageReport[i].popupWindowURI)
|
||||
continue;
|
||||
var popupURIspec = pageReport[i].popupWindowURI.spec;
|
||||
|
@ -1674,16 +1674,12 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
|||
|
||||
// Called when we enter DOM full-screen mode. Note we can already be in browser
|
||||
// full-screen mode when we enter DOM full-screen mode.
|
||||
window.addEventListener("mozfullscreenchange", onMozFullScreenChange, true);
|
||||
|
||||
// When a restricted key is pressed in DOM full-screen mode, we should display
|
||||
// the "Press ESC to exit" warning message.
|
||||
window.addEventListener("MozShowFullScreenWarning", onShowFullScreenWarning, true);
|
||||
window.addEventListener("MozEnteredDomFullscreen", onMozEnteredDomFullscreen, true);
|
||||
|
||||
if (window.fullScreen)
|
||||
onFullScreen();
|
||||
if (document.mozFullScreen)
|
||||
onMozFullScreenChange();
|
||||
onMozEnteredDomFullscreen();
|
||||
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
// initialize the sync UI
|
||||
|
@ -2929,12 +2925,8 @@ function onFullScreen(event) {
|
|||
FullScreen.toggle(event);
|
||||
}
|
||||
|
||||
function onMozFullScreenChange(event) {
|
||||
FullScreen.enterDomFullScreen(event);
|
||||
}
|
||||
|
||||
function onShowFullScreenWarning(event) {
|
||||
FullScreen.showWarning(false);
|
||||
function onMozEnteredDomFullscreen(event) {
|
||||
FullScreen.enterDomFullscreen(event);
|
||||
}
|
||||
|
||||
function getWebNavigation()
|
||||
|
@ -3148,7 +3140,7 @@ function FillInHTMLTooltip(tipElement)
|
|||
|
||||
[titleText, XLinkTitleText, SVGTitleText].forEach(function (t) {
|
||||
if (t && /\S/.test(t)) {
|
||||
// Make CRLF and CR render one line break each.
|
||||
// Make CRLF and CR render one line break each.
|
||||
t = t.replace(/\r\n?/g, '\n');
|
||||
|
||||
tipNode.setAttribute("label", t);
|
||||
|
@ -3483,7 +3475,7 @@ const BrowserSearch = {
|
|||
}
|
||||
win = window.openDialog(getBrowserURL(), "_blank",
|
||||
"chrome,all,dialog=no", "about:blank");
|
||||
Services.obs.addObserver(observer, "browser-delayed-startup-finished", false);
|
||||
Services.obs.addObserver(observer, "browser-delayed-startup-finished", false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -4019,33 +4011,29 @@ var FullScreen = {
|
|||
// middle of window lowering. See bug 729872.
|
||||
setTimeout(this.exitDomFullScreen.bind(this), 0);
|
||||
break;
|
||||
case "transitionend":
|
||||
if (event.propertyName == "opacity")
|
||||
this.cancelWarning();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
enterDomFullScreen : function(event) {
|
||||
if (!document.mozFullScreen) {
|
||||
enterDomFullscreen : function(event) {
|
||||
if (!document.mozFullScreen)
|
||||
return;
|
||||
|
||||
// However, if we receive a "MozEnteredDomFullScreen" event for a document
|
||||
// which is not a subdocument of the currently selected tab, we know that
|
||||
// we've switched tabs since the request to enter full-screen was made,
|
||||
// so we should exit full-screen since the "full-screen document" isn't
|
||||
// acutally visible.
|
||||
if (event.target.defaultView.top != gBrowser.contentWindow) {
|
||||
document.mozCancelFullScreen();
|
||||
return;
|
||||
}
|
||||
|
||||
// We receive "mozfullscreenchange" events for each subdocument which
|
||||
// is an ancestor of the document containing the element which requested
|
||||
// full-screen. Only add listeners and show warning etc when the event we
|
||||
// receive is targeted at the chrome document, i.e. only once every time
|
||||
// we enter DOM full-screen mode.
|
||||
if (event.target != document) {
|
||||
// However, if we receive a "mozfullscreenchange" event for a document
|
||||
// which is not a subdocument of the currently selected tab, we know that
|
||||
// we've switched tabs since the request to enter full-screen was made,
|
||||
// so we should exit full-screen since the "full-screen document" isn't
|
||||
// acutally visible.
|
||||
if (event.target.defaultView.top != gBrowser.contentWindow) {
|
||||
document.mozCancelFullScreen();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let focusManger = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
|
||||
if (focusManger.activeWindow != window) {
|
||||
let focusManager = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
|
||||
if (focusManager.activeWindow != window) {
|
||||
// The top-level window has lost focus since the request to enter
|
||||
// full-screen was made. Cancel full-screen.
|
||||
document.mozCancelFullScreen();
|
||||
|
@ -4059,7 +4047,7 @@ var FullScreen = {
|
|||
if (gFindBarInitialized)
|
||||
gFindBar.close();
|
||||
|
||||
this.showWarning(true);
|
||||
this.showWarning(event.target);
|
||||
|
||||
// Exit DOM full-screen mode upon open, close, or change tab.
|
||||
gBrowser.tabContainer.addEventListener("TabOpen", this.exitDomFullScreen);
|
||||
|
@ -4104,9 +4092,8 @@ var FullScreen = {
|
|||
gBrowser.tabContainer.removeEventListener("TabOpen", this.exitDomFullScreen);
|
||||
gBrowser.tabContainer.removeEventListener("TabClose", this.exitDomFullScreen);
|
||||
gBrowser.tabContainer.removeEventListener("TabSelect", this.exitDomFullScreen);
|
||||
if (!this.useLionFullScreen) {
|
||||
if (!this.useLionFullScreen)
|
||||
window.removeEventListener("deactivate", this);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -4240,81 +4227,116 @@ var FullScreen = {
|
|||
},
|
||||
|
||||
cancelWarning: function(event) {
|
||||
if (!this.warningBox) {
|
||||
if (!this.warningBox)
|
||||
return;
|
||||
}
|
||||
if (this.onWarningHidden) {
|
||||
this.warningBox.removeEventListener("transitionend", this.onWarningHidden, false);
|
||||
this.onWarningHidden = null;
|
||||
}
|
||||
this.fullscreenDocUri = null;
|
||||
this.warningBox.removeEventListener("transitionend", this);
|
||||
if (this.warningFadeOutTimeout) {
|
||||
clearTimeout(this.warningFadeOutTimeout);
|
||||
this.warningFadeOutTimeout = null;
|
||||
}
|
||||
if (this.revealBrowserTimeout) {
|
||||
clearTimeout(this.revealBrowserTimeout);
|
||||
this.revealBrowserTimeout = null;
|
||||
}
|
||||
this.warningBox.removeAttribute("fade-warning-out");
|
||||
this.warningBox.removeAttribute("stop-obscuring-browser");
|
||||
this.warningBox.removeAttribute("obscure-browser");
|
||||
|
||||
// Ensure focus switches away from the (now hidden) warning box. If the user
|
||||
// clicked buttons in the fullscreen key authorization UI, it would have been
|
||||
// focused, and any key events would be directed at the (now hidden) chrome
|
||||
// document instead of the target document.
|
||||
gBrowser.selectedBrowser.focus();
|
||||
|
||||
this.warningBox.setAttribute("hidden", true);
|
||||
this.warningBox.removeAttribute("fade-warning-out");
|
||||
this.warningBox.removeAttribute("obscure-browser");
|
||||
this.warningBox = null;
|
||||
},
|
||||
|
||||
setFullscreenAllowed: function(isApproved) {
|
||||
let remember = document.getElementById("full-screen-remember-decision").checked;
|
||||
if (remember)
|
||||
Services.perms.add(this.fullscreenDocUri,
|
||||
"fullscreen",
|
||||
isApproved ? Services.perms.ALLOW_ACTION : Services.perms.DENY_ACTION,
|
||||
Services.perms.EXPIRE_NEVER);
|
||||
else if (isApproved) {
|
||||
// The user has only temporarily approved fullscren for this domain.
|
||||
// Add the permission (so Gecko knows fullscreen is approved) but add a
|
||||
// listener to remove the permission when the chrome document exits fullscreen.
|
||||
Services.perms.add(this.fullscreenDocUri,
|
||||
"fullscreen",
|
||||
Services.perms.ALLOW_ACTION,
|
||||
Services.perms.EXPIRE_SESSION);
|
||||
let host = this.fullscreenDocUri.host;
|
||||
function onFullscreenchange(event) {
|
||||
if (event.target == document && document.mozFullScreenElement == null) {
|
||||
// The chrome document has left fullscreen. Remove the temporary permission grant.
|
||||
Services.perms.remove(host, "fullscreen");
|
||||
document.removeEventListener("mozfullscreenchange", onFullscreenchange);
|
||||
}
|
||||
}
|
||||
document.addEventListener("mozfullscreenchange", onFullscreenchange);
|
||||
}
|
||||
if (this.warningBox)
|
||||
this.warningBox.setAttribute("fade-warning-out", "true");
|
||||
if (!isApproved)
|
||||
document.mozCancelFullScreen();
|
||||
},
|
||||
|
||||
warningBox: null,
|
||||
warningFadeOutTimeout: null,
|
||||
revealBrowserTimeout: null,
|
||||
onWarningHidden: null,
|
||||
fullscreenDocUri: null,
|
||||
|
||||
// Fade in a warning that document has entered full-screen, and then fade it
|
||||
// out after a few seconds.
|
||||
showWarning: function(obscureBackground) {
|
||||
if (!document.mozFullScreen || !gPrefService.getBoolPref("full-screen-api.warning.enabled")) {
|
||||
// Shows the fullscreen approval UI, or if the domain has already been approved
|
||||
// for fullscreen, shows a warning that the site has entered fullscreen for a short
|
||||
// duration.
|
||||
showWarning: function(targetDoc) {
|
||||
if (!document.mozFullScreen ||
|
||||
!gPrefService.getBoolPref("full-screen-api.approval-required"))
|
||||
return;
|
||||
}
|
||||
if (this.warningBox) {
|
||||
// Warning is already showing. Reset the timer which fades out the warning message,
|
||||
// and we'll restart the timer down below.
|
||||
if (this.warningFadeOutTimeout) {
|
||||
clearTimeout(this.warningFadeOutTimeout);
|
||||
this.warningFadeOutTimeout = null;
|
||||
}
|
||||
} else {
|
||||
|
||||
// Set the strings on the fullscreen approval UI.
|
||||
this.fullscreenDocUri = targetDoc.nodePrincipal.URI;
|
||||
let utils = {};
|
||||
Cu.import("resource://gre/modules/DownloadUtils.jsm", utils);
|
||||
let [displayHost, fullHost] = utils.DownloadUtils.getURIHost(this.fullscreenDocUri.spec);
|
||||
let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
|
||||
let domainText = bundle.formatStringFromName("fullscreen.entered", [displayHost], 1);
|
||||
document.getElementById("full-screen-domain-text").textContent = domainText;
|
||||
let rememberText = bundle.formatStringFromName("fullscreen.rememberDecision", [displayHost], 1);
|
||||
document.getElementById("full-screen-remember-decision").label = rememberText;
|
||||
|
||||
// Note: the warning box can be non-null if the warning box from the previous request
|
||||
// wasn't hidden before another request was made.
|
||||
if (!this.warningBox) {
|
||||
this.warningBox = document.getElementById("full-screen-warning-container");
|
||||
// Add a listener to clean up state after the warning is hidden.
|
||||
this.onWarningHidden =
|
||||
function(event) {
|
||||
if (event.propertyName != "opacity")
|
||||
return;
|
||||
this.cancelWarning();
|
||||
}.bind(this);
|
||||
this.warningBox.addEventListener("transitionend", this.onWarningHidden, false);
|
||||
this.warningBox.addEventListener("transitionend", this);
|
||||
this.warningBox.removeAttribute("hidden");
|
||||
}
|
||||
|
||||
if (obscureBackground) {
|
||||
// Partially obscure the <browser> element underneath the warning panel...
|
||||
// If fullscreen mode has not yet been approved for the fullscreen
|
||||
// document's domain, show the approval UI and don't auto fade out the
|
||||
// fullscreen warning box. Otherwise, we're just notifying of entry into
|
||||
// fullscreen mode.
|
||||
let isApproved =
|
||||
Services.perms.testPermission(this.fullscreenDocUri, "fullscreen") == Services.perms.ALLOW_ACTION;
|
||||
let authUI = document.getElementById("full-screen-approval-pane");
|
||||
document.getElementById("full-screen-remember-decision").checked = false;
|
||||
if (isApproved)
|
||||
authUI.setAttribute("hidden", "true");
|
||||
else {
|
||||
// Partially obscure the <browser> element underneath the approval UI.
|
||||
this.warningBox.setAttribute("obscure-browser", "true");
|
||||
// ...But set a timeout to stop obscuring the browser after a few moments.
|
||||
this.warningBox.removeAttribute("stop-obscuring-browser");
|
||||
this.revealBrowserTimeout =
|
||||
authUI.removeAttribute("hidden");
|
||||
}
|
||||
|
||||
// If we're not showing the fullscreen approval UI, we're just notifying the user
|
||||
// of the transition, so set a timeout to fade the warning out after a few moments.
|
||||
if (isApproved)
|
||||
this.warningFadeOutTimeout =
|
||||
setTimeout(
|
||||
function() {
|
||||
if (this.warningBox)
|
||||
this.warningBox.setAttribute("stop-obscuring-browser", "true");
|
||||
this.warningBox.setAttribute("fade-warning-out", "true");
|
||||
}.bind(this),
|
||||
1250);
|
||||
}
|
||||
|
||||
// Set a timeout to fade the warning out after a few moments.
|
||||
this.warningFadeOutTimeout =
|
||||
setTimeout(
|
||||
function() {
|
||||
if (this.warningBox)
|
||||
this.warningBox.setAttribute("fade-warning-out", "true");
|
||||
}.bind(this),
|
||||
3000);
|
||||
3000);
|
||||
},
|
||||
|
||||
mouseoverToggle: function(aShow, forceHide)
|
||||
|
@ -6146,7 +6168,7 @@ function UpdateCharsetDetector(target) {
|
|||
prefvalue = gPrefService.getComplexValue("intl.charset.detector", Ci.nsIPrefLocalizedString).data;
|
||||
}
|
||||
catch (ex) {}
|
||||
|
||||
|
||||
if (!prefvalue)
|
||||
prefvalue = "off";
|
||||
|
||||
|
@ -9127,12 +9149,12 @@ XPCOMUtils.defineLazyGetter(this, "HUDConsoleUI", function () {
|
|||
}
|
||||
});
|
||||
|
||||
// Prompt user to restart the browser in safe mode
|
||||
// Prompt user to restart the browser in safe mode
|
||||
function safeModeRestart()
|
||||
{
|
||||
// prompt the user to confirm
|
||||
// prompt the user to confirm
|
||||
let promptTitle = gNavigatorBundle.getString("safeModeRestartPromptTitle");
|
||||
let promptMessage =
|
||||
let promptMessage =
|
||||
gNavigatorBundle.getString("safeModeRestartPromptMessage");
|
||||
let restartText = gNavigatorBundle.getString("safeModeRestartButton");
|
||||
let buttonFlags = (Services.prompt.BUTTON_POS_0 *
|
||||
|
|
|
@ -409,7 +409,7 @@
|
|||
<label class="tooltip-label" value="&backForwardButtonMenu.tooltip;"/>
|
||||
#endif
|
||||
</tooltip>
|
||||
|
||||
|
||||
<tooltip id="forward-button-tooltip">
|
||||
<label class="tooltip-label" value="&forwardButton.tooltip;"/>
|
||||
#ifdef XP_MACOSX
|
||||
|
@ -989,9 +989,22 @@
|
|||
|
||||
<hbox id="full-screen-warning-container" hidden="true" fadeout="true">
|
||||
<hbox style="width: 100%;" pack="center"> <!-- Inner hbox needed due to bug 579776. -->
|
||||
<hbox id="full-screen-warning-message">
|
||||
<description id="full-screen-warning-text" value="&domFullScreenWarning.label;"></description>
|
||||
</hbox>
|
||||
<vbox id="full-screen-warning-message" align="center">
|
||||
<description id="full-screen-domain-text"/>
|
||||
<description class="full-screen-description" value="&fullscreenExitHint.value;"/>
|
||||
<vbox id="full-screen-approval-pane" align="center">
|
||||
<description class="full-screen-description" value="&fullscreenApproval.value;"/>
|
||||
<hbox>
|
||||
<button label="&fullscreenAllowButton.label;"
|
||||
oncommand="FullScreen.setFullscreenAllowed(true);"
|
||||
class="full-screen-approval-button"/>
|
||||
<button label="&fullscreenExitButton.label;"
|
||||
oncommand="FullScreen.setFullscreenAllowed(false);"
|
||||
class="full-screen-approval-button"/>
|
||||
</hbox>
|
||||
<checkbox id="full-screen-remember-decision"/>
|
||||
</vbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</hbox>
|
||||
|
||||
|
|
|
@ -89,6 +89,7 @@
|
|||
<command id="cmd_popupDef" oncommand="onCheckboxClick('popup');"/>
|
||||
<command id="cmd_cookieDef" oncommand="onCheckboxClick('cookie');"/>
|
||||
<command id="cmd_installDef" oncommand="onCheckboxClick('install');"/>
|
||||
<command id="cmd_fullscreenDef" oncommand="onCheckboxClick('fullscreen');"/>
|
||||
<command id="cmd_geoDef" oncommand="onCheckboxClick('geo');"/>
|
||||
<command id="cmd_indexedDBDef" oncommand="onCheckboxClick('indexedDB');"/>
|
||||
<command id="cmd_pluginsDef" oncommand="onCheckboxClick('plugins');"/>
|
||||
|
@ -96,6 +97,7 @@
|
|||
<command id="cmd_popupToggle" oncommand="onRadioClick('popup');"/>
|
||||
<command id="cmd_cookieToggle" oncommand="onRadioClick('cookie');"/>
|
||||
<command id="cmd_installToggle" oncommand="onRadioClick('install');"/>
|
||||
<command id="cmd_fullscreenToggle" oncommand="onRadioClick('fullscreen');"/>
|
||||
<command id="cmd_geoToggle" oncommand="onRadioClick('geo');"/>
|
||||
<command id="cmd_indexedDBToggle" oncommand="onRadioClick('indexedDB');"/>
|
||||
<command id="cmd_pluginsToggle" oncommand="onRadioClick('plugins');"/>
|
||||
|
@ -416,6 +418,19 @@
|
|||
</radiogroup>
|
||||
</hbox>
|
||||
</vbox>
|
||||
<vbox class="permission">
|
||||
<label class="permissionLabel" id="permFullscreenLabel"
|
||||
value="&permFullscreen;" control="fullscreenRadioGroup"/>
|
||||
<hbox role="group" aria-labelledby="permFullscreenLabel">
|
||||
<checkbox id="fullscreenDef" command="cmd_fullscreenDef" label="&permUseDefault;"/>
|
||||
<spacer flex="1"/>
|
||||
<radiogroup id="fullscreenRadioGroup" orient="horizontal">
|
||||
<radio id="fullscreen#0" command="cmd_fullscreenToggle" label="&permAskAlways;"/>
|
||||
<radio id="fullscreen#1" command="cmd_fullscreenToggle" label="&permAllow;"/>
|
||||
<radio id="fullscreen#2" command="cmd_fullscreenToggle" label="&permBlock;"/>
|
||||
</radiogroup>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</vbox>
|
||||
</vbox>
|
||||
|
||||
|
|
|
@ -33,9 +33,11 @@
|
|||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
const ALLOW = nsIPermissionManager.ALLOW_ACTION; // 1
|
||||
const BLOCK = nsIPermissionManager.DENY_ACTION; // 2
|
||||
const SESSION = nsICookiePermission.ACCESS_SESSION;// 8
|
||||
|
||||
const UNKNOWN = nsIPermissionManager.UNKNOWN_ACTION; // 0
|
||||
const ALLOW = nsIPermissionManager.ALLOW_ACTION; // 1
|
||||
const BLOCK = nsIPermissionManager.DENY_ACTION; // 2
|
||||
const SESSION = nsICookiePermission.ACCESS_SESSION; // 8
|
||||
|
||||
const nsIIndexedDatabaseManager =
|
||||
Components.interfaces.nsIIndexedDatabaseManager;
|
||||
|
@ -88,6 +90,10 @@ var gPermObj = {
|
|||
if (gPrefs.getBoolPref("plugins.click_to_play"))
|
||||
return BLOCK;
|
||||
return ALLOW;
|
||||
},
|
||||
fullscreen: function getFullscreenDefaultPermissions()
|
||||
{
|
||||
return UNKNOWN;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -200,6 +206,9 @@ function onRadioClick(aPartId)
|
|||
if (aPartId == "indexedDB" && permission == BLOCK) {
|
||||
permissionManager.remove(gPermURI.host, "indexedDB-unlimited");
|
||||
}
|
||||
if (aPartId == "fullscreen" && permission == UNKNOWN) {
|
||||
permissionManager.remove(gPermURI.host, "fullscreen");
|
||||
}
|
||||
}
|
||||
|
||||
function setRadioState(aPartId, aValue)
|
||||
|
|
|
@ -364,6 +364,17 @@ let PermissionDefaults = {
|
|||
set plugins(aValue) {
|
||||
let value = (aValue != this.ALLOW);
|
||||
Services.prefs.setBoolPref("plugins.click_to_play", value);
|
||||
},
|
||||
|
||||
get fullscreen() {
|
||||
if (!Services.prefs.getBoolPref("full-screen-api.enabled")) {
|
||||
return this.DENY;
|
||||
}
|
||||
return this.UNKNOWN;
|
||||
},
|
||||
set fullscreen(aValue) {
|
||||
let value = (aValue != this.DENY);
|
||||
Services.prefs.setBoolPref("full-screen-api.enabled", value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -403,12 +414,12 @@ let AboutPermissions = {
|
|||
*
|
||||
* Potential future additions: "sts/use", "sts/subd"
|
||||
*/
|
||||
_supportedPermissions: ["password", "cookie", "geo", "indexedDB", "popup", "plugins"],
|
||||
_supportedPermissions: ["password", "cookie", "geo", "indexedDB", "popup", "plugins", "fullscreen"],
|
||||
|
||||
/**
|
||||
* Permissions that don't have a global "Allow" option.
|
||||
*/
|
||||
_noGlobalAllow: ["geo", "indexedDB"],
|
||||
_noGlobalAllow: ["geo", "indexedDB", "fullscreen"],
|
||||
|
||||
/**
|
||||
* Permissions that don't have a global "Deny" option.
|
||||
|
@ -436,6 +447,7 @@ let AboutPermissions = {
|
|||
Services.prefs.addObserver("dom.indexedDB.enabled", this, false);
|
||||
Services.prefs.addObserver("dom.disable_open_during_load", this, false);
|
||||
Services.prefs.addObserver("plugins.click_to_play", this, false);
|
||||
Services.prefs.addObserver("full-screen-api.enabled", this, false);
|
||||
|
||||
Services.obs.addObserver(this, "perm-changed", false);
|
||||
Services.obs.addObserver(this, "passwordmgr-storage-changed", false);
|
||||
|
@ -457,6 +469,7 @@ let AboutPermissions = {
|
|||
Services.prefs.removeObserver("dom.indexedDB.enabled", this, false);
|
||||
Services.prefs.removeObserver("dom.disable_open_during_load", this, false);
|
||||
Services.prefs.removeObserver("plugins.click_to_play", this, false);
|
||||
Services.prefs.removeObserver("full-screen-api.enabled", this, false);
|
||||
|
||||
Services.obs.removeObserver(this, "perm-changed", false);
|
||||
Services.obs.removeObserver(this, "passwordmgr-storage-changed", false);
|
||||
|
|
|
@ -244,6 +244,27 @@
|
|||
</vbox>
|
||||
</hbox>
|
||||
|
||||
<!-- Fullscreen -->
|
||||
<hbox id="fullscreen-pref-item"
|
||||
class="pref-item" align="top">
|
||||
<image class="pref-icon" type="fullscreen"/>
|
||||
<vbox>
|
||||
<label class="pref-title" value="&fullscreen.label;"/>
|
||||
<hbox align="center">
|
||||
<menulist id="fullscreen-menulist"
|
||||
class="pref-menulist"
|
||||
type="fullscreen"
|
||||
oncommand="AboutPermissions.onPermissionCommand(event);">
|
||||
<menupopup>
|
||||
<menuitem id="fullscreen-0" value="0" label="&permission.alwaysAsk;"/>
|
||||
<menuitem id="fullscreen-1" value="1" label="&permission.allow;"/>
|
||||
<menuitem id="fullscreen-2" value="2" label="&permission.block;"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
||||
|
|
|
@ -22,16 +22,18 @@ const TEST_PERMS = {
|
|||
"geo": PERM_UNKNOWN,
|
||||
"indexedDB": PERM_UNKNOWN,
|
||||
"popup": PERM_DENY,
|
||||
"plugins" : PERM_ALLOW
|
||||
"plugins" : PERM_ALLOW,
|
||||
"fullscreen" : PERM_UNKNOWN,
|
||||
};
|
||||
|
||||
const NO_GLOBAL_ALLOW = [
|
||||
"geo",
|
||||
"indexedDB"
|
||||
"indexedDB",
|
||||
"fullscreen"
|
||||
];
|
||||
|
||||
// number of managed permissions in the interface
|
||||
const TEST_PERMS_COUNT = 6;
|
||||
const TEST_PERMS_COUNT = 7;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
|
|
@ -107,6 +107,10 @@ let PageThumbs = {
|
|||
* containing the image data.
|
||||
*/
|
||||
capture: function PageThumbs_capture(aWindow, aCallback) {
|
||||
if (!this._prefEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let telemetryCaptureTime = new Date();
|
||||
let [sw, sh, scale] = this._determineCropSize(aWindow);
|
||||
|
||||
|
@ -137,6 +141,10 @@ let PageThumbs = {
|
|||
* @param aCallback The function to be called when finished (optional).
|
||||
*/
|
||||
captureAndStore: function PageThumbs_captureAndStore(aBrowser, aCallback) {
|
||||
if (!this._prefEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let url = aBrowser.currentURI.spec;
|
||||
let channel = aBrowser.docShell.currentDocumentChannel;
|
||||
let originalURL = channel.originalURI.spec;
|
||||
|
@ -224,7 +232,16 @@ let PageThumbs = {
|
|||
this._thumbnailHeight = Math.round(height.value / 3);
|
||||
}
|
||||
return [this._thumbnailWidth, this._thumbnailHeight];
|
||||
}
|
||||
},
|
||||
|
||||
_prefEnabled: function PageThumbs_prefEnabled() {
|
||||
try {
|
||||
return Services.prefs.getBoolPref("browser.pageThumbs.enabled");
|
||||
}
|
||||
catch (e) {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let PageThumbsStorage = {
|
||||
|
|
|
@ -294,8 +294,8 @@
|
|||
; JavaScript components
|
||||
@BINPATH@/components/ConsoleAPI.manifest
|
||||
@BINPATH@/components/ConsoleAPI.js
|
||||
@BINPATH@/components/BrowserElementAPI.manifest
|
||||
@BINPATH@/components/BrowserElementAPI.js
|
||||
@BINPATH@/components/BrowserElementParent.manifest
|
||||
@BINPATH@/components/BrowserElementParent.js
|
||||
@BINPATH@/components/FeedProcessor.manifest
|
||||
@BINPATH@/components/FeedProcessor.js
|
||||
@BINPATH@/components/BrowserFeeds.manifest
|
||||
|
|
|
@ -90,7 +90,10 @@ can reach it easily. -->
|
|||
<!ENTITY fullScreenAutohide.accesskey "H">
|
||||
<!ENTITY fullScreenExit.label "Exit Full Screen Mode">
|
||||
<!ENTITY fullScreenExit.accesskey "F">
|
||||
<!ENTITY domFullScreenWarning.label "Press ESC to leave full-screen mode">
|
||||
<!ENTITY fullscreenAllowButton.label "Allow">
|
||||
<!ENTITY fullscreenExitButton.label "Deny">
|
||||
<!ENTITY fullscreenApproval.value "Allow fullscreen?">
|
||||
<!ENTITY fullscreenExitHint.value "Press ESC at any time to exit fullscreen.">
|
||||
|
||||
<!ENTITY closeWindow.label "Close Window">
|
||||
<!ENTITY closeWindow.accesskey "d">
|
||||
|
|
|
@ -352,3 +352,8 @@ webapps.requestInstall = Do you want to install "%1$S" from this site (%2$S)?
|
|||
# LOCALIZATION NOTE (telemetryOptOutPrompt): %1$S and %3$S will be replaced by
|
||||
# brandFullName, and %2$S by the value of the toolkit.telemetry.server_owner preference.
|
||||
telemetryOptOutPrompt = %1$S sends information about performance, hardware, usage and customizations back to %2$S to help improve %3$S.
|
||||
|
||||
# LOCALIZATION NOTE (fullscreen.entered): displayed when we enter HTML5 fullscreen mode, %S is the domain name of the focused website (e.g. mozilla.com).
|
||||
fullscreen.entered=%S is now fullscreen.
|
||||
# LOCALIZATION NOTE (fullscreen.rememberDecision): displayed when we enter HTML5 fullscreen mode, %S is the domain name of the focused website (e.g. mozilla.com).
|
||||
fullscreen.rememberDecision=Remember decision for %S
|
||||
|
|
|
@ -99,6 +99,7 @@
|
|||
<!ENTITY permInstall "Install Extensions or Themes">
|
||||
<!ENTITY permGeo "Share Location">
|
||||
<!ENTITY permPlugins "Activate Plugins">
|
||||
<!ENTITY permFullscreen "Enter Fullscreen">
|
||||
|
||||
<!ENTITY permIndexedDB "Maintain Offline Storage">
|
||||
<!ENTITY permClearStorage "Clear Storage">
|
||||
|
|
|
@ -35,3 +35,5 @@
|
|||
<!ENTITY indexedDB.label "Maintain Offline Storage">
|
||||
|
||||
<!ENTITY popup.label "Open Pop-up Windows">
|
||||
|
||||
<!ENTITY fullscreen.label "Fullscreen">
|
||||
|
|
|
@ -207,7 +207,7 @@ menuitem.bookmark-item {
|
|||
list-style-image: url("moz-icon://stock/gtk-directory?size=menu");
|
||||
}
|
||||
|
||||
.bookmark-item[container][livemark] {
|
||||
.bookmark-item[container][livemark] {
|
||||
list-style-image: url("chrome://browser/skin/feeds/feedIcon16.png");
|
||||
}
|
||||
|
||||
|
@ -1307,7 +1307,7 @@ toolbar[iconsize="small"] #feed-button {
|
|||
}
|
||||
|
||||
#treecolAutoCompleteImage {
|
||||
max-width : 36px;
|
||||
max-width : 36px;
|
||||
}
|
||||
|
||||
.ac-result-type-bookmark,
|
||||
|
@ -1359,7 +1359,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
|||
color: inherit !important;
|
||||
}
|
||||
|
||||
.autocomplete-treebody::-moz-tree-cell-text(suggesthint, treecolAutoCompleteComment),
|
||||
.autocomplete-treebody::-moz-tree-cell-text(suggesthint, treecolAutoCompleteComment),
|
||||
.autocomplete-treebody::-moz-tree-cell-text(suggestfirst, treecolAutoCompleteComment) {
|
||||
color: GrayText;
|
||||
font-size: smaller;
|
||||
|
@ -2152,7 +2152,6 @@ html|*#highlighter-nodeinfobar-pseudo-classes {
|
|||
#full-screen-warning-message {
|
||||
background-color: hsl(0,0%,15%);
|
||||
color: white;
|
||||
font-size: 32px;
|
||||
border-radius: 8px;
|
||||
margin-top: 30px;
|
||||
padding: 30px 50px;
|
||||
|
@ -2160,13 +2159,20 @@ html|*#highlighter-nodeinfobar-pseudo-classes {
|
|||
}
|
||||
|
||||
#full-screen-warning-container[obscure-browser] {
|
||||
background-color: rgba(0,0,0,0.75);
|
||||
background-color: rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
#full-screen-warning-container[stop-obscuring-browser] {
|
||||
-moz-transition-property: background-color;
|
||||
-moz-transition-duration: 500ms;
|
||||
background-color: rgba(0,0,0,0);
|
||||
.full-screen-description {
|
||||
font-size: 150%;
|
||||
}
|
||||
|
||||
#full-screen-domain-text {
|
||||
font-size: 300%;
|
||||
}
|
||||
|
||||
.full-screen-approval-button,
|
||||
#full-screen-remember-decision {
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
/* Highlighter toolbar - breadcrumbs */
|
||||
|
|
|
@ -90,6 +90,9 @@
|
|||
.pref-icon[type="plugins"] {
|
||||
list-style-image: url(chrome://mozapps/skin/plugins/pluginGeneric.png);
|
||||
}
|
||||
.pref-icon[type="fullscreen"] {
|
||||
list-style-image: url(chrome://global/skin/icons/question-64.png);
|
||||
}
|
||||
|
||||
.pref-title {
|
||||
font-size: 125%;
|
||||
|
|
|
@ -1207,8 +1207,8 @@ window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][s
|
|||
color: inherit !important;
|
||||
}
|
||||
|
||||
.autocomplete-treebody::-moz-tree-cell-text(suggesthint, treecolAutoCompleteComment),
|
||||
.autocomplete-treebody::-moz-tree-cell-text(suggestfirst, treecolAutoCompleteComment)
|
||||
.autocomplete-treebody::-moz-tree-cell-text(suggesthint, treecolAutoCompleteComment),
|
||||
.autocomplete-treebody::-moz-tree-cell-text(suggestfirst, treecolAutoCompleteComment)
|
||||
{
|
||||
color: GrayText;
|
||||
font-size: smaller;
|
||||
|
@ -1224,8 +1224,8 @@ window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][s
|
|||
#go-button,
|
||||
#urlbar > toolbarbutton {
|
||||
margin: 0;
|
||||
-moz-padding-start: 2px;
|
||||
-moz-padding-end: 1px;
|
||||
-moz-padding-start: 2px;
|
||||
-moz-padding-end: 1px;
|
||||
background-origin: border-box;
|
||||
list-style-image: url("chrome://browser/skin/reload-stop-go.png");
|
||||
}
|
||||
|
@ -2901,7 +2901,6 @@ html|*#highlighter-nodeinfobar-pseudo-classes {
|
|||
#full-screen-warning-message {
|
||||
background-color: hsl(0,0%,15%);
|
||||
color: white;
|
||||
font-size: 32px;
|
||||
border-radius: 8px;
|
||||
margin-top: 30px;
|
||||
padding: 30px 50px;
|
||||
|
@ -2909,13 +2908,20 @@ html|*#highlighter-nodeinfobar-pseudo-classes {
|
|||
}
|
||||
|
||||
#full-screen-warning-container[obscure-browser] {
|
||||
background-color: rgba(0,0,0,0.75);
|
||||
background-color: rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
#full-screen-warning-container[stop-obscuring-browser] {
|
||||
-moz-transition-property: background-color;
|
||||
-moz-transition-duration: 500ms;
|
||||
background-color: rgba(0,0,0,0);
|
||||
.full-screen-description {
|
||||
font-size: 150%;
|
||||
}
|
||||
|
||||
#full-screen-domain-text {
|
||||
font-size: 300%;
|
||||
}
|
||||
|
||||
.full-screen-approval-button,
|
||||
#full-screen-remember-decision {
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
/* Highlighter toolbar - breadcrumbs */
|
||||
|
|
|
@ -94,6 +94,9 @@
|
|||
.pref-icon[type="plugins"] {
|
||||
list-style-image: url(chrome://mozapps/skin/plugins/pluginGeneric.png);
|
||||
}
|
||||
.pref-icon[type="fullscreen"] {
|
||||
list-style-image: url(chrome://global/skin/icons/question-64.png);
|
||||
}
|
||||
|
||||
.pref-title {
|
||||
font-size: 125%;
|
||||
|
|
|
@ -603,7 +603,7 @@ menuitem.bookmark-item {
|
|||
-moz-image-region: rect(16px, 32px, 32px, 16px);
|
||||
}
|
||||
|
||||
.bookmark-item[container][livemark] {
|
||||
.bookmark-item[container][livemark] {
|
||||
list-style-image: url("chrome://browser/skin/livemark-folder.png");
|
||||
-moz-image-region: auto;
|
||||
}
|
||||
|
@ -1299,7 +1299,7 @@ html|*.urlbar-input:-moz-lwtheme:-moz-placeholder,
|
|||
.urlbar-textbox-container {
|
||||
-moz-box-align: stretch;
|
||||
}
|
||||
|
||||
|
||||
.urlbar-input-box {
|
||||
-moz-margin-start: 0;
|
||||
}
|
||||
|
@ -1504,7 +1504,7 @@ html|*.urlbar-input:-moz-lwtheme:-moz-placeholder,
|
|||
.autocomplete-treebody::-moz-tree-image(bookmark, treecolAutoCompleteImage) {
|
||||
list-style-image: url("chrome://browser/skin/places/editBookmark.png");
|
||||
-moz-image-region: rect(0px 16px 16px 0px);
|
||||
width: 16px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
|
@ -1519,7 +1519,7 @@ html|*.urlbar-input:-moz-lwtheme:-moz-placeholder,
|
|||
.ac-result-type-tag,
|
||||
.autocomplete-treebody::-moz-tree-image(tag, treecolAutoCompleteImage) {
|
||||
list-style-image: url("chrome://browser/skin/places/tag.png");
|
||||
width: 16px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
|
@ -1565,8 +1565,8 @@ richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-
|
|||
color: inherit !important;
|
||||
}
|
||||
|
||||
.autocomplete-treebody::-moz-tree-cell-text(suggesthint, treecolAutoCompleteComment),
|
||||
.autocomplete-treebody::-moz-tree-cell-text(suggestfirst, treecolAutoCompleteComment)
|
||||
.autocomplete-treebody::-moz-tree-cell-text(suggesthint, treecolAutoCompleteComment),
|
||||
.autocomplete-treebody::-moz-tree-cell-text(suggestfirst, treecolAutoCompleteComment)
|
||||
{
|
||||
color: GrayText;
|
||||
font-size: smaller;
|
||||
|
@ -1670,7 +1670,7 @@ richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-
|
|||
|
||||
#star-button:hover {
|
||||
background-image: -moz-radial-gradient(center, circle closest-side, hsla(45,100%,73%,.3), hsla(45,100%,73%,0));
|
||||
-moz-image-region: rect(0px 32px 16px 16px);
|
||||
-moz-image-region: rect(0px 32px 16px 16px);
|
||||
}
|
||||
|
||||
#star-button:hover:active {
|
||||
|
@ -2822,7 +2822,6 @@ html|*#highlighter-nodeinfobar-pseudo-classes {
|
|||
#full-screen-warning-message {
|
||||
background-color: hsl(0,0%,15%);
|
||||
color: white;
|
||||
font-size: 32px;
|
||||
border-radius: 8px;
|
||||
margin-top: 30px;
|
||||
padding: 30px 50px;
|
||||
|
@ -2830,13 +2829,20 @@ html|*#highlighter-nodeinfobar-pseudo-classes {
|
|||
}
|
||||
|
||||
#full-screen-warning-container[obscure-browser] {
|
||||
background-color: rgba(0,0,0,0.75);
|
||||
background-color: rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
#full-screen-warning-container[stop-obscuring-browser] {
|
||||
-moz-transition-property: background-color;
|
||||
-moz-transition-duration: 500ms;
|
||||
background-color: rgba(0,0,0,0);
|
||||
.full-screen-description {
|
||||
font-size: 150%;
|
||||
}
|
||||
|
||||
#full-screen-domain-text {
|
||||
font-size: 300%;
|
||||
}
|
||||
|
||||
.full-screen-approval-button,
|
||||
#full-screen-remember-decision {
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
/* Highlighter toolbar - breadcrumbs */
|
||||
|
|
|
@ -93,6 +93,9 @@
|
|||
.pref-icon[type="plugins"] {
|
||||
list-style-image: url(chrome://mozapps/skin/plugins/pluginGeneric.png);
|
||||
}
|
||||
.pref-icon[type="fullscreen"] {
|
||||
list-style-image: url(chrome://global/skin/icons/question-64.png);
|
||||
}
|
||||
|
||||
.pref-title {
|
||||
font-size: 125%;
|
||||
|
|
|
@ -24,6 +24,7 @@ class DeviceManagerADB(DeviceManager):
|
|||
self.useZip = False
|
||||
self.packageName = None
|
||||
self.tempDir = None
|
||||
self.deviceRoot = None
|
||||
|
||||
# the path to adb, or 'adb' to assume that it's on the PATH
|
||||
self.adbPath = adbPath
|
||||
|
@ -50,6 +51,9 @@ class DeviceManagerADB(DeviceManager):
|
|||
# verify that we can connect to the device. can't continue
|
||||
self.verifyDevice()
|
||||
|
||||
# set up device root
|
||||
self.setupDeviceRoot()
|
||||
|
||||
# Can we use run-as? (currently not required)
|
||||
try:
|
||||
self.verifyRunAs()
|
||||
|
@ -91,9 +95,16 @@ class DeviceManagerADB(DeviceManager):
|
|||
# success: <return code>
|
||||
# failure: None
|
||||
def shell(self, cmd, outputfile, env=None, cwd=None):
|
||||
# need to quote special characters here
|
||||
# need to quote and escape special characters here
|
||||
for (index, arg) in enumerate(cmd):
|
||||
if arg.find(" ") or arg.find("(") or arg.find(")") or arg.find("\""):
|
||||
arg.replace('&', '\&')
|
||||
|
||||
needsQuoting = False
|
||||
for char in [ ' ', '(', ')', '"', '&' ]:
|
||||
if arg.find(char):
|
||||
needsQuoting = True
|
||||
break
|
||||
if needsQuoting:
|
||||
cmd[index] = '\'%s\'' % arg
|
||||
|
||||
# This is more complex than you'd think because adb doesn't actually
|
||||
|
@ -171,6 +182,9 @@ class DeviceManagerADB(DeviceManager):
|
|||
result = self.runCmdAs(["shell", "mkdir", name]).stdout.read()
|
||||
if 'read-only file system' in result.lower():
|
||||
return None
|
||||
if 'file exists' in result.lower():
|
||||
return name
|
||||
|
||||
self.chmodDir(name)
|
||||
return name
|
||||
except:
|
||||
|
@ -525,6 +539,26 @@ class DeviceManagerADB(DeviceManager):
|
|||
data = p = subprocess.Popen(["ls", "-l", filename], stdout=subprocess.PIPE).stdout.read()
|
||||
return data.split()[4]
|
||||
|
||||
# Internal method to setup the device root and cache its value
|
||||
def setupDeviceRoot(self):
|
||||
# /mnt/sdcard/tests is preferred to /data/local/tests, but this can be
|
||||
# over-ridden by creating /data/local/tests
|
||||
testRoot = "/data/local/tests"
|
||||
if (self.dirExists(testRoot)):
|
||||
self.deviceRoot = testRoot
|
||||
return
|
||||
|
||||
for (basePath, subPath) in [('/mnt/sdcard', 'tests'),
|
||||
('/data/local', 'tests')]:
|
||||
if self.dirExists(basePath):
|
||||
testRoot = os.path.join(basePath, subPath)
|
||||
if self.mkDir(testRoot):
|
||||
self.deviceRoot = testRoot
|
||||
return
|
||||
|
||||
raise DMError("Unable to set up device root as /mnt/sdcard/tests "
|
||||
"or /data/local/tests")
|
||||
|
||||
# Gets the device root for the testing area on the device
|
||||
# For all devices we will use / type slashes and depend on the device-agent
|
||||
# to sort those out. The agent will return us the device location where we
|
||||
|
@ -543,22 +577,7 @@ class DeviceManagerADB(DeviceManager):
|
|||
# success: path for device root
|
||||
# failure: None
|
||||
def getDeviceRoot(self):
|
||||
# /mnt/sdcard/tests is preferred to /data/local/tests, but this can be
|
||||
# over-ridden by creating /data/local/tests
|
||||
testRoot = "/data/local/tests"
|
||||
if (self.dirExists(testRoot)):
|
||||
return testRoot
|
||||
|
||||
root = "/mnt/sdcard"
|
||||
if self.dirExists(root):
|
||||
testRoot = root + "/tests"
|
||||
if self.mkDir(testRoot):
|
||||
return testRoot
|
||||
|
||||
testRoot = "/data/local/tests"
|
||||
if (not self.dirExists(testRoot)):
|
||||
self.mkDir(testRoot)
|
||||
return testRoot
|
||||
return self.deviceRoot
|
||||
|
||||
# Gets the temporary directory we are using on this device
|
||||
# base on our device root, ensuring also that it exists.
|
||||
|
|
|
@ -9,9 +9,8 @@ import StringIO
|
|||
class DroidMixin(object):
|
||||
"""Mixin to extend DeviceManager with Android-specific functionality"""
|
||||
|
||||
def launchApplication(self, app, activity="App",
|
||||
intent="android.intent.action.VIEW", env=None,
|
||||
url=None, extra_args=None):
|
||||
def launchApplication(self, appName, activityName, intent, url=None,
|
||||
extras=None):
|
||||
"""
|
||||
Launches an Android application
|
||||
returns:
|
||||
|
@ -19,26 +18,26 @@ class DroidMixin(object):
|
|||
failure: False
|
||||
"""
|
||||
# only one instance of an application may be running at once
|
||||
if self.processExist(app):
|
||||
if self.processExist(appName):
|
||||
return False
|
||||
|
||||
acmd = [ "am", "start", "-W", "-n", "%s/.%s" % (app, activity)]
|
||||
acmd = [ "am", "start", "-W", "-n", "%s/%s" % (appName, activityName)]
|
||||
|
||||
if intent:
|
||||
acmd.extend(["-a", intent])
|
||||
|
||||
if extra_args:
|
||||
acmd.extend(["--es", "args", " ".join(extra_args)])
|
||||
|
||||
if env:
|
||||
envCnt = 0
|
||||
# env is expected to be a dict of environment variables
|
||||
for envkey, envval in env.iteritems():
|
||||
acmd.extend(["--es", "env" + str(envCnt), envkey + "=" + envval])
|
||||
envCnt += 1
|
||||
if extras:
|
||||
for (key, val) in extras.iteritems():
|
||||
if type(val) is int:
|
||||
extraTypeParam = "--ei"
|
||||
elif type(val) is bool:
|
||||
extraTypeParam = "--ez"
|
||||
else:
|
||||
extraTypeParam = "--es"
|
||||
acmd.extend([extraTypeParam, str(key), str(val)])
|
||||
|
||||
if url:
|
||||
acmd.extend(["-d", ''.join(["'", url, "'"])])
|
||||
acmd.extend(["-d", url])
|
||||
|
||||
# shell output not that interesting and debugging logs should already
|
||||
# show what's going on here... so just create an empty memory buffer
|
||||
|
@ -49,6 +48,34 @@ class DroidMixin(object):
|
|||
|
||||
return False
|
||||
|
||||
def launchFennec(self, appName, intent="android.intent.action.VIEW",
|
||||
mozEnv=None, extraArgs=None, url=None):
|
||||
"""
|
||||
Convenience method to launch Fennec on Android with various debugging
|
||||
arguments
|
||||
WARNING: FIXME: This would go better in mozrunner. Please do not
|
||||
use this method if you are not comfortable with it going away sometime
|
||||
in the near future
|
||||
returns:
|
||||
success: True
|
||||
failure: False
|
||||
"""
|
||||
extras = {}
|
||||
|
||||
if mozEnv:
|
||||
# mozEnv is expected to be a dictionary of environment variables: Fennec
|
||||
# itself will set them when launched
|
||||
for (envCnt, (envkey, envval)) in enumerate(mozEnv.iteritems()):
|
||||
extras["env" + str(envCnt)] = envkey + "=" + envval
|
||||
|
||||
# Additional command line arguments that fennec will read and use (e.g.
|
||||
# with a custom profile)
|
||||
if extraArgs:
|
||||
extras['args'] = " ".join(extraArgs)
|
||||
|
||||
return self.launchApplication(appName, ".App", intent, url=url,
|
||||
extras=extras)
|
||||
|
||||
class DroidADB(DeviceManagerADB, DroidMixin):
|
||||
pass
|
||||
|
||||
|
|
|
@ -254,6 +254,7 @@ if not os.path.exists(source_dir):
|
|||
extract(gmp_source_tar, source_dir)
|
||||
extract(gcc_source_tar, source_dir)
|
||||
patch('plugin_finish_decl.diff', 0, gcc_source_dir)
|
||||
patch('libtool-74c8993c178a1386ea5e2363a01d919738402f30.patch', 1, gcc_source_dir)
|
||||
patch('pr49911.diff', 1, gcc_source_dir)
|
||||
patch('r159628-r163231-r171807.patch', 1, gcc_source_dir)
|
||||
patch('gcc-fixinc.patch', 1, gcc_source_dir)
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
diff -ruN a/ltmain.sh b/ltmain.sh
|
||||
--- a/ltmain.sh 2009-12-05 12:18:53.000000000 -0500
|
||||
+++ b/ltmain.sh 2012-05-07 16:19:31.871827967 -0400
|
||||
@@ -2932,7 +2932,7 @@
|
||||
func_extract_an_archive "$my_xdir" "$my_xabs"
|
||||
;;
|
||||
esac
|
||||
- my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
|
||||
+ my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
|
||||
done
|
||||
|
||||
func_extract_archives_result="$my_oldobjs"
|
|
@ -614,10 +614,17 @@ public:
|
|||
static void SplitExpatName(const PRUnichar *aExpatName, nsIAtom **aPrefix,
|
||||
nsIAtom **aTagName, PRInt32 *aNameSpaceID);
|
||||
|
||||
// Get a permission-manager setting for the given uri and type.
|
||||
// Get a permission-manager setting for the given principal and type.
|
||||
// If the pref doesn't exist or if it isn't ALLOW_ACTION, false is
|
||||
// returned, otherwise true is returned.
|
||||
static bool IsSitePermAllow(nsIURI* aURI, const char* aType);
|
||||
// returned, otherwise true is returned. Always returns true for the
|
||||
// system principal, and false for a null principal.
|
||||
static bool IsSitePermAllow(nsIPrincipal* aPrincipal, const char* aType);
|
||||
|
||||
// Get a permission-manager setting for the given principal and type.
|
||||
// If the pref doesn't exist or if it isn't DENY_ACTION, false is
|
||||
// returned, otherwise true is returned. Always returns false for the
|
||||
// system principal, and true for a null principal.
|
||||
static bool IsSitePermDeny(nsIPrincipal* aPrincipal, const char* aType);
|
||||
|
||||
static nsILineBreaker* LineBreaker()
|
||||
{
|
||||
|
@ -1842,13 +1849,6 @@ public:
|
|||
*/
|
||||
static bool IsRequestFullScreenAllowed();
|
||||
|
||||
/**
|
||||
* Returns true if key input is restricted in DOM full-screen mode
|
||||
* to non-alpha-numeric key codes only. This mirrors the
|
||||
* "full-screen-api.key-input-restricted" pref.
|
||||
*/
|
||||
static bool IsFullScreenKeyInputRestricted();
|
||||
|
||||
/**
|
||||
* Returns true if the doc tree branch which contains aDoc contains any
|
||||
* plugins which we don't control event dispatch for, i.e. do any plugins
|
||||
|
@ -2121,7 +2121,6 @@ private:
|
|||
static bool sAllowXULXBL_for_file;
|
||||
static bool sIsFullScreenApiEnabled;
|
||||
static bool sTrustedFullScreenOnly;
|
||||
static bool sFullScreenKeyInputRestricted;
|
||||
static PRUint32 sHandlingInputTimeout;
|
||||
|
||||
static nsHtml5StringParser* sHTMLFragmentParser;
|
||||
|
|
|
@ -44,6 +44,7 @@ interface nsIURI;
|
|||
interface nsIFrame;
|
||||
interface nsIChromeFrameMessageManager;
|
||||
interface nsIVariant;
|
||||
interface nsIDOMElement;
|
||||
|
||||
typedef unsigned long long nsContentViewId;
|
||||
|
||||
|
@ -141,7 +142,7 @@ interface nsIContentViewManager : nsISupports
|
|||
readonly attribute nsIContentView rootContentView;
|
||||
};
|
||||
|
||||
[scriptable, uuid(efc0b731-45dc-4189-8ffa-d3eeeb850977)]
|
||||
[scriptable, uuid(fc338eea-47dc-475e-add7-a3933fcfa07c)]
|
||||
interface nsIFrameLoader : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -272,6 +273,14 @@ interface nsIFrameLoader : nsISupports
|
|||
* Defaults to true.
|
||||
*/
|
||||
attribute boolean clampScrollPosition;
|
||||
|
||||
/**
|
||||
* The element which owns this frame loader.
|
||||
*
|
||||
* For example, if this is a frame loader for an <iframe>, this attribute
|
||||
* returns the iframe element.
|
||||
*/
|
||||
readonly attribute nsIDOMElement ownerElement;
|
||||
};
|
||||
|
||||
native alreadyAddRefed_nsFrameLoader(already_AddRefed<nsFrameLoader>);
|
||||
|
|
|
@ -288,7 +288,6 @@ nsString* nsContentUtils::sModifierSeparator = nsnull;
|
|||
bool nsContentUtils::sInitialized = false;
|
||||
bool nsContentUtils::sIsFullScreenApiEnabled = false;
|
||||
bool nsContentUtils::sTrustedFullScreenOnly = true;
|
||||
bool nsContentUtils::sFullScreenKeyInputRestricted = true;
|
||||
|
||||
PRUint32 nsContentUtils::sHandlingInputTimeout = 1000;
|
||||
|
||||
|
@ -425,9 +424,6 @@ nsContentUtils::Init()
|
|||
Preferences::AddBoolVarCache(&sTrustedFullScreenOnly,
|
||||
"full-screen-api.allow-trusted-requests-only");
|
||||
|
||||
Preferences::AddBoolVarCache(&sFullScreenKeyInputRestricted,
|
||||
"full-screen-api.key-input-restricted");
|
||||
|
||||
Preferences::AddUintVarCache(&sHandlingInputTimeout,
|
||||
"dom.event.handling-user-input-time-limit",
|
||||
1000);
|
||||
|
@ -2805,18 +2801,44 @@ nsContentUtils::IsDraggableLink(const nsIContent* aContent) {
|
|||
return aContent->IsLink(getter_AddRefs(absURI));
|
||||
}
|
||||
|
||||
bool
|
||||
nsContentUtils::IsSitePermAllow(nsIURI* aURI, const char* aType)
|
||||
static bool
|
||||
TestSitePerm(nsIPrincipal* aPrincipal, const char* aType, PRUint32 aPerm)
|
||||
{
|
||||
if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
|
||||
// System principal is always allowed and never denied permission.
|
||||
return aPerm == nsIPermissionManager::ALLOW_ACTION;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
if (NS_FAILED(!aPrincipal ||
|
||||
aPrincipal->GetURI(getter_AddRefs(uri))) ||
|
||||
!uri) {
|
||||
// We always deny (i.e. don't allow) the permission if we don't
|
||||
// have a principal or we don't know the URI.
|
||||
return aPerm != nsIPermissionManager::ALLOW_ACTION;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> permMgr =
|
||||
do_GetService("@mozilla.org/permissionmanager;1");
|
||||
NS_ENSURE_TRUE(permMgr, false);
|
||||
|
||||
PRUint32 perm;
|
||||
nsresult rv = permMgr->TestPermission(aURI, aType, &perm);
|
||||
nsresult rv = permMgr->TestPermission(uri, aType, &perm);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
return perm == nsIPermissionManager::ALLOW_ACTION;
|
||||
return perm == aPerm;
|
||||
}
|
||||
|
||||
bool
|
||||
nsContentUtils::IsSitePermAllow(nsIPrincipal* aPrincipal, const char* aType)
|
||||
{
|
||||
return TestSitePerm(aPrincipal, aType, nsIPermissionManager::ALLOW_ACTION);
|
||||
}
|
||||
|
||||
bool
|
||||
nsContentUtils::IsSitePermDeny(nsIPrincipal* aPrincipal, const char* aType)
|
||||
{
|
||||
return TestSitePerm(aPrincipal, aType, nsIPermissionManager::DENY_ACTION);
|
||||
}
|
||||
|
||||
static const char *gEventNames[] = {"event"};
|
||||
|
@ -3451,19 +3473,10 @@ nsContentUtils::DispatchChromeEvent(nsIDocument *aDoc,
|
|||
if (!aDoc->GetWindow())
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
nsIDOMEventTarget* piTarget = aDoc->GetWindow()->GetChromeEventHandler();
|
||||
nsIDOMEventTarget* piTarget = aDoc->GetWindow()->GetParentTarget();
|
||||
if (!piTarget)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(piTarget);
|
||||
if (flo) {
|
||||
nsRefPtr<nsFrameLoader> fl = flo->GetFrameLoader();
|
||||
if (fl) {
|
||||
nsIDOMEventTarget* t = fl->GetTabChildGlobalAsEventTarget();
|
||||
piTarget = t ? t : piTarget;
|
||||
}
|
||||
}
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
rv = piTarget->DispatchDOMEvent(nsnull, event, nsnull, &status);
|
||||
if (aDefaultAction) {
|
||||
|
@ -6339,7 +6352,7 @@ nsContentUtils::AllowXULXBLForPrincipal(nsIPrincipal* aPrincipal)
|
|||
|
||||
return princURI &&
|
||||
((sAllowXULXBL_for_file && SchemeIs(princURI, "file")) ||
|
||||
IsSitePermAllow(princURI, "allowXULXBL"));
|
||||
IsSitePermAllow(aPrincipal, "allowXULXBL"));
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDocumentLoaderFactory>
|
||||
|
@ -6512,19 +6525,14 @@ nsContentUtils::IsFullScreenApiEnabled()
|
|||
return sIsFullScreenApiEnabled;
|
||||
}
|
||||
|
||||
bool nsContentUtils::IsRequestFullScreenAllowed()
|
||||
bool
|
||||
nsContentUtils::IsRequestFullScreenAllowed()
|
||||
{
|
||||
return !sTrustedFullScreenOnly ||
|
||||
nsEventStateManager::IsHandlingUserInput() ||
|
||||
IsCallerChrome();
|
||||
}
|
||||
|
||||
bool
|
||||
nsContentUtils::IsFullScreenKeyInputRestricted()
|
||||
{
|
||||
return sFullScreenKeyInputRestricted;
|
||||
}
|
||||
|
||||
static void
|
||||
CheckForWindowedPlugins(nsIContent* aContent, void* aResult)
|
||||
{
|
||||
|
|
|
@ -1702,6 +1702,7 @@ NS_INTERFACE_TABLE_HEAD(nsDocument)
|
|||
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMDocumentTouch)
|
||||
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsITouchEventReceiver)
|
||||
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIInlineEventHandlers)
|
||||
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIObserver)
|
||||
NS_OFFSET_AND_INTERFACE_TABLE_END
|
||||
NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
|
||||
NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsDocument)
|
||||
|
@ -8758,6 +8759,20 @@ nsDocument::RestorePreviousFullScreenState()
|
|||
} else {
|
||||
// Else we popped the top of the stack, and there's still another
|
||||
// element in there, so that will become the full-screen element.
|
||||
if (fullScreenDoc != doc) {
|
||||
// We've popped so enough off the stack that we've rolled back to
|
||||
// a fullscreen element in a parent document. If this document isn't
|
||||
// authorized for fullscreen, dispatch an event to chrome so it
|
||||
// knows to show the authorization UI.
|
||||
if (!nsContentUtils::IsSitePermAllow(doc->NodePrincipal(), "fullscreen")) {
|
||||
nsRefPtr<nsAsyncDOMEvent> e =
|
||||
new nsAsyncDOMEvent(doc,
|
||||
NS_LITERAL_STRING("MozEnteredDomFullscreen"),
|
||||
true,
|
||||
true);
|
||||
e->PostDOMEvent();
|
||||
}
|
||||
}
|
||||
sFullScreenDoc = do_GetWeakReference(doc);
|
||||
break;
|
||||
}
|
||||
|
@ -9076,6 +9091,13 @@ nsDocument::RequestFullScreen(Element* aElement, bool aWasCallerChrome)
|
|||
DispatchFullScreenChange(changed[changed.Length() - i - 1]);
|
||||
}
|
||||
|
||||
nsRefPtr<nsAsyncDOMEvent> e =
|
||||
new nsAsyncDOMEvent(this,
|
||||
NS_LITERAL_STRING("MozEnteredDomFullscreen"),
|
||||
true,
|
||||
true);
|
||||
e->PostDOMEvent();
|
||||
|
||||
// Remember this is the requesting full-screen document.
|
||||
sFullScreenDoc = do_GetWeakReference(static_cast<nsIDocument*>(this));
|
||||
|
||||
|
@ -9225,6 +9247,159 @@ DispatchPointerLockError(nsIDocument* aTarget)
|
|||
e->PostDOMEvent();
|
||||
}
|
||||
|
||||
// Manages asynchronously requesting pointer lock. Used to dispatch an
|
||||
// event to request pointer lock once fullscreen has been approved.
|
||||
class nsAsyncPointerLockRequest : public nsRunnable
|
||||
{
|
||||
public:
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
sInstance = nsnull;
|
||||
if (mDocument && mElement) {
|
||||
mDocument->RequestPointerLock(mElement);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static void Request(Element* aElement, nsIDocument* aDocument)
|
||||
{
|
||||
if (sInstance) {
|
||||
// We already have an event instance pending. Change the requestee
|
||||
// to the new pointer lock requestee.
|
||||
sInstance->mElement = aElement;
|
||||
sInstance->mDocument = aDocument;
|
||||
} else {
|
||||
// Create a new event instance. Owning ref is held by the nsIEventTarget
|
||||
// to which this is dispatched.
|
||||
sInstance = new nsAsyncPointerLockRequest(aElement, aDocument);
|
||||
NS_DispatchToCurrentThread(sInstance);
|
||||
}
|
||||
}
|
||||
|
||||
static void Cancel()
|
||||
{
|
||||
if (sInstance) {
|
||||
// Revoke references to requesting element/document, when the
|
||||
// dispatched event runs. The event will do nothing, and then be
|
||||
// destroyed.
|
||||
sInstance->mElement = nsnull;
|
||||
sInstance->mDocument = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsAsyncPointerLockRequest(Element* aElement, nsIDocument* aDocument)
|
||||
: mElement(aElement),
|
||||
mDocument(aDocument)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsAsyncPointerLockRequest);
|
||||
}
|
||||
|
||||
~nsAsyncPointerLockRequest()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsAsyncPointerLockRequest);
|
||||
}
|
||||
|
||||
// Reference to the instance of any pending event. This is not an owning
|
||||
// reference; the nsIEventTarget to which this is dispatched holds the only
|
||||
// owning reference to this instance. This reference is valid between
|
||||
// an instance being created, and its Run() method being called.
|
||||
static nsAsyncPointerLockRequest* sInstance;
|
||||
|
||||
// Element and document which reqested pointer lock.
|
||||
nsCOMPtr<Element> mElement;
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
};
|
||||
|
||||
nsAsyncPointerLockRequest* nsAsyncPointerLockRequest::sInstance = nsnull;
|
||||
nsWeakPtr nsDocument::sPendingPointerLockDoc;
|
||||
nsWeakPtr nsDocument::sPendingPointerLockElement;
|
||||
|
||||
/* static */
|
||||
void
|
||||
nsDocument::ClearPendingPointerLockRequest(bool aDispatchErrorEvents)
|
||||
{
|
||||
nsAsyncPointerLockRequest::Cancel();
|
||||
|
||||
if (!sPendingPointerLockDoc) {
|
||||
// No pending request.
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIDocument> doc(do_QueryReferent(sPendingPointerLockDoc));
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
if (!os) {
|
||||
NS_WARNING("Lost observer service in ClearPendingPointerLockRequest()!");
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserver> obs(do_QueryInterface(doc));
|
||||
if (!os) {
|
||||
NS_WARNING("Document must implement nsIObserver");
|
||||
return;
|
||||
}
|
||||
os->RemoveObserver(obs, "perm-changed");
|
||||
|
||||
if (aDispatchErrorEvents) {
|
||||
DispatchPointerLockError(doc);
|
||||
}
|
||||
nsCOMPtr<Element> element(do_QueryReferent(sPendingPointerLockElement));
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<Element> pointerLockedElement =
|
||||
do_QueryReferent(nsEventStateManager::sPointerLockedElement);
|
||||
NS_ASSERTION(pointerLockedElement != element,
|
||||
"We shouldn't be clearing pointer locked flag on pointer locked element!");
|
||||
#endif
|
||||
if (element) {
|
||||
element->ClearPointerLock();
|
||||
}
|
||||
sPendingPointerLockDoc = nsnull;
|
||||
sPendingPointerLockElement = nsnull;
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
nsDocument::SetPendingPointerLockRequest(Element* aElement)
|
||||
{
|
||||
// If there's an existing pending pointer lock request, deny it.
|
||||
ClearPendingPointerLockRequest(true);
|
||||
|
||||
NS_ENSURE_TRUE(aElement != nsnull, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
NS_ENSURE_TRUE(os != nsnull, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIObserver> obs(do_QueryInterface(aElement->OwnerDoc()));
|
||||
NS_ENSURE_TRUE(obs != nsnull, NS_ERROR_FAILURE);
|
||||
|
||||
nsresult res = os->AddObserver(obs, "perm-changed", true);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
sPendingPointerLockDoc = do_GetWeakReference(aElement->OwnerDoc());
|
||||
sPendingPointerLockElement = do_GetWeakReference(aElement);
|
||||
|
||||
// Set the pointer lock flag, so that if the element is removed from
|
||||
// its document we know to cancel the pending request.
|
||||
aElement->SetPointerLock();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDocument::Observe(nsISupports *aSubject,
|
||||
const char *aTopic,
|
||||
const PRUnichar *aData)
|
||||
{
|
||||
if (strcmp("perm-changed", aTopic) == 0) {
|
||||
nsCOMPtr<nsIDocument> doc(do_QueryReferent(sPendingPointerLockDoc));
|
||||
if (nsContentUtils::IsSitePermAllow(doc->NodePrincipal(), "fullscreen")) {
|
||||
nsCOMPtr<Element> element(do_QueryReferent(sPendingPointerLockElement));
|
||||
nsDocument::ClearPendingPointerLockRequest(false);
|
||||
nsAsyncPointerLockRequest::Request(element, doc);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::RequestPointerLock(Element* aElement)
|
||||
{
|
||||
|
@ -9238,8 +9413,25 @@ nsDocument::RequestPointerLock(Element* aElement)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!ShouldLockPointer(aElement) ||
|
||||
!SetPointerLock(aElement, NS_STYLE_CURSOR_NONE)) {
|
||||
if (!ShouldLockPointer(aElement)) {
|
||||
DispatchPointerLockError(this);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nsContentUtils::IsSitePermAllow(NodePrincipal(), "fullscreen")) {
|
||||
// Domain isn't yet approved for fullscreen, so we must wait until
|
||||
// it's been approved.
|
||||
if (NS_FAILED(SetPendingPointerLockRequest(aElement))) {
|
||||
NS_WARNING("Failed to make pointer lock request pending!");
|
||||
DispatchPointerLockError(this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If there's an existing pending pointer lock request, deny it.
|
||||
nsDocument::ClearPendingPointerLockRequest(true);
|
||||
|
||||
if (!SetPointerLock(aElement, NS_STYLE_CURSOR_NONE)) {
|
||||
DispatchPointerLockError(this);
|
||||
return;
|
||||
}
|
||||
|
@ -9353,6 +9545,10 @@ nsDocument::SetPointerLock(Element* aElement, int aCursorStyle)
|
|||
void
|
||||
nsDocument::UnlockPointer()
|
||||
{
|
||||
// If our pointer lock request is pending awaiting authorization, deny the
|
||||
// request.
|
||||
ClearPendingPointerLockRequest(true);
|
||||
|
||||
if (!nsEventStateManager::sIsPointerLocked) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -500,7 +500,8 @@ class nsDocument : public nsIDocument,
|
|||
public nsIApplicationCacheContainer,
|
||||
public nsStubMutationObserver,
|
||||
public nsIDOMDocumentTouch,
|
||||
public nsIInlineEventHandlers
|
||||
public nsIInlineEventHandlers,
|
||||
public nsIObserver
|
||||
{
|
||||
public:
|
||||
typedef mozilla::dom::Element Element;
|
||||
|
@ -788,6 +789,9 @@ public:
|
|||
// nsIInlineEventHandlers
|
||||
NS_DECL_NSIINLINEEVENTHANDLERS
|
||||
|
||||
// nsIObserver
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
virtual nsresult Init();
|
||||
|
||||
virtual void AddXMLEventsContent(nsIContent * aXMLEventsElement);
|
||||
|
@ -1134,6 +1138,15 @@ protected:
|
|||
// document is hidden/navigation occurs.
|
||||
static nsWeakPtr sFullScreenRootDoc;
|
||||
|
||||
// Weak reference to the document which owned the pending pointer lock
|
||||
// element, at the time it requested pointer lock.
|
||||
static nsWeakPtr sPendingPointerLockDoc;
|
||||
|
||||
// Weak reference to the element which requested pointer lock. This request
|
||||
// is "pending", and will be processed once the element's document has had
|
||||
// the "fullscreen" permission granted.
|
||||
static nsWeakPtr sPendingPointerLockElement;
|
||||
|
||||
// Stack of full-screen elements. When we request full-screen we push the
|
||||
// full-screen element onto this stack, and when we cancel full-screen we
|
||||
// pop one off this stack, restoring the previous full-screen state
|
||||
|
@ -1194,9 +1207,6 @@ protected:
|
|||
// "mozaudioavailable" event.
|
||||
bool mHasAudioAvailableListener:1;
|
||||
|
||||
// Whether we are currently in full-screen mode, as per the DOM API.
|
||||
bool mIsFullScreen:1;
|
||||
|
||||
// Whether we're currently under a FlushPendingNotifications call to
|
||||
// our presshell. This is used to handle flush reentry correctly.
|
||||
bool mInFlush:1;
|
||||
|
@ -1244,6 +1254,16 @@ private:
|
|||
nsresult CheckFrameOptions();
|
||||
nsresult InitCSP();
|
||||
|
||||
// Sets aElement to be the pending pointer lock element. Once this document's
|
||||
// node principal's URI is granted the "fullscreen" permission, the pointer
|
||||
// lock request will be processed. At any one time there can be only one
|
||||
// pending pointer lock request; calling this clears the previous pending
|
||||
// request.
|
||||
static nsresult SetPendingPointerLockRequest(Element* aElement);
|
||||
|
||||
// Clears any pending pointer lock request.
|
||||
static void ClearPendingPointerLockRequest(bool aDispatchErrorEvents);
|
||||
|
||||
/**
|
||||
* See if aDocument is a child of this. If so, return the frame element in
|
||||
* this document that holds currentDoc (or an ancestor).
|
||||
|
|
|
@ -933,6 +933,12 @@ nsFrameLoader::ShowRemoteFrame(const nsIntSize& size)
|
|||
mRemoteBrowserShown = true;
|
||||
|
||||
EnsureMessageManager();
|
||||
|
||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||
if (OwnerIsBrowserFrame() && os) {
|
||||
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
|
||||
"remote-browser-frame-shown", NULL);
|
||||
}
|
||||
} else {
|
||||
nsRect dimensions;
|
||||
NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), false);
|
||||
|
@ -1512,11 +1518,11 @@ nsFrameLoader::MaybeCreateDocShell()
|
|||
mDocShell->SetChromeEventHandler(chromeEventHandler);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
|
||||
if (browserFrame) {
|
||||
bool isBrowserFrame = false;
|
||||
browserFrame->GetReallyIsBrowser(&isBrowserFrame);
|
||||
mDocShell->SetIsBrowserFrame(isBrowserFrame);
|
||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||
if (OwnerIsBrowserFrame() && os) {
|
||||
mDocShell->SetIsBrowserFrame(true);
|
||||
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
|
||||
"in-process-browser-frame-shown", NULL);
|
||||
}
|
||||
|
||||
// This is nasty, this code (the do_GetInterface(mDocShell) below)
|
||||
|
@ -2182,7 +2188,7 @@ nsFrameLoader::EnsureMessageManager()
|
|||
return rv;
|
||||
}
|
||||
|
||||
if (!mIsTopLevelContent && !mRemoteFrame) {
|
||||
if (!mIsTopLevelContent && !OwnerIsBrowserFrame() && !mRemoteFrame) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -2217,10 +2223,7 @@ nsFrameLoader::EnsureMessageManager()
|
|||
mRemoteBrowserShown ? this : nsnull,
|
||||
static_cast<nsFrameMessageManager*>(parentManager.get()),
|
||||
cx);
|
||||
NS_ENSURE_TRUE(mMessageManager, NS_ERROR_OUT_OF_MEMORY);
|
||||
} else
|
||||
{
|
||||
|
||||
} else {
|
||||
mMessageManager = new nsFrameMessageManager(true,
|
||||
nsnull,
|
||||
SendAsyncMessageToChild,
|
||||
|
@ -2228,7 +2231,6 @@ nsFrameLoader::EnsureMessageManager()
|
|||
nsnull,
|
||||
static_cast<nsFrameMessageManager*>(parentManager.get()),
|
||||
cx);
|
||||
NS_ENSURE_TRUE(mMessageManager, NS_ERROR_OUT_OF_MEMORY);
|
||||
mChildMessageManager =
|
||||
new nsInProcessTabChildGlobal(mDocShell, mOwnerContent, mMessageManager);
|
||||
mMessageManager->SetCallbackData(this);
|
||||
|
@ -2241,3 +2243,11 @@ nsFrameLoader::GetTabChildGlobalAsEventTarget()
|
|||
{
|
||||
return static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get());
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameLoader::GetOwnerElement(nsIDOMElement **aElement)
|
||||
{
|
||||
nsCOMPtr<nsIDOMElement> ownerElement = do_QueryInterface(mOwnerContent);
|
||||
ownerElement.forget(aElement);
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -285,14 +285,14 @@ public:
|
|||
nsFrameMessageManager* GetFrameMessageManager() { return mMessageManager; }
|
||||
|
||||
mozilla::dom::Element* GetOwnerContent() { return mOwnerContent; }
|
||||
void SetOwnerContent(mozilla::dom::Element* aContent);
|
||||
|
||||
bool ShouldClipSubdocument() { return mClipSubdocument; }
|
||||
|
||||
bool ShouldClampScrollPosition() { return mClampScrollPosition; }
|
||||
|
||||
private:
|
||||
|
||||
void SetOwnerContent(mozilla::dom::Element* aContent);
|
||||
|
||||
bool ShouldUseRemoteProcess();
|
||||
|
||||
/**
|
||||
|
|
|
@ -6482,6 +6482,20 @@ nsINode::Length() const
|
|||
}
|
||||
}
|
||||
|
||||
static const char*
|
||||
GetFullScreenError(nsIDocument* aDoc)
|
||||
{
|
||||
if (!nsContentUtils::IsRequestFullScreenAllowed()) {
|
||||
return "FullScreenDeniedNotInputDriven";
|
||||
}
|
||||
|
||||
if (nsContentUtils::IsSitePermDeny(aDoc->NodePrincipal(), "fullscreen")) {
|
||||
return "FullScreenDeniedBlocked";
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsresult nsGenericElement::MozRequestFullScreen()
|
||||
{
|
||||
// Only grant full-screen requests if this is called from inside a trusted
|
||||
|
@ -6489,11 +6503,12 @@ nsresult nsGenericElement::MozRequestFullScreen()
|
|||
// This stops the full-screen from being abused similar to the popups of old,
|
||||
// and it also makes it harder for bad guys' script to go full-screen and
|
||||
// spoof the browser chrome/window and phish logins etc.
|
||||
if (!nsContentUtils::IsRequestFullScreenAllowed()) {
|
||||
const char* error = GetFullScreenError(OwnerDoc());
|
||||
if (error) {
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
||||
"DOM", OwnerDoc(),
|
||||
nsContentUtils::eDOM_PROPERTIES,
|
||||
"FullScreenDeniedNotInputDriven");
|
||||
error);
|
||||
nsRefPtr<nsAsyncDOMEvent> e =
|
||||
new nsAsyncDOMEvent(OwnerDoc(),
|
||||
NS_LITERAL_STRING("mozfullscreenerror"),
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include "nsFrameLoader.h"
|
||||
#include "nsIPrivateDOMEvent.h"
|
||||
#include "xpcpublic.h"
|
||||
#include "nsIMozBrowserFrame.h"
|
||||
|
||||
bool SendSyncMessageToParent(void* aCallbackData,
|
||||
const nsAString& aMessage,
|
||||
|
@ -115,6 +116,15 @@ nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell* aShell,
|
|||
: mDocShell(aShell), mInitialized(false), mLoadingScript(false),
|
||||
mDelayedDisconnect(false), mOwner(aOwner), mChromeMessageManager(aChrome)
|
||||
{
|
||||
|
||||
// If owner corresponds to an <iframe mozbrowser>, we'll have to tweak our
|
||||
// PreHandleEvent implementation.
|
||||
nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwner);
|
||||
bool isBrowser = false;
|
||||
if (browserFrame) {
|
||||
browserFrame->GetReallyIsBrowser(&isBrowser);
|
||||
}
|
||||
mIsBrowserFrame = isBrowser;
|
||||
}
|
||||
|
||||
nsInProcessTabChildGlobal::~nsInProcessTabChildGlobal()
|
||||
|
@ -270,7 +280,17 @@ nsresult
|
|||
nsInProcessTabChildGlobal::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mCanHandle = true;
|
||||
aVisitor.mParentTarget = mOwner;
|
||||
|
||||
if (mIsBrowserFrame) {
|
||||
if (mOwner) {
|
||||
nsPIDOMWindow* innerWindow = mOwner->OwnerDoc()->GetInnerWindow();
|
||||
if (innerWindow) {
|
||||
aVisitor.mParentTarget = innerWindow->GetParentTarget();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
aVisitor.mParentTarget = mOwner;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (mOwner) {
|
||||
|
|
|
@ -142,6 +142,10 @@ protected:
|
|||
bool mInitialized;
|
||||
bool mLoadingScript;
|
||||
bool mDelayedDisconnect;
|
||||
|
||||
// Is this the message manager for an in-process <iframe mozbrowser>? This
|
||||
// affects where events get sent, so it affects PreHandleEvent.
|
||||
bool mIsBrowserFrame;
|
||||
public:
|
||||
nsIContent* mOwner;
|
||||
nsFrameMessageManager* mChromeMessageManager;
|
||||
|
|
|
@ -69,6 +69,7 @@ CPPSRCS = \
|
|||
DocumentRendererParent.cpp \
|
||||
DocumentRendererChild.cpp \
|
||||
ImageData.cpp \
|
||||
WebGLExtensionCompressedTextureS3TC.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_WEBGL
|
||||
|
@ -82,6 +83,7 @@ CPPSRCS += \
|
|||
WebGLExtensionStandardDerivatives.cpp \
|
||||
WebGLExtensionTextureFilterAnisotropic.cpp \
|
||||
WebGLExtensionLoseContext.cpp \
|
||||
WebGLTexelConversions.cpp \
|
||||
$(NULL)
|
||||
|
||||
DEFINES += -DUSE_ANGLE
|
||||
|
|
|
@ -501,6 +501,41 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ANDROID
|
||||
// bug 736123, blacklist WebGL on Adreno
|
||||
//
|
||||
// The Adreno driver in WebGL context creation, specifically in the first MakeCurrent
|
||||
// call on the newly created OpenGL context.
|
||||
//
|
||||
// Notice that we can't rely on GfxInfo for this blacklisting,
|
||||
// as GfxInfo on Android currently doesn't know the GL strings, which are,
|
||||
// AFAIK, the only way to identify Adreno GPUs.
|
||||
//
|
||||
// Somehow, the Layers' OpenGL context creation doesn't crash, and neither does
|
||||
// the global GL context creation. So we currently use the Renderer() id from the
|
||||
// global context. This is not future-proof, as the plan is to get rid of the global
|
||||
// context soon with OMTC. We need to replace this by getting the renderer id from
|
||||
// the Layers' GL context, but as with OMTC the LayerManager lives on a different
|
||||
// thread, this will have to involve some message-passing.
|
||||
if (!forceEnabled) {
|
||||
GLContext *globalContext = GLContextProvider::GetGlobalContext();
|
||||
if (!globalContext) {
|
||||
// make sure that we don't forget to update this code once the globalContext
|
||||
// is removed
|
||||
NS_RUNTIMEABORT("No global context anymore? Then you need to update "
|
||||
"this code, or force-enable WebGL.");
|
||||
}
|
||||
int renderer = globalContext->Renderer();
|
||||
if (renderer == gl::GLContext::RendererAdreno200 ||
|
||||
renderer == gl::GLContext::RendererAdreno205)
|
||||
{
|
||||
LogMessage("WebGL blocked on this Adreno driver!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// if we're forcing osmesa, do it first
|
||||
if (forceOSMesa) {
|
||||
gl = gl::GLContextProviderOSMesa::CreateOffscreen(gfxIntSize(width, height), format);
|
||||
|
@ -883,10 +918,13 @@ bool WebGLContext::IsExtensionSupported(WebGLExtensionID ei)
|
|||
case WebGL_EXT_texture_filter_anisotropic:
|
||||
isSupported = gl->IsExtensionSupported(GLContext::EXT_texture_filter_anisotropic);
|
||||
break;
|
||||
case WebGL_MOZ_WEBGL_lose_context:
|
||||
case WebGL_WEBGL_lose_context:
|
||||
// We always support this extension.
|
||||
isSupported = true;
|
||||
break;
|
||||
case WebGL_WEBGL_compressed_texture_s3tc:
|
||||
isSupported = gl->IsExtensionSupported(GLContext::EXT_texture_compression_s3tc);
|
||||
break;
|
||||
default:
|
||||
isSupported = false;
|
||||
}
|
||||
|
@ -927,8 +965,12 @@ WebGLContext::GetExtension(const nsAString& aName)
|
|||
ei = WebGL_EXT_texture_filter_anisotropic;
|
||||
}
|
||||
else if (aName.EqualsLiteral("MOZ_WEBGL_lose_context")) {
|
||||
if (IsExtensionSupported(WebGL_MOZ_WEBGL_lose_context))
|
||||
ei = WebGL_MOZ_WEBGL_lose_context;
|
||||
if (IsExtensionSupported(WebGL_WEBGL_lose_context))
|
||||
ei = WebGL_WEBGL_lose_context;
|
||||
}
|
||||
else if (aName.EqualsLiteral("MOZ_WEBGL_compressed_texture_s3tc")) {
|
||||
if (IsExtensionSupported(WebGL_WEBGL_compressed_texture_s3tc))
|
||||
ei = WebGL_WEBGL_compressed_texture_s3tc;
|
||||
}
|
||||
|
||||
if (ei != WebGLExtensionID_Max) {
|
||||
|
@ -940,9 +982,12 @@ WebGLContext::GetExtension(const nsAString& aName)
|
|||
case WebGL_EXT_texture_filter_anisotropic:
|
||||
mEnabledExtensions[ei] = new WebGLExtensionTextureFilterAnisotropic(this);
|
||||
break;
|
||||
case WebGL_MOZ_WEBGL_lose_context:
|
||||
case WebGL_WEBGL_lose_context:
|
||||
mEnabledExtensions[ei] = new WebGLExtensionLoseContext(this);
|
||||
break;
|
||||
case WebGL_WEBGL_compressed_texture_s3tc:
|
||||
mEnabledExtensions[ei] = new WebGLExtensionCompressedTextureS3TC(this);
|
||||
break;
|
||||
// create an extension for any types that don't
|
||||
// have any additional tokens or methods
|
||||
default:
|
||||
|
@ -1518,8 +1563,10 @@ WebGLContext::GetSupportedExtensions(Nullable< nsTArray<nsString> > &retval)
|
|||
arr.AppendElement(NS_LITERAL_STRING("OES_standard_derivatives"));
|
||||
if (IsExtensionSupported(WebGL_EXT_texture_filter_anisotropic))
|
||||
arr.AppendElement(NS_LITERAL_STRING("MOZ_EXT_texture_filter_anisotropic"));
|
||||
if (IsExtensionSupported(WebGL_MOZ_WEBGL_lose_context))
|
||||
if (IsExtensionSupported(WebGL_WEBGL_lose_context))
|
||||
arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_lose_context"));
|
||||
if (IsExtensionSupported(WebGL_WEBGL_compressed_texture_s3tc))
|
||||
arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_s3tc"));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -128,16 +128,51 @@ struct BackbufferClearingStatus {
|
|||
enum { NotClearedSinceLastPresented, ClearedToDefaultValues, HasBeenDrawnTo };
|
||||
};
|
||||
|
||||
struct WebGLTexelFormat {
|
||||
enum { Generic, Auto, RGBA8, RGB8, RGBX8, BGRA8, BGR8, BGRX8, RGBA5551, RGBA4444, RGB565, R8, RA8, A8,
|
||||
RGBA32F, RGB32F, A32F, R32F, RA32F };
|
||||
namespace WebGLTexelConversions {
|
||||
|
||||
/*
|
||||
* The formats that may participate, either as source or destination formats,
|
||||
* in WebGL texture conversions. This includes:
|
||||
* - all the formats accepted by WebGL.texImage2D, e.g. RGBA4444
|
||||
* - additional formats provided by extensions, e.g. RGB32F
|
||||
* - additional source formats, depending on browser details, used when uploading
|
||||
* textures from DOM elements. See gfxImageSurface::Format().
|
||||
*/
|
||||
enum WebGLTexelFormat
|
||||
{
|
||||
// dummy error code returned by GetWebGLTexelFormat in error cases,
|
||||
// after assertion failure (so this never happens in debug builds)
|
||||
BadFormat,
|
||||
// dummy pseudo-format meaning "use the other format".
|
||||
// For example, if SrcFormat=Auto and DstFormat=RGB8, then the source
|
||||
// is implicitly treated as being RGB8 itself.
|
||||
Auto,
|
||||
// 1-channel formats
|
||||
R8,
|
||||
A8,
|
||||
R32F, // used for OES_texture_float extension
|
||||
A32F, // used for OES_texture_float extension
|
||||
// 2-channel formats
|
||||
RA8,
|
||||
RA32F,
|
||||
// 3-channel formats
|
||||
RGB8,
|
||||
BGRX8, // used for DOM elements. Source format only.
|
||||
RGB565,
|
||||
RGB32F, // used for OES_texture_float extension
|
||||
// 4-channel formats
|
||||
RGBA8,
|
||||
BGRA8, // used for DOM elements
|
||||
RGBA5551,
|
||||
RGBA4444,
|
||||
RGBA32F // used for OES_texture_float extension
|
||||
};
|
||||
|
||||
struct WebGLTexelPremultiplicationOp {
|
||||
enum { Generic, None, Premultiply, Unmultiply };
|
||||
};
|
||||
} // end namespace WebGLTexelConversions
|
||||
|
||||
int GetWebGLTexelFormat(GLenum format, GLenum type);
|
||||
using WebGLTexelConversions::WebGLTexelFormat;
|
||||
|
||||
WebGLTexelFormat GetWebGLTexelFormat(GLenum format, GLenum type);
|
||||
|
||||
// Zero is not an integer power of two.
|
||||
inline bool is_pot_assuming_nonnegative(WebGLsizei x)
|
||||
|
@ -536,6 +571,7 @@ class WebGLContext :
|
|||
{
|
||||
friend class WebGLMemoryMultiReporterWrapper;
|
||||
friend class WebGLExtensionLoseContext;
|
||||
friend class WebGLExtensionCompressedTextureS3TC;
|
||||
friend class WebGLContextUserData;
|
||||
friend class WebGLMemoryPressureObserver;
|
||||
|
||||
|
@ -1160,7 +1196,8 @@ protected:
|
|||
WebGL_OES_texture_float,
|
||||
WebGL_OES_standard_derivatives,
|
||||
WebGL_EXT_texture_filter_anisotropic,
|
||||
WebGL_MOZ_WEBGL_lose_context,
|
||||
WebGL_WEBGL_lose_context,
|
||||
WebGL_WEBGL_compressed_texture_s3tc,
|
||||
WebGLExtensionID_Max
|
||||
};
|
||||
nsAutoTArray<nsRefPtr<WebGLExtension>, WebGLExtensionID_Max> mEnabledExtensions;
|
||||
|
@ -1170,6 +1207,8 @@ protected:
|
|||
}
|
||||
bool IsExtensionSupported(WebGLExtensionID ei);
|
||||
|
||||
nsTArray<WebGLenum> mCompressedTextureFormats;
|
||||
|
||||
bool InitAndValidateGL();
|
||||
bool ValidateBuffers(PRInt32* maxAllowedCount, const char *info);
|
||||
bool ValidateCapabilityEnum(WebGLenum cap, const char *info);
|
||||
|
@ -1192,7 +1231,11 @@ protected:
|
|||
bool ValidateGLSLCharacter(PRUnichar c);
|
||||
bool ValidateGLSLString(const nsAString& string, const char *info);
|
||||
|
||||
static PRUint32 GetTexelSize(WebGLenum format, WebGLenum type);
|
||||
bool ValidateTexImage2DTarget(WebGLenum target, WebGLsizei width, WebGLsizei height, const char* info);
|
||||
bool ValidateCompressedTextureSize(WebGLint level, WebGLenum format, WebGLsizei width, WebGLsizei height, uint32_t byteLength, const char* info);
|
||||
bool ValidateLevelWidthHeightForTarget(WebGLenum target, WebGLint level, WebGLsizei width, WebGLsizei height, const char* info);
|
||||
|
||||
static PRUint32 GetBitsPerTexel(WebGLenum format, WebGLenum type);
|
||||
|
||||
void Invalidate();
|
||||
void DestroyResourcesAndContext();
|
||||
|
@ -1205,26 +1248,26 @@ protected:
|
|||
WebGLenum format, WebGLenum type,
|
||||
void *data, PRUint32 byteLength,
|
||||
int jsArrayType,
|
||||
int srcFormat, bool srcPremultiplied);
|
||||
WebGLTexelFormat srcFormat, bool srcPremultiplied);
|
||||
void TexSubImage2D_base(WebGLenum target, WebGLint level,
|
||||
WebGLint xoffset, WebGLint yoffset,
|
||||
WebGLsizei width, WebGLsizei height, WebGLsizei srcStrideOrZero,
|
||||
WebGLenum format, WebGLenum type,
|
||||
void *pixels, PRUint32 byteLength,
|
||||
int jsArrayType,
|
||||
int srcFormat, bool srcPremultiplied);
|
||||
WebGLTexelFormat srcFormat, bool srcPremultiplied);
|
||||
void TexParameter_base(WebGLenum target, WebGLenum pname,
|
||||
WebGLint *intParamPtr, WebGLfloat *floatParamPtr);
|
||||
|
||||
void ConvertImage(size_t width, size_t height, size_t srcStride, size_t dstStride,
|
||||
const PRUint8*src, PRUint8 *dst,
|
||||
int srcFormat, bool srcPremultiplied,
|
||||
int dstFormat, bool dstPremultiplied,
|
||||
WebGLTexelFormat srcFormat, bool srcPremultiplied,
|
||||
WebGLTexelFormat dstFormat, bool dstPremultiplied,
|
||||
size_t dstTexelSize);
|
||||
|
||||
nsresult DOMElementToImageSurface(dom::Element* imageOrCanvas,
|
||||
gfxImageSurface **imageOut,
|
||||
int *format);
|
||||
WebGLTexelFormat *format);
|
||||
|
||||
void CopyTexSubImage2D_base(WebGLenum target,
|
||||
WebGLint level,
|
||||
|
@ -1678,8 +1721,8 @@ public:
|
|||
PRInt64 MemoryUsage() const {
|
||||
if (!mIsDefined)
|
||||
return 0;
|
||||
PRInt64 texelSize = WebGLContext::GetTexelSize(mFormat, mType);
|
||||
return PRInt64(mWidth) * PRInt64(mHeight) * texelSize;
|
||||
PRInt64 texelSizeInBits = WebGLContext::GetBitsPerTexel(mFormat, mType);
|
||||
return PRInt64(mWidth) * PRInt64(mHeight) * texelSizeInBits / 8;
|
||||
}
|
||||
WebGLenum Format() const { return mFormat; }
|
||||
WebGLenum Type() const { return mType; }
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
#include "gfxImageSurface.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxPlatform.h"
|
||||
//#include "nsIDOMHTMLCanvasElement.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMError.h"
|
||||
|
@ -2483,7 +2482,8 @@ WebGLContext::GetParameter(JSContext* cx, WebGLenum pname, ErrorResult& rv)
|
|||
return JS::Int32Value(0);
|
||||
case LOCAL_GL_COMPRESSED_TEXTURE_FORMATS:
|
||||
{
|
||||
JSObject* obj = Uint32Array::Create(cx, 0);
|
||||
PRUint32 length = mCompressedTextureFormats.Length();
|
||||
JSObject* obj = Uint32Array::Create(cx, length, mCompressedTextureFormats.Elements());
|
||||
if (!obj) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
@ -4296,198 +4296,9 @@ WebGLContext::StencilOpSeparate(WebGLenum face, WebGLenum sfail, WebGLenum dpfai
|
|||
gl->fStencilOpSeparate(face, sfail, dpfail, dppass);
|
||||
}
|
||||
|
||||
struct WebGLImageConverter
|
||||
{
|
||||
bool flip;
|
||||
size_t width, height, srcStride, dstStride, srcTexelSize, dstTexelSize;
|
||||
const PRUint8 *src;
|
||||
PRUint8 *dst;
|
||||
|
||||
WebGLImageConverter()
|
||||
{
|
||||
memset(this, 0, sizeof(WebGLImageConverter));
|
||||
}
|
||||
|
||||
template<typename SrcType, typename DstType, typename UnpackType,
|
||||
void unpackingFunc(const SrcType*, UnpackType*),
|
||||
void packingFunc(const UnpackType*, DstType*)>
|
||||
void run()
|
||||
{
|
||||
// Note -- even though the functions take UnpackType, the
|
||||
// pointers below are all in terms of PRUint8; otherwise
|
||||
// pointer math starts getting tricky.
|
||||
for (size_t src_row = 0; src_row < height; ++src_row) {
|
||||
size_t dst_row = flip ? (height - 1 - src_row) : src_row;
|
||||
PRUint8 *dst_row_ptr = dst + dst_row * dstStride;
|
||||
const PRUint8 *src_row_ptr = src + src_row * srcStride;
|
||||
const PRUint8 *src_row_end = src_row_ptr + width * srcTexelSize; // != src_row_ptr + byteStride
|
||||
while (src_row_ptr != src_row_end) {
|
||||
UnpackType tmp[4];
|
||||
unpackingFunc(reinterpret_cast<const SrcType*>(src_row_ptr), tmp);
|
||||
packingFunc(tmp, reinterpret_cast<DstType*>(dst_row_ptr));
|
||||
src_row_ptr += srcTexelSize;
|
||||
dst_row_ptr += dstTexelSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
WebGLContext::ConvertImage(size_t width, size_t height, size_t srcStride, size_t dstStride,
|
||||
const PRUint8*src, PRUint8 *dst,
|
||||
int srcFormat, bool srcPremultiplied,
|
||||
int dstFormat, bool dstPremultiplied,
|
||||
size_t dstTexelSize)
|
||||
{
|
||||
if (width <= 0 || height <= 0)
|
||||
return;
|
||||
|
||||
if (srcFormat == dstFormat &&
|
||||
srcPremultiplied == dstPremultiplied)
|
||||
{
|
||||
// fast exit path: we just have to memcpy all the rows.
|
||||
//
|
||||
// The case where absolutely nothing needs to be done is supposed to have
|
||||
// been handled earlier (in TexImage2D_base, etc).
|
||||
//
|
||||
// So the case we're handling here is when even though no format conversion is needed,
|
||||
// we still might have to flip vertically and/or to adjust to a different stride.
|
||||
|
||||
NS_ASSERTION(mPixelStoreFlipY || srcStride != dstStride, "Performance trap -- should handle this case earlier, to avoid memcpy");
|
||||
|
||||
size_t row_size = width * dstTexelSize; // doesn't matter, src and dst formats agree
|
||||
const PRUint8* src_row = src;
|
||||
const PRUint8* src_end = src + height * srcStride;
|
||||
|
||||
PRUint8* dst_row = mPixelStoreFlipY ? dst + (height-1) * dstStride : dst;
|
||||
ptrdiff_t dstStrideSigned(dstStride);
|
||||
ptrdiff_t dst_delta = mPixelStoreFlipY ? -dstStrideSigned : dstStrideSigned;
|
||||
|
||||
while(src_row != src_end) {
|
||||
memcpy(dst_row, src_row, row_size);
|
||||
src_row += srcStride;
|
||||
dst_row += dst_delta;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
WebGLImageConverter converter;
|
||||
converter.flip = mPixelStoreFlipY;
|
||||
converter.width = width;
|
||||
converter.height = height;
|
||||
converter.srcStride = srcStride;
|
||||
converter.dstStride = dstStride;
|
||||
converter.dstTexelSize = dstTexelSize;
|
||||
converter.src = src;
|
||||
converter.dst = dst;
|
||||
|
||||
int premultiplicationOp = (!srcPremultiplied && dstPremultiplied) ? WebGLTexelPremultiplicationOp::Premultiply
|
||||
: (srcPremultiplied && !dstPremultiplied) ? WebGLTexelPremultiplicationOp::Unmultiply
|
||||
: WebGLTexelPremultiplicationOp::None;
|
||||
|
||||
#define HANDLE_DSTFORMAT(format, SrcType, DstType, unpackFunc, packFunc) \
|
||||
case WebGLTexelFormat::format: \
|
||||
switch (premultiplicationOp) { \
|
||||
case WebGLTexelPremultiplicationOp::Premultiply: \
|
||||
converter.run<SrcType, DstType, PRUint8, \
|
||||
WebGLTexelConversions::unpackFunc, \
|
||||
WebGLTexelConversions::packFunc##Premultiply>(); \
|
||||
break; \
|
||||
case WebGLTexelPremultiplicationOp::Unmultiply: \
|
||||
converter.run<SrcType, DstType, PRUint8, \
|
||||
WebGLTexelConversions::unpackFunc, \
|
||||
WebGLTexelConversions::packFunc##Unmultiply>(); \
|
||||
break; \
|
||||
default: \
|
||||
converter.run<SrcType, DstType, PRUint8, \
|
||||
WebGLTexelConversions::unpackFunc, \
|
||||
WebGLTexelConversions::packFunc>(); \
|
||||
break; \
|
||||
} \
|
||||
break;
|
||||
|
||||
#define HANDLE_SRCFORMAT(format, size, SrcType, unpackFunc) \
|
||||
case WebGLTexelFormat::format: \
|
||||
converter.srcTexelSize = size; \
|
||||
switch (dstFormat) { \
|
||||
HANDLE_DSTFORMAT(RGBA8, SrcType, PRUint8, unpackFunc, packRGBA8ToRGBA8) \
|
||||
HANDLE_DSTFORMAT(RGB8, SrcType, PRUint8, unpackFunc, packRGBA8ToRGB8) \
|
||||
HANDLE_DSTFORMAT(R8, SrcType, PRUint8, unpackFunc, packRGBA8ToR8) \
|
||||
HANDLE_DSTFORMAT(RA8, SrcType, PRUint8, unpackFunc, packRGBA8ToRA8) \
|
||||
HANDLE_DSTFORMAT(RGBA5551, SrcType, PRUint16, unpackFunc, packRGBA8ToUnsignedShort5551) \
|
||||
HANDLE_DSTFORMAT(RGBA4444, SrcType, PRUint16, unpackFunc, packRGBA8ToUnsignedShort4444) \
|
||||
HANDLE_DSTFORMAT(RGB565, SrcType, PRUint16, unpackFunc, packRGBA8ToUnsignedShort565) \
|
||||
/* A8 needs to be special-cased as it doesn't have color channels to premultiply */ \
|
||||
case WebGLTexelFormat::A8: \
|
||||
converter.run<SrcType, PRUint8, PRUint8, \
|
||||
WebGLTexelConversions::unpackFunc, \
|
||||
WebGLTexelConversions::packRGBA8ToA8>(); \
|
||||
break; \
|
||||
default: \
|
||||
NS_ASSERTION(false, "Coding error?! Should never reach this point."); \
|
||||
return; \
|
||||
} \
|
||||
break;
|
||||
|
||||
#define HANDLE_FLOAT_DSTFORMAT(format, unpackFunc, packFunc) \
|
||||
case WebGLTexelFormat::format: \
|
||||
switch (premultiplicationOp) { \
|
||||
case WebGLTexelPremultiplicationOp::Premultiply: \
|
||||
converter.run<float, float, float, \
|
||||
WebGLTexelConversions::unpackFunc, \
|
||||
WebGLTexelConversions::packFunc##Premultiply>(); \
|
||||
break; \
|
||||
case WebGLTexelPremultiplicationOp::Unmultiply: \
|
||||
NS_ASSERTION(false, "Floating point can't be un-premultiplied -- we have no premultiplied source data!"); \
|
||||
break; \
|
||||
default: \
|
||||
converter.run<float, float, float, \
|
||||
WebGLTexelConversions::unpackFunc, \
|
||||
WebGLTexelConversions::packFunc>(); \
|
||||
break; \
|
||||
} \
|
||||
break;
|
||||
|
||||
#define HANDLE_FLOAT_SRCFORMAT(format, size, unpackFunc) \
|
||||
case WebGLTexelFormat::format: \
|
||||
converter.srcTexelSize = size; \
|
||||
switch (dstFormat) { \
|
||||
HANDLE_FLOAT_DSTFORMAT(RGB32F, unpackFunc, packRGBA32FToRGB32F) \
|
||||
HANDLE_FLOAT_DSTFORMAT(A32F, unpackFunc, packRGBA32FToA32F) \
|
||||
HANDLE_FLOAT_DSTFORMAT(R32F, unpackFunc, packRGBA32FToR32F) \
|
||||
HANDLE_FLOAT_DSTFORMAT(RA32F, unpackFunc, packRGBA32FToRA32F) \
|
||||
default: \
|
||||
NS_ASSERTION(false, "Coding error?! Should never reach this point."); \
|
||||
return; \
|
||||
} \
|
||||
break;
|
||||
|
||||
switch (srcFormat) {
|
||||
HANDLE_SRCFORMAT(RGBA8, 4, PRUint8, unpackRGBA8ToRGBA8)
|
||||
HANDLE_SRCFORMAT(RGBX8, 4, PRUint8, unpackRGB8ToRGBA8)
|
||||
HANDLE_SRCFORMAT(RGB8, 3, PRUint8, unpackRGB8ToRGBA8)
|
||||
HANDLE_SRCFORMAT(BGRA8, 4, PRUint8, unpackBGRA8ToRGBA8)
|
||||
HANDLE_SRCFORMAT(BGRX8, 4, PRUint8, unpackBGR8ToRGBA8)
|
||||
HANDLE_SRCFORMAT(BGR8, 3, PRUint8, unpackBGR8ToRGBA8)
|
||||
HANDLE_SRCFORMAT(R8, 1, PRUint8, unpackR8ToRGBA8)
|
||||
HANDLE_SRCFORMAT(A8, 1, PRUint8, unpackA8ToRGBA8)
|
||||
HANDLE_SRCFORMAT(RA8, 2, PRUint8, unpackRA8ToRGBA8)
|
||||
HANDLE_SRCFORMAT(RGBA5551, 2, PRUint16, unpackRGBA5551ToRGBA8)
|
||||
HANDLE_SRCFORMAT(RGBA4444, 2, PRUint16, unpackRGBA4444ToRGBA8)
|
||||
HANDLE_SRCFORMAT(RGB565, 2, PRUint16, unpackRGB565ToRGBA8)
|
||||
HANDLE_FLOAT_SRCFORMAT(RGB32F, 12, unpackRGB32FToRGBA32F)
|
||||
HANDLE_FLOAT_SRCFORMAT(RA32F, 8, unpackRA32FToRGBA32F)
|
||||
HANDLE_FLOAT_SRCFORMAT(R32F, 4, unpackR32FToRGBA32F)
|
||||
HANDLE_FLOAT_SRCFORMAT(A32F, 4, unpackA32FToRGBA32F)
|
||||
default:
|
||||
NS_ASSERTION(false, "Coding error?! Should never reach this point.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
WebGLContext::DOMElementToImageSurface(Element* imageOrCanvas,
|
||||
gfxImageSurface **imageOut, int *format)
|
||||
gfxImageSurface **imageOut, WebGLTexelFormat *format)
|
||||
{
|
||||
if (!imageOrCanvas) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -4556,16 +4367,16 @@ WebGLContext::DOMElementToImageSurface(Element* imageOrCanvas,
|
|||
|
||||
switch (surf->Format()) {
|
||||
case gfxASurface::ImageFormatARGB32:
|
||||
*format = WebGLTexelFormat::BGRA8; // careful, our ARGB means BGRA
|
||||
*format = WebGLTexelConversions::BGRA8; // careful, our ARGB means BGRA
|
||||
break;
|
||||
case gfxASurface::ImageFormatRGB24:
|
||||
*format = WebGLTexelFormat::BGRX8; // careful, our RGB24 is not tightly packed. Whence BGRX8.
|
||||
*format = WebGLTexelConversions::BGRX8; // careful, our RGB24 is not tightly packed. Whence BGRX8.
|
||||
break;
|
||||
case gfxASurface::ImageFormatA8:
|
||||
*format = WebGLTexelFormat::A8;
|
||||
*format = WebGLTexelConversions::A8;
|
||||
break;
|
||||
case gfxASurface::ImageFormatRGB16_565:
|
||||
*format = WebGLTexelFormat::RGB565;
|
||||
*format = WebGLTexelConversions::RGB565;
|
||||
break;
|
||||
default:
|
||||
NS_ASSERTION(false, "Unsupported image format. Unimplemented.");
|
||||
|
@ -5271,11 +5082,37 @@ WebGLContext::CompressedTexImage2D(WebGLenum target, WebGLint level, WebGLenum i
|
|||
return;
|
||||
}
|
||||
|
||||
WebGLTexture *tex = activeBoundTextureForTarget(target);
|
||||
if (!tex)
|
||||
return ErrorInvalidOperation("compressedTexImage2D: no texture is bound to this target");
|
||||
if (!ValidateTexImage2DTarget(target, width, height, "compressedTexImage2D")) {
|
||||
return;
|
||||
}
|
||||
|
||||
return ErrorInvalidEnum("compressedTexImage2D: compressed textures are not supported");
|
||||
WebGLTexture *tex = activeBoundTextureForTarget(target);
|
||||
if (!tex) {
|
||||
ErrorInvalidOperation("compressedTexImage2D: no texture is bound to this target");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mCompressedTextureFormats.Contains(internalformat)) {
|
||||
ErrorInvalidEnum("compressedTexImage2D: compressed texture format 0x%x is not supported", internalformat);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateLevelWidthHeightForTarget(target, level, width, height, "compressedTexImage2D")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (border) {
|
||||
ErrorInvalidValue("compressedTexImage2D: border is not 0");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t byteLength = view.mLength;
|
||||
if (!ValidateCompressedTextureSize(level, internalformat, width, height, byteLength, "compressedTexImage2D")) {
|
||||
return;
|
||||
}
|
||||
|
||||
gl->fCompressedTexImage2D(target, level, internalformat, width, height, border, byteLength, view.mData);
|
||||
tex->SetImageInfo(target, level, width, height, internalformat, LOCAL_GL_UNSIGNED_BYTE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -5302,12 +5139,82 @@ WebGLContext::CompressedTexSubImage2D(WebGLenum target, WebGLint level, WebGLint
|
|||
return;
|
||||
}
|
||||
|
||||
WebGLTexture *tex = activeBoundTextureForTarget(target);
|
||||
if (!tex) {
|
||||
return ErrorInvalidOperation("compressedTexSubImage2D: no texture is bound to this target");
|
||||
switch (target) {
|
||||
case LOCAL_GL_TEXTURE_2D:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
|
||||
break;
|
||||
default:
|
||||
return ErrorInvalidEnumInfo("texSubImage2D: target", target);
|
||||
}
|
||||
|
||||
return ErrorInvalidEnum("compressedTexSubImage2D: compressed textures are not supported");
|
||||
WebGLTexture *tex = activeBoundTextureForTarget(target);
|
||||
if (!tex) {
|
||||
ErrorInvalidOperation("compressedTexSubImage2D: no texture is bound to this target");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mCompressedTextureFormats.Contains(format)) {
|
||||
ErrorInvalidEnum("compressedTexSubImage2D: compressed texture format 0x%x is not supported", format);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateLevelWidthHeightForTarget(target, level, width, height, "compressedTexSubImage2D")) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t byteLength = view.mLength;
|
||||
if (!ValidateCompressedTextureSize(level, format, width, height, byteLength, "compressedTexSubImage2D")) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t face = WebGLTexture::FaceForTarget(target);
|
||||
|
||||
if (!tex->HasImageInfoAt(level, face)) {
|
||||
ErrorInvalidOperation("compressedTexSubImage2D: no texture image previously defined for this level and face");
|
||||
return;
|
||||
}
|
||||
|
||||
const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(level, face);
|
||||
|
||||
if (!CanvasUtils::CheckSaneSubrectSize(xoffset, yoffset, width, height, imageInfo.Width(), imageInfo.Height())) {
|
||||
ErrorInvalidValue("compressedTexSubImage2D: subtexture rectangle out of bounds");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
|
||||
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
|
||||
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
|
||||
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
|
||||
{
|
||||
if (xoffset < 0 || xoffset % 4 != 0) {
|
||||
ErrorInvalidOperation("compressedTexSubImage2D: xoffset is not a multiple of 4");
|
||||
return;
|
||||
}
|
||||
if (yoffset < 0 || yoffset % 4 != 0) {
|
||||
ErrorInvalidOperation("compressedTexSubImage2D: yoffset is not a multiple of 4");
|
||||
return;
|
||||
}
|
||||
if (width % 4 != 0 && width != imageInfo.Width()) {
|
||||
ErrorInvalidOperation("compressedTexSubImage2D: width is not a multiple of 4 or equal to texture width");
|
||||
return;
|
||||
}
|
||||
if (height % 4 != 0 && height != imageInfo.Height()) {
|
||||
ErrorInvalidOperation("compressedTexSubImage2D: height is not a multiple of 4 or equal to texture height");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gl->fCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, byteLength, view.mData);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -5644,22 +5551,10 @@ WebGLContext::TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum intern
|
|||
WebGLenum format, WebGLenum type,
|
||||
void *data, PRUint32 byteLength,
|
||||
int jsArrayType, // a TypedArray format enum, or -1 if not relevant
|
||||
int srcFormat, bool srcPremultiplied)
|
||||
WebGLTexelFormat srcFormat, bool srcPremultiplied)
|
||||
{
|
||||
switch (target) {
|
||||
case LOCAL_GL_TEXTURE_2D:
|
||||
break;
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
|
||||
if (width != height)
|
||||
return ErrorInvalidValue("texImage2D: with cube map targets, width and height must be equal");
|
||||
break;
|
||||
default:
|
||||
return ErrorInvalidEnumInfo("texImage2D: target", target);
|
||||
if (!ValidateTexImage2DTarget(target, width, height, "texImage2D")) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
|
@ -5676,19 +5571,9 @@ WebGLContext::TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum intern
|
|||
if (format != internalformat)
|
||||
return ErrorInvalidOperation("texImage2D: format does not match internalformat");
|
||||
|
||||
WebGLsizei maxTextureSize = MaxTextureSizeForTarget(target);
|
||||
|
||||
if (level < 0)
|
||||
return ErrorInvalidValue("texImage2D: level must be >= 0");
|
||||
|
||||
if (!(maxTextureSize >> level))
|
||||
return ErrorInvalidValue("texImage2D: 2^level exceeds maximum texture size");
|
||||
|
||||
if (width < 0 || height < 0)
|
||||
return ErrorInvalidValue("texImage2D: width and height must be >= 0");
|
||||
|
||||
if (width > maxTextureSize || height > maxTextureSize)
|
||||
return ErrorInvalidValue("texImage2D: width or height exceeds maximum texture size");
|
||||
if (!ValidateLevelWidthHeightForTarget(target, level, width, height, "texImage2D")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (level >= 1) {
|
||||
if (!(is_pot_assuming_nonnegative(width) &&
|
||||
|
@ -5699,14 +5584,19 @@ WebGLContext::TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum intern
|
|||
if (border != 0)
|
||||
return ErrorInvalidValue("TexImage2D: border must be 0");
|
||||
|
||||
PRUint32 texelSize = 0;
|
||||
if (!ValidateTexFormatAndType(format, type, jsArrayType, &texelSize, "texImage2D"))
|
||||
PRUint32 dstTexelSize = 0;
|
||||
if (!ValidateTexFormatAndType(format, type, jsArrayType, &dstTexelSize, "texImage2D"))
|
||||
return;
|
||||
|
||||
CheckedUint32 checked_neededByteLength =
|
||||
GetImageSize(height, width, texelSize, mPixelStoreUnpackAlignment);
|
||||
WebGLTexelFormat dstFormat = GetWebGLTexelFormat(format, type);
|
||||
WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelConversions::Auto ? dstFormat : srcFormat;
|
||||
|
||||
CheckedUint32 checked_plainRowSize = CheckedUint32(width) * texelSize;
|
||||
PRUint32 srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(actualSrcFormat);
|
||||
|
||||
CheckedUint32 checked_neededByteLength =
|
||||
GetImageSize(height, width, srcTexelSize, mPixelStoreUnpackAlignment);
|
||||
|
||||
CheckedUint32 checked_plainRowSize = CheckedUint32(width) * srcTexelSize;
|
||||
|
||||
CheckedUint32 checked_alignedRowSize =
|
||||
RoundedToNextMultipleOf(checked_plainRowSize.value(), mPixelStoreUnpackAlignment);
|
||||
|
@ -5734,11 +5624,9 @@ WebGLContext::TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum intern
|
|||
GLenum error = LOCAL_GL_NO_ERROR;
|
||||
|
||||
if (byteLength) {
|
||||
int dstFormat = GetWebGLTexelFormat(format, type);
|
||||
int actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat;
|
||||
size_t srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
|
||||
|
||||
size_t dstPlainRowSize = texelSize * width;
|
||||
size_t dstPlainRowSize = dstTexelSize * width;
|
||||
size_t unpackAlignment = mPixelStoreUnpackAlignment;
|
||||
size_t dstStride = ((dstPlainRowSize + unpackAlignment-1) / unpackAlignment) * unpackAlignment;
|
||||
|
||||
|
@ -5753,11 +5641,12 @@ WebGLContext::TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum intern
|
|||
}
|
||||
else
|
||||
{
|
||||
nsAutoArrayPtr<PRUint8> convertedData(new PRUint8[bytesNeeded]);
|
||||
size_t convertedDataSize = height * dstStride;
|
||||
nsAutoArrayPtr<PRUint8> convertedData(new PRUint8[convertedDataSize]);
|
||||
ConvertImage(width, height, srcStride, dstStride,
|
||||
(PRUint8*)data, convertedData,
|
||||
actualSrcFormat, srcPremultiplied,
|
||||
dstFormat, mPixelStorePremultiplyAlpha, texelSize);
|
||||
dstFormat, mPixelStorePremultiplyAlpha, dstTexelSize);
|
||||
error = CheckedTexImage2D(target, level, internalformat,
|
||||
width, height, border, format, type, convertedData);
|
||||
}
|
||||
|
@ -5814,7 +5703,7 @@ WebGLContext::TexImage2D(JSContext* cx, WebGLenum target, WebGLint level,
|
|||
pixels ? pixels->mData : 0,
|
||||
pixels ? pixels->mLength : 0,
|
||||
pixels ? (int)JS_GetTypedArrayType(pixels->mObj, cx) : -1,
|
||||
WebGLTexelFormat::Auto, false);
|
||||
WebGLTexelConversions::Auto, false);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -5832,7 +5721,7 @@ WebGLContext::TexImage2D_imageData(WebGLenum target, WebGLint level, WebGLenum i
|
|||
pixels ? JS_GetArrayBufferViewData(pixels, cx) : 0,
|
||||
pixels ? JS_GetArrayBufferViewByteLength(pixels, cx) : 0,
|
||||
-1,
|
||||
WebGLTexelFormat::RGBA8, false);
|
||||
WebGLTexelConversions::RGBA8, false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -5853,7 +5742,7 @@ WebGLContext::TexImage2D(JSContext* cx, WebGLenum target, WebGLint level,
|
|||
return TexImage2D_base(target, level, internalformat, pixels->GetWidth(),
|
||||
pixels->GetHeight(), 4*pixels->GetWidth(), 0,
|
||||
format, type, arr.mData, arr.mLength, -1,
|
||||
WebGLTexelFormat::RGBA8, false);
|
||||
WebGLTexelConversions::RGBA8, false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -5877,7 +5766,7 @@ WebGLContext::TexImage2D(JSContext* /* unused */, WebGLenum target,
|
|||
|
||||
nsRefPtr<gfxImageSurface> isurf;
|
||||
|
||||
int srcFormat;
|
||||
WebGLTexelFormat srcFormat;
|
||||
rv = DOMElementToImageSurface(elt, getter_AddRefs(isurf), &srcFormat);
|
||||
if (rv.Failed())
|
||||
return;
|
||||
|
@ -5908,7 +5797,7 @@ WebGLContext::TexSubImage2D_base(WebGLenum target, WebGLint level,
|
|||
WebGLenum format, WebGLenum type,
|
||||
void *pixels, PRUint32 byteLength,
|
||||
int jsArrayType,
|
||||
int srcFormat, bool srcPremultiplied)
|
||||
WebGLTexelFormat srcFormat, bool srcPremultiplied)
|
||||
{
|
||||
switch (target) {
|
||||
case LOCAL_GL_TEXTURE_2D:
|
||||
|
@ -5923,19 +5812,9 @@ WebGLContext::TexSubImage2D_base(WebGLenum target, WebGLint level,
|
|||
return ErrorInvalidEnumInfo("texSubImage2D: target", target);
|
||||
}
|
||||
|
||||
WebGLsizei maxTextureSize = MaxTextureSizeForTarget(target);
|
||||
|
||||
if (level < 0)
|
||||
return ErrorInvalidValue("texSubImage2D: level must be >= 0");
|
||||
|
||||
if (!(maxTextureSize >> level))
|
||||
return ErrorInvalidValue("texSubImage2D: 2^level exceeds maximum texture size");
|
||||
|
||||
if (width < 0 || height < 0)
|
||||
return ErrorInvalidValue("texSubImage2D: width and height must be >= 0");
|
||||
|
||||
if (width > maxTextureSize || height > maxTextureSize)
|
||||
return ErrorInvalidValue("texSubImage2D: width or height exceeds maximum texture size");
|
||||
if (!ValidateLevelWidthHeightForTarget(target, level, width, height, "texSubImage2D")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (level >= 1) {
|
||||
if (!(is_pot_assuming_nonnegative(width) &&
|
||||
|
@ -5943,17 +5822,22 @@ WebGLContext::TexSubImage2D_base(WebGLenum target, WebGLint level,
|
|||
return ErrorInvalidValue("texSubImage2D: with level > 0, width and height must be powers of two");
|
||||
}
|
||||
|
||||
PRUint32 texelSize = 0;
|
||||
if (!ValidateTexFormatAndType(format, type, jsArrayType, &texelSize, "texSubImage2D"))
|
||||
PRUint32 dstTexelSize = 0;
|
||||
if (!ValidateTexFormatAndType(format, type, jsArrayType, &dstTexelSize, "texSubImage2D"))
|
||||
return;
|
||||
|
||||
WebGLTexelFormat dstFormat = GetWebGLTexelFormat(format, type);
|
||||
WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelConversions::Auto ? dstFormat : srcFormat;
|
||||
|
||||
PRUint32 srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(actualSrcFormat);
|
||||
|
||||
if (width == 0 || height == 0)
|
||||
return; // ES 2.0 says it has no effect, we better return right now
|
||||
|
||||
CheckedUint32 checked_neededByteLength =
|
||||
GetImageSize(height, width, texelSize, mPixelStoreUnpackAlignment);
|
||||
GetImageSize(height, width, srcTexelSize, mPixelStoreUnpackAlignment);
|
||||
|
||||
CheckedUint32 checked_plainRowSize = CheckedUint32(width) * texelSize;
|
||||
CheckedUint32 checked_plainRowSize = CheckedUint32(width) * srcTexelSize;
|
||||
|
||||
CheckedUint32 checked_alignedRowSize =
|
||||
RoundedToNextMultipleOf(checked_plainRowSize.value(), mPixelStoreUnpackAlignment);
|
||||
|
@ -5986,11 +5870,9 @@ WebGLContext::TexSubImage2D_base(WebGLenum target, WebGLint level,
|
|||
|
||||
MakeContextCurrent();
|
||||
|
||||
int dstFormat = GetWebGLTexelFormat(format, type);
|
||||
int actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat;
|
||||
size_t srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
|
||||
|
||||
size_t dstPlainRowSize = texelSize * width;
|
||||
size_t dstPlainRowSize = dstTexelSize * width;
|
||||
// There are checks above to ensure that this won't overflow.
|
||||
size_t dstStride = RoundedToNextMultipleOf(dstPlainRowSize, mPixelStoreUnpackAlignment).value();
|
||||
|
||||
|
@ -6004,11 +5886,12 @@ WebGLContext::TexSubImage2D_base(WebGLenum target, WebGLint level,
|
|||
}
|
||||
else
|
||||
{
|
||||
nsAutoArrayPtr<PRUint8> convertedData(new PRUint8[bytesNeeded]);
|
||||
size_t convertedDataSize = height * dstStride;
|
||||
nsAutoArrayPtr<PRUint8> convertedData(new PRUint8[convertedDataSize]);
|
||||
ConvertImage(width, height, srcStride, dstStride,
|
||||
(const PRUint8*)pixels, convertedData,
|
||||
actualSrcFormat, srcPremultiplied,
|
||||
dstFormat, mPixelStorePremultiplyAlpha, texelSize);
|
||||
dstFormat, mPixelStorePremultiplyAlpha, dstTexelSize);
|
||||
|
||||
gl->fTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, convertedData);
|
||||
}
|
||||
|
@ -6051,7 +5934,7 @@ WebGLContext::TexSubImage2D(JSContext* cx, WebGLenum target, WebGLint level,
|
|||
width, height, 0, format, type,
|
||||
pixels->mData, pixels->mLength,
|
||||
JS_GetTypedArrayType(pixels->mObj, cx),
|
||||
WebGLTexelFormat::Auto, false);
|
||||
WebGLTexelConversions::Auto, false);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -6075,7 +5958,7 @@ WebGLContext::TexSubImage2D_imageData(WebGLenum target, WebGLint level,
|
|||
width, height, 4*width, format, type,
|
||||
JS_GetArrayBufferViewData(pixels, cx), JS_GetArrayBufferViewByteLength(pixels, cx),
|
||||
-1,
|
||||
WebGLTexelFormat::RGBA8, false);
|
||||
WebGLTexelConversions::RGBA8, false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -6097,7 +5980,7 @@ WebGLContext::TexSubImage2D(JSContext* cx, WebGLenum target, WebGLint level,
|
|||
4*pixels->GetWidth(), format, type,
|
||||
arr.mData, arr.mLength,
|
||||
-1,
|
||||
WebGLTexelFormat::RGBA8, false);
|
||||
WebGLTexelConversions::RGBA8, false);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -6122,7 +6005,7 @@ WebGLContext::TexSubImage2D(JSContext* /* unused */, WebGLenum target,
|
|||
|
||||
nsRefPtr<gfxImageSurface> isurf;
|
||||
|
||||
int srcFormat;
|
||||
WebGLTexelFormat srcFormat;
|
||||
rv = DOMElementToImageSurface(elt, getter_AddRefs(isurf), &srcFormat);
|
||||
if (rv.Failed())
|
||||
return;
|
||||
|
@ -6232,52 +6115,52 @@ BaseTypeAndSizeFromUniformType(WebGLenum uType, WebGLenum *baseType, WebGLint *u
|
|||
}
|
||||
|
||||
|
||||
int mozilla::GetWebGLTexelFormat(GLenum format, GLenum type)
|
||||
WebGLTexelFormat mozilla::GetWebGLTexelFormat(GLenum format, GLenum type)
|
||||
{
|
||||
if (type == LOCAL_GL_UNSIGNED_BYTE) {
|
||||
switch (format) {
|
||||
case LOCAL_GL_RGBA:
|
||||
return WebGLTexelFormat::RGBA8;
|
||||
return WebGLTexelConversions::RGBA8;
|
||||
case LOCAL_GL_RGB:
|
||||
return WebGLTexelFormat::RGB8;
|
||||
return WebGLTexelConversions::RGB8;
|
||||
case LOCAL_GL_ALPHA:
|
||||
return WebGLTexelFormat::A8;
|
||||
return WebGLTexelConversions::A8;
|
||||
case LOCAL_GL_LUMINANCE:
|
||||
return WebGLTexelFormat::R8;
|
||||
return WebGLTexelConversions::R8;
|
||||
case LOCAL_GL_LUMINANCE_ALPHA:
|
||||
return WebGLTexelFormat::RA8;
|
||||
return WebGLTexelConversions::RA8;
|
||||
default:
|
||||
NS_ASSERTION(false, "Coding mistake?! Should never reach this point.");
|
||||
return WebGLTexelFormat::Generic;
|
||||
NS_ABORT_IF_FALSE(false, "Coding mistake?! Should never reach this point.");
|
||||
return WebGLTexelConversions::BadFormat;
|
||||
}
|
||||
} else if (type == LOCAL_GL_FLOAT) {
|
||||
// OES_texture_float
|
||||
switch (format) {
|
||||
case LOCAL_GL_RGBA:
|
||||
return WebGLTexelFormat::RGBA32F;
|
||||
return WebGLTexelConversions::RGBA32F;
|
||||
case LOCAL_GL_RGB:
|
||||
return WebGLTexelFormat::RGB32F;
|
||||
return WebGLTexelConversions::RGB32F;
|
||||
case LOCAL_GL_ALPHA:
|
||||
return WebGLTexelFormat::A32F;
|
||||
return WebGLTexelConversions::A32F;
|
||||
case LOCAL_GL_LUMINANCE:
|
||||
return WebGLTexelFormat::R32F;
|
||||
return WebGLTexelConversions::R32F;
|
||||
case LOCAL_GL_LUMINANCE_ALPHA:
|
||||
return WebGLTexelFormat::RA32F;
|
||||
return WebGLTexelConversions::RA32F;
|
||||
default:
|
||||
NS_ASSERTION(false, "Coding mistake?! Should never reach this point.");
|
||||
return WebGLTexelFormat::Generic;
|
||||
NS_ABORT_IF_FALSE(false, "Coding mistake?! Should never reach this point.");
|
||||
return WebGLTexelConversions::BadFormat;
|
||||
}
|
||||
} else {
|
||||
switch (type) {
|
||||
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
|
||||
return WebGLTexelFormat::RGBA4444;
|
||||
return WebGLTexelConversions::RGBA4444;
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
|
||||
return WebGLTexelFormat::RGBA5551;
|
||||
return WebGLTexelConversions::RGBA5551;
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
|
||||
return WebGLTexelFormat::RGB565;
|
||||
return WebGLTexelConversions::RGB565;
|
||||
default:
|
||||
NS_ASSERTION(false, "Coding mistake?! Should never reach this point.");
|
||||
return WebGLTexelFormat::Generic;
|
||||
NS_ABORT_IF_FALSE(false, "Coding mistake?! Should never reach this point.");
|
||||
return WebGLTexelConversions::BadFormat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,3 +57,4 @@ DOMCI_DATA(WebGLExtension, void)
|
|||
DOMCI_DATA(WebGLExtensionStandardDerivatives, void)
|
||||
DOMCI_DATA(WebGLExtensionTextureFilterAnisotropic, void)
|
||||
DOMCI_DATA(WebGLExtensionLoseContext, void)
|
||||
DOMCI_DATA(WebGLExtensionCompressedTextureS3TC, void)
|
||||
|
|
|
@ -371,10 +371,118 @@ bool WebGLContext::ValidateGLSLString(const nsAString& string, const char *info)
|
|||
return true;
|
||||
}
|
||||
|
||||
PRUint32 WebGLContext::GetTexelSize(WebGLenum format, WebGLenum type)
|
||||
bool WebGLContext::ValidateTexImage2DTarget(WebGLenum target, WebGLsizei width, WebGLsizei height,
|
||||
const char* info)
|
||||
{
|
||||
switch (target) {
|
||||
case LOCAL_GL_TEXTURE_2D:
|
||||
break;
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
|
||||
if (width != height) {
|
||||
ErrorInvalidValue("%s: with cube map targets, width and height must be equal", info);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ErrorInvalidEnum("%s: invalid target enum 0x%x", info, target);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebGLContext::ValidateCompressedTextureSize(WebGLint level, WebGLenum format, WebGLsizei width,
|
||||
WebGLsizei height, uint32_t byteLength, const char* info)
|
||||
{
|
||||
CheckedUint32 calculated_byteLength = 0;
|
||||
CheckedUint32 checked_byteLength = byteLength;
|
||||
if (!checked_byteLength.valid()) {
|
||||
ErrorInvalidValue("%s: data length out of bounds", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
|
||||
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
|
||||
{
|
||||
calculated_byteLength = ((CheckedUint32(width) + 3) / 4) * ((CheckedUint32(height) + 3) / 4) * 8;
|
||||
if (!calculated_byteLength.valid() || !(checked_byteLength == calculated_byteLength)) {
|
||||
ErrorInvalidValue("%s: data size does not match dimensions", info);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
|
||||
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
|
||||
{
|
||||
calculated_byteLength = ((CheckedUint32(width) + 3) / 4) * ((CheckedUint32(height) + 3) / 4) * 16;
|
||||
if (!calculated_byteLength.valid() || !(checked_byteLength == calculated_byteLength)) {
|
||||
ErrorInvalidValue("%s: data size does not match dimensions", info);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
|
||||
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
|
||||
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
|
||||
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
|
||||
{
|
||||
if (level == 0 && width % 4 == 0 && height % 4 == 0) {
|
||||
return true;
|
||||
}
|
||||
if (level > 0
|
||||
&& (width == 0 || width == 1 || width == 2 || width % 4 == 0)
|
||||
&& (height == 0 || height == 1 || height == 2 || height % 4 == 0))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ErrorInvalidOperation("%s: level parameter does not match width and height", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WebGLContext::ValidateLevelWidthHeightForTarget(WebGLenum target, WebGLint level, WebGLsizei width,
|
||||
WebGLsizei height, const char* info)
|
||||
{
|
||||
WebGLsizei maxTextureSize = MaxTextureSizeForTarget(target);
|
||||
|
||||
if (level < 0) {
|
||||
ErrorInvalidValue("%s: level must be >= 0", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(maxTextureSize >> level)) {
|
||||
ErrorInvalidValue("%s: 2^level exceeds maximum texture size");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (width < 0 || height < 0) {
|
||||
ErrorInvalidValue("%s: width and height must be >= 0");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (width > maxTextureSize || height > maxTextureSize) {
|
||||
ErrorInvalidValue("%s: width or height exceeds maximum texture size");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PRUint32 WebGLContext::GetBitsPerTexel(WebGLenum format, WebGLenum type)
|
||||
{
|
||||
if (type == LOCAL_GL_UNSIGNED_BYTE || type == LOCAL_GL_FLOAT) {
|
||||
int multiplier = type == LOCAL_GL_FLOAT ? 4 : 1;
|
||||
int multiplier = type == LOCAL_GL_FLOAT ? 32 : 8;
|
||||
switch (format) {
|
||||
case LOCAL_GL_ALPHA:
|
||||
case LOCAL_GL_LUMINANCE:
|
||||
|
@ -385,6 +493,12 @@ PRUint32 WebGLContext::GetTexelSize(WebGLenum format, WebGLenum type)
|
|||
return 3 * multiplier;
|
||||
case LOCAL_GL_RGBA:
|
||||
return 4 * multiplier;
|
||||
case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
|
||||
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
|
||||
return 4;
|
||||
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
|
||||
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
|
||||
return 8;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -392,7 +506,7 @@ PRUint32 WebGLContext::GetTexelSize(WebGLenum format, WebGLenum type)
|
|||
type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 ||
|
||||
type == LOCAL_GL_UNSIGNED_SHORT_5_6_5)
|
||||
{
|
||||
return 2;
|
||||
return 16;
|
||||
}
|
||||
|
||||
NS_ABORT();
|
||||
|
@ -518,20 +632,6 @@ WebGLContext::InitAndValidateGL()
|
|||
return false;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
// bug 736123, blacklist WebGL on Adreno because they do not implement
|
||||
// glTexSubImage2D in a way that is safe to expose to WebGL </euphemism>
|
||||
// We don't rely on GfxInfo for this blacklisting, because GfxInfo on Android doesn't know
|
||||
// about GL strings and GL strings are the only way I know to detect Adreno (EGL Vendor only
|
||||
// says 'Android'), and it is not convenient to have to create a GL context before GfxInfo::Init()
|
||||
// is first called.
|
||||
if (gl->Renderer() == gl::GLContext::RendererAdreno200 ||
|
||||
gl->Renderer() == gl::GLContext::RendererAdreno205)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
mMinCapability = Preferences::GetBool("webgl.min_capability_mode", false);
|
||||
mDisableExtensions = Preferences::GetBool("webgl.disable-extensions", false);
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/* 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 "WebGLContext.h"
|
||||
#include "WebGLExtensions.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
WebGLExtensionCompressedTextureS3TC::WebGLExtensionCompressedTextureS3TC(WebGLContext* context)
|
||||
: WebGLExtension(context)
|
||||
{
|
||||
context->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT);
|
||||
context->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT);
|
||||
context->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT);
|
||||
context->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT);
|
||||
}
|
||||
|
||||
WebGLExtensionCompressedTextureS3TC::~WebGLExtensionCompressedTextureS3TC()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(WebGLExtensionCompressedTextureS3TC, WebGLExtension)
|
||||
NS_IMPL_RELEASE_INHERITED(WebGLExtensionCompressedTextureS3TC, WebGLExtension)
|
||||
|
||||
DOMCI_DATA(WebGLExtensionCompressedTextureS3TC, WebGLExtensionCompressedTextureS3TC)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(WebGLExtensionCompressedTextureS3TC)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIWebGLExtensionCompressedTextureS3TC)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, WebGLExtension)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtensionCompressedTextureS3TC)
|
||||
NS_INTERFACE_MAP_END_INHERITING(WebGLExtension)
|
|
@ -36,14 +36,9 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "WebGLContext.h"
|
||||
#include "WebGLExtensions.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
WebGLExtensionLoseContext::WebGLExtensionLoseContext(WebGLContext* context) :
|
||||
|
|
|
@ -36,14 +36,9 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "WebGLContext.h"
|
||||
#include "WebGLExtensions.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
WebGLExtensionStandardDerivatives::WebGLExtensionStandardDerivatives(WebGLContext* context) :
|
||||
|
|
|
@ -36,14 +36,9 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "WebGLContext.h"
|
||||
#include "WebGLExtensions.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
WebGLExtensionTextureFilterAnisotropic::WebGLExtensionTextureFilterAnisotropic(WebGLContext* context) :
|
||||
|
|
|
@ -77,6 +77,18 @@ public:
|
|||
NS_DECL_NSIWEBGLEXTENSION
|
||||
};
|
||||
|
||||
class WebGLExtensionCompressedTextureS3TC :
|
||||
public nsIWebGLExtensionCompressedTextureS3TC,
|
||||
public WebGLExtension
|
||||
{
|
||||
public:
|
||||
WebGLExtensionCompressedTextureS3TC(WebGLContext* context);
|
||||
virtual ~WebGLExtensionCompressedTextureS3TC();
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIWEBGLEXTENSION
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // WEBGLEXTENSIONS_H_
|
||||
|
|
|
@ -0,0 +1,382 @@
|
|||
/* 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 "WebGLTexelConversions.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace WebGLTexelConversions;
|
||||
|
||||
namespace {
|
||||
|
||||
/** @class WebGLImageConverter
|
||||
*
|
||||
* This class is just a helper to implement WebGLContext::ConvertImage below.
|
||||
*
|
||||
* Design comments:
|
||||
*
|
||||
* WebGLContext::ConvertImage has to handle hundreds of format conversion paths.
|
||||
* It is important to minimize executable code size here. Instead of passing around
|
||||
* a large number of function parameters hundreds of times, we create a
|
||||
* WebGLImageConverter object once, storing these parameters, and then we call
|
||||
* the run() method on it.
|
||||
*/
|
||||
class WebGLImageConverter
|
||||
{
|
||||
const size_t mWidth, mHeight;
|
||||
const void* const mSrcStart;
|
||||
void* const mDstStart;
|
||||
const ptrdiff_t mSrcStride, mDstStride;
|
||||
bool mAlreadyRun;
|
||||
bool mSuccess;
|
||||
|
||||
/*
|
||||
* Returns sizeof(texel)/sizeof(type). The point is that we will iterate over
|
||||
* texels with typed pointers and this value will tell us by how much we need
|
||||
* to increment these pointers to advance to the next texel.
|
||||
*/
|
||||
template<int Format>
|
||||
static size_t NumElementsPerTexelForFormat() {
|
||||
switch (Format) {
|
||||
case R8:
|
||||
case A8:
|
||||
case R32F:
|
||||
case A32F:
|
||||
case RGBA5551:
|
||||
case RGBA4444:
|
||||
case RGB565:
|
||||
return 1;
|
||||
case RA8:
|
||||
case RA32F:
|
||||
return 2;
|
||||
case RGB8:
|
||||
case RGB32F:
|
||||
return 3;
|
||||
case RGBA8:
|
||||
case BGRA8:
|
||||
case BGRX8:
|
||||
case RGBA32F:
|
||||
return 4;
|
||||
default:
|
||||
NS_ABORT_IF_FALSE(false, "Unknown texel format. Coding mistake?");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the completely format-specific templatized conversion function,
|
||||
* that will be instantiated hundreds of times for all different combinations.
|
||||
* It is important to avoid generating useless code here. In particular, many
|
||||
* instantiations of this function template will never be called, so we try
|
||||
* to return immediately in these cases to allow the compiler to avoid generating
|
||||
* useless code.
|
||||
*/
|
||||
template<WebGLTexelFormat SrcFormat,
|
||||
WebGLTexelFormat DstFormat,
|
||||
WebGLTexelPremultiplicationOp PremultiplicationOp>
|
||||
void run()
|
||||
{
|
||||
// check for never-called cases. We early-return to allow the compiler
|
||||
// to avoid generating this code. It would be tempting to abort() instead,
|
||||
// as returning early does leave the destination surface with uninitialized
|
||||
// data, but that would not allow the compiler to avoid generating this code.
|
||||
// So instead, we return early, so Success() will return false, and the caller
|
||||
// must check that and abort in that case. See WebGLContext::ConvertImage.
|
||||
|
||||
if (SrcFormat == DstFormat &&
|
||||
PremultiplicationOp == NoPremultiplicationOp)
|
||||
{
|
||||
// Should have used a fast exit path earlier, rather than entering this function.
|
||||
// we explicitly return here to allow the compiler to avoid generating this code
|
||||
return;
|
||||
}
|
||||
|
||||
// Only textures uploaded from DOM elements or ImageData can allow DstFormat != SrcFormat.
|
||||
// DOM elements can only give BGRA8, BGRX8, A8, RGB565 formats. See DOMElementToImageSurface.
|
||||
// ImageData is always RGBA8. So all other SrcFormat will always satisfy DstFormat==SrcFormat,
|
||||
// so we can avoid compiling the code for all the unreachable paths.
|
||||
const bool CanSrcFormatComeFromDOMElementOrImageData
|
||||
= SrcFormat == BGRA8 ||
|
||||
SrcFormat == BGRX8 ||
|
||||
SrcFormat == A8 ||
|
||||
SrcFormat == RGB565 ||
|
||||
SrcFormat == RGBA8;
|
||||
if (!CanSrcFormatComeFromDOMElementOrImageData &&
|
||||
SrcFormat != DstFormat)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Likewise, only textures uploaded from DOM elements or ImageData can possibly have to be unpremultiplied.
|
||||
if (!CanSrcFormatComeFromDOMElementOrImageData &&
|
||||
PremultiplicationOp == Unpremultiply)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// there is no point in premultiplication/unpremultiplication
|
||||
// in the following cases:
|
||||
// - the source format has no alpha
|
||||
// - the source format has no color
|
||||
// - the destination format has no color
|
||||
if (!HasAlpha(SrcFormat) ||
|
||||
!HasColor(SrcFormat) ||
|
||||
!HasColor(DstFormat))
|
||||
{
|
||||
|
||||
if (PremultiplicationOp != NoPremultiplicationOp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// end of early return cases.
|
||||
|
||||
NS_ABORT_IF_FALSE(!mAlreadyRun, "converter should be run only once!");
|
||||
mAlreadyRun = true;
|
||||
|
||||
// gather some compile-time meta-data about the formats at hand.
|
||||
|
||||
typedef
|
||||
typename DataTypeForFormat<SrcFormat>::Type
|
||||
SrcType;
|
||||
typedef
|
||||
typename DataTypeForFormat<DstFormat>::Type
|
||||
DstType;
|
||||
|
||||
const int IntermediateSrcFormat
|
||||
= IntermediateFormat<SrcFormat>::Value;
|
||||
const int IntermediateDstFormat
|
||||
= IntermediateFormat<DstFormat>::Value;
|
||||
typedef
|
||||
typename DataTypeForFormat<IntermediateSrcFormat>::Type
|
||||
IntermediateSrcType;
|
||||
typedef
|
||||
typename DataTypeForFormat<IntermediateDstFormat>::Type
|
||||
IntermediateDstType;
|
||||
|
||||
const size_t NumElementsPerSrcTexel = NumElementsPerTexelForFormat<SrcFormat>();
|
||||
const size_t NumElementsPerDstTexel = NumElementsPerTexelForFormat<DstFormat>();
|
||||
const size_t MaxElementsPerTexel = 4;
|
||||
NS_ABORT_IF_FALSE(NumElementsPerSrcTexel <= MaxElementsPerTexel, "unhandled format");
|
||||
NS_ABORT_IF_FALSE(NumElementsPerDstTexel <= MaxElementsPerTexel, "unhandled format");
|
||||
|
||||
// we assume that the strides are multiples of the sizeof of respective types.
|
||||
// this assumption will allow us to iterate over src and dst images using typed
|
||||
// pointers, e.g. uint8_t* or uint16_t* or float*, instead of untyped pointers.
|
||||
// So this assumption allows us to write cleaner and safer code, but it might
|
||||
// not be true forever and if it eventually becomes wrong, we'll have to revert
|
||||
// to always iterating using uint8_t* pointers regardless of the types at hand.
|
||||
NS_ABORT_IF_FALSE(mSrcStride % sizeof(SrcType) == 0 &&
|
||||
mDstStride % sizeof(DstType) == 0,
|
||||
"Unsupported: texture stride is not a multiple of sizeof(type)");
|
||||
const ptrdiff_t srcStrideInElements = mSrcStride / sizeof(SrcType);
|
||||
const ptrdiff_t dstStrideInElements = mDstStride / sizeof(DstType);
|
||||
|
||||
const SrcType *srcRowStart = static_cast<const SrcType*>(mSrcStart);
|
||||
DstType *dstRowStart = static_cast<DstType*>(mDstStart);
|
||||
|
||||
// the loop performing the texture format conversion
|
||||
for (size_t i = 0; i < mHeight; ++i) {
|
||||
const SrcType *srcRowEnd = srcRowStart + mWidth * NumElementsPerSrcTexel;
|
||||
const SrcType *srcPtr = srcRowStart;
|
||||
DstType *dstPtr = dstRowStart;
|
||||
while (srcPtr != srcRowEnd) {
|
||||
// convert a single texel. We proceed in 3 steps: unpack the source texel
|
||||
// so the corresponding interchange format (e.g. unpack RGB565 to RGBA8),
|
||||
// convert the resulting data type to the destination type (e.g. convert
|
||||
// from RGBA8 to RGBA32F), and finally pack the destination texel
|
||||
// (e.g. pack RGBA32F to RGB32F).
|
||||
IntermediateSrcType unpackedSrc[MaxElementsPerTexel];
|
||||
IntermediateDstType unpackedDst[MaxElementsPerTexel];
|
||||
|
||||
// unpack a src texel to corresponding intermediate src format.
|
||||
// for example, unpack RGB565 to RGBA8
|
||||
unpack<SrcFormat>(srcPtr, unpackedSrc);
|
||||
// convert the data type to the destination type, if needed.
|
||||
// for example, convert RGBA8 to RGBA32F
|
||||
convertType(unpackedSrc, unpackedDst);
|
||||
// pack the destination texel.
|
||||
// for example, pack RGBA32F to RGB32F
|
||||
pack<DstFormat, PremultiplicationOp>(unpackedDst, dstPtr);
|
||||
|
||||
srcPtr += NumElementsPerSrcTexel;
|
||||
dstPtr += NumElementsPerDstTexel;
|
||||
}
|
||||
srcRowStart += srcStrideInElements;
|
||||
dstRowStart += dstStrideInElements;
|
||||
}
|
||||
|
||||
mSuccess = true;
|
||||
return;
|
||||
}
|
||||
|
||||
template<WebGLTexelFormat SrcFormat, WebGLTexelFormat DstFormat>
|
||||
void run(WebGLTexelPremultiplicationOp premultiplicationOp)
|
||||
{
|
||||
#define WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(PremultiplicationOp) \
|
||||
case PremultiplicationOp: \
|
||||
return run<SrcFormat, DstFormat, PremultiplicationOp>();
|
||||
|
||||
switch (premultiplicationOp) {
|
||||
WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(NoPremultiplicationOp)
|
||||
WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(Premultiply)
|
||||
WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(Unpremultiply)
|
||||
default:
|
||||
NS_ABORT_IF_FALSE(false, "unhandled case. Coding mistake?");
|
||||
}
|
||||
|
||||
#undef WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP
|
||||
}
|
||||
|
||||
template<WebGLTexelFormat SrcFormat>
|
||||
void run(WebGLTexelFormat dstFormat,
|
||||
WebGLTexelPremultiplicationOp premultiplicationOp)
|
||||
{
|
||||
#define WEBGLIMAGECONVERTER_CASE_DSTFORMAT(DstFormat) \
|
||||
case DstFormat: \
|
||||
return run<SrcFormat, DstFormat>(premultiplicationOp);
|
||||
|
||||
switch (dstFormat) {
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(R8)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(A8)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(R32F)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(A32F)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(RA8)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(RA32F)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(RGB8)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(RGB565)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(RGB32F)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(RGBA8)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(RGBA5551)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(RGBA4444)
|
||||
WEBGLIMAGECONVERTER_CASE_DSTFORMAT(RGBA32F)
|
||||
default:
|
||||
NS_ABORT_IF_FALSE(false, "unhandled case. Coding mistake?");
|
||||
}
|
||||
|
||||
#undef WEBGLIMAGECONVERTER_CASE_DSTFORMAT
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void run(WebGLTexelFormat srcFormat,
|
||||
WebGLTexelFormat dstFormat,
|
||||
WebGLTexelPremultiplicationOp premultiplicationOp)
|
||||
{
|
||||
#define WEBGLIMAGECONVERTER_CASE_SRCFORMAT(SrcFormat) \
|
||||
case SrcFormat: \
|
||||
return run<SrcFormat>(dstFormat, premultiplicationOp);
|
||||
|
||||
switch (srcFormat) {
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(R8)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(A8)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(R32F)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(A32F)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(RA8)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(RA32F)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(RGB8)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(BGRX8) // source format only
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(RGB565)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(RGB32F)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(RGBA8)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(BGRA8)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(RGBA5551)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(RGBA4444)
|
||||
WEBGLIMAGECONVERTER_CASE_SRCFORMAT(RGBA32F)
|
||||
default:
|
||||
NS_ABORT_IF_FALSE(false, "unhandled case. Coding mistake?");
|
||||
}
|
||||
|
||||
#undef WEBGLIMAGECONVERTER_CASE_SRCFORMAT
|
||||
}
|
||||
|
||||
WebGLImageConverter(size_t width, size_t height,
|
||||
const void* srcStart, void* dstStart,
|
||||
ptrdiff_t srcStride, ptrdiff_t dstStride)
|
||||
: mWidth(width), mHeight(height),
|
||||
mSrcStart(srcStart), mDstStart(dstStart),
|
||||
mSrcStride(srcStride), mDstStride(dstStride),
|
||||
mAlreadyRun(false), mSuccess(false)
|
||||
{}
|
||||
|
||||
bool Success() const {
|
||||
return mSuccess;
|
||||
}
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
void
|
||||
WebGLContext::ConvertImage(size_t width, size_t height, size_t srcStride, size_t dstStride,
|
||||
const uint8_t* src, uint8_t *dst,
|
||||
WebGLTexelFormat srcFormat, bool srcPremultiplied,
|
||||
WebGLTexelFormat dstFormat, bool dstPremultiplied,
|
||||
size_t dstTexelSize)
|
||||
{
|
||||
if (width <= 0 || height <= 0)
|
||||
return;
|
||||
|
||||
const bool FormatsRequireNoPremultiplicationOp =
|
||||
!HasAlpha(srcFormat) ||
|
||||
!HasColor(srcFormat) ||
|
||||
!HasColor(dstFormat);
|
||||
|
||||
if (srcFormat == dstFormat &&
|
||||
(FormatsRequireNoPremultiplicationOp || srcPremultiplied == dstPremultiplied))
|
||||
{
|
||||
// fast exit path: we just have to memcpy all the rows.
|
||||
//
|
||||
// The case where absolutely nothing needs to be done is supposed to have
|
||||
// been handled earlier (in TexImage2D_base, etc).
|
||||
//
|
||||
// So the case we're handling here is when even though no format conversion is needed,
|
||||
// we still might have to flip vertically and/or to adjust to a different stride.
|
||||
|
||||
NS_ABORT_IF_FALSE(mPixelStoreFlipY || srcStride != dstStride, "Performance trap -- should handle this case earlier, to avoid memcpy");
|
||||
|
||||
size_t row_size = width * dstTexelSize; // doesn't matter, src and dst formats agree
|
||||
const uint8_t* ptr = src;
|
||||
const uint8_t* src_end = src + height * srcStride;
|
||||
|
||||
uint8_t* dst_row = mPixelStoreFlipY
|
||||
? dst + (height-1) * dstStride
|
||||
: dst;
|
||||
ptrdiff_t dstStrideSigned(dstStride);
|
||||
ptrdiff_t dst_delta = mPixelStoreFlipY ? -dstStrideSigned : dstStrideSigned;
|
||||
|
||||
while(ptr != src_end) {
|
||||
memcpy(dst_row, ptr, row_size);
|
||||
ptr += srcStride;
|
||||
dst_row += dst_delta;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t* dstStart = dst;
|
||||
ptrdiff_t signedDstStride = dstStride;
|
||||
if (mPixelStoreFlipY) {
|
||||
dstStart = dst + (height - 1) * dstStride;
|
||||
signedDstStride = -dstStride;
|
||||
}
|
||||
|
||||
WebGLImageConverter converter(width, height, src, dstStart, srcStride, signedDstStride);
|
||||
|
||||
const WebGLTexelPremultiplicationOp premultiplicationOp
|
||||
= FormatsRequireNoPremultiplicationOp ? NoPremultiplicationOp
|
||||
: (!srcPremultiplied && dstPremultiplied) ? Premultiply
|
||||
: (srcPremultiplied && !dstPremultiplied) ? Unpremultiply
|
||||
: NoPremultiplicationOp;
|
||||
|
||||
converter.run(srcFormat, dstFormat, premultiplicationOp);
|
||||
|
||||
if (!converter.Success()) {
|
||||
// the dst image may be left uninitialized, so we better not try to
|
||||
// continue even in release builds. This should never happen anyway,
|
||||
// and would be a bug in our code.
|
||||
NS_RUNTIMEABORT("programming mistake in WebGL texture conversions");
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace mozilla
|
|
@ -25,17 +25,6 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// the pixel conversions code here is originally from this file:
|
||||
// http://trac.webkit.org/browser/trunk/WebCore/platform/graphics/GraphicsContext3D.cpp
|
||||
|
||||
// Keep as much as possible unchanged to ease sharing code with the WebKit guys.
|
||||
// Changes:
|
||||
// * added BGR8 path, we need it in Mozilla to load textures from DOMElements
|
||||
// * enclosing in a namespace WebGLTexelConversions to make it clear it is, in profilers and in symbol table dumps
|
||||
// * added __restrict keywords. Although non-standard, this is very well supported across all compilers
|
||||
// that I know of (GCC/LLVM/MSC/ICC/XLC...)
|
||||
// * optimized scaleFactor computation in Unmultiply functions (1 div instead of 2)
|
||||
|
||||
#ifndef WEBGLTEXELCONVERSIONS_H_
|
||||
#define WEBGLTEXELCONVERSIONS_H_
|
||||
|
||||
|
@ -44,6 +33,7 @@
|
|||
#endif
|
||||
|
||||
#include "WebGLContext.h"
|
||||
#include "mozilla/StandardInteger.h"
|
||||
|
||||
#if defined _MSC_VER
|
||||
#define FORCE_INLINE __forceinline
|
||||
|
@ -57,410 +47,647 @@ namespace mozilla {
|
|||
|
||||
namespace WebGLTexelConversions {
|
||||
|
||||
enum WebGLTexelPremultiplicationOp
|
||||
{
|
||||
NoPremultiplicationOp,
|
||||
Premultiply,
|
||||
Unpremultiply
|
||||
};
|
||||
|
||||
template<int Format>
|
||||
struct IsFloatFormat
|
||||
{
|
||||
static const bool Value =
|
||||
Format == RGBA32F ||
|
||||
Format == RGB32F ||
|
||||
Format == RA32F ||
|
||||
Format == R32F ||
|
||||
Format == A32F;
|
||||
};
|
||||
|
||||
template<int Format>
|
||||
struct Is16bppFormat
|
||||
{
|
||||
static const bool Value =
|
||||
Format == RGBA4444 ||
|
||||
Format == RGBA5551 ||
|
||||
Format == RGB565;
|
||||
};
|
||||
|
||||
template<int Format,
|
||||
bool IsFloat = IsFloatFormat<Format>::Value,
|
||||
bool Is16bpp = Is16bppFormat<Format>::Value>
|
||||
struct DataTypeForFormat
|
||||
{
|
||||
typedef uint8_t Type;
|
||||
};
|
||||
|
||||
template<int Format>
|
||||
struct DataTypeForFormat<Format, true, false>
|
||||
{
|
||||
typedef float Type;
|
||||
};
|
||||
|
||||
template<int Format>
|
||||
struct DataTypeForFormat<Format, false, true>
|
||||
{
|
||||
typedef uint16_t Type;
|
||||
};
|
||||
|
||||
template<int Format>
|
||||
struct IntermediateFormat
|
||||
{
|
||||
static const int Value = IsFloatFormat<Format>::Value ? RGBA32F : RGBA8;
|
||||
};
|
||||
|
||||
inline size_t TexelBytesForFormat(int format) {
|
||||
switch (format) {
|
||||
case WebGLTexelConversions::R8:
|
||||
case WebGLTexelConversions::A8:
|
||||
return 1;
|
||||
case WebGLTexelConversions::RA8:
|
||||
case WebGLTexelConversions::RGBA5551:
|
||||
case WebGLTexelConversions::RGBA4444:
|
||||
case WebGLTexelConversions::RGB565:
|
||||
return 2;
|
||||
case WebGLTexelConversions::RGB8:
|
||||
return 3;
|
||||
case WebGLTexelConversions::RGBA8:
|
||||
case WebGLTexelConversions::BGRA8:
|
||||
case WebGLTexelConversions::BGRX8:
|
||||
case WebGLTexelConversions::R32F:
|
||||
case WebGLTexelConversions::A32F:
|
||||
return 4;
|
||||
case WebGLTexelConversions::RA32F:
|
||||
return 8;
|
||||
case WebGLTexelConversions::RGB32F:
|
||||
return 12;
|
||||
case WebGLTexelConversions::RGBA32F:
|
||||
return 16;
|
||||
default:
|
||||
NS_ABORT_IF_FALSE(false, "Unknown texel format. Coding mistake?");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
FORCE_INLINE bool HasAlpha(int format) {
|
||||
return format == A8 ||
|
||||
format == A32F ||
|
||||
format == RA8 ||
|
||||
format == RA32F ||
|
||||
format == RGBA8 ||
|
||||
format == BGRA8 ||
|
||||
format == RGBA32F ||
|
||||
format == RGBA4444 ||
|
||||
format == RGBA5551;
|
||||
}
|
||||
|
||||
FORCE_INLINE bool HasColor(int format) {
|
||||
return format == R8 ||
|
||||
format == R32F ||
|
||||
format == RA8 ||
|
||||
format == RA32F ||
|
||||
format == RGB8 ||
|
||||
format == BGRX8 ||
|
||||
format == RGB565 ||
|
||||
format == RGB32F ||
|
||||
format == RGBA8 ||
|
||||
format == BGRA8 ||
|
||||
format == RGBA32F ||
|
||||
format == RGBA4444 ||
|
||||
format == RGBA5551;
|
||||
}
|
||||
|
||||
|
||||
/****** BEGIN CODE SHARED WITH WEBKIT ******/
|
||||
|
||||
// the pack/unpack functions here are originally from this file:
|
||||
// http://trac.webkit.org/browser/trunk/WebCore/platform/graphics/GraphicsContext3D.cpp
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Pixel unpacking routines.
|
||||
|
||||
FORCE_INLINE void unpackRGBA8ToRGBA8(const uint8_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<int Format, typename SrcType, typename DstType>
|
||||
FORCE_INLINE void
|
||||
unpack(const SrcType* __restrict src,
|
||||
DstType* __restrict dst)
|
||||
{
|
||||
destination[0] = source[0];
|
||||
destination[1] = source[1];
|
||||
destination[2] = source[2];
|
||||
destination[3] = source[3];
|
||||
NS_ABORT_IF_FALSE(false, "Unimplemented texture format conversion");
|
||||
}
|
||||
|
||||
FORCE_INLINE void unpackRGB8ToRGBA8(const uint8_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
unpack<RGBA8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
destination[0] = source[0];
|
||||
destination[1] = source[1];
|
||||
destination[2] = source[2];
|
||||
destination[3] = 0xFF;
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
dst[3] = src[3];
|
||||
}
|
||||
|
||||
FORCE_INLINE void unpackBGRA8ToRGBA8(const uint8_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
unpack<RGB8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
destination[0] = source[2];
|
||||
destination[1] = source[1];
|
||||
destination[2] = source[0];
|
||||
destination[3] = source[3];
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
dst[3] = 0xFF;
|
||||
}
|
||||
|
||||
FORCE_INLINE void unpackBGR8ToRGBA8(const uint8_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
unpack<BGRA8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
destination[0] = source[2];
|
||||
destination[1] = source[1];
|
||||
destination[2] = source[0];
|
||||
destination[3] = 0xFF;
|
||||
dst[0] = src[2];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[0];
|
||||
dst[3] = src[3];
|
||||
}
|
||||
|
||||
FORCE_INLINE void unpackRGBA5551ToRGBA8(const uint16_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
unpack<BGRX8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
uint16_t packedValue = source[0];
|
||||
uint8_t r = packedValue >> 11;
|
||||
dst[0] = src[2];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[0];
|
||||
dst[3] = 0xFF;
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
unpack<RGBA5551, uint16_t, uint8_t>(const uint16_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
uint16_t packedValue = src[0];
|
||||
uint8_t r = (packedValue >> 11) & 0x1F;
|
||||
uint8_t g = (packedValue >> 6) & 0x1F;
|
||||
uint8_t b = (packedValue >> 1) & 0x1F;
|
||||
destination[0] = (r << 3) | (r & 0x7);
|
||||
destination[1] = (g << 3) | (g & 0x7);
|
||||
destination[2] = (b << 3) | (b & 0x7);
|
||||
destination[3] = (packedValue & 0x1) ? 0xFF : 0x0;
|
||||
dst[0] = (r << 3) | (r & 0x7);
|
||||
dst[1] = (g << 3) | (g & 0x7);
|
||||
dst[2] = (b << 3) | (b & 0x7);
|
||||
dst[3] = (packedValue & 0x1) ? 0xFF : 0;
|
||||
}
|
||||
|
||||
FORCE_INLINE void unpackRGBA4444ToRGBA8(const uint16_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
unpack<RGBA4444, uint16_t, uint8_t>(const uint16_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
uint16_t packedValue = source[0];
|
||||
uint8_t r = packedValue >> 12;
|
||||
uint16_t packedValue = src[0];
|
||||
uint8_t r = (packedValue >> 12) & 0x0F;
|
||||
uint8_t g = (packedValue >> 8) & 0x0F;
|
||||
uint8_t b = (packedValue >> 4) & 0x0F;
|
||||
uint8_t a = packedValue & 0x0F;
|
||||
destination[0] = r << 4 | r;
|
||||
destination[1] = g << 4 | g;
|
||||
destination[2] = b << 4 | b;
|
||||
destination[3] = a << 4 | a;
|
||||
dst[0] = (r << 4) | r;
|
||||
dst[1] = (g << 4) | g;
|
||||
dst[2] = (b << 4) | b;
|
||||
dst[3] = (a << 4) | a;
|
||||
}
|
||||
|
||||
FORCE_INLINE void unpackRGB565ToRGBA8(const uint16_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
unpack<RGB565, uint16_t, uint8_t>(const uint16_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
uint16_t packedValue = source[0];
|
||||
uint8_t r = packedValue >> 11;
|
||||
uint16_t packedValue = src[0];
|
||||
uint8_t r = (packedValue >> 11) & 0x1F;
|
||||
uint8_t g = (packedValue >> 5) & 0x3F;
|
||||
uint8_t b = packedValue & 0x1F;
|
||||
destination[0] = (r << 3) | (r & 0x7);
|
||||
destination[1] = (g << 2) | (g & 0x3);
|
||||
destination[2] = (b << 3) | (b & 0x7);
|
||||
destination[3] = 0xFF;
|
||||
dst[0] = (r << 3) | (r & 0x7);
|
||||
dst[1] = (g << 2) | (g & 0x3);
|
||||
dst[2] = (b << 3) | (b & 0x7);
|
||||
dst[3] = 0xFF;
|
||||
}
|
||||
|
||||
FORCE_INLINE void unpackR8ToRGBA8(const uint8_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
unpack<R8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
destination[0] = source[0];
|
||||
destination[1] = source[0];
|
||||
destination[2] = source[0];
|
||||
destination[3] = 0xFF;
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[0];
|
||||
dst[2] = src[0];
|
||||
dst[3] = 0xFF;
|
||||
}
|
||||
|
||||
FORCE_INLINE void unpackRA8ToRGBA8(const uint8_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
unpack<RA8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
destination[0] = source[0];
|
||||
destination[1] = source[0];
|
||||
destination[2] = source[0];
|
||||
destination[3] = source[1];
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[0];
|
||||
dst[2] = src[0];
|
||||
dst[3] = src[1];
|
||||
}
|
||||
|
||||
FORCE_INLINE void unpackA8ToRGBA8(const uint8_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
unpack<A8, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
destination[0] = 0x0;
|
||||
destination[1] = 0x0;
|
||||
destination[2] = 0x0;
|
||||
destination[3] = source[0];
|
||||
dst[0] = 0;
|
||||
dst[1] = 0;
|
||||
dst[2] = 0;
|
||||
dst[3] = src[0];
|
||||
}
|
||||
|
||||
FORCE_INLINE void unpackRGB32FToRGBA32F(const float* __restrict source, float* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
unpack<RGBA32F, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
destination[0] = source[0];
|
||||
destination[1] = source[1];
|
||||
destination[2] = source[2];
|
||||
destination[3] = 1;
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
dst[3] = src[3];
|
||||
}
|
||||
|
||||
FORCE_INLINE void unpackR32FToRGBA32F(const float* __restrict source, float* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
unpack<RGB32F, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
destination[0] = source[0];
|
||||
destination[1] = source[0];
|
||||
destination[2] = source[0];
|
||||
destination[3] = 1;
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
dst[3] = 1.0f;
|
||||
}
|
||||
|
||||
FORCE_INLINE void unpackRA32FToRGBA32F(const float* __restrict source, float* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
unpack<R32F, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
destination[0] = source[0];
|
||||
destination[1] = source[0];
|
||||
destination[2] = source[0];
|
||||
destination[3] = source[1];
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[0];
|
||||
dst[2] = src[0];
|
||||
dst[3] = 1.0f;
|
||||
}
|
||||
|
||||
FORCE_INLINE void unpackA32FToRGBA32F(const float* __restrict source, float* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
unpack<RA32F, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
destination[0] = 0;
|
||||
destination[1] = 0;
|
||||
destination[2] = 0;
|
||||
destination[3] = source[0];
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[0];
|
||||
dst[2] = src[0];
|
||||
dst[3] = src[1];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
unpack<A32F, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
dst[0] = 0;
|
||||
dst[1] = 0;
|
||||
dst[2] = 0;
|
||||
dst[3] = src[0];
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Pixel packing routines.
|
||||
//
|
||||
|
||||
FORCE_INLINE void packRGBA8ToA8(const uint8_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<int Format, int PremultiplicationOp, typename SrcType, typename DstType>
|
||||
FORCE_INLINE void
|
||||
pack(const SrcType* __restrict src,
|
||||
DstType* __restrict dst)
|
||||
{
|
||||
destination[0] = source[3];
|
||||
NS_ABORT_IF_FALSE(false, "Unimplemented texture format conversion");
|
||||
}
|
||||
|
||||
FORCE_INLINE void packRGBA8ToR8(const uint8_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<A8, NoPremultiplicationOp, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
destination[0] = source[0];
|
||||
dst[0] = src[3];
|
||||
}
|
||||
|
||||
FORCE_INLINE void packRGBA8ToR8Premultiply(const uint8_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<A8, Premultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = source[3] / 255.0f;
|
||||
uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
|
||||
destination[0] = sourceR;
|
||||
dst[0] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<A8, Unpremultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
dst[0] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<R8, NoPremultiplicationOp, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<R8, Premultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3] / 255.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
dst[0] = srcR;
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<R8, Unpremultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3] ? 255.0f / src[3] : 1.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
dst[0] = srcR;
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RA8, NoPremultiplicationOp, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RA8, Premultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3] / 255.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
dst[0] = srcR;
|
||||
dst[1] = src[3];
|
||||
}
|
||||
|
||||
// FIXME: this routine is lossy and must be removed.
|
||||
FORCE_INLINE void packRGBA8ToR8Unmultiply(const uint8_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<RA8, Unpremultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
|
||||
uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
|
||||
destination[0] = sourceR;
|
||||
float scaleFactor = src[3] ? 255.0f / src[3] : 1.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
dst[0] = srcR;
|
||||
dst[1] = src[3];
|
||||
}
|
||||
|
||||
FORCE_INLINE void packRGBA8ToRA8(const uint8_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGB8, NoPremultiplicationOp, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
destination[0] = source[0];
|
||||
destination[1] = source[3];
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
}
|
||||
|
||||
FORCE_INLINE void packRGBA8ToRA8Premultiply(const uint8_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGB8, Premultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = source[3] / 255.0f;
|
||||
uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
|
||||
destination[0] = sourceR;
|
||||
destination[1] = source[3];
|
||||
float scaleFactor = src[3] / 255.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
uint8_t srcG = static_cast<uint8_t>(src[1] * scaleFactor);
|
||||
uint8_t srcB = static_cast<uint8_t>(src[2] * scaleFactor);
|
||||
dst[0] = srcR;
|
||||
dst[1] = srcG;
|
||||
dst[2] = srcB;
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGB8, Unpremultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3] ? 255.0f / src[3] : 1.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
uint8_t srcG = static_cast<uint8_t>(src[1] * scaleFactor);
|
||||
uint8_t srcB = static_cast<uint8_t>(src[2] * scaleFactor);
|
||||
dst[0] = srcR;
|
||||
dst[1] = srcG;
|
||||
dst[2] = srcB;
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGBA8, NoPremultiplicationOp, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
dst[3] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGBA8, Premultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = src[3] / 255.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
uint8_t srcG = static_cast<uint8_t>(src[1] * scaleFactor);
|
||||
uint8_t srcB = static_cast<uint8_t>(src[2] * scaleFactor);
|
||||
dst[0] = srcR;
|
||||
dst[1] = srcG;
|
||||
dst[2] = srcB;
|
||||
dst[3] = src[3];
|
||||
}
|
||||
|
||||
// FIXME: this routine is lossy and must be removed.
|
||||
FORCE_INLINE void packRGBA8ToRA8Unmultiply(const uint8_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGBA8, Unpremultiply, uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
|
||||
uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
|
||||
destination[0] = sourceR;
|
||||
destination[1] = source[3];
|
||||
float scaleFactor = src[3] ? 255.0f / src[3] : 1.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
uint8_t srcG = static_cast<uint8_t>(src[1] * scaleFactor);
|
||||
uint8_t srcB = static_cast<uint8_t>(src[2] * scaleFactor);
|
||||
dst[0] = srcR;
|
||||
dst[1] = srcG;
|
||||
dst[2] = srcB;
|
||||
dst[3] = src[3];
|
||||
}
|
||||
|
||||
FORCE_INLINE void packRGBA8ToRGB8(const uint8_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGBA4444, NoPremultiplicationOp, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
{
|
||||
destination[0] = source[0];
|
||||
destination[1] = source[1];
|
||||
destination[2] = source[2];
|
||||
*dst = ( ((src[0] & 0xF0) << 8)
|
||||
| ((src[1] & 0xF0) << 4)
|
||||
| (src[2] & 0xF0)
|
||||
| (src[3] >> 4) );
|
||||
}
|
||||
|
||||
FORCE_INLINE void packRGBA8ToRGB8Premultiply(const uint8_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGBA4444, Premultiply, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = source[3] / 255.0f;
|
||||
uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
|
||||
uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
|
||||
uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
|
||||
destination[0] = sourceR;
|
||||
destination[1] = sourceG;
|
||||
destination[2] = sourceB;
|
||||
float scaleFactor = src[3] / 255.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
uint8_t srcG = static_cast<uint8_t>(src[1] * scaleFactor);
|
||||
uint8_t srcB = static_cast<uint8_t>(src[2] * scaleFactor);
|
||||
*dst = ( ((srcR & 0xF0) << 8)
|
||||
| ((srcG & 0xF0) << 4)
|
||||
| (srcB & 0xF0)
|
||||
| (src[3] >> 4));
|
||||
}
|
||||
|
||||
// FIXME: this routine is lossy and must be removed.
|
||||
FORCE_INLINE void packRGBA8ToRGB8Unmultiply(const uint8_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGBA4444, Unpremultiply, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
|
||||
uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
|
||||
uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
|
||||
uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
|
||||
destination[0] = sourceR;
|
||||
destination[1] = sourceG;
|
||||
destination[2] = sourceB;
|
||||
float scaleFactor = src[3] ? 255.0f / src[3] : 1.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
uint8_t srcG = static_cast<uint8_t>(src[1] * scaleFactor);
|
||||
uint8_t srcB = static_cast<uint8_t>(src[2] * scaleFactor);
|
||||
*dst = ( ((srcR & 0xF0) << 8)
|
||||
| ((srcG & 0xF0) << 4)
|
||||
| (srcB & 0xF0)
|
||||
| (src[3] >> 4));
|
||||
}
|
||||
|
||||
// This is only used when the source format is different than kSourceFormatRGBA8.
|
||||
FORCE_INLINE void packRGBA8ToRGBA8(const uint8_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGBA5551, NoPremultiplicationOp, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
{
|
||||
destination[0] = source[0];
|
||||
destination[1] = source[1];
|
||||
destination[2] = source[2];
|
||||
destination[3] = source[3];
|
||||
*dst = ( ((src[0] & 0xF8) << 8)
|
||||
| ((src[1] & 0xF8) << 3)
|
||||
| ((src[2] & 0xF8) >> 2)
|
||||
| (src[3] >> 7));
|
||||
}
|
||||
|
||||
FORCE_INLINE void packRGBA8ToRGBA8Premultiply(const uint8_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGBA5551, Premultiply, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = source[3] / 255.0f;
|
||||
uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
|
||||
uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
|
||||
uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
|
||||
destination[0] = sourceR;
|
||||
destination[1] = sourceG;
|
||||
destination[2] = sourceB;
|
||||
destination[3] = source[3];
|
||||
float scaleFactor = src[3] / 255.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
uint8_t srcG = static_cast<uint8_t>(src[1] * scaleFactor);
|
||||
uint8_t srcB = static_cast<uint8_t>(src[2] * scaleFactor);
|
||||
*dst = ( ((srcR & 0xF8) << 8)
|
||||
| ((srcG & 0xF8) << 3)
|
||||
| ((srcB & 0xF8) >> 2)
|
||||
| (src[3] >> 7));
|
||||
}
|
||||
|
||||
// FIXME: this routine is lossy and must be removed.
|
||||
FORCE_INLINE void packRGBA8ToRGBA8Unmultiply(const uint8_t* __restrict source, uint8_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGBA5551, Unpremultiply, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
|
||||
uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
|
||||
uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
|
||||
uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
|
||||
destination[0] = sourceR;
|
||||
destination[1] = sourceG;
|
||||
destination[2] = sourceB;
|
||||
destination[3] = source[3];
|
||||
float scaleFactor = src[3] ? 255.0f / src[3] : 1.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
uint8_t srcG = static_cast<uint8_t>(src[1] * scaleFactor);
|
||||
uint8_t srcB = static_cast<uint8_t>(src[2] * scaleFactor);
|
||||
*dst = ( ((srcR & 0xF8) << 8)
|
||||
| ((srcG & 0xF8) << 3)
|
||||
| ((srcB & 0xF8) >> 2)
|
||||
| (src[3] >> 7));
|
||||
}
|
||||
|
||||
FORCE_INLINE void packRGBA8ToUnsignedShort4444(const uint8_t* __restrict source, uint16_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGB565, NoPremultiplicationOp, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
{
|
||||
*destination = (((source[0] & 0xF0) << 8)
|
||||
| ((source[1] & 0xF0) << 4)
|
||||
| (source[2] & 0xF0)
|
||||
| (source[3] >> 4));
|
||||
*dst = ( ((src[0] & 0xF8) << 8)
|
||||
| ((src[1] & 0xFC) << 3)
|
||||
| ((src[2] & 0xF8) >> 3));
|
||||
}
|
||||
|
||||
FORCE_INLINE void packRGBA8ToUnsignedShort4444Premultiply(const uint8_t* __restrict source, uint16_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGB565, Premultiply, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = source[3] / 255.0f;
|
||||
uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
|
||||
uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
|
||||
uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
|
||||
*destination = (((sourceR & 0xF0) << 8)
|
||||
| ((sourceG & 0xF0) << 4)
|
||||
| (sourceB & 0xF0)
|
||||
| (source[3] >> 4));
|
||||
float scaleFactor = src[3] / 255.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
uint8_t srcG = static_cast<uint8_t>(src[1] * scaleFactor);
|
||||
uint8_t srcB = static_cast<uint8_t>(src[2] * scaleFactor);
|
||||
*dst = ( ((srcR & 0xF8) << 8)
|
||||
| ((srcG & 0xFC) << 3)
|
||||
| ((srcB & 0xF8) >> 3));
|
||||
}
|
||||
|
||||
// FIXME: this routine is lossy and must be removed.
|
||||
FORCE_INLINE void packRGBA8ToUnsignedShort4444Unmultiply(const uint8_t* __restrict source, uint16_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGB565, Unpremultiply, uint8_t, uint16_t>(const uint8_t* __restrict src, uint16_t* __restrict dst)
|
||||
{
|
||||
float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
|
||||
uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
|
||||
uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
|
||||
uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
|
||||
*destination = (((sourceR & 0xF0) << 8)
|
||||
| ((sourceG & 0xF0) << 4)
|
||||
| (sourceB & 0xF0)
|
||||
| (source[3] >> 4));
|
||||
float scaleFactor = src[3] ? 255.0f / src[3] : 1.0f;
|
||||
uint8_t srcR = static_cast<uint8_t>(src[0] * scaleFactor);
|
||||
uint8_t srcG = static_cast<uint8_t>(src[1] * scaleFactor);
|
||||
uint8_t srcB = static_cast<uint8_t>(src[2] * scaleFactor);
|
||||
*dst = ( ((srcR & 0xF8) << 8)
|
||||
| ((srcG & 0xFC) << 3)
|
||||
| ((srcB & 0xF8) >> 3));
|
||||
}
|
||||
|
||||
FORCE_INLINE void packRGBA8ToUnsignedShort5551(const uint8_t* __restrict source, uint16_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGB32F, NoPremultiplicationOp, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
*destination = (((source[0] & 0xF8) << 8)
|
||||
| ((source[1] & 0xF8) << 3)
|
||||
| ((source[2] & 0xF8) >> 2)
|
||||
| (source[3] >> 7));
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
}
|
||||
|
||||
FORCE_INLINE void packRGBA8ToUnsignedShort5551Premultiply(const uint8_t* __restrict source, uint16_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGB32F, Premultiply, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
float scaleFactor = source[3] / 255.0f;
|
||||
uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
|
||||
uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
|
||||
uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
|
||||
*destination = (((sourceR & 0xF8) << 8)
|
||||
| ((sourceG & 0xF8) << 3)
|
||||
| ((sourceB & 0xF8) >> 2)
|
||||
| (source[3] >> 7));
|
||||
float scaleFactor = src[3];
|
||||
dst[0] = src[0] * scaleFactor;
|
||||
dst[1] = src[1] * scaleFactor;
|
||||
dst[2] = src[2] * scaleFactor;
|
||||
}
|
||||
|
||||
// FIXME: this routine is lossy and must be removed.
|
||||
FORCE_INLINE void packRGBA8ToUnsignedShort5551Unmultiply(const uint8_t* __restrict source, uint16_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGBA32F, NoPremultiplicationOp, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
|
||||
uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
|
||||
uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
|
||||
uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
|
||||
*destination = (((sourceR & 0xF8) << 8)
|
||||
| ((sourceG & 0xF8) << 3)
|
||||
| ((sourceB & 0xF8) >> 2)
|
||||
| (source[3] >> 7));
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
dst[3] = src[3];
|
||||
}
|
||||
|
||||
FORCE_INLINE void packRGBA8ToUnsignedShort565(const uint8_t* __restrict source, uint16_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<RGBA32F, Premultiply, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
*destination = (((source[0] & 0xF8) << 8)
|
||||
| ((source[1] & 0xFC) << 3)
|
||||
| ((source[2] & 0xF8) >> 3));
|
||||
float scaleFactor = src[3];
|
||||
dst[0] = src[0] * scaleFactor;
|
||||
dst[1] = src[1] * scaleFactor;
|
||||
dst[2] = src[2] * scaleFactor;
|
||||
dst[3] = src[3];
|
||||
}
|
||||
|
||||
FORCE_INLINE void packRGBA8ToUnsignedShort565Premultiply(const uint8_t* __restrict source, uint16_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<A32F, NoPremultiplicationOp, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
float scaleFactor = source[3] / 255.0f;
|
||||
uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
|
||||
uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
|
||||
uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
|
||||
*destination = (((sourceR & 0xF8) << 8)
|
||||
| ((sourceG & 0xFC) << 3)
|
||||
| ((sourceB & 0xF8) >> 3));
|
||||
dst[0] = src[3];
|
||||
}
|
||||
|
||||
// FIXME: this routine is lossy and must be removed.
|
||||
FORCE_INLINE void packRGBA8ToUnsignedShort565Unmultiply(const uint8_t* __restrict source, uint16_t* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<A32F, Premultiply, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
|
||||
uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
|
||||
uint8_t sourceG = static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
|
||||
uint8_t sourceB = static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
|
||||
*destination = (((sourceR & 0xF8) << 8)
|
||||
| ((sourceG & 0xFC) << 3)
|
||||
| ((sourceB & 0xF8) >> 3));
|
||||
dst[0] = src[3];
|
||||
}
|
||||
|
||||
FORCE_INLINE void packRGBA32FToRGB32F(const float* __restrict source, float* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<R32F, NoPremultiplicationOp, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
destination[0] = source[0];
|
||||
destination[1] = source[1];
|
||||
destination[2] = source[2];
|
||||
dst[0] = src[0];
|
||||
}
|
||||
|
||||
FORCE_INLINE void packRGBA32FToRGB32FPremultiply(const float* __restrict source, float* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<R32F, Premultiply, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
float scaleFactor = source[3];
|
||||
destination[0] = source[0] * scaleFactor;
|
||||
destination[1] = source[1] * scaleFactor;
|
||||
destination[2] = source[2] * scaleFactor;
|
||||
float scaleFactor = src[3];
|
||||
dst[0] = src[0] * scaleFactor;
|
||||
}
|
||||
|
||||
FORCE_INLINE void packRGBA32FToRGBA32FPremultiply(const float* __restrict source, float* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<RA32F, NoPremultiplicationOp, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
float scaleFactor = source[3];
|
||||
destination[0] = source[0] * scaleFactor;
|
||||
destination[1] = source[1] * scaleFactor;
|
||||
destination[2] = source[2] * scaleFactor;
|
||||
destination[3] = source[3];
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[3];
|
||||
}
|
||||
|
||||
FORCE_INLINE void packRGBA32FToA32F(const float* __restrict source, float* __restrict destination)
|
||||
template<> FORCE_INLINE void
|
||||
pack<RA32F, Premultiply, float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
destination[0] = source[3];
|
||||
}
|
||||
|
||||
// identical to above, to avoid special-casing
|
||||
FORCE_INLINE void packRGBA32FToA32FPremultiply(const float* __restrict source, float* __restrict destination)
|
||||
{
|
||||
destination[0] = source[3];
|
||||
}
|
||||
|
||||
FORCE_INLINE void packRGBA32FToR32F(const float* __restrict source, float* __restrict destination)
|
||||
{
|
||||
destination[0] = source[0];
|
||||
}
|
||||
|
||||
FORCE_INLINE void packRGBA32FToR32FPremultiply(const float* __restrict source, float* __restrict destination)
|
||||
{
|
||||
float scaleFactor = source[3];
|
||||
destination[0] = source[0] * scaleFactor;
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE void packRGBA32FToRA32F(const float* __restrict source, float* __restrict destination)
|
||||
{
|
||||
destination[0] = source[0];
|
||||
destination[1] = source[3];
|
||||
}
|
||||
|
||||
FORCE_INLINE void packRGBA32FToRA32FPremultiply(const float* __restrict source, float* __restrict destination)
|
||||
{
|
||||
float scaleFactor = source[3];
|
||||
destination[0] = source[0] * scaleFactor;
|
||||
destination[1] = scaleFactor;
|
||||
float scaleFactor = src[3];
|
||||
dst[0] = src[0] * scaleFactor;
|
||||
dst[1] = scaleFactor;
|
||||
}
|
||||
|
||||
/****** END CODE SHARED WITH WEBKIT ******/
|
||||
|
||||
template<typename SrcType, typename DstType> FORCE_INLINE void
|
||||
convertType(const SrcType* __restrict src, DstType* __restrict dst)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(false, "Unimplemented texture format conversion");
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
convertType<uint8_t, uint8_t>(const uint8_t* __restrict src, uint8_t* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
dst[3] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
convertType<float, float>(const float* __restrict src, float* __restrict dst)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
dst[3] = src[3];
|
||||
}
|
||||
|
||||
template<> FORCE_INLINE void
|
||||
convertType<uint8_t, float>(const uint8_t* __restrict src, float* __restrict dst)
|
||||
{
|
||||
const float scaleFactor = 1.f / 255.0f;
|
||||
dst[0] = src[0] * scaleFactor;
|
||||
dst[1] = src[1] * scaleFactor;
|
||||
dst[2] = src[2] * scaleFactor;
|
||||
dst[3] = src[3] * scaleFactor;
|
||||
}
|
||||
|
||||
#undef FORCE_INLINE
|
||||
|
||||
} // end namespace WebGLTexelConversions
|
||||
|
||||
} // end namespace mozilla
|
||||
|
|
|
@ -530,17 +530,8 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
|
|||
if (!nsContentUtils::IsChromeDoc(doc)) {
|
||||
nsPIDOMWindow* win = doc ? doc->GetInnerWindow() : nsnull;
|
||||
// If we can't dispatch the event to chrome, do nothing.
|
||||
nsIDOMEventTarget* piTarget = win ? win->GetChromeEventHandler() : nsnull;
|
||||
nsIDOMEventTarget* piTarget = win ? win->GetParentTarget() : nsnull;
|
||||
NS_ENSURE_TRUE(piTarget, NS_OK);
|
||||
|
||||
nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(piTarget);
|
||||
if (flo) {
|
||||
nsRefPtr<nsFrameLoader> fl = flo->GetFrameLoader();
|
||||
if (fl) {
|
||||
nsIDOMEventTarget* t = fl->GetTabChildGlobalAsEventTarget();
|
||||
piTarget = t ? t : piTarget;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the target to be the original dispatch target,
|
||||
aEvent->target = target;
|
||||
|
|
|
@ -47,10 +47,10 @@ MODULE = dom
|
|||
DIRS = \
|
||||
interfaces/base \
|
||||
interfaces/canvas \
|
||||
interfaces/contacts \
|
||||
interfaces/core \
|
||||
interfaces/html \
|
||||
interfaces/events \
|
||||
interfaces/contacts \
|
||||
interfaces/settings \
|
||||
interfaces/stylesheets \
|
||||
interfaces/sidebar \
|
||||
|
|
|
@ -1,296 +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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
let Cu = Components.utils;
|
||||
let Ci = Components.interfaces;
|
||||
let Cc = Components.classes;
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
|
||||
const BROWSER_FRAMES_ENABLED_PREF = "dom.mozBrowserFramesEnabled";
|
||||
|
||||
/**
|
||||
* The BrowserElementAPI implements <iframe mozbrowser>.
|
||||
*
|
||||
* We detect windows and docshells contained inside <iframe mozbrowser>s and
|
||||
* alter their behavior so that the page inside the iframe can't tell that it's
|
||||
* framed and the page outside the iframe can observe changes within the iframe
|
||||
* (e.g. loadstart/loadstart, locationchange).
|
||||
*/
|
||||
|
||||
function BrowserElementAPI() {}
|
||||
BrowserElementAPI.prototype = {
|
||||
classID: Components.ID("{5d6fcab3-6c12-4db6-80fb-352df7a41602}"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
|
||||
/**
|
||||
* The keys of this map are the set of chrome event handlers we've observed
|
||||
* which contain a mozbrowser window.
|
||||
*
|
||||
* The values in this map are ignored.
|
||||
*/
|
||||
_chromeEventHandlersWatching: new WeakMap(),
|
||||
|
||||
/**
|
||||
* The keys of this map are the set of windows we've observed that are
|
||||
* directly contained in <iframe mozbrowser>s.
|
||||
*
|
||||
* The values in this map are ignored.
|
||||
*/
|
||||
_topLevelBrowserWindows: new WeakMap(),
|
||||
|
||||
_browserFramesPrefEnabled: function BA_browserFramesPrefEnabled() {
|
||||
var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
|
||||
try {
|
||||
return prefs.getBoolPref(BROWSER_FRAMES_ENABLED_PREF);
|
||||
}
|
||||
catch(e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called on browser start, and also when we observe a change in
|
||||
* the browser-frames-enabled pref.
|
||||
*/
|
||||
_init: function BA_init() {
|
||||
if (this._initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If browser frames are disabled, watch the pref so we can enable
|
||||
// ourselves if the pref is flipped. This is important for tests, if
|
||||
// nothing else.
|
||||
if (!this._browserFramesPrefEnabled()) {
|
||||
var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
|
||||
prefs.addObserver(BROWSER_FRAMES_ENABLED_PREF, this, /* ownsWeak = */ true);
|
||||
return;
|
||||
}
|
||||
|
||||
this._initialized = true;
|
||||
this._progressListener._browserElementAPI = this;
|
||||
|
||||
var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
|
||||
os.addObserver(this, 'content-document-global-created', /* ownsWeak = */ true);
|
||||
os.addObserver(this, 'docshell-marked-as-browser-frame', /* ownsWeak = */ true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when we observe a docshell-marked-as-browser-frame event, which
|
||||
* happens when a docshell is created inside an <iframe mozbrowser>.
|
||||
*
|
||||
* A docshell may not be un-marked as a browser frame -- this ensures that
|
||||
* this event will never fire twice for the same docshell, which guarantees
|
||||
* that we'll never register duplicate listeners.
|
||||
*/
|
||||
_observeDocshellMarkedAsBrowserFrame: function BA_observeDocshellMarkedAsBrowserFrame(docshell) {
|
||||
docshell.QueryInterface(Ci.nsIWebProgress)
|
||||
.addProgressListener(this._progressListener,
|
||||
Ci.nsIWebProgress.NOTIFY_LOCATION |
|
||||
Ci.nsIWebProgress.NOTIFY_STATE_WINDOW);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when a content window is created. If the window is directly or
|
||||
* indirectly contained in an <iframe mozbrowser>, we'll modify it.
|
||||
*/
|
||||
_observeContentGlobalCreated: function BA_observeContentGlobalCreated(win) {
|
||||
var docshell = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell);
|
||||
|
||||
// If this window is not directly or indirectly inside an
|
||||
// <iframe mozbrowser>, BrowserElementAPI does nothing to it.
|
||||
if (!docshell.containedInBrowserFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._initBrowserWindow(win, docshell.isBrowserFrame);
|
||||
|
||||
// If this window is directly contained in an <iframe mozbrowser>, do some
|
||||
// extra work.
|
||||
if (docshell.isBrowserFrame) {
|
||||
this._topLevelBrowserWindows.set(win, true);
|
||||
this._initTopLevelBrowserWindow(win);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize a content window which is indirectly or directly contained by
|
||||
* an <iframe mozbrowser>.
|
||||
*
|
||||
* |isTopLevel| is true iff |win| is directly contained by an
|
||||
* <iframe mozbrowser>.
|
||||
*/
|
||||
_initBrowserWindow: function BA_initBrowserWindow(win, isTopLevel) {
|
||||
// XPCNativeWrapper.unwrap gets us the object that content sees; this is
|
||||
// the object object that we must define properties on. Otherwise, the
|
||||
// properties will be visible only to chrome!
|
||||
var unwrappedWin = XPCNativeWrapper.unwrap(win);
|
||||
|
||||
// This property should exist only on the x-ray wrapped object, not on the
|
||||
// unwrapped object, so we define it on |win|, not |unwrappedWin|.
|
||||
Object.defineProperty(win, 'browserFrameTop', {
|
||||
get: function() {
|
||||
if (isTopLevel) {
|
||||
return win;
|
||||
}
|
||||
|
||||
if ('browserFrameTop' in win.parent) {
|
||||
return win.parent.browserFrameTop;
|
||||
}
|
||||
|
||||
// This shouldn't happen, but let's at least throw a semi-meaningful
|
||||
// error message if it does.
|
||||
throw new Error('Internal error in window.browserFrameTop.');
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(unwrappedWin, 'top', {
|
||||
get: function() {
|
||||
return win.browserFrameTop;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(unwrappedWin, 'parent', {
|
||||
get: function() {
|
||||
if (isTopLevel) {
|
||||
return win;
|
||||
}
|
||||
return win.parent;
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(unwrappedWin, 'frameElement', {
|
||||
get: function() {
|
||||
if (isTopLevel) {
|
||||
return null;
|
||||
}
|
||||
return win.frameElement;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize a content window directly contained by an <iframe mozbrowser>.
|
||||
*/
|
||||
_initTopLevelBrowserWindow: function BA_initTopLevelBrowserWindow(win) {
|
||||
// If we haven't seen this window's chrome event handler before, register
|
||||
// listeners on it.
|
||||
var chromeHandler = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell)
|
||||
.chromeEventHandler;
|
||||
|
||||
if (chromeHandler && !this._chromeEventHandlersWatching.has(chromeHandler)) {
|
||||
this._chromeEventHandlersWatching.set(chromeHandler, true);
|
||||
this._addChromeEventHandlerListeners(chromeHandler);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Add some listeners to a chrome event handler. Don't call this twice for
|
||||
* the same chrome event handler or we'll get duplicate listeners!
|
||||
*/
|
||||
_addChromeEventHandlerListeners: function BA_addChromeEventHandlerListeners(chromeHandler) {
|
||||
var browserElementAPI = this;
|
||||
|
||||
// Listen for DOMTitleChanged events on top-level <iframe mozbrowser>
|
||||
// windows. (The chrome event handler handles
|
||||
chromeHandler.addEventListener(
|
||||
'DOMTitleChanged',
|
||||
function(e) {
|
||||
var win = e.target.defaultView;
|
||||
if (browserElementAPI._topLevelBrowserWindows.has(win)) {
|
||||
browserElementAPI._fireCustomEvent('titlechange', e.target.title,
|
||||
win, win.frameElement);
|
||||
}
|
||||
},
|
||||
/* useCapture = */ false,
|
||||
/* wantsUntrusted = */ false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Asynchronously fire a vanilla event at the given window's frame element.
|
||||
* (Presumably, the window's frame element is an <iframe mozbrowser>.)
|
||||
*
|
||||
* We'll prepend 'mozbrowser' to the event's name.
|
||||
*/
|
||||
_fireEvent: function BA_fireEvent(name, win) {
|
||||
// Because we're chrome, win.frameElement ignores <iframe mozbrowser>
|
||||
// boundaries, as desired.
|
||||
var evt = new win.Event('mozbrowser' + name);
|
||||
win.setTimeout(function() { win.frameElement.dispatchEvent(evt) }, 0);
|
||||
},
|
||||
|
||||
/**
|
||||
* Like _fireEvent, but fire a customevent with the given data, instead of a
|
||||
* vanilla event.
|
||||
*/
|
||||
_fireCustomEvent: function BA_fireCustomEvent(name, data, win) {
|
||||
var evt = new win.CustomEvent('mozbrowser' + name, {detail: data});
|
||||
win.setTimeout(function() { win.frameElement.dispatchEvent(evt) }, 0);
|
||||
},
|
||||
|
||||
/**
|
||||
* An nsIWebProgressListener registered on docshells directly contained in an
|
||||
* <iframe mozbrowser>.
|
||||
*/
|
||||
_progressListener: {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
|
||||
Ci.nsISupportsWeakReference,
|
||||
Ci.nsISupports]),
|
||||
|
||||
_getWindow: function(webProgress) {
|
||||
return webProgress.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindow);
|
||||
},
|
||||
|
||||
onLocationChange: function(webProgress, request, location, flags) {
|
||||
this._browserElementAPI._fireCustomEvent('locationchange', location.spec,
|
||||
this._getWindow(webProgress));
|
||||
},
|
||||
|
||||
onStateChange: function(webProgress, request, stateFlags, status) {
|
||||
if (stateFlags & Ci.nsIWebProgressListener.STATE_START) {
|
||||
this._browserElementAPI._fireEvent('loadstart', this._getWindow(webProgress));
|
||||
}
|
||||
if (stateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
|
||||
this._browserElementAPI._fireEvent('loadend', this._getWindow(webProgress));
|
||||
}
|
||||
},
|
||||
|
||||
onStatusChange: function(webProgress, request, status, message) {},
|
||||
onProgressChange: function(webProgress, request, curSelfProgress,
|
||||
maxSelfProgress, curTotalProgress, maxTotalProgress) {},
|
||||
onSecurityChange: function(webProgress, request, aState) {}
|
||||
},
|
||||
|
||||
/**
|
||||
* nsIObserver::Observe
|
||||
*/
|
||||
observe: function BA_observe(subject, topic, data) {
|
||||
switch(topic) {
|
||||
case 'app-startup':
|
||||
this._init();
|
||||
break;
|
||||
case 'content-document-global-created':
|
||||
this._observeContentGlobalCreated(subject);
|
||||
break;
|
||||
case 'docshell-marked-as-browser-frame':
|
||||
this._observeDocshellMarkedAsBrowserFrame(subject);
|
||||
break;
|
||||
case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID:
|
||||
if (data == BROWSER_FRAMES_ENABLED_PREF) {
|
||||
this._init();
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
var NSGetFactory = XPCOMUtils.generateNSGetFactory([BrowserElementAPI]);
|
|
@ -1,3 +0,0 @@
|
|||
component {5d6fcab3-6c12-4db6-80fb-352df7a41602} BrowserElementAPI.js
|
||||
contract @mozilla.org/browser-element-api;1 {5d6fcab3-6c12-4db6-80fb-352df7a41602}
|
||||
category app-startup BrowserElementAPI service,@mozilla.org/browser-element-api;1
|
|
@ -0,0 +1,109 @@
|
|||
/* 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";
|
||||
|
||||
let Cu = Components.utils;
|
||||
let Ci = Components.interfaces;
|
||||
let Cc = Components.classes;
|
||||
|
||||
function debug(msg) {
|
||||
dump("BrowserElementChild - " + msg + "\n");
|
||||
}
|
||||
|
||||
function sendAsyncMsg(msg, data) {
|
||||
sendAsyncMessage('browser-element-api:' + msg, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* The BrowserElementChild implements one half of <iframe mozbrowser>.
|
||||
* (The other half is, unsurprisingly, BrowserElementParent.)
|
||||
*
|
||||
* This script is injected into an <iframe mozbrowser> via
|
||||
* nsIMessageManager::LoadFrameScript().
|
||||
*
|
||||
* Our job here is to listen for events within this frame and bubble them up to
|
||||
* the parent process.
|
||||
*/
|
||||
|
||||
function BrowserElementChild() {
|
||||
this._init();
|
||||
};
|
||||
|
||||
BrowserElementChild.prototype = {
|
||||
_init: function() {
|
||||
debug("Starting up.");
|
||||
sendAsyncMsg("hello");
|
||||
|
||||
docShell.QueryInterface(Ci.nsIWebProgress)
|
||||
.addProgressListener(this._progressListener,
|
||||
Ci.nsIWebProgress.NOTIFY_LOCATION |
|
||||
Ci.nsIWebProgress.NOTIFY_STATE_WINDOW);
|
||||
|
||||
addEventListener('DOMTitleChanged',
|
||||
this._titleChangedHandler.bind(this),
|
||||
/* useCapture = */ true,
|
||||
/* wantsUntrusted = */ false);
|
||||
},
|
||||
|
||||
_titleChangedHandler: function(e) {
|
||||
debug("Got titlechanged: (" + e.target.title + ")");
|
||||
var win = e.target.defaultView;
|
||||
|
||||
// Ignore titlechanges which don't come from the top-level
|
||||
// <iframe mozbrowser> window.
|
||||
if (win == content) {
|
||||
sendAsyncMsg('titlechange', e.target.title);
|
||||
}
|
||||
else {
|
||||
debug("Not top level!");
|
||||
}
|
||||
},
|
||||
|
||||
// The docShell keeps a weak reference to the progress listener, so we need
|
||||
// to keep a strong ref to it ourselves.
|
||||
_progressListener: {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
|
||||
Ci.nsISupportsWeakReference,
|
||||
Ci.nsISupports]),
|
||||
_seenLoadStart: false,
|
||||
|
||||
onLocationChange: function(webProgress, request, location, flags) {
|
||||
// We get progress events from subshells here, which is kind of weird.
|
||||
if (webProgress != docShell) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore locationchange events which occur before the first loadstart.
|
||||
// These are usually about:blank loads we don't care about.
|
||||
if (!this._seenLoadStart) {
|
||||
return;
|
||||
}
|
||||
|
||||
sendAsyncMsg('locationchange', location.spec);
|
||||
},
|
||||
|
||||
onStateChange: function(webProgress, request, stateFlags, status) {
|
||||
if (webProgress != docShell) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (stateFlags & Ci.nsIWebProgressListener.STATE_START) {
|
||||
this._seenLoadStart = true;
|
||||
sendAsyncMsg('loadstart');
|
||||
}
|
||||
|
||||
if (stateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
|
||||
sendAsyncMsg('loadend');
|
||||
}
|
||||
},
|
||||
|
||||
onStatusChange: function(webProgress, request, status, message) {},
|
||||
onProgressChange: function(webProgress, request, curSelfProgress,
|
||||
maxSelfProgress, curTotalProgress, maxTotalProgress) {},
|
||||
onSecurityChange: function(webProgress, request, aState) {}
|
||||
},
|
||||
};
|
||||
|
||||
var api = new BrowserElementChild();
|
|
@ -0,0 +1,158 @@
|
|||
/* 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";
|
||||
|
||||
let Cu = Components.utils;
|
||||
let Ci = Components.interfaces;
|
||||
let Cc = Components.classes;
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
|
||||
const BROWSER_FRAMES_ENABLED_PREF = "dom.mozBrowserFramesEnabled";
|
||||
|
||||
function debug(msg) {
|
||||
dump("BrowserElementParent - " + msg + "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* The BrowserElementParent implements one half of <iframe mozbrowser>.
|
||||
* (The other half is, unsurprisingly, BrowserElementChild.)
|
||||
*
|
||||
* We detect windows and docshells contained inside <iframe mozbrowser>s and
|
||||
* inject script to listen for certain events in the child. We then listen to
|
||||
* messages from the child script and take appropriate action here.
|
||||
*/
|
||||
|
||||
function BrowserElementParent() {}
|
||||
BrowserElementParent.prototype = {
|
||||
classID: Components.ID("{ddeafdac-cb39-47c4-9cb8-c9027ee36d26}"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
|
||||
/**
|
||||
* Called on app startup, and also when the browser frames enabled pref is
|
||||
* changed.
|
||||
*/
|
||||
_init: function() {
|
||||
debug("_init");
|
||||
|
||||
if (this._initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the pref is disabled, do nothing except wait for the pref to change.
|
||||
// (This is important for tests, if nothing else.)
|
||||
if (!this._browserFramesPrefEnabled()) {
|
||||
var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
|
||||
prefs.addObserver(BROWSER_FRAMES_ENABLED_PREF, this, /* ownsWeak = */ true);
|
||||
return;
|
||||
}
|
||||
|
||||
this._initialized = true;
|
||||
|
||||
var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
|
||||
os.addObserver(this, 'remote-browser-frame-shown', /* ownsWeak = */ true);
|
||||
os.addObserver(this, 'in-process-browser-frame-shown', /* ownsWeak = */ true);
|
||||
},
|
||||
|
||||
_browserFramesPrefEnabled: function() {
|
||||
var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
|
||||
try {
|
||||
return prefs.getBoolPref(BROWSER_FRAMES_ENABLED_PREF);
|
||||
}
|
||||
catch(e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
_observeInProcessBrowserFrameShown: function(frameLoader) {
|
||||
debug("In-process browser frame shown " + frameLoader);
|
||||
this._setUpMessageManagerListeners(frameLoader);
|
||||
},
|
||||
|
||||
_observeRemoteBrowserFrameShown: function(frameLoader) {
|
||||
debug("Remote browser frame shown " + frameLoader);
|
||||
this._setUpMessageManagerListeners(frameLoader);
|
||||
},
|
||||
|
||||
_setUpMessageManagerListeners: function(frameLoader) {
|
||||
let frameElement = frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerElement;
|
||||
if (!frameElement) {
|
||||
debug("No frame element?");
|
||||
return;
|
||||
}
|
||||
|
||||
let mm = frameLoader.messageManager;
|
||||
|
||||
// Messages we receive are handled by functions with parameters
|
||||
// (frameElement, data), where |data| is the message manager's data object.
|
||||
|
||||
function addMessageListener(msg, handler) {
|
||||
mm.addMessageListener('browser-element-api:' + msg, handler.bind(this, frameElement));
|
||||
}
|
||||
|
||||
addMessageListener("hello", this._recvHello);
|
||||
addMessageListener("locationchange", this._fireEventFromMsg);
|
||||
addMessageListener("loadstart", this._fireEventFromMsg);
|
||||
addMessageListener("loadend", this._fireEventFromMsg);
|
||||
addMessageListener("titlechange", this._fireEventFromMsg);
|
||||
|
||||
mm.loadFrameScript("chrome://global/content/BrowserElementChild.js",
|
||||
/* allowDelayedLoad = */ true);
|
||||
},
|
||||
|
||||
_recvHello: function(frameElement, data) {
|
||||
debug("recvHello " + frameElement);
|
||||
},
|
||||
|
||||
/**
|
||||
* Fire either a vanilla or a custom event, depending on the contents of
|
||||
* |data|.
|
||||
*/
|
||||
_fireEventFromMsg: function(frameElement, data) {
|
||||
let name = data.name;
|
||||
let detail = data.json;
|
||||
|
||||
debug('fireEventFromMsg: ' + name + ' ' + detail);
|
||||
let evtName = name.substring('browser-element-api:'.length);
|
||||
let win = frameElement.ownerDocument.defaultView;
|
||||
let evt;
|
||||
|
||||
// This will have to change if we ever want to send a CustomEvent with null
|
||||
// detail. For now, it's OK.
|
||||
if (detail !== undefined && detail !== null) {
|
||||
evt = new win.CustomEvent('mozbrowser' + evtName, {detail: detail});
|
||||
}
|
||||
else {
|
||||
evt = new win.Event('mozbrowser' + evtName);
|
||||
}
|
||||
|
||||
frameElement.dispatchEvent(evt);
|
||||
},
|
||||
|
||||
observe: function(subject, topic, data) {
|
||||
switch(topic) {
|
||||
case 'app-startup':
|
||||
this._init();
|
||||
break;
|
||||
case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID:
|
||||
if (data == BROWSER_FRAMES_ENABLED_PREF) {
|
||||
this._init();
|
||||
}
|
||||
break;
|
||||
case 'remote-browser-frame-shown':
|
||||
this._observeRemoteBrowserFrameShown(subject);
|
||||
break;
|
||||
case 'in-process-browser-frame-shown':
|
||||
this._observeInProcessBrowserFrameShown(subject);
|
||||
break;
|
||||
case 'content-document-global-created':
|
||||
this._observeContentGlobalCreated(subject);
|
||||
break;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
var NSGetFactory = XPCOMUtils.generateNSGetFactory([BrowserElementParent]);
|
|
@ -0,0 +1,3 @@
|
|||
component {ddeafdac-cb39-47c4-9cb8-c9027ee36d26} BrowserElementParent.js
|
||||
contract @mozilla.org/browser-element-parent;1 {ddeafdac-cb39-47c4-9cb8-c9027ee36d26}
|
||||
category app-startup BrowserElementParent service,@mozilla.org/browser-element-parent;1
|
|
@ -54,8 +54,8 @@ DIRS = \
|
|||
EXTRA_PP_COMPONENTS = \
|
||||
ConsoleAPI.js \
|
||||
ConsoleAPI.manifest \
|
||||
BrowserElementAPI.js \
|
||||
BrowserElementAPI.manifest \
|
||||
BrowserElementParent.js \
|
||||
BrowserElementParent.manifest \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_JS_MODULES = ConsoleAPIStorage.jsm \
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#ifndef mozilla_dom_ScreenOrientation_h
|
||||
#define mozilla_dom_ScreenOrientation_h
|
||||
|
||||
#include "IPC/IPCMessageUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -22,24 +24,6 @@ enum ScreenOrientation {
|
|||
eScreenOrientation_EndGuard
|
||||
};
|
||||
|
||||
/**
|
||||
* ScreenOrientationWrapper is a class wrapping ScreenOrientation so it can be
|
||||
* used with Observer<T> which is taking a class, not an enum.
|
||||
* C++11 should make this useless.
|
||||
*/
|
||||
class ScreenOrientationWrapper {
|
||||
public:
|
||||
ScreenOrientationWrapper()
|
||||
: orientation(eScreenOrientation_None)
|
||||
{}
|
||||
|
||||
ScreenOrientationWrapper(ScreenOrientation aOrientation)
|
||||
: orientation(aOrientation)
|
||||
{}
|
||||
|
||||
ScreenOrientation orientation;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -478,8 +478,9 @@ DOMApplicationManifest.prototype = {
|
|||
},
|
||||
|
||||
fullLaunchPath: function(aStartPoint) {
|
||||
let startPoint = aStartPoint || "";
|
||||
let launchPath = this._localeProp("launch_path") || "";
|
||||
return this._origin.resolve(launchPath + aStartPoint);
|
||||
return this._origin.resolve(launchPath + startPoint);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1546,6 +1546,9 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
|||
NS_DEFINE_CLASSINFO_DATA(WebGLExtensionLoseContext, WebGLExtensionSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS |
|
||||
nsIXPCScriptable::WANT_ADDPROPERTY)
|
||||
NS_DEFINE_CLASSINFO_DATA(WebGLExtensionCompressedTextureS3TC, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS |
|
||||
nsIXPCScriptable::WANT_ADDPROPERTY)
|
||||
|
||||
NS_DEFINE_CLASSINFO_DATA(PaintRequest, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
|
@ -4250,6 +4253,10 @@ nsDOMClassInfo::Init()
|
|||
DOM_CLASSINFO_MAP_ENTRY(nsIWebGLExtensionLoseContext)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(WebGLExtensionCompressedTextureS3TC, nsIWebGLExtensionCompressedTextureS3TC)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIWebGLExtensionCompressedTextureS3TC)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(PaintRequest, nsIDOMPaintRequest)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMPaintRequest)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
|
|
@ -489,6 +489,7 @@ DOMCI_CLASS(WebGLExtension)
|
|||
DOMCI_CLASS(WebGLExtensionStandardDerivatives)
|
||||
DOMCI_CLASS(WebGLExtensionTextureFilterAnisotropic)
|
||||
DOMCI_CLASS(WebGLExtensionLoseContext)
|
||||
DOMCI_CLASS(WebGLExtensionCompressedTextureS3TC)
|
||||
|
||||
DOMCI_CLASS(PaintRequest)
|
||||
DOMCI_CLASS(PaintRequestList)
|
||||
|
|
|
@ -2341,19 +2341,46 @@ nsGlobalWindow::SetOpenerWindow(nsIDOMWindow* aOpener,
|
|||
#endif
|
||||
}
|
||||
|
||||
static
|
||||
already_AddRefed<nsIDOMEventTarget>
|
||||
TryGetTabChildGlobalAsEventTarget(nsISupports *aFrom)
|
||||
{
|
||||
nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner = do_QueryInterface(aFrom);
|
||||
if (!frameLoaderOwner) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nsRefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
|
||||
if (!frameLoader) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMEventTarget> eventTarget =
|
||||
frameLoader->GetTabChildGlobalAsEventTarget();
|
||||
return eventTarget.forget();
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::UpdateParentTarget()
|
||||
{
|
||||
nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(mChromeEventHandler);
|
||||
if (flo) {
|
||||
nsRefPtr<nsFrameLoader> fl = flo->GetFrameLoader();
|
||||
if (fl) {
|
||||
mParentTarget = fl->GetTabChildGlobalAsEventTarget();
|
||||
}
|
||||
// Try to get our frame element's tab child global (its in-process message
|
||||
// manager). If that fails, fall back to the chrome event handler's tab
|
||||
// child global, and if it doesn't have one, just use the chrome event
|
||||
// handler itself.
|
||||
|
||||
nsCOMPtr<nsIDOMElement> frameElement = GetFrameElementInternal();
|
||||
nsCOMPtr<nsIDOMEventTarget> eventTarget =
|
||||
TryGetTabChildGlobalAsEventTarget(frameElement);
|
||||
|
||||
if (!eventTarget) {
|
||||
eventTarget = TryGetTabChildGlobalAsEventTarget(mChromeEventHandler);
|
||||
}
|
||||
if (!mParentTarget) {
|
||||
mParentTarget = mChromeEventHandler;
|
||||
|
||||
if (!eventTarget) {
|
||||
eventTarget = mChromeEventHandler;
|
||||
}
|
||||
|
||||
mParentTarget = eventTarget;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -82,8 +82,10 @@ nsScreen::Create(nsPIDOMWindow* aWindow)
|
|||
nsRefPtr<nsScreen> screen = new nsScreen();
|
||||
screen->BindToOwner(aWindow);
|
||||
|
||||
hal::RegisterScreenOrientationObserver(screen);
|
||||
hal::GetCurrentScreenOrientation(&(screen->mOrientation));
|
||||
hal::RegisterScreenConfigurationObserver(screen);
|
||||
hal::ScreenConfiguration config;
|
||||
hal::GetCurrentScreenConfiguration(&config);
|
||||
screen->mOrientation = config.orientation();
|
||||
|
||||
return screen.forget();
|
||||
}
|
||||
|
@ -95,7 +97,7 @@ nsScreen::nsScreen()
|
|||
|
||||
nsScreen::~nsScreen()
|
||||
{
|
||||
hal::UnregisterScreenOrientationObserver(this);
|
||||
hal::UnregisterScreenConfigurationObserver(this);
|
||||
}
|
||||
|
||||
|
||||
|
@ -285,10 +287,10 @@ nsScreen::GetAvailRect(nsRect& aRect)
|
|||
}
|
||||
|
||||
void
|
||||
nsScreen::Notify(const ScreenOrientationWrapper& aOrientation)
|
||||
nsScreen::Notify(const hal::ScreenConfiguration& aConfiguration)
|
||||
{
|
||||
ScreenOrientation previousOrientation = mOrientation;
|
||||
mOrientation = aOrientation.orientation;
|
||||
mOrientation = aConfiguration.orientation();
|
||||
|
||||
NS_ASSERTION(mOrientation != eScreenOrientation_None &&
|
||||
mOrientation != eScreenOrientation_EndGuard &&
|
||||
|
|
|
@ -37,14 +37,13 @@
|
|||
#ifndef nsScreen_h___
|
||||
#define nsScreen_h___
|
||||
|
||||
#include "mozilla/dom/ScreenOrientation.h"
|
||||
#include "mozilla/Hal.h"
|
||||
#include "nsIDOMScreen.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/dom/ScreenOrientation.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
#include "mozilla/Observer.h"
|
||||
|
||||
class nsIDocShell;
|
||||
class nsDeviceContext;
|
||||
|
@ -53,7 +52,7 @@ struct nsRect;
|
|||
// Script "screen" object
|
||||
class nsScreen : public nsDOMEventTargetHelper
|
||||
, public nsIDOMScreen
|
||||
, public mozilla::hal::ScreenOrientationObserver
|
||||
, public mozilla::hal::ScreenConfigurationObserver
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<nsScreen> Create(nsPIDOMWindow* aWindow);
|
||||
|
@ -67,7 +66,7 @@ public:
|
|||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsScreen,
|
||||
nsDOMEventTargetHelper)
|
||||
|
||||
void Notify(const mozilla::dom::ScreenOrientationWrapper& aOrientation);
|
||||
void Notify(const mozilla::hal::ScreenConfiguration& aConfiguration);
|
||||
|
||||
protected:
|
||||
nsDeviceContext* GetDeviceContext();
|
||||
|
|
|
@ -175,7 +175,7 @@ Contact.prototype = {
|
|||
// ContactManager
|
||||
|
||||
const CONTACTMANAGER_CONTRACTID = "@mozilla.org/contactManager;1";
|
||||
const CONTACTMANAGER_CID = Components.ID("{50a820b0-ced0-11e0-9572-0800200c9a66}");
|
||||
const CONTACTMANAGER_CID = Components.ID("{d9ca0950-93d1-11e1-b0c4-0800200c9a66}");
|
||||
const nsIDOMContactManager = Components.interfaces.nsIDOMContactManager;
|
||||
|
||||
function ContactManager()
|
||||
|
@ -185,6 +185,18 @@ function ContactManager()
|
|||
|
||||
ContactManager.prototype = {
|
||||
__proto__: DOMRequestIpcHelper.prototype,
|
||||
_oncontactchange: null,
|
||||
|
||||
set oncontactchange(aCallback) {
|
||||
if (this.hasPrivileges)
|
||||
this._oncontactchange = aCallback;
|
||||
else
|
||||
throw Components.results.NS_ERROR_FAILURE;
|
||||
},
|
||||
|
||||
get oncontactchange() {
|
||||
return this._oncontactchange;
|
||||
},
|
||||
|
||||
save: function save(aContact) {
|
||||
let request;
|
||||
|
@ -216,17 +228,21 @@ ContactManager.prototype = {
|
|||
for (let field in newContact.properties)
|
||||
newContact.properties[field] = aContact[field];
|
||||
|
||||
let reason;
|
||||
if (aContact.id == "undefined") {
|
||||
// for example {25c00f01-90e5-c545-b4d4-21E2ddbab9e0} becomes
|
||||
// 25c00f0190e5c545b4d421E2ddbab9e0
|
||||
aContact.id = this._getRandomId().replace('-', '').replace('{', '').replace('}', '');
|
||||
aContact.id = this._getRandomId().replace('-', '', 'g').replace('{', '').replace('}', '');
|
||||
reason = "create";
|
||||
} else {
|
||||
reason = "update";
|
||||
}
|
||||
|
||||
this._setMetaData(newContact, aContact);
|
||||
debug("send: " + JSON.stringify(newContact));
|
||||
request = this.createRequest();
|
||||
cpmm.sendAsyncMessage("Contact:Save", {contact: newContact,
|
||||
requestID: this.getRequestId(request)});
|
||||
requestID: this.getRequestId({request: request, reason: reason })});
|
||||
return request;
|
||||
} else {
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
@ -238,7 +254,7 @@ ContactManager.prototype = {
|
|||
if (this.hasPrivileges) {
|
||||
request = this.createRequest();
|
||||
cpmm.sendAsyncMessage("Contact:Remove", {id: aRecord.id,
|
||||
requestID: this.getRequestId(request)});
|
||||
requestID: this.getRequestId({request: request, reason: "remove"})});
|
||||
return request;
|
||||
} else {
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
@ -273,7 +289,7 @@ ContactManager.prototype = {
|
|||
if (req) {
|
||||
let result = this._convertContactsArray(contacts);
|
||||
debug("result: " + JSON.stringify(result));
|
||||
Services.DOMRequest.fireSuccess(req, result);
|
||||
Services.DOMRequest.fireSuccess(req.request, result);
|
||||
} else {
|
||||
debug("no request stored!" + msg.requestID);
|
||||
}
|
||||
|
@ -283,7 +299,13 @@ ContactManager.prototype = {
|
|||
case "Contact:Remove:Return:OK":
|
||||
req = this.getRequest(msg.requestID);
|
||||
if (req)
|
||||
Services.DOMRequest.fireSuccess(req, null);
|
||||
Services.DOMRequest.fireSuccess(req.request, null);
|
||||
|
||||
// Fire oncontactchange event
|
||||
if (this._oncontactchange) {
|
||||
let event = new MozContactEvent(msg.contactID, req.reason);
|
||||
this._oncontactchange.handleEvent(event);
|
||||
}
|
||||
break;
|
||||
case "Contacts:Find:Return:KO":
|
||||
case "Contact:Save:Return:KO":
|
||||
|
@ -291,7 +313,7 @@ ContactManager.prototype = {
|
|||
case "Contacts:Clear:Return:KO":
|
||||
req = this.getRequest(msg.requestID);
|
||||
if (req)
|
||||
Services.DOMRequest.fireError(req, msg.errorMsg);
|
||||
Services.DOMRequest.fireError(req.request, msg.errorMsg);
|
||||
break;
|
||||
default:
|
||||
debug("Wrong message: " + aMessage.name);
|
||||
|
@ -304,7 +326,7 @@ ContactManager.prototype = {
|
|||
if (this.hasPrivileges) {
|
||||
request = this.createRequest();
|
||||
cpmm.sendAsyncMessage("Contacts:Find", {findOptions: aOptions,
|
||||
requestID: this.getRequestId(request)});
|
||||
requestID: this.getRequestId({request: request, reason: "find"})});
|
||||
return request;
|
||||
} else {
|
||||
debug("find not allowed");
|
||||
|
@ -316,7 +338,7 @@ ContactManager.prototype = {
|
|||
let request;
|
||||
if (this.hasPrivileges) {
|
||||
request = this.createRequest();
|
||||
cpmm.sendAsyncMessage("Contacts:Clear", {requestID: this.getRequestId(request)});
|
||||
cpmm.sendAsyncMessage("Contacts:Clear", {requestID: this.getRequestId({request: request, reason: "remove"})});
|
||||
return request;
|
||||
} else {
|
||||
debug("clear not allowed");
|
||||
|
@ -346,6 +368,13 @@ ContactManager.prototype = {
|
|||
debug("has privileges :" + this.hasPrivileges);
|
||||
},
|
||||
|
||||
// Called from DOMRequestIpcHelper
|
||||
uninit: function uninit() {
|
||||
debug("uninit call");
|
||||
if (this._oncontactchange)
|
||||
this._oncontactchange = null;
|
||||
},
|
||||
|
||||
classID : CONTACTMANAGER_CID,
|
||||
QueryInterface : XPCOMUtils.generateQI([nsIDOMContactManager, Ci.nsIDOMGlobalPropertyInitializer]),
|
||||
|
||||
|
@ -356,4 +385,31 @@ ContactManager.prototype = {
|
|||
flags: nsIClassInfo.DOM_OBJECT})
|
||||
}
|
||||
|
||||
// MozContactEvent object
|
||||
function MozContactEvent(aContactID, aReason) {
|
||||
debug("ContactEventConstr: " + aContactID + ", " + aReason);
|
||||
this._contactID = aContactID;
|
||||
this._reason = aReason;
|
||||
}
|
||||
|
||||
MozContactEvent.prototype = {
|
||||
get contactID() {
|
||||
return this._contactID;
|
||||
},
|
||||
|
||||
get reason() {
|
||||
return this._reason;
|
||||
},
|
||||
|
||||
classID: Components.ID("{a8cd4ba0-93d1-11e1-b0c4-0800200c9a66}"),
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.mozIDOMContactEvent]),
|
||||
|
||||
classInfo: XPCOMUtils.generateCI({classID: Components.ID("{a8cd4ba0-93d1-11e1-b0c4-0800200c9a66}"),
|
||||
contractID: "@mozilla.org/contact-event;1",
|
||||
interfaces: [Ci.mozIDOMContactEvent],
|
||||
flags: Ci.nsIClassInfo.DOM_OBJECT,
|
||||
classDescription: "Contact Change Event"})
|
||||
}
|
||||
|
||||
const NSGetFactory = XPCOMUtils.generateNSGetFactory([Contact, ContactManager, ContactProperties, ContactAddress, ContactFindOptions])
|
||||
|
|
|
@ -11,6 +11,6 @@ component {da0f7040-388b-11e1-b86c-0800200c9a66} ContactManager.js
|
|||
contract @mozilla.org/contact;1 {da0f7040-388b-11e1-b86c-0800200c9a66}
|
||||
category JavaScript-global-constructor mozContact @mozilla.org/contact;1
|
||||
|
||||
component {50a820b0-ced0-11e0-9572-0800200c9a66} ContactManager.js
|
||||
contract @mozilla.org/contactManager;1 {50a820b0-ced0-11e0-9572-0800200c9a66}
|
||||
component {d9ca0950-93d1-11e1-b0c4-0800200c9a66} ContactManager.js
|
||||
contract @mozilla.org/contactManager;1 {d9ca0950-93d1-11e1-b0c4-0800200c9a66}
|
||||
category JavaScript-navigator-property mozContacts @mozilla.org/contactManager;1
|
||||
|
|
|
@ -95,21 +95,28 @@ let DOMContactManager = {
|
|||
debug("result:" + JSON.stringify(result));
|
||||
ppmm.sendAsyncMessage("Contacts:Find:Return:OK", {requestID: msg.requestID, contacts: result});
|
||||
}.bind(this),
|
||||
function(aErrorMsg) { ppmm.sendAsyncMessage("Contacts:Find:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }) }.bind(this),
|
||||
function(aErrorMsg) { ppmm.sendAsyncMessage("Contacts:Find:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }) }.bind(this),
|
||||
msg.findOptions);
|
||||
break;
|
||||
case "Contact:Save":
|
||||
this._db.saveContact(msg.contact, function() { ppmm.sendAsyncMessage("Contact:Save:Return:OK", { requestID: msg.requestID }); }.bind(this),
|
||||
function(aErrorMsg) { ppmm.sendAsyncMessage("Contact:Save:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this));
|
||||
this._db.saveContact(
|
||||
msg.contact,
|
||||
function() { ppmm.sendAsyncMessage("Contact:Save:Return:OK", { requestID: msg.requestID, contactID: msg.contact.id }); }.bind(this),
|
||||
function(aErrorMsg) { ppmm.sendAsyncMessage("Contact:Save:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this)
|
||||
);
|
||||
break;
|
||||
case "Contact:Remove":
|
||||
this._db.removeContact(msg.id,
|
||||
function() { ppmm.sendAsyncMessage("Contact:Remove:Return:OK", { requestID: msg.requestID }); }.bind(this),
|
||||
function(aErrorMsg) { ppmm.sendAsyncMessage("Contact:Remove:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this));
|
||||
this._db.removeContact(
|
||||
msg.id,
|
||||
function() { ppmm.sendAsyncMessage("Contact:Remove:Return:OK", { requestID: msg.requestID, contactID: msg.id }); }.bind(this),
|
||||
function(aErrorMsg) { ppmm.sendAsyncMessage("Contact:Remove:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this)
|
||||
);
|
||||
break;
|
||||
case "Contacts:Clear":
|
||||
this._db.clear(function() { ppmm.sendAsyncMessage("Contacts:Clear:Return:OK", { requestID: msg.requestID }); }.bind(this),
|
||||
function(aErrorMsg) { ppmm.sendAsyncMessage("Contacts:Clear:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this));
|
||||
this._db.clear(
|
||||
function() { ppmm.sendAsyncMessage("Contacts:Clear:Return:OK", { requestID: msg.requestID }); }.bind(this),
|
||||
function(aErrorMsg) { ppmm.sendAsyncMessage("Contacts:Clear:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -231,6 +231,12 @@ var steps = [
|
|||
ok(true, "Adding a new contact1");
|
||||
createResult1 = new mozContact();
|
||||
createResult1.init(properties1);
|
||||
|
||||
mozContacts.oncontactchange = function(event) {
|
||||
is(event.contactID, createResult1.id, "Same contactID");
|
||||
is(event.reason, "create", "Same reason");
|
||||
}
|
||||
|
||||
req = navigator.mozContacts.save(createResult1);
|
||||
req.onsuccess = function () {
|
||||
ok(createResult1.id, "The contact now has an ID.");
|
||||
|
@ -255,11 +261,135 @@ var steps = [
|
|||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Retrieving by substring and update");
|
||||
mozContacts.oncontactchange = function(event) {
|
||||
is(event.contactID, findResult1.id, "Same contactID");
|
||||
is(event.reason, "update", "Same reason");
|
||||
}
|
||||
var options = {filterBy: ["name"],
|
||||
filterOp: "contains",
|
||||
filterValue: properties1.name.substring(0,3)};
|
||||
req = mozContacts.find(options);
|
||||
req.onsuccess = function () {
|
||||
ok(req.result.length == 1, "Found exactly 1 contact.");
|
||||
findResult1 = req.result[0];
|
||||
findResult1.jobTitle = ["new Job"];
|
||||
ok(findResult1.id == sample_id1, "Same ID");
|
||||
checkContacts(createResult1, properties1);
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Adding a new contact");
|
||||
mozContacts.oncontactchange = function(event) {
|
||||
is(event.contactID, createResult2.id, "Same contactID");
|
||||
is(event.reason, "create", "Same reason");
|
||||
}
|
||||
createResult2 = new mozContact();
|
||||
createResult2.init({name: "newName"});
|
||||
req = navigator.mozContacts.save(createResult2);
|
||||
req.onsuccess = function () {
|
||||
ok(createResult2.id, "The contact now has an ID.");
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Retrieving by substring");
|
||||
var options = {filterBy: ["name"],
|
||||
filterOp: "contains",
|
||||
filterValue: properties1.name.substring(0,3)};
|
||||
req = mozContacts.find(options);
|
||||
req.onsuccess = function () {
|
||||
ok(req.result.length == 1, "Found exactly 1 contact.");
|
||||
findResult1 = req.result[0];
|
||||
checkContacts(createResult1, findResult1);
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Remove contact1");
|
||||
mozContacts.oncontactchange = function(event) {
|
||||
is(event.contactID, createResult1.id, "Same contactID");
|
||||
is(event.reason, "remove", "Same reason");
|
||||
}
|
||||
req = navigator.mozContacts.remove(createResult1);
|
||||
req.onsuccess = function () {
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Retrieving by substring");
|
||||
var options = {filterBy: ["name"],
|
||||
filterOp: "contains",
|
||||
filterValue: properties1.name.substring(0,3)};
|
||||
req = mozContacts.find(options);
|
||||
req.onsuccess = function () {
|
||||
ok(req.result.length == 0, "Found no contact.");
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Remove contact2");
|
||||
mozContacts.oncontactchange = function(event) {
|
||||
is(event.contactID, createResult2.id, "Same contactID");
|
||||
is(event.reason, "remove", "Same reason");
|
||||
}
|
||||
req = navigator.mozContacts.remove(createResult2);
|
||||
req.onsuccess = function () {
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Retrieving by substring");
|
||||
var options = {filterBy: ["name"],
|
||||
filterOp: "contains",
|
||||
filterValue: properties1.name.substring(0,3)};
|
||||
req = mozContacts.find(options);
|
||||
req.onsuccess = function () {
|
||||
ok(req.result.length == 0, "Found no contact.");
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Deleting database");
|
||||
mozContacts.oncontactchange = function(event) {
|
||||
is(event.contactID, "undefined", "Same contactID");
|
||||
is(event.reason, "remove", "Same reason");
|
||||
}
|
||||
req = mozContacts.clear();
|
||||
req.onsuccess = function () {
|
||||
ok(true, "Deleted the database");
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Adding a new contact with properties1");
|
||||
createResult1 = new mozContact();
|
||||
createResult1.init(properties1);
|
||||
req = navigator.mozContacts.save(createResult1);
|
||||
req.onsuccess = function () {
|
||||
ok(createResult1.id, "The contact now has an ID.");
|
||||
sample_id1 = createResult1.id;
|
||||
checkContacts(properties1, createResult1);
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Retrieving by substring tel1");
|
||||
var options = {filterBy: ["tel"],
|
||||
filterOp: "contains",
|
||||
filterValue: properties1.tel[1].substring(1,5)};
|
||||
mozContacts.oncontactchange = null;
|
||||
req = mozContacts.find(options);
|
||||
req.onsuccess = function () {
|
||||
ok(req.result.length == 1, "Found exactly 1 contact.");
|
||||
|
|
|
@ -178,6 +178,16 @@ interface nsIWebGLExtensionTextureFilterAnisotropic : nsIWebGLExtension
|
|||
const WebGLenum MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF;
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(a1508b6f-f2ab-44cf-bbb4-3cfb339e1e8a)]
|
||||
interface nsIWebGLExtensionCompressedTextureS3TC : nsIWebGLExtension
|
||||
{
|
||||
/* Compressed Texture Formats */
|
||||
const WebGLenum COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0;
|
||||
const WebGLenum COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1;
|
||||
const WebGLenum COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2;
|
||||
const WebGLenum COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3;
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(a1fdfb76-6a08-4a1a-b0c9-d92ef3357cb9)]
|
||||
interface nsIDOMWebGLRenderingContext : nsISupports
|
||||
{
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "domstubs.idl"
|
||||
#include "nsIDOMContactProperties.idl"
|
||||
#include "nsIDOMEvent.idl"
|
||||
|
||||
interface nsIArray;
|
||||
interface nsIDOMContactFindOptions;
|
||||
|
@ -20,7 +21,14 @@ interface nsIDOMContact : nsIDOMContactProperties
|
|||
void init(in nsIDOMContactProperties properties); // Workaround BUG 723206
|
||||
};
|
||||
|
||||
[scriptable, uuid(50a820b0-ced0-11e0-9572-0800200c9a66)]
|
||||
[scriptable, uuid(a8cd4ba0-93d1-11e1-b0c4-0800200c9a66)]
|
||||
interface mozIDOMContactEvent : nsIDOMEvent
|
||||
{
|
||||
readonly attribute DOMString contactID;
|
||||
readonly attribute DOMString reason;
|
||||
};
|
||||
|
||||
[scriptable, uuid(d9ca0950-93d1-11e1-b0c4-0800200c9a66)]
|
||||
interface nsIDOMContactManager : nsISupports
|
||||
{
|
||||
nsIDOMDOMRequest find(in nsIDOMContactFindOptions options);
|
||||
|
@ -30,4 +38,6 @@ interface nsIDOMContactManager : nsISupports
|
|||
nsIDOMDOMRequest save(in nsIDOMContact contact);
|
||||
|
||||
nsIDOMDOMRequest remove(in nsIDOMContact contact);
|
||||
};
|
||||
|
||||
attribute nsIDOMEventListener oncontactchange;
|
||||
};
|
||||
|
|
|
@ -51,4 +51,4 @@ interface nsIDOMContactProperties : nsISupports
|
|||
attribute jsval anniversary; // Date
|
||||
attribute jsval sex; // DOMString
|
||||
attribute jsval genderIdentity; // DOMString
|
||||
};
|
||||
};
|
||||
|
|
|
@ -629,7 +629,8 @@ bool
|
|||
TabParent::RecvGetDPI(float* aValue)
|
||||
{
|
||||
TryCacheDPI();
|
||||
NS_ABORT_IF_FALSE(mDPI > 0,
|
||||
|
||||
NS_ABORT_IF_FALSE(mDPI > 0,
|
||||
"Must not ask for DPI before OwnerElement is received!");
|
||||
*aValue = mDPI;
|
||||
return true;
|
||||
|
@ -864,6 +865,17 @@ TabParent::TryCacheDPI()
|
|||
}
|
||||
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
|
||||
if (!widget && mFrameElement) {
|
||||
// Even if we don't have a widget (e.g. because we're display:none), there's
|
||||
// probably a widget somewhere in the hierarchy our frame element lives in.
|
||||
nsCOMPtr<nsIDOMDocument> ownerDoc;
|
||||
mFrameElement->GetOwnerDocument(getter_AddRefs(ownerDoc));
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(ownerDoc);
|
||||
widget = nsContentUtils::WidgetForDocument(doc);
|
||||
}
|
||||
|
||||
if (widget) {
|
||||
mDPI = widget->GetDPI();
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
toolkit.jar:
|
||||
content/global/test-ipc.xul (test.xul)
|
||||
content/global/remote-test-ipc.js (remote-test.js)
|
||||
content/global/BrowserElementChild.js (../base/BrowserElementChild.js)
|
||||
|
|
|
@ -116,6 +116,7 @@ nsIDOMWindowInternalWarning=Use of nsIDOMWindowInternal is deprecated. Use nsIDO
|
|||
InputEncodingWarning=Use of inputEncoding is deprecated.
|
||||
# LOCALIZATION NOTE: Do not translate "MozBeforePaint" and "mozRequestAnimationFrame"
|
||||
MozBeforePaintWarning=MozBeforePaint events are no longer supported. mozRequestAnimationFrame must be passed a non-null callback argument.
|
||||
FullScreenDeniedBlocked=Request for full-screen was denied because this domain has been blocked from full-screen by user.
|
||||
FullScreenDeniedDisabled=Request for full-screen was denied because full-screen API is disabled by user preference.
|
||||
FullScreenDeniedFocusedPlugin=Request for full-screen was denied because a windowed plugin is focused.
|
||||
FullScreenDeniedHidden=Request for full-screen was denied because the document is no longer visible.
|
||||
|
|
|
@ -71,8 +71,10 @@
|
|||
|
||||
USING_WORKERS_NAMESPACE
|
||||
using namespace mozilla::dom::gonk;
|
||||
using namespace mozilla::dom::bluetooth;
|
||||
using namespace mozilla::ipc;
|
||||
#ifdef MOZ_B2G_BT
|
||||
using namespace mozilla::dom::bluetooth;
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -394,10 +396,8 @@ SystemWorkerManager::InitBluetooth(JSContext *cx)
|
|||
// see if we can load functions out of bluedroid. If not, assume
|
||||
// it's an emulator and don't start the bluetooth thread.
|
||||
if(EnsureBluetoothInit()) {
|
||||
#endif
|
||||
#endif
|
||||
StartDBus();
|
||||
#ifdef MOZ_B2G_BT
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -59,6 +59,7 @@ DIRS += \
|
|||
storageevent \
|
||||
pointerlock \
|
||||
browser-frame \
|
||||
webapps \
|
||||
$(NULL)
|
||||
|
||||
#needs IPC support, also tests do not run successfully in Firefox for now
|
||||
|
|
|
@ -54,7 +54,6 @@ _TEST_FILES = \
|
|||
test_browserFrame5.html \
|
||||
test_browserFrame6.html \
|
||||
test_browserFrame7.html \
|
||||
test_browserFrame8.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
|
|
|
@ -3,75 +3,91 @@
|
|||
// Helpers for managing the browser frame preferences.
|
||||
|
||||
const browserFrameHelpers = {
|
||||
'getEnabledPref': function() {
|
||||
_getBoolPref: function(pref) {
|
||||
try {
|
||||
return SpecialPowers.getBoolPref('dom.mozBrowserFramesEnabled');
|
||||
return SpecialPowers.getBoolPref(pref);
|
||||
}
|
||||
catch(e) {
|
||||
catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
|
||||
'getWhitelistPref': function() {
|
||||
try {
|
||||
return SpecialPowers.getCharPref('dom.mozBrowserFramesWhitelist');
|
||||
}
|
||||
catch(e) {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
|
||||
'getOOPDisabledPref': function() {
|
||||
try {
|
||||
return SpecialPowers.getBoolPref('dom.ipc.tabs.disabled');
|
||||
}
|
||||
catch(e) {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
|
||||
'setEnabledPref': function(enabled) {
|
||||
if (enabled !== undefined) {
|
||||
SpecialPowers.setBoolPref('dom.mozBrowserFramesEnabled', enabled);
|
||||
}
|
||||
else {
|
||||
SpecialPowers.clearUserPref('dom.mozBrowserFramesEnabled');
|
||||
}
|
||||
},
|
||||
|
||||
'setWhitelistPref': function(whitelist) {
|
||||
if (whitelist !== undefined) {
|
||||
SpecialPowers.setCharPref('dom.mozBrowserFramesWhitelist', whitelist);
|
||||
}
|
||||
else {
|
||||
SpecialPowers.clearUserPref('dom.mozBrowserFramesWhitelist');
|
||||
}
|
||||
},
|
||||
|
||||
'setOOPDisabledPref': function(value) {
|
||||
_setBoolPref: function(pref, value) {
|
||||
if (value !== undefined) {
|
||||
SpecialPowers.setBoolPref('dom.ipc.tabs.disabled', value);
|
||||
SpecialPowers.setBoolPref(pref, value);
|
||||
}
|
||||
else {
|
||||
SpecialPowers.clearUserPref('dom.ipc.tabs.disabled');
|
||||
SpecialPowers.clearUserPref(pref);
|
||||
}
|
||||
},
|
||||
|
||||
'addToWhitelist': function() {
|
||||
var whitelist = browserFrameHelpers.getWhitelistPref();
|
||||
whitelist += ', http://' + window.location.host + ', ';
|
||||
browserFrameHelpers.setWhitelistPref(whitelist);
|
||||
_getCharPref: function(pref) {
|
||||
try {
|
||||
return SpecialPowers.getCharPref(pref);
|
||||
}
|
||||
catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
|
||||
'restoreOriginalPrefs': function() {
|
||||
browserFrameHelpers.setEnabledPref(browserFrameHelpers.origEnabledPref);
|
||||
browserFrameHelpers.setWhitelistPref(browserFrameHelpers.origWhitelistPref);
|
||||
browserFrameHelpers.setOOPDisabledPref(browserFrameHelpers.origOOPDisabledPref);
|
||||
_setCharPref: function(pref, value) {
|
||||
if (value !== undefined) {
|
||||
SpecialPowers.setCharPref(pref, value);
|
||||
}
|
||||
else {
|
||||
SpecialPowers.clearUserPref(pref);
|
||||
}
|
||||
},
|
||||
|
||||
getEnabledPref: function() {
|
||||
return this._getBoolPref('dom.mozBrowserFramesEnabled');
|
||||
},
|
||||
|
||||
setEnabledPref: function(value) {
|
||||
this._setBoolPref('dom.mozBrowserFramesEnabled', value);
|
||||
},
|
||||
|
||||
getWhitelistPref: function() {
|
||||
return this._getCharPref('dom.mozBrowserFramesWhitelist');
|
||||
},
|
||||
|
||||
setWhitelistPref: function(whitelist) {
|
||||
this._setCharPref('dom.mozBrowserFramesWhitelist', whitelist);
|
||||
},
|
||||
|
||||
getOOPDisabledPref: function() {
|
||||
return this._getBoolPref('dom.ipc.tabs.disabled');
|
||||
},
|
||||
|
||||
setOOPDisabledPref: function(value) {
|
||||
this._setBoolPref('dom.ipc.tabs.disabled', value);
|
||||
},
|
||||
|
||||
getPageThumbsEnabledPref: function() {
|
||||
return this._getBoolPref('browser.pageThumbs.enabled');
|
||||
},
|
||||
|
||||
setPageThumbsEnabledPref: function(value) {
|
||||
this._setBoolPref('browser.pageThumbs.enabled', value);
|
||||
},
|
||||
|
||||
addToWhitelist: function() {
|
||||
var whitelist = this.getWhitelistPref();
|
||||
whitelist += ', http://' + window.location.host + ', ';
|
||||
this.setWhitelistPref(whitelist);
|
||||
},
|
||||
|
||||
restoreOriginalPrefs: function() {
|
||||
this.setEnabledPref(this.origEnabledPref);
|
||||
this.setWhitelistPref(this.origWhitelistPref);
|
||||
this.setOOPDisabledPref(this.origOOPDisabledPref);
|
||||
this.setPageThumbsEnabledPref(this.origPageThumbsEnabledPref);
|
||||
},
|
||||
|
||||
'origEnabledPref': null,
|
||||
'origWhitelistPref': null,
|
||||
'origOOPDisabledPref': null,
|
||||
'origPageThumbsEnabledPref': null,
|
||||
|
||||
// Two basically-empty pages from two different domains you can load.
|
||||
'emptyPage1': 'http://example.com' +
|
||||
|
@ -85,10 +101,19 @@ const browserFrameHelpers = {
|
|||
browserFrameHelpers.origEnabledPref = browserFrameHelpers.getEnabledPref();
|
||||
browserFrameHelpers.origWhitelistPref = browserFrameHelpers.getWhitelistPref();
|
||||
browserFrameHelpers.origOOPDisabledPref = browserFrameHelpers.getOOPDisabledPref();
|
||||
browserFrameHelpers.origPageThumbsEnabledPref = browserFrameHelpers.getPageThumbsEnabledPref();
|
||||
|
||||
// Set OOPDisabledPref to true, because none of these tests pass with OOP
|
||||
// browser frames, at the moment.
|
||||
browserFrameHelpers.setOOPDisabledPref(true);
|
||||
// Disable tab view; it seriously messes us up.
|
||||
browserFrameHelpers.setPageThumbsEnabledPref(false);
|
||||
|
||||
// OOP must be disabled on Windows; it doesn't work there. Enable it
|
||||
// everywhere else.
|
||||
if (navigator.platform.indexOf('Win') != -1) {
|
||||
browserFrameHelpers.setOOPDisabledPref(true);
|
||||
}
|
||||
else {
|
||||
browserFrameHelpers.setOOPDisabledPref(false);
|
||||
}
|
||||
|
||||
addEventListener('unload', function() {
|
||||
browserFrameHelpers.restoreOriginalPrefs();
|
||||
|
|
|
@ -31,12 +31,11 @@ function runTest() {
|
|||
// Load emptypage1 into the iframe, wait for that to finish loading, then
|
||||
// call runTest2.
|
||||
//
|
||||
// This should trigger loadstart, load, and loadend events, but not a
|
||||
// locationchange, because this is the initial load into the iframe.
|
||||
// This should trigger loadstart, locationchange, and loadend events.
|
||||
|
||||
var seenLoad = false;
|
||||
var seenLoadEnd = false;
|
||||
var seenLoadStart = false;
|
||||
var seenLocationChange = false;
|
||||
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.mozbrowser = true;
|
||||
|
@ -45,7 +44,6 @@ function runTest() {
|
|||
|
||||
function loadstart(e) {
|
||||
ok(e.isTrusted, 'Event should be trusted.');
|
||||
ok(!seenLoad, 'loadstart before load.');
|
||||
ok(!seenLoadEnd, 'loadstart before loadend.');
|
||||
ok(!seenLoadStart, 'Just one loadstart event.');
|
||||
seenLoadStart = true;
|
||||
|
@ -53,32 +51,26 @@ function runTest() {
|
|||
|
||||
function locationchange(e) {
|
||||
ok(e.isTrusted, 'Event should be trusted.');
|
||||
ok(false, 'Unexpected locationchange.');
|
||||
ok(!seenLocationChange, 'Just one locationchange event.');
|
||||
seenLocationChange = true;
|
||||
ok(seenLoadStart, 'Location change after load start.');
|
||||
ok(!seenLoadEnd, 'Location change before load end.');
|
||||
ok(e.detail, browserFrameHelpers.emptyPage1, "event's reported location");
|
||||
}
|
||||
|
||||
function loadend(e) {
|
||||
ok(e.isTrusted, 'Event should be trusted.');
|
||||
ok(seenLoadStart, 'loadend after loadstart.');
|
||||
ok(seenLoad, 'loadend after load.');
|
||||
ok(!seenLoadEnd, 'Just one loadend event.');
|
||||
seenLoadEnd = true;
|
||||
}
|
||||
|
||||
function load(e) {
|
||||
ok(e.isTrusted, 'Event should be trusted.');
|
||||
ok(seenLoadStart, 'load after loadstart.');
|
||||
ok(!seenLoad, 'Just one load event.');
|
||||
ok(!seenLoadEnd, 'load before loadend.');
|
||||
seenLoad = true;
|
||||
}
|
||||
|
||||
iframe.addEventListener('mozbrowserloadstart', loadstart);
|
||||
iframe.addEventListener('mozbrowserlocationchange', locationchange);
|
||||
iframe.addEventListener('mozbrowserloadend', loadend);
|
||||
iframe.addEventListener('load', load);
|
||||
|
||||
function waitForAllCallbacks() {
|
||||
if (!seenLoadStart || !seenLoad || !seenLoadEnd) {
|
||||
if (!seenLoadStart || !seenLoadEnd) {
|
||||
SimpleTest.executeSoon(waitForAllCallbacks);
|
||||
return;
|
||||
}
|
||||
|
@ -86,7 +78,6 @@ function runTest() {
|
|||
iframe.removeEventListener('mozbrowserloadstart', loadstart);
|
||||
iframe.removeEventListener('mozbrowserlocationchange', locationchange);
|
||||
iframe.removeEventListener('mozbrowserloadend', loadend);
|
||||
iframe.removeEventListener('load', load);
|
||||
runTest2();
|
||||
}
|
||||
|
||||
|
@ -96,7 +87,6 @@ function runTest() {
|
|||
|
||||
function runTest2() {
|
||||
var seenLoadStart = false;
|
||||
var seenLoad = false;
|
||||
var seenLoadEnd = false;
|
||||
var seenLocationChange = false;
|
||||
|
||||
|
@ -105,7 +95,6 @@ function runTest2() {
|
|||
ok(e.isTrusted, 'Event should be trusted.');
|
||||
ok(!seenLoadStart, 'Just one loadstart event.');
|
||||
seenLoadStart = true;
|
||||
ok(!seenLoad, 'Got mozbrowserloadstart event before load.');
|
||||
ok(!seenLoadEnd, 'Got mozbrowserloadstart before loadend.');
|
||||
ok(!seenLocationChange, 'Got mozbrowserloadstart before locationchange.');
|
||||
});
|
||||
|
@ -115,20 +104,10 @@ function runTest2() {
|
|||
ok(!seenLocationChange, 'Just one locationchange event.');
|
||||
seenLocationChange = true;
|
||||
ok(seenLoadStart, 'Location change after load start.');
|
||||
ok(!seenLoad, 'Location change before load.');
|
||||
ok(!seenLoadEnd, 'Location change before load end.');
|
||||
ok(e.detail, browserFrameHelpers.emptyPage2, "event's reported location");
|
||||
});
|
||||
|
||||
iframe.addEventListener('load', function(e) {
|
||||
ok(e.isTrusted, 'Event should be trusted.');
|
||||
ok(!seenLoad, 'Just one load event.');
|
||||
seenLoad = true;
|
||||
ok(seenLoadStart, 'Load after loadstart.');
|
||||
ok(seenLocationChange, 'Load after locationchange.');
|
||||
ok(!seenLoadEnd, 'Load before loadend.');
|
||||
});
|
||||
|
||||
iframe.addEventListener('mozbrowserloadend', function(e) {
|
||||
ok(e.isTrusted, 'Event should be trusted.');
|
||||
ok(!seenLoadEnd, 'Just one load end event.');
|
||||
|
@ -140,7 +119,7 @@ function runTest2() {
|
|||
iframe.src = browserFrameHelpers.emptyPage2;
|
||||
|
||||
function waitForAllCallbacks() {
|
||||
if (!seenLoadStart || !seenLoad || !seenLoadEnd || !seenLocationChange) {
|
||||
if (!seenLoadStart || !seenLoadEnd || !seenLocationChange) {
|
||||
SimpleTest.executeSoon(waitForAllCallbacks);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -27,8 +27,9 @@ function runTest() {
|
|||
var iframe1 = document.createElement('iframe');
|
||||
iframe1.mozbrowser = true;
|
||||
iframe1.id = 'iframe1';
|
||||
iframe1.addEventListener('load', function() {
|
||||
iframe1.removeEventListener('load', arguments.callee);
|
||||
iframe1.addEventListener('mozbrowserloadend', function() {
|
||||
iframe1.removeEventListener('mozbrowserloadend', arguments.callee);
|
||||
ok(true, 'Got first loadend event.');
|
||||
SimpleTest.executeSoon(runTest2);
|
||||
});
|
||||
iframe1.src = browserFrameHelpers.emptyPage1;
|
||||
|
@ -39,25 +40,25 @@ function runTest2() {
|
|||
var iframe1 = document.getElementById('iframe1');
|
||||
var iframe2 = document.getElementById('iframe2');
|
||||
|
||||
var sawLoad = false;
|
||||
var sawLoadEnd = false;
|
||||
var sawLocationChange = false;
|
||||
|
||||
iframe1.addEventListener('mozbrowserlocationchange', function(e) {
|
||||
ok(e.isTrusted, 'Event should be trusted.');
|
||||
ok(!sawLocationChange, 'Just one locationchange event.');
|
||||
ok(!sawLoad, 'locationchange before load.');
|
||||
ok(!sawLoadEnd, 'locationchange before load.');
|
||||
is(e.detail, 'data:text/html,1', "event's reported location");
|
||||
sawLocationChange = true;
|
||||
});
|
||||
|
||||
iframe1.addEventListener('load', function() {
|
||||
ok(sawLocationChange, 'Load after locationchange.');
|
||||
ok(!sawLoad, 'Just one load event.');
|
||||
sawLoad = true;
|
||||
iframe1.addEventListener('mozbrowserloadend', function() {
|
||||
ok(sawLocationChange, 'Loadend after locationchange.');
|
||||
ok(!sawLoadEnd, 'Just one loadend event.');
|
||||
sawLoadEnd = true;
|
||||
});
|
||||
|
||||
function iframe2Load() {
|
||||
if (!sawLoad || !sawLocationChange) {
|
||||
if (!sawLoadEnd || !sawLocationChange) {
|
||||
// Spin if iframe1 hasn't loaded yet.
|
||||
SimpleTest.executeSoon(iframe2Load);
|
||||
return;
|
||||
|
|
|
@ -44,12 +44,20 @@ function runTest() {
|
|||
var numTitleChanges = 0;
|
||||
|
||||
iframe1.addEventListener('mozbrowsertitlechange', function(e) {
|
||||
// Ignore empty titles; these come from about:blank.
|
||||
if (e.detail == '')
|
||||
return;
|
||||
|
||||
numTitleChanges++;
|
||||
|
||||
if (numTitleChanges == 1) {
|
||||
is(e.detail, 'Title');
|
||||
iframe1.contentDocument.title = 'New title';
|
||||
iframe2.contentDocument.title = 'BAD TITLE 2';
|
||||
SpecialPowers.getBrowserFrameMessageManager(iframe1)
|
||||
.loadFrameScript("data:,content.document.title='New title';",
|
||||
/* allowDelayedLoad = */ false);
|
||||
SpecialPowers.getBrowserFrameMessageManager(iframe2)
|
||||
.loadFrameScript("data:,content.document.title='BAD TITLE 2';",
|
||||
/* allowDelayedLoad = */ false);
|
||||
}
|
||||
else if (numTitleChanges == 2) {
|
||||
is(e.detail, 'New title');
|
||||
|
|
|
@ -14,9 +14,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=725796
|
|||
|
||||
<!--
|
||||
Test that an <iframe mozbrowser> is a window.{top,parent,frameElement} barrier.
|
||||
|
||||
If <iframe mozbrowser> is changed to run in a separate process, this test
|
||||
will not work.
|
||||
-->
|
||||
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
@ -25,30 +22,79 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=725796
|
|||
browserFrameHelpers.setEnabledPref(true);
|
||||
browserFrameHelpers.addToWhitelist();
|
||||
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.addEventListener('load', function() {
|
||||
outerIframeLoaded();
|
||||
});
|
||||
iframe.mozbrowser = true;
|
||||
iframe.src = 'data:text/html,Outer iframe';
|
||||
document.body.appendChild(iframe);
|
||||
// This test works only with OOP browser frames. If browserFramesHelpers
|
||||
// didn't decide to enable OOP browser frames, just skip this test.
|
||||
if (browserFrameHelpers.getOOPDisabledPref()) {
|
||||
ok(true, "Skipping test because OOP browser frames are disabled.");
|
||||
}
|
||||
else {
|
||||
runTest();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
var iframe;
|
||||
function runTest() {
|
||||
iframe = document.createElement('iframe');
|
||||
iframe.addEventListener('mozbrowserloadend', function() {
|
||||
try {
|
||||
outerIframeLoaded();
|
||||
} catch(e) {
|
||||
dump("Got error: " + e + '\n');
|
||||
}
|
||||
});
|
||||
iframe.mozbrowser = true;
|
||||
iframe.src = 'data:text/html,Outer iframe <iframe id="inner-iframe"></iframe>';
|
||||
// For kicks, this test uses a display:none iframe. This shouldn't make a
|
||||
// difference in anything.
|
||||
iframe.style.display = 'none';
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
}
|
||||
|
||||
var numMsgReceived = 0;
|
||||
function outerIframeLoaded() {
|
||||
var innerIframe = iframe.contentDocument.createElement('iframe');
|
||||
iframe.contentDocument.body.appendChild(innerIframe);
|
||||
var injectedScript =
|
||||
"data:,function is(a, b, desc) { \
|
||||
if (a == b) { \
|
||||
sendAsyncMessage('test:test-pass', desc); \
|
||||
} else { \
|
||||
sendAsyncMessage('test:test-fail', desc + ' ' + a + ' != ' + b); \
|
||||
} \
|
||||
} \
|
||||
is(content.window.top, content.window, 'top'); \
|
||||
is(content.window.parent, content.window, 'parent'); \
|
||||
is(content.window.frameElement, null, 'frameElement'); \
|
||||
var innerIframe = content.document.getElementById('inner-iframe'); \
|
||||
var innerWindow = innerIframe.contentWindow; \
|
||||
is(innerWindow.top, content.window, 'inner top'); \
|
||||
is(innerWindow.parent, content.window, 'inner parent'); \
|
||||
is(innerWindow.frameElement, innerIframe, 'inner frameElement');"
|
||||
|
||||
var iframeCw = iframe.contentWindow;
|
||||
var innerCw = innerIframe.contentWindow;
|
||||
var mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
|
||||
|
||||
is(iframeCw.top, iframeCw, 'iframe top');
|
||||
is(iframeCw.parent, iframeCw, 'iframe parent');
|
||||
is(iframeCw.frameElement, null, 'iframe frameElement');
|
||||
function onRecvTestPass(msg) {
|
||||
numMsgReceived++;
|
||||
ok(true, msg.json);
|
||||
}
|
||||
mm.addMessageListener('test:test-pass', onRecvTestPass);
|
||||
|
||||
is(innerCw.top, iframeCw, 'inner iframe top');
|
||||
is(innerCw.parent, iframeCw, 'inner iframe parent');
|
||||
is(innerCw.frameElement, innerIframe, 'inner iframe frameElement');
|
||||
function onRecvTestFail(msg) {
|
||||
numMsgReceived++;
|
||||
ok(false, msg.json);
|
||||
}
|
||||
mm.addMessageListener('test:test-fail', onRecvTestFail);
|
||||
|
||||
mm.loadFrameScript(injectedScript, /* allowDelayedLoad = */ false);
|
||||
|
||||
waitForMessages(6);
|
||||
}
|
||||
|
||||
function waitForMessages(num) {
|
||||
if (numMsgReceived < num) {
|
||||
SimpleTest.executeSoon(function() { waitForMessages(num); });
|
||||
return;
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,62 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=742448
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 742448</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="browserFrameHelpers.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=742448">Mozilla Bug 742448</a>
|
||||
|
||||
<!--
|
||||
Test that <iframe mozbrowser>'s window.{top,parent,frameElement} methods are
|
||||
not confused if we override window.top ourselves.
|
||||
-->
|
||||
|
||||
<script type="application/javascript;version=1.7">
|
||||
"use strict";
|
||||
|
||||
browserFrameHelpers.setEnabledPref(true);
|
||||
browserFrameHelpers.addToWhitelist();
|
||||
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.addEventListener('load', function() {
|
||||
outerIframeLoaded();
|
||||
});
|
||||
iframe.mozbrowser = true;
|
||||
iframe.src = 'data:text/html,Outer iframe';
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function outerIframeLoaded() {
|
||||
var innerIframe = iframe.contentDocument.createElement('iframe');
|
||||
iframe.contentDocument.body.appendChild(innerIframe);
|
||||
|
||||
var iframeCw = iframe.contentWindow;
|
||||
var innerCw = innerIframe.contentWindow;
|
||||
|
||||
// Override window.top in the parent iframe. This shouldn't confuse the
|
||||
// inner one.
|
||||
Object.defineProperty(iframe.contentWindow, 'top', {
|
||||
get: function() { return 42; }
|
||||
});
|
||||
|
||||
is(iframeCw.top, 42, 'iframe top');
|
||||
is(iframeCw.parent, iframeCw, 'iframe parent');
|
||||
is(iframeCw.frameElement, null, 'iframe frameElement');
|
||||
|
||||
is(innerCw.top, iframeCw, 'inner iframe top');
|
||||
is(innerCw.parent, iframeCw, 'inner iframe parent');
|
||||
is(innerCw.frameElement, innerIframe, 'inner iframe frameElement');
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -45,8 +45,8 @@ include $(DEPTH)/config/autoconf.mk
|
|||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
_TEST_FILES = \
|
||||
test_dom_fullscreen_warning.xul \
|
||||
dom_fullscreen_warning.xul \
|
||||
test_MozEnteredDomFullscreen_event.xul \
|
||||
MozEnteredDomFullscreen_chrome.xul \
|
||||
test_fullscreen.xul \
|
||||
fullscreen.xul \
|
||||
test_fullscreen_preventdefault.xul \
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
|
||||
<!--
|
||||
Test that "MozEnteredFullscreen" is dispatched to chrome on documents that enter fullscreen.
|
||||
|
||||
Test Description:
|
||||
|
||||
This chrome window has a browser. The browser's contentDocument (the "outer document")
|
||||
in turn has an iframe (the "inner document").
|
||||
|
||||
We request fullscreen in the outer document, and check that MozEnteredDomFullscreen is
|
||||
dispatched to chrome, targeted at the outer document.
|
||||
|
||||
Then we request fullscreen in the inner document, and check that MozEnteredDomFullscreen
|
||||
is dispatched to chrome, targeted at the inner document.
|
||||
|
||||
Then we cancel fullscreen in the inner document, and check that MozEnteredDomFullscreen is
|
||||
dispatched again to chrome, targeted at the outer document. This still happens, since the
|
||||
outer document's domain was never approved for fullscreen.
|
||||
-->
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" onload="start();">
|
||||
|
||||
<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript"><![CDATA[
|
||||
|
||||
function ok(condition, msg) {
|
||||
window.opener.wrappedJSObject.ok(condition, msg);
|
||||
}
|
||||
|
||||
function is(a, b, msg) {
|
||||
window.opener.wrappedJSObject.is(a, b, msg);
|
||||
}
|
||||
|
||||
var gBrowser = null;
|
||||
var gOuterDoc = null;
|
||||
var gInnerDoc = null;
|
||||
|
||||
function firstEntry(event) {
|
||||
is(event.target, gOuterDoc, "First MozEnteredDomFullscreen should be targeted at outer doc");
|
||||
window.removeEventListener("MozEnteredDomFullscreen", firstEntry, false);
|
||||
ok(gOuterDoc.mozFullScreenElement != null, "Outer doc should be in fullscreen");
|
||||
gInnerDoc = gOuterDoc.getElementById("innerFrame").contentDocument;
|
||||
window.addEventListener("MozEnteredDomFullscreen", secondEntry, false);
|
||||
gInnerDoc.defaultView.focus();
|
||||
gInnerDoc.body.mozRequestFullScreen();
|
||||
}
|
||||
|
||||
function secondEntry(event) {
|
||||
is(event.target, gInnerDoc, "Second MozEnteredDomFullscreen should be targeted at inner doc");
|
||||
ok(gInnerDoc.mozFullScreenElement != null, "Inner doc should be in fullscreen");
|
||||
window.removeEventListener("MozEnteredDomFullscreen", secondEntry, false);
|
||||
window.addEventListener("MozEnteredDomFullscreen", thirdEntry, false);
|
||||
gInnerDoc.mozCancelFullScreen();
|
||||
}
|
||||
|
||||
function thirdEntry(event) {
|
||||
is(event.target, gOuterDoc, "Third MozEnteredDomFullscreen should be targeted at outer doc");
|
||||
ok(gOuterDoc.mozFullScreenElement != null, "Outer doc return to fullscreen after cancel fullscreen in inner doc");
|
||||
window.removeEventListener("MozEnteredDomFullscreen", thirdEntry, false);
|
||||
gOuterDoc.mozCancelFullScreen();
|
||||
window.opener.wrappedJSObject.done();
|
||||
}
|
||||
|
||||
function start() {
|
||||
SimpleTest.waitForFocus(
|
||||
function() {
|
||||
gBrowser = document.getElementById("browser");
|
||||
gOuterDoc = gBrowser.contentDocument;
|
||||
gBrowser.contentWindow.focus();
|
||||
window.addEventListener("MozEnteredDomFullscreen", firstEntry, false);
|
||||
gOuterDoc.body.mozRequestFullScreen();
|
||||
});
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
<!-- chrome://mochitests/content/chrome/dom/tests/mochitest/chrome/test_MozEnteredDomFullscreen_event.xul -->
|
||||
<browser type="content" id="browser" width="400" height="400" src="http://mochi.test:8888/tests/dom/tests/mochitest/general/file_MozEnteredDomFullscreen.html"/>
|
||||
|
||||
</window>
|
|
@ -1,263 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
|
||||
<!--
|
||||
Test that "MozShowFullScreenWarning" is dispatched to chrome on restricted keypress.
|
||||
-->
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" onload="start();">
|
||||
|
||||
<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript"><![CDATA[
|
||||
|
||||
// List of key codes, and whether they should cause a warning in full-screen mode.
|
||||
var keyList = [
|
||||
// Allowed: DOM_VK_CANCEL to DOM_VK_CAPS_LOCK, inclusive
|
||||
{ code: "VK_CANCEL", warn: true},
|
||||
{ code: "VK_HELP", warn: true},
|
||||
{ code: "VK_BACK_SPACE", warn: true},
|
||||
{ code: "VK_TAB", warn: false},
|
||||
{ code: "VK_CLEAR", warn: true},
|
||||
{ code: "VK_RETURN", warn: true},
|
||||
{ code: "VK_ENTER", warn: true},
|
||||
{ code: "VK_SHIFT", warn: false},
|
||||
{ code: "VK_CONTROL", warn: false},
|
||||
{ code: "VK_ALT", warn: false},
|
||||
{ code: "VK_PAUSE", warn: true},
|
||||
{ code: "VK_CAPS_LOCK", warn: true},
|
||||
{ code: "VK_KANA", warn: true},
|
||||
{ code: "VK_HANGUL", warn: true},
|
||||
{ code: "VK_JUNJA", warn: true},
|
||||
{ code: "VK_FINAL", warn: true},
|
||||
{ code: "VK_HANJA", warn: true},
|
||||
{ code: "VK_KANJI", warn: true},
|
||||
{ code: "VK_ESCAPE", warn: false, exit: true},
|
||||
{ code: "VK_CONVERT", warn: true},
|
||||
{ code: "VK_NONCONVERT", warn: true},
|
||||
{ code: "VK_ACCEPT", warn: true},
|
||||
{ code: "VK_MODECHANGE", warn: true},
|
||||
{ code: "VK_SPACE", warn: false},
|
||||
{ code: "VK_PAGE_UP", warn: false},
|
||||
{ code: "VK_PAGE_DOWN", warn: false},
|
||||
{ code: "VK_END", warn: false},
|
||||
{ code: "VK_HOME", warn: false},
|
||||
{ code: "VK_LEFT", warn: false},
|
||||
{ code: "VK_UP", warn: false},
|
||||
{ code: "VK_RIGHT", warn: false},
|
||||
{ code: "VK_DOWN", warn: false},
|
||||
{ code: "VK_SELECT", warn: true},
|
||||
{ code: "VK_PRINT", warn: true},
|
||||
{ code: "VK_EXECUTE", warn: true},
|
||||
{ code: "VK_PRINTSCREEN", warn: true},
|
||||
{ code: "VK_INSERT", warn: true},
|
||||
{ code: "VK_DELETE", warn: true},
|
||||
{ code: "VK_0", warn: true},
|
||||
{ code: "VK_1", warn: true},
|
||||
{ code: "VK_2", warn: true},
|
||||
{ code: "VK_3", warn: true},
|
||||
{ code: "VK_4", warn: true},
|
||||
{ code: "VK_5", warn: true},
|
||||
{ code: "VK_6", warn: true},
|
||||
{ code: "VK_7", warn: true},
|
||||
{ code: "VK_8", warn: true},
|
||||
{ code: "VK_9", warn: true},
|
||||
{ code: "VK_SEMICOLON", warn: true},
|
||||
{ code: "VK_EQUALS", warn: true},
|
||||
{ code: "VK_A", warn: true},
|
||||
{ code: "VK_B", warn: true},
|
||||
{ code: "VK_C", warn: true},
|
||||
{ code: "VK_D", warn: true},
|
||||
{ code: "VK_E", warn: true},
|
||||
{ code: "VK_F", warn: true},
|
||||
{ code: "VK_G", warn: true},
|
||||
{ code: "VK_H", warn: true},
|
||||
{ code: "VK_I", warn: true},
|
||||
{ code: "VK_J", warn: true},
|
||||
{ code: "VK_K", warn: true},
|
||||
{ code: "VK_L", warn: true},
|
||||
{ code: "VK_M", warn: true},
|
||||
{ code: "VK_N", warn: true},
|
||||
{ code: "VK_O", warn: true},
|
||||
{ code: "VK_P", warn: true},
|
||||
{ code: "VK_Q", warn: true},
|
||||
{ code: "VK_R", warn: true},
|
||||
{ code: "VK_S", warn: true},
|
||||
{ code: "VK_T", warn: true},
|
||||
{ code: "VK_U", warn: true},
|
||||
{ code: "VK_V", warn: true},
|
||||
{ code: "VK_W", warn: true},
|
||||
{ code: "VK_X", warn: true},
|
||||
{ code: "VK_Y", warn: true},
|
||||
{ code: "VK_Z", warn: true},
|
||||
{ code: "VK_CONTEXT_MENU", warn: true},
|
||||
{ code: "VK_SLEEP", warn: true},
|
||||
{ code: "VK_NUMPAD0", warn: true},
|
||||
{ code: "VK_NUMPAD1", warn: true},
|
||||
{ code: "VK_NUMPAD2", warn: true},
|
||||
{ code: "VK_NUMPAD3", warn: true},
|
||||
{ code: "VK_NUMPAD4", warn: true},
|
||||
{ code: "VK_NUMPAD5", warn: true},
|
||||
{ code: "VK_NUMPAD6", warn: true},
|
||||
{ code: "VK_NUMPAD7", warn: true},
|
||||
{ code: "VK_NUMPAD8", warn: true},
|
||||
{ code: "VK_NUMPAD9", warn: true},
|
||||
{ code: "VK_MULTIPLY", warn: true},
|
||||
{ code: "VK_ADD", warn: true},
|
||||
{ code: "VK_SEPARATOR", warn: true},
|
||||
{ code: "VK_SUBTRACT", warn: true},
|
||||
{ code: "VK_DECIMAL", warn: true},
|
||||
{ code: "VK_DIVIDE", warn: true},
|
||||
{ code: "VK_F1", warn: true},
|
||||
{ code: "VK_F2", warn: true},
|
||||
{ code: "VK_F3", warn: true},
|
||||
{ code: "VK_F4", warn: true},
|
||||
{ code: "VK_F5", warn: true},
|
||||
{ code: "VK_F6", warn: true},
|
||||
{ code: "VK_F7", warn: true},
|
||||
{ code: "VK_F8", warn: true},
|
||||
{ code: "VK_F9", warn: true},
|
||||
{ code: "VK_F10", warn: true},
|
||||
{ code: "VK_F11", warn: true}, // F11 exit full-screen handler is in browser.js, so won't cause exit here.
|
||||
{ code: "VK_F12", warn: true},
|
||||
{ code: "VK_F13", warn: true},
|
||||
{ code: "VK_F14", warn: true},
|
||||
{ code: "VK_F15", warn: true},
|
||||
{ code: "VK_F16", warn: true},
|
||||
{ code: "VK_F17", warn: true},
|
||||
{ code: "VK_F18", warn: true},
|
||||
{ code: "VK_F19", warn: true},
|
||||
{ code: "VK_F20", warn: true},
|
||||
{ code: "VK_F21", warn: true},
|
||||
{ code: "VK_F22", warn: true},
|
||||
{ code: "VK_F23", warn: true},
|
||||
{ code: "VK_F24", warn: true},
|
||||
{ code: "VK_NUM_LOCK", warn: true},
|
||||
{ code: "VK_SCROLL_LOCK", warn: true},
|
||||
{ code: "VK_COMMA", warn: true},
|
||||
{ code: "VK_PERIOD", warn: true},
|
||||
{ code: "VK_SLASH", warn: true},
|
||||
{ code: "VK_BACK_QUOTE", warn: true},
|
||||
{ code: "VK_OPEN_BRACKET", warn: true},
|
||||
{ code: "VK_BACK_SLASH", warn: true},
|
||||
{ code: "VK_CLOSE_BRACKET", warn: true},
|
||||
{ code: "VK_QUOTE", warn: true},
|
||||
{ code: "VK_META", warn: false},
|
||||
];
|
||||
|
||||
function ok(condition, msg) {
|
||||
window.opener.wrappedJSObject.ok(condition, msg);
|
||||
}
|
||||
|
||||
function is(a, b, msg) {
|
||||
window.opener.wrappedJSObject.is(a, b, msg);
|
||||
}
|
||||
|
||||
var gKeyTestIndex = 0;
|
||||
var gKeyName;
|
||||
var gKeyCode;
|
||||
var gWarningEventReceived = false;
|
||||
var gExpectWarning;
|
||||
var gExpectExit;
|
||||
var gBrowser;
|
||||
|
||||
function checkKeyEffect() {
|
||||
is(gBrowser.contentDocument.mozFullScreen, !gExpectExit,
|
||||
(gExpectExit ? ("Should exit full-screen for " + gKeyName + " press ")
|
||||
: ("Should remain in full-screen for " + gKeyName + " press")));
|
||||
is(gWarningEventReceived, gExpectWarning, "Should " + (gExpectWarning ? "" : "not ") +
|
||||
"receive MozShowFullScreenWarning for " + gKeyName + " press");
|
||||
if (gKeyTestIndex < keyList.length) {
|
||||
setTimeout(startNextTest, 0);
|
||||
} else {
|
||||
gBrowser.contentDocument.mozCancelFullScreen();
|
||||
window.opener.wrappedJSObject.done();
|
||||
}
|
||||
}
|
||||
|
||||
function testTrustedKeyEvents() {
|
||||
gBrowser.contentWindow.focus();
|
||||
gWarningEventReceived = false;
|
||||
synthesizeKey(gKeyName, {});
|
||||
setTimeout(checkKeyEffect, 0);
|
||||
}
|
||||
|
||||
function testScriptInitiatedKeyEvents() {
|
||||
// Script initiated untrusted key events should not cause the warning to show.
|
||||
gBrowser.contentWindow.focus();
|
||||
gWarningEventReceived = false;
|
||||
var evt = gBrowser.contentDocument.createEvent("KeyEvents");
|
||||
evt.initKeyEvent("keydown", true, true, window,
|
||||
false, false, false, false,
|
||||
gKeyCode, 0);
|
||||
gBrowser.contentDocument.body.dispatchEvent(evt);
|
||||
|
||||
evt = gBrowser.contentDocument.createEvent("KeyEvents");
|
||||
evt.initKeyEvent("keypress", true, true, window,
|
||||
false, false, false, false,
|
||||
gKeyCode, 0);
|
||||
gBrowser.contentDocument.body.dispatchEvent(evt);
|
||||
|
||||
evt = gBrowser.contentDocument.createEvent("KeyEvents");
|
||||
evt.initKeyEvent("keyup", true, true, window,
|
||||
false, false, false, false,
|
||||
gKeyCode, 0);
|
||||
gBrowser.contentDocument.body.dispatchEvent(evt);
|
||||
|
||||
setTimeout(checkScriptInitiatedEvents, 0);
|
||||
}
|
||||
|
||||
function checkScriptInitiatedEvents() {
|
||||
is(gWarningEventReceived, false, "Should not receive MozShowFullScreenWarning on synthesized key events.");
|
||||
ok(gBrowser.contentDocument.mozFullScreen,
|
||||
"Should remain in full-screen mode for script initiated key events for " + gKeyName);
|
||||
testTrustedKeyEvents();
|
||||
}
|
||||
|
||||
function testNextKey() {
|
||||
ok(gBrowser.contentDocument.mozFullScreen, "Must be in full-screen mode");
|
||||
|
||||
gKeyName = keyList[gKeyTestIndex].code;
|
||||
gKeyCode = KeyEvent["DOM_" + gKeyName];
|
||||
gExpectWarning = keyList[gKeyTestIndex].warn;
|
||||
gExpectExit = (keyList[gKeyTestIndex].exit != undefined) ?
|
||||
keyList[gKeyTestIndex].exit : false;
|
||||
gKeyTestIndex++;
|
||||
|
||||
testScriptInitiatedKeyEvents();
|
||||
}
|
||||
|
||||
function startNextTest() {
|
||||
if (!gBrowser.contentDocument.mozFullScreen) {
|
||||
gBrowser.contentDocument.body.mozRequestFullScreen();
|
||||
}
|
||||
// mozRequestFullScreen is async...
|
||||
setTimeout(testNextKey, 0);
|
||||
}
|
||||
|
||||
function keyHandler(event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
window.addEventListener("MozShowFullScreenWarning", function(){ gWarningEventReceived = true; }, true);
|
||||
|
||||
window.addEventListener("keydown", keyHandler, true);
|
||||
window.addEventListener("keyup", keyHandler, true);
|
||||
window.addEventListener("keypress", keyHandler, true);
|
||||
|
||||
function start() {
|
||||
SimpleTest.waitForFocus(
|
||||
function() {
|
||||
gBrowser = document.getElementById("browser");
|
||||
gBrowser.contentWindow.focus();
|
||||
gBrowser.contentDocument.body.mozRequestFullScreen();
|
||||
setTimeout(startNextTest, 0);
|
||||
});
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<browser type="content" id="browser" width="400" height="400"/>
|
||||
|
||||
</window>
|
|
@ -18,8 +18,21 @@ SpecialPowers.setBoolPref("full-screen-api.enabled", true);
|
|||
var gPrevTrusted = SpecialPowers.getBoolPref("full-screen-api.allow-trusted-requests-only");
|
||||
SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
newwindow = window.open("dom_fullscreen_warning.xul", "_blank","chrome,resizable=yes,width=400,height=400");
|
||||
function make_uri(url) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newURI(url, null, null);
|
||||
}
|
||||
|
||||
// Ensure "fullscreen" permissions are not present on the test URI.
|
||||
var pm = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
|
||||
var uri = make_uri("http://mochi.test:8888");
|
||||
pm.remove(uri.host, "fullscreen");
|
||||
|
||||
newwindow = window.open("MozEnteredDomFullscreen_chrome.xul", "_blank","chrome,resizable=yes,width=400,height=400");
|
||||
|
||||
function done()
|
||||
{
|
|
@ -45,6 +45,7 @@ include $(DEPTH)/config/autoconf.mk
|
|||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
_TEST_FILES = \
|
||||
file_MozEnteredDomFullscreen.html \
|
||||
test_outerHTML.html \
|
||||
test_outerHTML.xhtml \
|
||||
497633.html \
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body style="background-color: blue;">
|
||||
<p>Outer doc</p>
|
||||
<iframe id="innerFrame" src="data:text/html,<html><body style='background-color: red;'><p>Inner doc</p></body></html>"></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -15,6 +15,7 @@ include $(topsrcdir)/config/rules.mk
|
|||
_TEST_FILES = \
|
||||
test_pointerlock-api.html \
|
||||
pointerlock_utils.js \
|
||||
file_approval.html \
|
||||
file_pointerlock-api.html \
|
||||
file_pointerlockerror.html \
|
||||
file_escapeKey.html \
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--https://bugzilla.mozilla.org/show_bug.cgi?id=746885-->
|
||||
<head>
|
||||
<title>Bug 746885</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="pointerlock_utils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=746885">
|
||||
Mozilla Bug 746885
|
||||
</a>
|
||||
<div id="div"></div>
|
||||
<pre id="test">
|
||||
<script type="text/javascript">
|
||||
/*
|
||||
* Test for Bug 746885
|
||||
* When requesting pointer lock on a domain that doesn't have fullscreen
|
||||
* permission, the pointer lock request should be delayed until approval
|
||||
* has been granted.
|
||||
*/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// Ensure fullscreen won't be automatically granted for this document's domain.
|
||||
SpecialPowers.removeFullscreenAllowed(document);
|
||||
|
||||
var div = document.getElementById("div");
|
||||
var isApproved = false;
|
||||
|
||||
document.addEventListener("mozpointerlockchange",
|
||||
function (e) {
|
||||
is(isApproved, true, "Should only receive mozpointerlockchange when we've been approved for fullscreen.");
|
||||
document.mozCancelFullScreen();
|
||||
}, false);
|
||||
|
||||
function approveFullscreen() {
|
||||
isApproved = true;
|
||||
SpecialPowers.setFullscreenAllowed(document);
|
||||
}
|
||||
|
||||
document.addEventListener("mozfullscreenchange", function(e) {
|
||||
if (document.mozFullScreenElement === div) {
|
||||
// First entered fullscreen. Request pointer lock...
|
||||
div.mozRequestPointerLock();
|
||||
// ... But only approve fullscreen after a delay, giving the pointer
|
||||
// lock request time to run if it were going to. Note we need two timeouts
|
||||
// here to because if we were to fail and the pointer lock request were to
|
||||
// succeed without approval, we'd need to give it time to run, and time for
|
||||
// its asynchronously dispatched mozpointerlockchange to run.
|
||||
setTimeout(function(){ setTimeout(approveFullscreen, 0); }, 0);
|
||||
} else {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}, false);
|
||||
|
||||
function start() {
|
||||
div.mozRequestFullScreen();
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -19,10 +19,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=633602
|
|||
<script type="application/javascript">
|
||||
/**
|
||||
* Pointer Lock tests for bug 633602. These depend on the fullscreen api
|
||||
* which doesn't work well on all platforms when run in an iframe, even
|
||||
* when allowing fullscreen on the iframe. To get around this, all tests
|
||||
* are run in a child window, which can go fullscreen. This method is
|
||||
* borrowed from content/html/content/test/test_fullscreen-api.html.
|
||||
* which doesn't work when run in the mochitests' iframe, since the
|
||||
* mochitests' iframe doesn't have a mozallowfullscreen attribute. To get
|
||||
* around this, all tests are run in a child window, which can go fullscreen.
|
||||
* This method is borrowed from content/html/content/test/test_fullscreen-api.html.
|
||||
**/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
@ -33,10 +33,15 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=633602
|
|||
// Disable the requirement for trusted contexts only, so the tests are easier to write.
|
||||
SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
|
||||
|
||||
// Grant "fullscreen" permission on the test domain. This means fullscreen will be
|
||||
// automatically approved, so pointer lock in the tests will be too.
|
||||
SpecialPowers.setFullscreenAllowed(document);
|
||||
|
||||
// Run the tests which go full-screen in new window, as Mochitests
|
||||
// normally run in an iframe, which by default will not have the
|
||||
// mozallowfullscreen attribute set, so full-screen won't work.
|
||||
var gTestFiles = [
|
||||
"file_approval.html",
|
||||
"file_screenClientXYConst.html",
|
||||
"file_childIframe.html",
|
||||
"file_doubleLock.html",
|
||||
|
@ -63,15 +68,22 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=633602
|
|||
const isWinXP = navigator.userAgent.indexOf("Windows NT 5.1") != -1;
|
||||
const isOSXLion = navigator.userAgent.indexOf("Mac OS X 10.7") != -1;
|
||||
|
||||
function finish() {
|
||||
SpecialPowers.clearUserPref("full-screen-api.enabled");
|
||||
SpecialPowers.clearUserPref("full-screen-api.allow-trusted-requests-only");
|
||||
SpecialPowers.removeFullscreenAllowed(document)
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function nextTest() {
|
||||
if (isWinXP) {
|
||||
todo(false, "Can't reliably run full-screen tests on Windows XP due to bug 704010");
|
||||
SimpleTest.finish();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
if (isOSXLion) {
|
||||
todo(false, "Can't reliably run full-screen tests on OS X Lion, see bug 744125");
|
||||
SimpleTest.finish();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
if (gTestWindow) {
|
||||
|
@ -85,9 +97,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=633602
|
|||
gTestWindow = window.open(gTestFiles[gTestIndex], "", "width=500,height=500");
|
||||
gTestIndex++;
|
||||
} else {
|
||||
SpecialPowers.clearUserPref("full-screen-api.enabled");
|
||||
SpecialPowers.clearUserPref("full-screen-api.allow-trusted-requests-only");
|
||||
SimpleTest.finish();
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
# 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/.
|
||||
|
||||
DEPTH = ../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
relativesrcdir = dom/tests/mochitest/webapps
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = \
|
||||
apps \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
_TEST_FILES = \
|
||||
test_install_app.xul \
|
||||
test_list_api.xul \
|
||||
test_install_errors.xul \
|
||||
test_cross_domain.xul \
|
||||
test_install_utf8.xul \
|
||||
test_install_receipts.xul \
|
||||
jshelper.js \
|
||||
apphelper.js \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
$(INSTALL) $^ $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const MODE_READONLY = 0x01;
|
||||
const PERMS_FILE = 0644;
|
||||
|
||||
var popupNotifications = getPopupNotifications(window.top);
|
||||
|
||||
var event_listener_loaded = {};
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
|
||||
Components.classes["@mozilla.org/permissionmanager;1"]
|
||||
.getService(Components.interfaces.nsIPermissionManager)
|
||||
.add(SpecialPowers.getDocumentURIObject(window.document),
|
||||
"webapps-manage",
|
||||
Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
|
||||
|
||||
SpecialPowers.setCharPref("dom.mozApps.whitelist", "http://mochi.test:8888");
|
||||
SpecialPowers.setBoolPref('dom.mozBrowserFramesEnabled', true);
|
||||
SpecialPowers.setBoolPref('browser.mozApps.installer.dry_run', true);
|
||||
SpecialPowers.setBoolPref("dom.mozBrowserFramesWhitelist", "http://www.example.com");
|
||||
|
||||
var triggered = false;
|
||||
|
||||
function iterateMethods(label, root, suppress) {
|
||||
var arr = [];
|
||||
for (var f in root) {
|
||||
if (suppress && suppress.indexOf(f) != -1)
|
||||
continue;
|
||||
if (typeof root[f] === 'function')
|
||||
arr.push(label + f);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
function getPopupNotifications(aWindow) {
|
||||
var Ci = Components.interfaces;
|
||||
var chromeWin = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell)
|
||||
.chromeEventHandler.ownerDocument.defaultView;
|
||||
|
||||
return chromeWin.PopupNotifications;
|
||||
}
|
||||
|
||||
function triggerMainCommand(popup) {
|
||||
var notifications = popup.childNodes;
|
||||
ok(notifications.length > 0, "at least one notification displayed");
|
||||
var notification = notifications[0];
|
||||
debug("triggering command: " + notification.getAttribute("buttonlabel"));
|
||||
|
||||
notification.button.doCommand();
|
||||
}
|
||||
|
||||
function mainCommand() {
|
||||
triggerMainCommand(this);
|
||||
}
|
||||
|
||||
function popup_listener() {
|
||||
debug("here in popup listener");
|
||||
popupNotifications.panel.addEventListener("popupshown", mainCommand, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads text from a file and returns the string.
|
||||
*
|
||||
* @param aFile
|
||||
* The file to read from.
|
||||
* @return The string of text read from the file.
|
||||
*/
|
||||
function readFile(aFile) {
|
||||
|
||||
var file = Components.classes["@mozilla.org/file/directory_service;1"].
|
||||
getService(Components.interfaces.nsIProperties).
|
||||
get("CurWorkD", Components.interfaces.nsILocalFile);
|
||||
var fis = Components.classes["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Components.interfaces.nsIFileInputStream);
|
||||
var paths = "chrome/dom/tests/mochitest/webapps" + aFile;
|
||||
var split = paths.split("/");
|
||||
var sis = Components.classes["@mozilla.org/scriptableinputstream;1"].
|
||||
createInstance(Components.interfaces.nsIScriptableInputStream);
|
||||
var utf8Converter = Components.classes["@mozilla.org/intl/utf8converterservice;1"].
|
||||
getService(Components.interfaces.nsIUTF8ConverterService);
|
||||
|
||||
for(var i = 0; i < split.length; ++i) {
|
||||
file.append(split[i]);
|
||||
}
|
||||
fis.init(file, MODE_READONLY, PERMS_FILE, 0);
|
||||
sis.init(fis);
|
||||
var text = sis.read(sis.available());
|
||||
text = utf8Converter.convertURISpecToUTF8 (text, "UTF-8");
|
||||
sis.close();
|
||||
debug (text);
|
||||
return text;
|
||||
}
|
||||
|
||||
function getOrigin(url) {
|
||||
return Services.io.newURI(url, null, null).prePath;
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
debug("in " + arguments.callee.name);
|
||||
uninstallAll();
|
||||
popupNotifications.panel.removeEventListener("popupshown", mainCommand, false);
|
||||
SpecialPowers.clearUserPref('browser.mozApps.installer.dry_run');
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
# 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/.
|
||||
|
||||
DEPTH = ../../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
relativesrcdir = dom/tests/mochitest/webapps/apps
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
_TEST_FILES = \
|
||||
include.html \
|
||||
wild_crazy.webapp \
|
||||
wild_crazy.webapp^headers^ \
|
||||
super_crazy.webapp \
|
||||
super_crazy.webapp^headers^ \
|
||||
missing_required_field.webapp \
|
||||
missing_required_field.webapp^headers^ \
|
||||
json_syntax_error.webapp \
|
||||
json_syntax_error.webapp^headers^ \
|
||||
no_delegated_install.webapp \
|
||||
no_delegated_install.webapp^headers^ \
|
||||
bad_content_type.webapp \
|
||||
manifest_with_bom.webapp \
|
||||
manifest_with_bom.webapp^headers^ \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
$(INSTALL) $^ $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"name": "An app served with a bad header. The .json ext doesn't trigger proper headers in the test harness webserver.",
|
||||
"default_locale": "en",
|
||||
"installs_allowed_from": [ "*" ]
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче