mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-12 04:45:45 +00:00
Merge from mozilla-central.
This commit is contained in:
commit
d7f19cfeca
@ -105,7 +105,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
||||
roles::PUSHBUTTON,
|
||||
kUseMapRole,
|
||||
eNoValue,
|
||||
eClickAction,
|
||||
ePressAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
eARIAPressed
|
||||
@ -219,15 +219,6 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
||||
eNoLiveAttr,
|
||||
kNoReqStates
|
||||
},
|
||||
{
|
||||
"label",
|
||||
roles::LABEL,
|
||||
kUseMapRole,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates
|
||||
},
|
||||
{
|
||||
"link",
|
||||
roles::LINK,
|
||||
|
@ -78,6 +78,7 @@ enum EActionRule
|
||||
eNoAction,
|
||||
eActivateAction,
|
||||
eClickAction,
|
||||
ePressAction,
|
||||
eCheckUncheckAction,
|
||||
eExpandAction,
|
||||
eJumpAction,
|
||||
|
@ -1828,6 +1828,10 @@ nsAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
|
||||
aName.AssignLiteral("click");
|
||||
return NS_OK;
|
||||
|
||||
case ePressAction:
|
||||
aName.AssignLiteral("press");
|
||||
return NS_OK;
|
||||
|
||||
case eCheckUncheckAction:
|
||||
if (states & states::CHECKED)
|
||||
aName.AssignLiteral("uncheck");
|
||||
|
@ -49,6 +49,15 @@
|
||||
new scrollingChecker(getAccessible("bottom1"))
|
||||
]
|
||||
},
|
||||
{ // jump again (test for bug 437607)
|
||||
ID: "anchor1",
|
||||
actionName: "jump",
|
||||
actionIndex: 0,
|
||||
events: CLICK_EVENTS,
|
||||
eventSeq: [
|
||||
new scrollingChecker(getAccessible("bottom1"))
|
||||
]
|
||||
},
|
||||
{
|
||||
ID: "anchor2",
|
||||
actionName: "jump",
|
||||
|
@ -27,7 +27,7 @@
|
||||
},
|
||||
{
|
||||
ID: "button",
|
||||
actionName: "click",
|
||||
actionName: "press",
|
||||
events: CLICK_EVENTS
|
||||
},
|
||||
{
|
||||
|
@ -49,6 +49,22 @@ function currentTabDocument()
|
||||
return currentBrowser().contentDocument;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return browser element of the tab at the given index.
|
||||
*/
|
||||
function browserAt(aIndex)
|
||||
{
|
||||
return tabBrowser().getBrowserAtIndex(aIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return DOM document of the tab at the given index.
|
||||
*/
|
||||
function tabDocumentAt(aIndex)
|
||||
{
|
||||
return browserAt(aIndex).contentDocument;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return input element of address bar.
|
||||
*/
|
||||
|
@ -82,6 +82,7 @@ _TEST_FILES =\
|
||||
test_menu.xul \
|
||||
test_mutation.html \
|
||||
test_mutation.xhtml \
|
||||
test_scroll.xul \
|
||||
test_selection_aria.html \
|
||||
test_selection.html \
|
||||
test_selection.xul \
|
||||
|
@ -1,13 +1,6 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
|
||||
<!-- Firefox tabbrowser -->
|
||||
<?xml-stylesheet href="chrome://browser/content/browser.css"
|
||||
type="text/css"?>
|
||||
<!-- SeaMonkey tabbrowser -->
|
||||
<?xml-stylesheet href="chrome://navigator/content/navigator.css"
|
||||
type="text/css"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
|
||||
@ -16,7 +9,7 @@
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/utilityOverlay.js"/>
|
||||
src="chrome://mochikit/content/chrome-harness.js"/>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="../common.js" />
|
||||
@ -26,95 +19,74 @@
|
||||
src="../states.js" />
|
||||
<script type="application/javascript"
|
||||
src="../events.js" />
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/chrome-harness.js"/>
|
||||
src="../browser.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Hacks to make xul:tabbrowser work
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const CC = Components.classes;
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var handleDroppedLink = null;
|
||||
|
||||
var XULBrowserWindow = {
|
||||
isBusy: false,
|
||||
setOverLink: function (link, b) {
|
||||
}
|
||||
};
|
||||
|
||||
var gURLBar = {
|
||||
focused: false
|
||||
};
|
||||
|
||||
var gFindBarInitialized = false;
|
||||
|
||||
function goSetCommandEnabled() {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Tests
|
||||
|
||||
function getTabDocument()
|
||||
function getAnchorJumpInTabDocument(aTabIdx)
|
||||
{
|
||||
return getNode("tabBrowser").selectedBrowser.contentDocument;
|
||||
var tabDoc = aTabIdx ? tabDocumentAt(aTabIdx) : currentTabDocument();
|
||||
return tabDoc.querySelector("a[name='link1']");
|
||||
}
|
||||
|
||||
function getAnchorJumpInTabDocument()
|
||||
function loadTab(aURL)
|
||||
{
|
||||
return getTabDocument().querySelector("a[name='link1']");
|
||||
}
|
||||
|
||||
function loadTab(aTabBrowserID, aURL)
|
||||
{
|
||||
function loadTabChecker()
|
||||
{
|
||||
this.type = EVENT_REORDER;
|
||||
this.match = function loadTabChecker_match(aEvent)
|
||||
{
|
||||
var target = aEvent.accessible;
|
||||
if (target.role == ROLE_INTERNAL_FRAME &&
|
||||
target.parent.parent == getAccessible(getNode(aTabBrowserID).mTabBox.tabpanels)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
this.eventSeq = [ new loadTabChecker() ];
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, currentTabDocument),
|
||||
new invokerChecker(EVENT_SCROLLING_START, getAnchorJumpInTabDocument)
|
||||
];
|
||||
|
||||
this.invoke = function loadTab_invoke()
|
||||
{
|
||||
getNode(aTabBrowserID).loadURI(aURL);
|
||||
tabBrowser().loadURI(aURL);
|
||||
}
|
||||
|
||||
this.getID = function loadTab_getID()
|
||||
{
|
||||
return "load tab " + aURL + " for " + prettyName(aTabBrowserID);
|
||||
return "load tab: " + aURL;
|
||||
}
|
||||
}
|
||||
|
||||
function advanceFocusIntoTab(aTabBrowserID)
|
||||
function loadTabInBackground(aURL)
|
||||
{
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, tabDocumentAt, 1)
|
||||
];
|
||||
|
||||
this.unexpectedEventSeq = [
|
||||
new invokerChecker(EVENT_SCROLLING_START, getAnchorJumpInTabDocument, 1)
|
||||
];
|
||||
|
||||
this.invoke = function loadTabInBackground_invoke()
|
||||
{
|
||||
tabBrowser().loadOneTab(aURL, null, "", null, true);
|
||||
}
|
||||
|
||||
this.getID = function loadTabInBackground_getID()
|
||||
{
|
||||
return "load tab in background: " + aURL;
|
||||
}
|
||||
}
|
||||
|
||||
function switchToBackgroundTab()
|
||||
{
|
||||
this.eventSeq = [
|
||||
new focusChecker(getTabDocument),
|
||||
new invokerChecker(EVENT_SCROLLING_START, getAnchorJumpInTabDocument)
|
||||
];
|
||||
|
||||
this.invoke = function advanceFocusIntoTab_invoke()
|
||||
this.invoke = function switchToBackgroundTab_invoke()
|
||||
{
|
||||
var tabDoc = getAccessible(getTabDocument());
|
||||
tabDoc.takeFocus();
|
||||
tabBrowser().selectTabAtIndex(1);
|
||||
}
|
||||
|
||||
this.getID = function advanceFocusIntoTab_getID()
|
||||
this.getID = function switchToBackgroundTab_getID()
|
||||
{
|
||||
return "advance focus into loaded tab";
|
||||
return "switch to background tab";
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,28 +110,22 @@
|
||||
var url = rootDir + "scroll.html#link1";
|
||||
|
||||
gQueue = new eventQueue();
|
||||
gQueue.push(new loadTab("tabBrowser", url));
|
||||
gQueue.push(new advanceFocusIntoTab("tabBrowser"));
|
||||
|
||||
gQueue.push(new loadTab(url));
|
||||
gQueue.push(new loadTabInBackground(url));
|
||||
gQueue.push(new switchToBackgroundTab());
|
||||
gQueue.onFinish = function() { closeBrowserWindow(); }
|
||||
|
||||
gQueue.invoke(); // Will call SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
openBrowserWindow(doTest);
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<hbox flex="1" style="overflow: auto;">
|
||||
<vbox flex="1" style="overflow: auto;">
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=437607"
|
||||
title="Clicking the 'Skip to main content' link once works, second time fails to initiate a V cursor jump">
|
||||
Mozilla Bug 437607
|
||||
</a><br/>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=519303"
|
||||
title="Same page links to targets with content fires scrolling start accessible event on leaf text node">
|
||||
Mozilla Bug 519303
|
||||
</a>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=691734"
|
||||
title="Make sure scrolling start event is fired when document receive focus">
|
||||
@ -173,33 +139,6 @@
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
<vbox flex="1">
|
||||
<!-- Hack to make xul:tabbrowser work -->
|
||||
<menubar>
|
||||
<menu label="menu">
|
||||
<menupopup>
|
||||
<menuitem label="close window hook" id="menu_closeWindow"/>
|
||||
<menuitem label="close hook" id="menu_close"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
</menubar>
|
||||
<keyset>
|
||||
<key id="key_close"/>
|
||||
</keyset>
|
||||
|
||||
<hbox>
|
||||
<tabs id="tabbrowser-tabs" class="tabbrowser-tabs"
|
||||
tabbrowser="tabBrowser"
|
||||
flex="1">
|
||||
<tab class="tabbrowser-tab" selected="true" label="tab"/>
|
||||
</tabs>
|
||||
</hbox>
|
||||
<tabbrowser id="tabBrowser"
|
||||
type="content-primary"
|
||||
tabcontainer="tabbrowser-tabs"
|
||||
flex="1"/>
|
||||
</vbox>
|
||||
<toolbar id="addon-bar"/>
|
||||
</hbox>
|
||||
|
||||
<vbox id="eventdump"></vbox>
|
||||
</vbox>
|
||||
</window>
|
||||
|
@ -131,7 +131,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=529289
|
||||
<tr><td>hi<td></tr></table>
|
||||
|
||||
<!-- test gEmptyRoleMap -->
|
||||
<table role="label">
|
||||
<table role="button">
|
||||
<tr>
|
||||
<td id="cell">cell</td>
|
||||
</tr>
|
||||
|
@ -37,15 +37,15 @@
|
||||
testChildAtPoint(txt, -10000, 10000, false, null);
|
||||
testChildAtPoint(txt, -10000, 10000, true, null);
|
||||
|
||||
// Not specific case, point is inside of label accessible.
|
||||
var label = getAccessible("label");
|
||||
var labelText = label.firstChild;
|
||||
testChildAtPoint(label, 1, 1, false, labelText);
|
||||
testChildAtPoint(label, 1, 1, true, labelText);
|
||||
// Not specific case, point is inside of btn accessible.
|
||||
var btn = getAccessible("btn");
|
||||
var btnText = btn.firstChild;
|
||||
testChildAtPoint(btn, 1, 1, false, btnText);
|
||||
testChildAtPoint(btn, 1, 1, true, btnText);
|
||||
|
||||
// Not specific case, point is outside of label accessible.
|
||||
testChildAtPoint(label, -1, 1, false, null);
|
||||
testChildAtPoint(label, -1, 1, true, null);
|
||||
// Not specific case, point is outside of btn accessible.
|
||||
testChildAtPoint(btn, -1, 1, false, null);
|
||||
testChildAtPoint(btn, -1, 1, true, null);
|
||||
|
||||
// Out of flow accessible testing, do not return out of flow accessible
|
||||
// because it's not a child of the accessible even visually it is.
|
||||
@ -78,7 +78,7 @@
|
||||
<div role="listitem" id="listitem"><span role="image" id="image">img</span>item</div>
|
||||
</div>
|
||||
|
||||
<span role="label">label1</span><span role="label" id="label">label2</span>
|
||||
<span role="button">button1</span><span role="button" id="btn">button2</span>
|
||||
|
||||
<span role="textbox">textbox1</span><span role="textbox" id="txt">textbox2</span>
|
||||
|
||||
|
@ -38,7 +38,6 @@
|
||||
#filter substitution
|
||||
|
||||
pref("toolkit.defaultChromeURI", "chrome://browser/content/shell.xul");
|
||||
pref("general.useragent.compatMode.firefox", true);
|
||||
pref("browser.chromeURL", "chrome://browser/content/");
|
||||
#ifdef MOZ_OFFICIAL_BRANDING
|
||||
pref("browser.homescreenURL", "file:///system/home/homescreen.html");
|
||||
@ -394,6 +393,15 @@ pref("layers.acceleration.force-enabled", true);
|
||||
pref("dom.screenEnabledProperty.enabled", true);
|
||||
pref("dom.screenBrightnessProperty.enabled", true);
|
||||
|
||||
// handle links targeting new windows
|
||||
// 1=current window/tab, 2=new window, 3=new tab in most recent window
|
||||
pref("browser.link.open_newwindow", 3);
|
||||
|
||||
// 0: no restrictions - divert everything
|
||||
// 1: don't divert window.open at all
|
||||
// 2: don't divert window.open with features
|
||||
pref("browser.link.open_newwindow.restriction", 0);
|
||||
|
||||
// Enable browser frame
|
||||
pref("dom.mozBrowserFramesEnabled", true);
|
||||
pref("dom.mozBrowserFramesWhitelist", "http://localhost:6666");
|
||||
@ -401,6 +409,7 @@ pref("dom.mozBrowserFramesWhitelist", "http://localhost:6666");
|
||||
// Temporary permission hack for WebSMS
|
||||
pref("dom.sms.enabled", true);
|
||||
pref("dom.sms.whitelist", "file://,http://localhost:6666");
|
||||
|
||||
// Ignore X-Frame-Options headers.
|
||||
pref("b2g.ignoreXFrameOptions", true);
|
||||
|
||||
|
@ -47,18 +47,16 @@ const LocalFile = CC('@mozilla.org/file/local;1',
|
||||
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
XPCOMUtils.defineLazyGetter(Services, 'env', function() {
|
||||
return Cc['@mozilla.org/process/environment;1']
|
||||
.getService(Ci.nsIEnvironment);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(Services, 'ss', function() {
|
||||
return Cc['@mozilla.org/content/style-sheet-service;1']
|
||||
.getService(Ci.nsIStyleSheetService);
|
||||
});
|
||||
XPCOMUtils.defineLazyGetter(Services, 'fm', function() {
|
||||
return Cc['@mozilla.org/focus-manager;1']
|
||||
.getService(Ci.nsIFocusManager);
|
||||
});
|
||||
|
||||
// In order to use http:// scheme instead of file:// scheme
|
||||
// (that is much more restricted) the following code kick-off
|
||||
@ -76,7 +74,7 @@ function startupHttpd(baseDir, port) {
|
||||
|
||||
// FIXME Bug 707625
|
||||
// until we have a proper security model, add some rights to
|
||||
// the pre-installed web applications
|
||||
// the pre-installed web applications
|
||||
function addPermissions(urls) {
|
||||
let permissions = [
|
||||
'indexedDB', 'indexedDB-unlimited', 'webapps-manage', 'offline-app'
|
||||
@ -84,7 +82,7 @@ function addPermissions(urls) {
|
||||
urls.forEach(function(url) {
|
||||
let uri = Services.io.newURI(url, null, null);
|
||||
let allow = Ci.nsIPermissionManager.ALLOW_ACTION;
|
||||
|
||||
|
||||
permissions.forEach(function(permission) {
|
||||
Services.perms.add(uri, permission, allow);
|
||||
});
|
||||
@ -96,9 +94,9 @@ var shell = {
|
||||
// FIXME/bug 678695: this should be a system setting
|
||||
preferredScreenBrightness: 1.0,
|
||||
|
||||
get home() {
|
||||
delete this.home;
|
||||
return this.home = document.getElementById('homescreen');
|
||||
get contentBrowser() {
|
||||
delete this.contentBrowser;
|
||||
return this.contentBrowser = document.getElementById('homescreen');
|
||||
},
|
||||
|
||||
get homeURL() {
|
||||
@ -131,7 +129,7 @@ var shell = {
|
||||
window.controllers.appendController(this);
|
||||
window.addEventListener('keypress', this);
|
||||
window.addEventListener('MozApplicationManifest', this);
|
||||
this.home.addEventListener('load', this, true);
|
||||
this.contentBrowser.addEventListener('load', this, true);
|
||||
|
||||
try {
|
||||
Services.io.offline = false;
|
||||
@ -156,7 +154,15 @@ var shell = {
|
||||
return alert(msg);
|
||||
}
|
||||
|
||||
let browser = this.home;
|
||||
// Load webapi+apps.js as a frame script
|
||||
let frameScriptUrl = 'chrome://browser/content/webapi.js';
|
||||
try {
|
||||
messageManager.loadFrameScript(frameScriptUrl, true);
|
||||
} catch (e) {
|
||||
dump('Error when loading ' + frameScriptUrl + ' as a frame script: ' + e + '\n');
|
||||
}
|
||||
|
||||
let browser = this.contentBrowser;
|
||||
browser.homePage = homeURL;
|
||||
browser.goHome();
|
||||
},
|
||||
@ -187,7 +193,7 @@ var shell = {
|
||||
doCommand: function shell_doCommand(cmd) {
|
||||
switch (cmd) {
|
||||
case 'cmd_close':
|
||||
this.home.contentWindow.postMessage('appclose', '*');
|
||||
content.postMessage('appclose', '*');
|
||||
break;
|
||||
}
|
||||
},
|
||||
@ -197,7 +203,7 @@ var shell = {
|
||||
case 'keypress':
|
||||
switch (evt.keyCode) {
|
||||
case evt.DOM_VK_HOME:
|
||||
this.sendEvent(this.home.contentWindow, 'home');
|
||||
this.sendEvent(content, 'home');
|
||||
break;
|
||||
case evt.DOM_VK_SLEEP:
|
||||
this.toggleScreen();
|
||||
@ -205,7 +211,7 @@ var shell = {
|
||||
let details = {
|
||||
'enabled': screen.mozEnabled
|
||||
};
|
||||
this.sendEvent(this.home.contentWindow, 'sleep', details);
|
||||
this.sendEvent(content, 'sleep', details);
|
||||
break;
|
||||
case evt.DOM_VK_ESCAPE:
|
||||
if (evt.defaultPrevented)
|
||||
@ -215,8 +221,12 @@ var shell = {
|
||||
}
|
||||
break;
|
||||
case 'load':
|
||||
this.home.removeEventListener('load', this, true);
|
||||
this.contentBrowser.removeEventListener('load', this, true);
|
||||
this.turnScreenOn();
|
||||
|
||||
let chromeWindow = window.QueryInterface(Ci.nsIDOMChromeWindow);
|
||||
chromeWindow.browserDOMWindow = new nsBrowserAccess();
|
||||
|
||||
this.sendEvent(window, 'ContentStart');
|
||||
break;
|
||||
case 'MozApplicationManifest':
|
||||
@ -229,7 +239,7 @@ var shell = {
|
||||
if (!documentElement)
|
||||
return;
|
||||
|
||||
let manifest = documentElement.getAttribute("manifest");
|
||||
let manifest = documentElement.getAttribute('manifest');
|
||||
if (!manifest)
|
||||
return;
|
||||
|
||||
@ -273,78 +283,47 @@ var shell = {
|
||||
turnScreenOn: function shell_turnScreenOn() {
|
||||
screen.mozEnabled = true;
|
||||
screen.mozBrightness = this.preferredScreenBrightness;
|
||||
},
|
||||
};
|
||||
|
||||
(function VirtualKeyboardManager() {
|
||||
let activeElement = null;
|
||||
let isKeyboardOpened = false;
|
||||
|
||||
let constructor = {
|
||||
handleEvent: function vkm_handleEvent(evt) {
|
||||
let contentWindow = shell.home.contentWindow.wrappedJSObject;
|
||||
|
||||
switch (evt.type) {
|
||||
case 'ContentStart':
|
||||
contentWindow.navigator.mozKeyboard = new MozKeyboard();
|
||||
break;
|
||||
case 'keypress':
|
||||
if (evt.keyCode != evt.DOM_VK_ESCAPE || !isKeyboardOpened)
|
||||
return;
|
||||
|
||||
shell.sendEvent(contentWindow, 'hideime');
|
||||
isKeyboardOpened = false;
|
||||
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
break;
|
||||
case 'mousedown':
|
||||
if (evt.target != activeElement || isKeyboardOpened)
|
||||
return;
|
||||
|
||||
let type = activeElement.type;
|
||||
shell.sendEvent(contentWindow, 'showime', { type: type });
|
||||
isKeyboardOpened = true;
|
||||
break;
|
||||
}
|
||||
},
|
||||
observe: function vkm_observe(subject, topic, data) {
|
||||
let contentWindow = shell.home.contentWindow;
|
||||
|
||||
let shouldOpen = parseInt(data);
|
||||
if (shouldOpen && !isKeyboardOpened) {
|
||||
activeElement = Services.fm.focusedElement;
|
||||
if (!activeElement)
|
||||
return;
|
||||
|
||||
let type = activeElement.type;
|
||||
shell.sendEvent(contentWindow, 'showime', { type: type });
|
||||
} else if (!shouldOpen && isKeyboardOpened) {
|
||||
shell.sendEvent(contentWindow, 'hideime');
|
||||
}
|
||||
isKeyboardOpened = shouldOpen;
|
||||
}
|
||||
};
|
||||
|
||||
Services.obs.addObserver(constructor, 'ime-enabled-state-changed', false);
|
||||
['ContentStart', 'keypress', 'mousedown'].forEach(function vkm_events(type) {
|
||||
window.addEventListener(type, constructor, true);
|
||||
});
|
||||
})();
|
||||
|
||||
|
||||
function MozKeyboard() {
|
||||
}
|
||||
|
||||
MozKeyboard.prototype = {
|
||||
sendKey: function mozKeyboardSendKey(keyCode, charCode) {
|
||||
charCode = (charCode == undefined) ? keyCode : charCode;
|
||||
|
||||
var utils = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
['keydown', 'keypress', 'keyup'].forEach(function sendKeyEvents(type) {
|
||||
utils.sendKeyEvent(type, keyCode, charCode, null);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
function nsBrowserAccess() {
|
||||
}
|
||||
|
||||
nsBrowserAccess.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserDOMWindow]),
|
||||
|
||||
openURI: function openURI(uri, opener, where, context) {
|
||||
// TODO This should be replaced by an 'open-browser-window' intent
|
||||
let contentWindow = content.wrappedJSObject;
|
||||
if (!('getApplicationManager' in contentWindow))
|
||||
return null;
|
||||
|
||||
let applicationManager = contentWindow.getApplicationManager();
|
||||
if (!applicationManager)
|
||||
return null;
|
||||
|
||||
let url = uri ? uri.spec : 'about:blank';
|
||||
let window = applicationManager.launch(url, where);
|
||||
return window.contentWindow;
|
||||
},
|
||||
|
||||
openURIInFrame: function openURIInFrame(uri, opener, where, context) {
|
||||
throw new Error('Not Implemented');
|
||||
},
|
||||
|
||||
isTabContentWindow: function isTabContentWindow(contentWindow) {
|
||||
return contentWindow == window;
|
||||
}
|
||||
};
|
||||
|
||||
// Pipe `console` log messages to the nsIConsoleService which writes them
|
||||
// to logcat.
|
||||
Services.obs.addObserver(function onConsoleAPILogEvent(subject, topic, data) {
|
||||
let message = subject.wrappedJSObject;
|
||||
let prefix = "Content JS " + message.level.toUpperCase() +
|
||||
" at " + message.filename + ":" + message.lineNumber +
|
||||
" in " + (message.functionName || "anonymous") + ": ";
|
||||
Services.console.logStringMessage(prefix + Array.join(message.arguments, " "));
|
||||
}, "console-api-log-event", false);
|
||||
|
@ -66,12 +66,12 @@
|
||||
events: ['mousedown', 'mousemove', 'mouseup', 'click', 'unload'],
|
||||
start: function teh_start() {
|
||||
this.events.forEach((function(evt) {
|
||||
shell.home.addEventListener(evt, this, true);
|
||||
shell.contentBrowser.addEventListener(evt, this, true);
|
||||
}).bind(this));
|
||||
},
|
||||
stop: function teh_stop() {
|
||||
this.events.forEach((function(evt) {
|
||||
shell.home.removeEventListener(evt, this, true);
|
||||
shell.contentBrowser.removeEventListener(evt, this, true);
|
||||
}).bind(this));
|
||||
},
|
||||
handleEvent: function teh_handleEvent(evt) {
|
||||
@ -139,12 +139,7 @@
|
||||
return;
|
||||
|
||||
case 'click':
|
||||
if (!isNewTouchAction) {
|
||||
debug('click: cancel');
|
||||
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
} else {
|
||||
if (isNewTouchAction) {
|
||||
// Mouse events has been cancelled so dispatch a sequence
|
||||
// of events to where touchend has been fired
|
||||
if (preventMouseEvents) {
|
||||
|
1791
b2g/chrome/content/webapi.js
Normal file
1791
b2g/chrome/content/webapi.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -9,6 +9,7 @@ chrome.jar:
|
||||
content/touch.js (content/touch.js)
|
||||
content/commandUtil.js (content/commandUtil.js)
|
||||
content/httpd.js (content/httpd.js)
|
||||
content/webapi.js (content/webapi.js)
|
||||
content/content.css (content/content.css)
|
||||
|
||||
% override chrome://global/content/netError.xhtml chrome://browser/content/netError.xhtml
|
||||
|
@ -38,7 +38,8 @@
|
||||
MOZ_APP_BASENAME=B2G
|
||||
MOZ_APP_VENDOR=Mozilla
|
||||
|
||||
MOZ_APP_VERSION=11.0a1
|
||||
MOZ_APP_VERSION=13.0a1
|
||||
MOZ_APP_UA_NAME=Firefox
|
||||
|
||||
MOZ_BRANDING_DIRECTORY=b2g/branding/unofficial
|
||||
MOZ_OFFICIAL_BRANDING_DIRECTORY=b2g/branding/official
|
||||
|
@ -1112,10 +1112,10 @@ pref("prompts.tab_modal.enabled", true);
|
||||
pref("browser.panorama.animate_zoom", true);
|
||||
|
||||
// Defines the url to be used for new tabs.
|
||||
pref("browser.newtab.url", "about:blank");
|
||||
pref("browser.newtab.url", "about:newtab");
|
||||
|
||||
// Toggles the content of 'about:newtab'. Shows the grid when enabled.
|
||||
pref("browser.newtabpage.enabled", false);
|
||||
pref("browser.newtabpage.enabled", true);
|
||||
|
||||
// Enable the DOM full-screen API.
|
||||
pref("full-screen-api.enabled", true);
|
||||
|
@ -5455,7 +5455,7 @@ var TabsInTitlebar = {
|
||||
if (!this._draghandle) {
|
||||
let tmp = {};
|
||||
Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp);
|
||||
this._draghandle = new tmp.WindowDraggingElement(tabsToolbar, window);
|
||||
this._draghandle = new tmp.WindowDraggingElement(tabsToolbar);
|
||||
this._draghandle.mouseDownCheck = function () {
|
||||
return !this._dragBindingAlive && TabsInTitlebar.enabled;
|
||||
};
|
||||
|
@ -5,7 +5,9 @@ const PREF_NEWTAB_ENABLED = "browser.newtabpage.enabled";
|
||||
|
||||
Services.prefs.setBoolPref(PREF_NEWTAB_ENABLED, true);
|
||||
|
||||
Cu.import("resource:///modules/NewTabUtils.jsm");
|
||||
let tmp = {};
|
||||
Cu.import("resource:///modules/NewTabUtils.jsm", tmp);
|
||||
let NewTabUtils = tmp.NewTabUtils;
|
||||
|
||||
registerCleanupFunction(function () {
|
||||
reset();
|
||||
|
@ -693,7 +693,10 @@ var gCookiesWindow = {
|
||||
}
|
||||
else {
|
||||
var rangeCount = seln.getRangeCount();
|
||||
for (var i = 0; i < rangeCount; ++i) {
|
||||
// Traverse backwards through selections to avoid messing
|
||||
// up the indices when they are deleted.
|
||||
// See bug 388079.
|
||||
for (var i = rangeCount - 1; i >= 0; --i) {
|
||||
var min = {}; var max = {};
|
||||
seln.getRangeAt(i, min, max);
|
||||
nextSelected = min.value;
|
||||
|
@ -160,6 +160,7 @@ _BROWSER_TEST_FILES = \
|
||||
browser_687710_2.js \
|
||||
browser_694378.js \
|
||||
browser_705597.js \
|
||||
browser_707862.js \
|
||||
$(NULL)
|
||||
|
||||
ifneq ($(OS_ARCH),Darwin)
|
||||
|
56
browser/components/sessionstore/test/browser_707862.js
Normal file
56
browser/components/sessionstore/test/browser_707862.js
Normal file
@ -0,0 +1,56 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let tabState = {
|
||||
entries: [{url: "about:home", children: [{url: "about:mozilla"}]}]
|
||||
};
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let tab = gBrowser.addTab("about:blank");
|
||||
registerCleanupFunction(function () gBrowser.removeTab(tab));
|
||||
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
whenBrowserLoaded(browser, function () {
|
||||
ss.setTabState(tab, JSON.stringify(tabState));
|
||||
|
||||
let sessionHistory = browser.sessionHistory;
|
||||
let entry = sessionHistory.getEntryAtIndex(0, false);
|
||||
|
||||
whenChildCount(entry, 1, function () {
|
||||
whenChildCount(entry, 2, function () {
|
||||
whenBrowserLoaded(browser, function () {
|
||||
let sessionHistory = browser.sessionHistory;
|
||||
let entry = sessionHistory.getEntryAtIndex(0, false);
|
||||
|
||||
whenChildCount(entry, 0, finish);
|
||||
});
|
||||
|
||||
// reload the browser to deprecate the subframes
|
||||
browser.reload();
|
||||
});
|
||||
|
||||
// create a dynamic subframe
|
||||
let doc = browser.contentDocument;
|
||||
let iframe = doc.createElement("iframe");
|
||||
iframe.setAttribute("src", "about:mozilla");
|
||||
doc.body.appendChild(iframe);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function whenBrowserLoaded(aBrowser, aCallback) {
|
||||
aBrowser.addEventListener("load", function onLoad() {
|
||||
aBrowser.removeEventListener("load", onLoad, true);
|
||||
executeSoon(aCallback);
|
||||
}, true);
|
||||
}
|
||||
|
||||
function whenChildCount(aEntry, aChildCount, aCallback) {
|
||||
if (aEntry.childCount == aChildCount)
|
||||
aCallback();
|
||||
else
|
||||
executeSoon(function () whenChildCount(aEntry, aChildCount, aCallback));
|
||||
}
|
@ -68,6 +68,18 @@ var gSetBackground = {
|
||||
if (this._screenWidth / this._screenHeight >= 1.6)
|
||||
document.getElementById("monitor").setAttribute("aspectratio", "16:10");
|
||||
|
||||
#ifdef XP_WIN
|
||||
// hide fill + fit options if <win7 since don't work
|
||||
var version = Components.classes["@mozilla.org/system-info;1"]
|
||||
.getService(Ci.nsIPropertyBag2)
|
||||
.getProperty("version");
|
||||
var isWindows7OrHigher = (parseFloat(version) >= 6.1);
|
||||
if (!isWindows7OrHigher) {
|
||||
document.getElementById("fillPosition").hidden = true;
|
||||
document.getElementById("fitPosition").hidden = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// make sure that the correct dimensions will be used
|
||||
setTimeout(function(self) {
|
||||
self.init(window.arguments[0]);
|
||||
@ -198,6 +210,39 @@ var gSetBackground = {
|
||||
var x = (this._screenWidth - this._image.naturalWidth) / 2;
|
||||
var y = (this._screenHeight - this._image.naturalHeight) / 2;
|
||||
ctx.drawImage(this._image, x, y);
|
||||
break;
|
||||
case "FILL":
|
||||
//Try maxing width first, overflow height
|
||||
var widthRatio = this._screenWidth / this._image.naturalWidth;
|
||||
var width = this._image.naturalWidth * widthRatio;
|
||||
var height = this._image.naturalHeight * widthRatio;
|
||||
if (height < this._screenHeight) {
|
||||
//height less than screen, max height and overflow width
|
||||
var heightRatio = this._screenHeight / this._image.naturalHeight;
|
||||
width = this._image.naturalWidth * heightRatio;
|
||||
height = this._image.naturalHeight * heightRatio;
|
||||
}
|
||||
var x = (this._screenWidth - width) / 2;
|
||||
var y = (this._screenHeight - height) / 2;
|
||||
ctx.drawImage(this._image, x, y, width, height);
|
||||
break;
|
||||
case "FIT":
|
||||
//Try maxing width first, top and bottom borders
|
||||
var widthRatio = this._screenWidth / this._image.naturalWidth;
|
||||
var width = this._image.naturalWidth * widthRatio;
|
||||
var height = this._image.naturalHeight * widthRatio;
|
||||
var x = 0;
|
||||
var y = (this._screenHeight - height) / 2;
|
||||
if (height > this._screenHeight) {
|
||||
//height overflow, maximise height, side borders
|
||||
var heightRatio = this._screenHeight / this._image.naturalHeight;
|
||||
width = this._image.naturalWidth * heightRatio;
|
||||
height = this._image.naturalHeight * heightRatio;
|
||||
x = (this._screenWidth - width) / 2;
|
||||
y = 0;
|
||||
}
|
||||
ctx.drawImage(this._image, x, y, width, height);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -78,6 +78,8 @@
|
||||
<menuitem label="¢er.label;" value="CENTER"/>
|
||||
<menuitem label="&tile.label;" value="TILE"/>
|
||||
<menuitem label="&stretch.label;" value="STRETCH"/>
|
||||
<menuitem label="&fill.label;" value="FILL" id="fillPosition"/>
|
||||
<menuitem label="&fit.label;" value="FIT" id="fitPosition"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
<spacer flex="1"/>
|
||||
|
@ -81,6 +81,7 @@ interface nsIShellService : nsISupports
|
||||
const long BACKGROUND_STRETCH = 2;
|
||||
const long BACKGROUND_CENTER = 3;
|
||||
const long BACKGROUND_FILL = 4;
|
||||
const long BACKGROUND_FIT = 5;
|
||||
|
||||
/**
|
||||
* Sets the desktop background image using either the HTML <IMG>
|
||||
|
@ -427,6 +427,10 @@ nsGNOMEShellService::SetDesktopBackground(nsIDOMElement* aElement,
|
||||
options.Assign("wallpaper");
|
||||
else if (aPosition == BACKGROUND_STRETCH)
|
||||
options.Assign("stretched");
|
||||
else if (aPosition == BACKGROUND_FILL)
|
||||
options.Assign("zoom");
|
||||
else if (aPosition == BACKGROUND_FIT)
|
||||
options.Assign("scaled");
|
||||
else
|
||||
options.Assign("centered");
|
||||
|
||||
|
@ -640,6 +640,14 @@ nsWindowsShellService::SetDesktopBackground(nsIDOMElement* aElement,
|
||||
style.AssignLiteral("2");
|
||||
tile.AssignLiteral("0");
|
||||
break;
|
||||
case BACKGROUND_FILL:
|
||||
style.AssignLiteral("10");
|
||||
tile.AssignLiteral("0");
|
||||
break;
|
||||
case BACKGROUND_FIT:
|
||||
style.AssignLiteral("6");
|
||||
tile.AssignLiteral("0");
|
||||
break;
|
||||
}
|
||||
|
||||
rv = regKey->WriteStringValue(NS_LITERAL_STRING("TileWallpaper"), tile);
|
||||
|
@ -52,7 +52,8 @@ function onPageLoad() {
|
||||
checkWallpaper(Ci.nsIShellService.BACKGROUND_TILE, "wallpaper");
|
||||
checkWallpaper(Ci.nsIShellService.BACKGROUND_STRETCH, "stretched");
|
||||
checkWallpaper(Ci.nsIShellService.BACKGROUND_CENTER, "centered");
|
||||
checkWallpaper(Ci.nsIShellService.BACKGROUND_FILL, "centered");
|
||||
checkWallpaper(Ci.nsIShellService.BACKGROUND_FILL, "zoom");
|
||||
checkWallpaper(Ci.nsIShellService.BACKGROUND_FIT, "scaled");
|
||||
|
||||
// Restore GConf and wallpaper
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Cu.import("resource:///modules/PageThumbs.jsm");
|
||||
let tmp = {};
|
||||
Cu.import("resource:///modules/PageThumbs.jsm", tmp);
|
||||
let PageThumbs = tmp.PageThumbs;
|
||||
let PageThumbsCache = tmp.PageThumbsCache;
|
||||
|
||||
registerCleanupFunction(function () {
|
||||
while (gBrowser.tabs.length > 1)
|
||||
|
@ -2,7 +2,9 @@
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
|
||||
let tmp = {};
|
||||
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm", tmp);
|
||||
let LayoutHelpers = tmp.LayoutHelpers;
|
||||
|
||||
function init(callback) {
|
||||
let iframe = gBrowser.ownerDocument.createElement("iframe");
|
||||
|
@ -5,7 +5,9 @@
|
||||
// - https://github.com/mozilla/gcli/blob/master/docs/index.md
|
||||
// - https://wiki.mozilla.org/DevTools/Features/GCLI
|
||||
|
||||
Components.utils.import("resource:///modules/gcli.jsm");
|
||||
let tmp = {};
|
||||
Components.utils.import("resource:///modules/gcli.jsm", tmp);
|
||||
let gcli = tmp.gcli;
|
||||
|
||||
let hud;
|
||||
let gcliterm;
|
||||
|
@ -2,6 +2,8 @@
|
||||
<!ENTITY tile.label "Tile">
|
||||
<!ENTITY center.label "Center">
|
||||
<!ENTITY stretch.label "Stretch">
|
||||
<!ENTITY fill.label "Fill">
|
||||
<!ENTITY fit.label "Fit">
|
||||
<!ENTITY preview.label "Preview">
|
||||
<!ENTITY color.label "Color:">
|
||||
<!ENTITY setDesktopBackground.title "Set Desktop Background">
|
||||
|
@ -14,8 +14,10 @@ class DeviceManagerADB(DeviceManager):
|
||||
self.retries = 0
|
||||
self._sock = None
|
||||
self.useRunAs = False
|
||||
self.haveRoot = False
|
||||
self.useZip = False
|
||||
self.packageName = None
|
||||
self.tempDir = None
|
||||
if packageName == None:
|
||||
if os.getenv('USER'):
|
||||
packageName = 'org.mozilla.fennec_' + os.getenv('USER')
|
||||
@ -36,18 +38,30 @@ class DeviceManagerADB(DeviceManager):
|
||||
self.verifyZip()
|
||||
except:
|
||||
self.useZip = False
|
||||
try:
|
||||
|
||||
def verifyRoot():
|
||||
# a test to see if we have root privs
|
||||
files = self.listFiles("/data/data")
|
||||
if (len(files) == 1):
|
||||
if (files[0].find("Permission denied") != -1):
|
||||
print "NOT running as root"
|
||||
raise Exception("not running as root")
|
||||
self.haveRoot = True
|
||||
|
||||
try:
|
||||
verifyRoot()
|
||||
except:
|
||||
try:
|
||||
self.checkCmd(["root"])
|
||||
# The root command does not fail even if ADB cannot get
|
||||
# root rights (e.g. due to production builds), so we have
|
||||
# to check again ourselves that we have root now.
|
||||
verifyRoot()
|
||||
except:
|
||||
print "restarting as root failed"
|
||||
if (self.useRunAs):
|
||||
print "restarting as root failed, but run-as available"
|
||||
else:
|
||||
print "restarting as root failed"
|
||||
|
||||
# external function
|
||||
# returns:
|
||||
@ -58,9 +72,12 @@ class DeviceManagerADB(DeviceManager):
|
||||
if (os.name == "nt"):
|
||||
destname = destname.replace('\\', '/')
|
||||
if (self.useRunAs):
|
||||
remoteTmpFile = self.tmpDir + "/" + os.path.basename(localname)
|
||||
remoteTmpFile = self.getTempDir() + "/" + os.path.basename(localname)
|
||||
self.checkCmd(["push", os.path.realpath(localname), remoteTmpFile])
|
||||
self.checkCmdAs(["shell", "cp", remoteTmpFile, destname])
|
||||
if self.useDDCopy:
|
||||
self.checkCmdAs(["shell", "dd", "if=" + remoteTmpFile, "of=" + destname])
|
||||
else:
|
||||
self.checkCmdAs(["shell", "cp", remoteTmpFile, destname])
|
||||
self.checkCmd(["shell", "rm", remoteTmpFile])
|
||||
else:
|
||||
self.checkCmd(["push", os.path.realpath(localname), destname])
|
||||
@ -329,7 +346,26 @@ class DeviceManagerADB(DeviceManager):
|
||||
# TODO: add debug flags and allow for printing stdout
|
||||
# self.runCmd(["pull", remoteFile, localFile])
|
||||
try:
|
||||
self.runCmd(["pull", remoteFile, localFile]).stdout.read()
|
||||
|
||||
# First attempt to pull file regularly
|
||||
outerr = self.runCmd(["pull", remoteFile, localFile]).communicate()
|
||||
|
||||
# Now check stderr for errors
|
||||
errl = outerr[1].splitlines()
|
||||
if (len(errl) == 1):
|
||||
if (((errl[0].find("Permission denied") != -1)
|
||||
or (errl[0].find("does not exist") != -1))
|
||||
and self.useRunAs):
|
||||
# If we lack permissions to read but have run-as, then we should try
|
||||
# to copy the file to a world-readable location first before attempting
|
||||
# to pull it again.
|
||||
remoteTmpFile = self.getTempDir() + "/" + os.path.basename(remoteFile)
|
||||
self.checkCmdAs(["shell", "dd", "if=" + remoteFile, "of=" + remoteTmpFile])
|
||||
self.checkCmdAs(["shell", "chmod", "777", remoteTmpFile])
|
||||
self.runCmd(["pull", remoteTmpFile, localFile]).stdout.read()
|
||||
# Clean up temporary file
|
||||
self.checkCmdAs(["shell", "rm", remoteTmpFile])
|
||||
|
||||
f = open(localFile)
|
||||
ret = f.read()
|
||||
f.close()
|
||||
@ -422,6 +458,23 @@ class DeviceManagerADB(DeviceManager):
|
||||
self.mkDir(testRoot)
|
||||
return testRoot
|
||||
|
||||
# Gets the temporary directory we are using on this device
|
||||
# base on our device root, ensuring also that it exists.
|
||||
#
|
||||
# internal function
|
||||
# returns:
|
||||
# success: path for temporary directory
|
||||
# failure: None
|
||||
def getTempDir(self):
|
||||
# Cache result to speed up operations depending
|
||||
# on the temporary directory.
|
||||
if self.tempDir == None:
|
||||
self.tempDir = self.getDeviceRoot() + "/tmp"
|
||||
if (not self.dirExists(self.tempDir)):
|
||||
return self.mkDir(self.tempDir)
|
||||
|
||||
return self.tempDir
|
||||
|
||||
# Either we will have /tests/fennec or /tests/firefox but we will never have
|
||||
# both. Return the one that exists
|
||||
# TODO: ensure we can support org.mozilla.firefox
|
||||
@ -543,6 +596,11 @@ class DeviceManagerADB(DeviceManager):
|
||||
return ret
|
||||
|
||||
def runCmd(self, args):
|
||||
# If we are not root but have run-as, and we're trying to execute
|
||||
# a shell command then using run-as is the best we can do
|
||||
if (not self.haveRoot and self.useRunAs and args[0] == "shell" and args[1] != "run-as"):
|
||||
args.insert(1, "run-as")
|
||||
args.insert(2, self.packageName)
|
||||
args.insert(0, "adb")
|
||||
return subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
@ -553,6 +611,11 @@ class DeviceManagerADB(DeviceManager):
|
||||
return self.runCmd(args)
|
||||
|
||||
def checkCmd(self, args):
|
||||
# If we are not root but have run-as, and we're trying to execute
|
||||
# a shell command then using run-as is the best we can do
|
||||
if (not self.haveRoot and self.useRunAs and args[0] == "shell" and args[1] != "run-as"):
|
||||
args.insert(1, "run-as")
|
||||
args.insert(2, self.packageName)
|
||||
args.insert(0, "adb")
|
||||
return subprocess.check_call(args)
|
||||
|
||||
@ -591,6 +654,11 @@ class DeviceManagerADB(DeviceManager):
|
||||
if (re.search('Usage', data)):
|
||||
return True
|
||||
else:
|
||||
data = self.runCmd(["shell", "dd", "-"]).stdout.read()
|
||||
if (re.search('unknown operand', data)):
|
||||
print "'cp' not found, but 'dd' was found as a replacement"
|
||||
self.useDDCopy = True
|
||||
return True
|
||||
print "unable to execute 'cp' on device; consider installing busybox from Android Market"
|
||||
return False
|
||||
|
||||
@ -605,12 +673,14 @@ class DeviceManagerADB(DeviceManager):
|
||||
self.useRunAs = False
|
||||
devroot = self.getDeviceRoot()
|
||||
if (packageName and self.isCpAvailable() and devroot):
|
||||
self.tmpDir = devroot + "/tmp"
|
||||
if (not self.dirExists(self.tmpDir)):
|
||||
self.mkDir(self.tmpDir)
|
||||
tmpDir = self.getTempDir()
|
||||
|
||||
self.checkCmd(["shell", "run-as", packageName, "mkdir", devroot + "/sanity"])
|
||||
self.checkCmd(["push", os.path.abspath(sys.argv[0]), self.tmpDir + "/tmpfile"])
|
||||
self.checkCmd(["shell", "run-as", packageName, "cp", self.tmpDir + "/tmpfile", devroot + "/sanity"])
|
||||
self.checkCmd(["push", os.path.abspath(sys.argv[0]), tmpDir + "/tmpfile"])
|
||||
if self.useDDCopy:
|
||||
self.checkCmd(["shell", "run-as", packageName, "dd", "if=" + tmpDir + "/tmpfile", "of=" + devroot + "/sanity/tmpfile"])
|
||||
else:
|
||||
self.checkCmd(["shell", "run-as", packageName, "cp", tmpDir + "/tmpfile", devroot + "/sanity"])
|
||||
if (self.fileExists(devroot + "/sanity/tmpfile")):
|
||||
print "will execute commands via run-as " + packageName
|
||||
self.packageName = packageName
|
||||
|
@ -134,11 +134,15 @@ public class FennecNativeDriver implements Driver {
|
||||
private void getGeckoInfo() {
|
||||
View geckoLayout = activity.findViewById(Integer.decode((String)locators.get("gecko_layout")));
|
||||
if (geckoLayout != null) {
|
||||
geckoTop = geckoLayout.getTop();
|
||||
geckoLeft = geckoLayout.getLeft();
|
||||
int[] pos = new int[2];
|
||||
geckoLayout.getLocationOnScreen(pos);
|
||||
geckoTop = pos[1];
|
||||
geckoLeft = pos[0];
|
||||
geckoWidth = geckoLayout.getWidth();
|
||||
geckoHeight = geckoLayout.getHeight();
|
||||
geckoInfo = true;
|
||||
} else {
|
||||
throw new RoboCopException("Unable to find view gecko_layout");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,6 +160,7 @@ MOZ_ZIPWRITER = @MOZ_ZIPWRITER@
|
||||
MOZ_OGG = @MOZ_OGG@
|
||||
MOZ_RAW = @MOZ_RAW@
|
||||
MOZ_SYDNEYAUDIO = @MOZ_SYDNEYAUDIO@
|
||||
MOZ_CUBEB = @MOZ_CUBEB@
|
||||
MOZ_WAVE = @MOZ_WAVE@
|
||||
MOZ_MEDIA = @MOZ_MEDIA@
|
||||
MOZ_VORBIS = @MOZ_VORBIS@
|
||||
|
@ -1050,4 +1050,5 @@ tremor/ivorbiscodec.h
|
||||
ogg/ogg.h
|
||||
ogg/os_types.h
|
||||
nestegg/nestegg.h
|
||||
cubeb/cubeb.h
|
||||
#endif
|
||||
|
22
configure.in
22
configure.in
@ -460,6 +460,9 @@ case "$target" in
|
||||
if test -z "$ANDROID_PACKAGE_NAME" ; then
|
||||
ANDROID_PACKAGE_NAME='org.mozilla.$(MOZ_APP_NAME)'
|
||||
fi
|
||||
if test -z "$MOZ_MOBILE_COMPAT" ; then
|
||||
MOZ_MOBILE_COMPAT='All'
|
||||
fi
|
||||
|
||||
AC_DEFINE(ANDROID)
|
||||
AC_DEFINE_UNQUOTED(ANDROID_VERSION, $android_version)
|
||||
@ -481,6 +484,7 @@ AC_SUBST(ANDROID_PLATFORM)
|
||||
AC_SUBST(ANDROID_SDK)
|
||||
AC_SUBST(ANDROID_PLATFORM_TOOLS)
|
||||
AC_SUBST(ANDROID_PACKAGE_NAME)
|
||||
AC_SUBST(MOZ_MOBILE_COMPAT)
|
||||
AC_SUBST(OBJCOPY)
|
||||
|
||||
dnl ========================================================
|
||||
@ -4582,6 +4586,7 @@ MOZ_AUTH_EXTENSION=1
|
||||
MOZ_OGG=1
|
||||
MOZ_RAW=
|
||||
MOZ_SYDNEYAUDIO=
|
||||
MOZ_CUBEB=
|
||||
MOZ_VORBIS=
|
||||
MOZ_TREMOR=
|
||||
MOZ_WAVE=1
|
||||
@ -5592,6 +5597,7 @@ MOZ_ARG_DISABLE_BOOL(ogg,
|
||||
if test -n "$MOZ_OGG"; then
|
||||
AC_DEFINE(MOZ_OGG)
|
||||
MOZ_SYDNEYAUDIO=1
|
||||
MOZ_CUBEB=1
|
||||
MOZ_MEDIA=1
|
||||
case "$target_cpu" in
|
||||
arm*)
|
||||
@ -5709,6 +5715,7 @@ AC_SUBST(MOZ_LIBVPX_LIBS)
|
||||
|
||||
if test -n "$MOZ_WEBM" -a -z "$MOZ_NATIVE_LIBVPX"; then
|
||||
MOZ_SYDNEYAUDIO=1
|
||||
MOZ_CUBEB=1
|
||||
MOZ_MEDIA=1
|
||||
case "$target_cpu" in
|
||||
arm*)
|
||||
@ -5820,17 +5827,29 @@ MOZ_ARG_DISABLE_BOOL(wave,
|
||||
if test -n "$MOZ_WAVE"; then
|
||||
AC_DEFINE(MOZ_WAVE)
|
||||
MOZ_SYDNEYAUDIO=1
|
||||
MOZ_CUBEB=1
|
||||
MOZ_MEDIA=1
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Handle dependent SYDNEYAUDIO and MEDIA defines
|
||||
dnl = Handle dependent SYDNEYAUDIO, CUBEB, and MEDIA defines
|
||||
dnl ========================================================
|
||||
|
||||
if test -n "$MOZ_SYDNEYAUDIO"; then
|
||||
AC_DEFINE(MOZ_SYDNEYAUDIO)
|
||||
fi
|
||||
|
||||
if test -n "$MOZ_CUBEB"; then
|
||||
case "$target" in
|
||||
*-mingw*)
|
||||
AC_DEFINE(MOZ_CUBEB)
|
||||
;;
|
||||
*)
|
||||
dnl Other targets will be enabled soon.
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if test -n "$MOZ_MEDIA"; then
|
||||
AC_DEFINE(MOZ_MEDIA)
|
||||
fi
|
||||
@ -8692,6 +8711,7 @@ AC_SUBST(MOZ_APP_EXTRA_LIBS)
|
||||
|
||||
AC_SUBST(MOZ_MEDIA)
|
||||
AC_SUBST(MOZ_SYDNEYAUDIO)
|
||||
AC_SUBST(MOZ_CUBEB)
|
||||
AC_SUBST(MOZ_WAVE)
|
||||
AC_SUBST(MOZ_VORBIS)
|
||||
AC_SUBST(MOZ_TREMOR)
|
||||
|
@ -1617,6 +1617,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual size_t SizeOfStyleSheets(nsMallocSizeOfFun aMallocSizeOf) const = 0;
|
||||
|
||||
private:
|
||||
PRUint64 mWarnedAbout;
|
||||
|
||||
|
@ -9140,3 +9140,18 @@ nsDocument::GetMozVisibilityState(nsAString& aState)
|
||||
aState.AssignASCII(states[mVisibilityState]);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static size_t
|
||||
SizeOfStyleSheetsElementIncludingThis(nsIStyleSheet* aStyleSheet,
|
||||
nsMallocSizeOfFun aMallocSizeOf,
|
||||
void* aData)
|
||||
{
|
||||
return aStyleSheet->SizeOfIncludingThis(aMallocSizeOf);
|
||||
}
|
||||
|
||||
/* virtual */ size_t
|
||||
nsDocument::SizeOfStyleSheets(nsMallocSizeOfFun aMallocSizeOf) const
|
||||
{
|
||||
return mStyleSheets.SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis,
|
||||
aMallocSizeOf);
|
||||
}
|
||||
|
@ -991,6 +991,8 @@ public:
|
||||
// Posts an event to call UpdateVisibilityState
|
||||
virtual void PostVisibilityUpdateEvent();
|
||||
|
||||
virtual size_t SizeOfStyleSheets(nsMallocSizeOfFun aMallocSizeOf) const;
|
||||
|
||||
protected:
|
||||
friend class nsNodeUtils;
|
||||
|
||||
|
@ -866,8 +866,6 @@ nsFrameScriptExecutor::InitTabChildGlobalInternal(nsISupports* aScope)
|
||||
|
||||
nsContentUtils::GetSecurityManager()->GetSystemPrincipal(getter_AddRefs(mPrincipal));
|
||||
|
||||
JS_SetNativeStackQuota(cx, 128 * sizeof(size_t) * 1024);
|
||||
|
||||
JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_PRIVATE_IS_NSISUPPORTS);
|
||||
JS_SetVersion(cx, JSVERSION_LATEST);
|
||||
JS_SetErrorReporter(cx, ContentScriptErrorReporter);
|
||||
|
@ -91,9 +91,9 @@ using namespace mozilla;
|
||||
#define TRUE_OR_FAIL_WEBSOCKET(x, ret) \
|
||||
PR_BEGIN_MACRO \
|
||||
if (NS_UNLIKELY(!(x))) { \
|
||||
NS_WARNING("ENSURE_TRUE_AND_FAIL_IF_FAILED(" #x ") failed"); \
|
||||
FailConnection(); \
|
||||
return ret; \
|
||||
NS_WARNING("ENSURE_TRUE_AND_FAIL_IF_FAILED(" #x ") failed"); \
|
||||
FailConnection(nsIWebSocketChannel::CLOSE_INTERNAL_ERROR); \
|
||||
return ret; \
|
||||
} \
|
||||
PR_END_MACRO
|
||||
|
||||
@ -102,7 +102,7 @@ using namespace mozilla;
|
||||
nsresult __rv = res; \
|
||||
if (NS_FAILED(__rv)) { \
|
||||
NS_ENSURE_SUCCESS_BODY(res, ret) \
|
||||
FailConnection(); \
|
||||
FailConnection(nsIWebSocketChannel::CLOSE_INTERNAL_ERROR); \
|
||||
return ret; \
|
||||
} \
|
||||
PR_END_MACRO
|
||||
@ -159,7 +159,8 @@ nsWebSocket::PrintErrorOnConsole(const char *aBundleURI,
|
||||
|
||||
// when this is called the browser side wants no more part of it
|
||||
nsresult
|
||||
nsWebSocket::CloseConnection()
|
||||
nsWebSocket::CloseConnection(PRUint16 aReasonCode,
|
||||
const nsACString& aReasonString)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||
if (mDisconnected)
|
||||
@ -172,7 +173,7 @@ nsWebSocket::CloseConnection()
|
||||
if (mReadyState == nsIWebSocket::CONNECTING) {
|
||||
SetReadyState(nsIWebSocket::CLOSED);
|
||||
if (mChannel) {
|
||||
mChannel->Close(mClientReasonCode, mClientReason);
|
||||
mChannel->Close(aReasonCode, aReasonString);
|
||||
}
|
||||
Disconnect();
|
||||
return NS_OK;
|
||||
@ -186,7 +187,7 @@ nsWebSocket::CloseConnection()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return mChannel->Close(mClientReasonCode, mClientReason);
|
||||
return mChannel->Close(aReasonCode, aReasonString);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -219,12 +220,13 @@ nsWebSocket::ConsoleError()
|
||||
|
||||
|
||||
nsresult
|
||||
nsWebSocket::FailConnection()
|
||||
nsWebSocket::FailConnection(PRUint16 aReasonCode,
|
||||
const nsACString& aReasonString)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||
ConsoleError();
|
||||
|
||||
nsresult rv = CloseConnection();
|
||||
nsresult rv = CloseConnection(aReasonCode, aReasonString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("error"));
|
||||
@ -322,7 +324,7 @@ nsWebSocket::OnStop(nsISupports *aContext, nsresult aStatusCode)
|
||||
if (mDisconnected)
|
||||
return NS_OK;
|
||||
|
||||
mClosedCleanly = NS_SUCCEEDED(aStatusCode);
|
||||
mCloseEventWasClean = NS_SUCCEEDED(aStatusCode);
|
||||
|
||||
if (aStatusCode == NS_BASE_STREAM_CLOSED &&
|
||||
mReadyState >= nsIWebSocket::CLOSING) {
|
||||
@ -360,10 +362,16 @@ nsWebSocket::OnServerClose(nsISupports *aContext, PRUint16 aCode,
|
||||
const nsACString &aReason)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||
mServerReasonCode = aCode;
|
||||
CopyUTF8toUTF16(aReason, mServerReason);
|
||||
|
||||
CloseConnection(); /* reciprocate! */
|
||||
// store code/string for onclose DOM event
|
||||
mCloseEventCode = aCode;
|
||||
CopyUTF8toUTF16(aReason, mCloseEventReason);
|
||||
|
||||
// Send reciprocal Close frame.
|
||||
// 5.5.1: "When sending a Close frame in response, the endpoint typically
|
||||
// echos the status code it received"
|
||||
CloseConnection(aCode, aReason);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -406,10 +414,9 @@ nsWebSocket::GetInterface(const nsIID &aIID, void **aResult)
|
||||
nsWebSocket::nsWebSocket() : mKeepingAlive(false),
|
||||
mCheckMustKeepAlive(true),
|
||||
mTriggeredCloseEvent(false),
|
||||
mClosedCleanly(false),
|
||||
mDisconnected(false),
|
||||
mClientReasonCode(0),
|
||||
mServerReasonCode(nsIWebSocketChannel::CLOSE_ABNORMAL),
|
||||
mCloseEventWasClean(false),
|
||||
mCloseEventCode(nsIWebSocketChannel::CLOSE_ABNORMAL),
|
||||
mReadyState(nsIWebSocket::CONNECTING),
|
||||
mOutgoingBufferedAmount(0),
|
||||
mBinaryType(WS_BINARY_TYPE_BLOB),
|
||||
@ -623,7 +630,7 @@ public:
|
||||
~nsAutoCloseWS()
|
||||
{
|
||||
if (!mWebSocket->mChannel) {
|
||||
mWebSocket->CloseConnection();
|
||||
mWebSocket->CloseConnection(nsIWebSocketChannel::CLOSE_INTERNAL_ERROR);
|
||||
}
|
||||
}
|
||||
private:
|
||||
@ -906,9 +913,9 @@ nsWebSocket::SetReadyState(PRUint16 aNewReadyState)
|
||||
mReadyState = aNewReadyState;
|
||||
|
||||
// The close event must be dispatched asynchronously.
|
||||
rv = NS_DispatchToMainThread(new nsWSCloseEvent(this, mClosedCleanly,
|
||||
mServerReasonCode,
|
||||
mServerReason),
|
||||
rv = NS_DispatchToMainThread(new nsWSCloseEvent(this, mCloseEventWasClean,
|
||||
mCloseEventCode,
|
||||
mCloseEventReason),
|
||||
NS_DISPATCH_NORMAL);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to dispatch the close event");
|
||||
@ -1413,29 +1420,27 @@ nsWebSocket::Close(PRUint16 code, const nsAString & reason, PRUint8 argc)
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||
|
||||
// the reason code is optional, but if provided it must be in a specific range
|
||||
PRUint16 closeCode = 0;
|
||||
if (argc >= 1) {
|
||||
if (code != 1000 && (code < 3000 || code > 4999))
|
||||
if (code != 1000 && (code < 3000 || code > 4999)) {
|
||||
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||
}
|
||||
closeCode = code;
|
||||
}
|
||||
|
||||
nsCAutoString utf8Reason;
|
||||
nsCAutoString closeReason;
|
||||
if (argc >= 2) {
|
||||
if (ContainsUnpairedSurrogates(reason))
|
||||
if (ContainsUnpairedSurrogates(reason)) {
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
|
||||
CopyUTF16toUTF8(reason, utf8Reason);
|
||||
}
|
||||
CopyUTF16toUTF8(reason, closeReason);
|
||||
|
||||
// The API requires the UTF-8 string to be 123 or less bytes
|
||||
if (utf8Reason.Length() > 123)
|
||||
if (closeReason.Length() > 123) {
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
// Format checks for reason and code both passed, they can now be assigned.
|
||||
if (argc >= 1)
|
||||
mClientReasonCode = code;
|
||||
if (argc >= 2)
|
||||
mClientReason = utf8Reason;
|
||||
|
||||
if (mReadyState == nsIWebSocket::CLOSING ||
|
||||
mReadyState == nsIWebSocket::CLOSED) {
|
||||
return NS_OK;
|
||||
@ -1446,12 +1451,12 @@ nsWebSocket::Close(PRUint16 code, const nsAString & reason, PRUint8 argc)
|
||||
// before calling it
|
||||
nsRefPtr<nsWebSocket> kungfuDeathGrip = this;
|
||||
|
||||
FailConnection();
|
||||
FailConnection(closeCode, closeReason);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// mReadyState == nsIWebSocket::OPEN
|
||||
CloseConnection();
|
||||
CloseConnection(closeCode, closeReason);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1594,8 +1599,7 @@ nsWebSocket::Cancel(nsresult aStatus)
|
||||
return NS_OK;
|
||||
|
||||
ConsoleError();
|
||||
mClientReasonCode = nsIWebSocketChannel::CLOSE_GOING_AWAY;
|
||||
return CloseConnection();
|
||||
return CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -111,9 +111,11 @@ protected:
|
||||
nsresult ParseURL(const nsString& aURL);
|
||||
nsresult EstablishConnection();
|
||||
|
||||
// these three methods when called can release the WebSocket object
|
||||
nsresult FailConnection();
|
||||
nsresult CloseConnection();
|
||||
// These methods when called can release the WebSocket object
|
||||
nsresult FailConnection(PRUint16 reasonCode,
|
||||
const nsACString& aReasonString = EmptyCString());
|
||||
nsresult CloseConnection(PRUint16 reasonCode,
|
||||
const nsACString& aReasonString = EmptyCString());
|
||||
nsresult Disconnect();
|
||||
|
||||
nsresult ConsoleError();
|
||||
@ -166,13 +168,12 @@ protected:
|
||||
bool mKeepingAlive;
|
||||
bool mCheckMustKeepAlive;
|
||||
bool mTriggeredCloseEvent;
|
||||
bool mClosedCleanly;
|
||||
bool mDisconnected;
|
||||
|
||||
nsCString mClientReason;
|
||||
nsString mServerReason;
|
||||
PRUint16 mClientReasonCode;
|
||||
PRUint16 mServerReasonCode;
|
||||
// Set attributes of DOM 'onclose' message
|
||||
bool mCloseEventWasClean;
|
||||
nsString mCloseEventReason;
|
||||
PRUint16 mCloseEventCode;
|
||||
|
||||
nsCString mAsciiHost; // hostname
|
||||
PRUint32 mPort;
|
||||
|
@ -216,6 +216,28 @@ nsHTMLCanvasElement::ToDataURL(const nsAString& aType, nsIVariant* aParams,
|
||||
return ToDataURLImpl(aType, aParams, aDataURL);
|
||||
}
|
||||
|
||||
// nsHTMLCanvasElement::mozFetchAsStream
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLCanvasElement::MozFetchAsStream(nsIInputStreamCallback *aCallback,
|
||||
const nsAString& aType)
|
||||
{
|
||||
if (!nsContentUtils::IsCallerChrome())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsresult rv;
|
||||
bool fellBackToPNG = false;
|
||||
nsCOMPtr<nsIInputStream> inputData;
|
||||
|
||||
rv = ExtractData(aType, EmptyString(), getter_AddRefs(inputData), fellBackToPNG);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> asyncData = do_QueryInterface(inputData, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return aCallback->OnInputStreamReady(asyncData);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLCanvasElement::ExtractData(const nsAString& aType,
|
||||
const nsAString& aOptions,
|
||||
|
@ -2087,10 +2087,6 @@ nsresult nsHTMLMediaElement::FinishDecoderSetup(nsMediaDecoder* aDecoder)
|
||||
{
|
||||
NS_ASSERTION(mLoadingSrc, "mLoadingSrc set up");
|
||||
|
||||
nsCAutoString src;
|
||||
GetCurrentSpec(src);
|
||||
printf("*** nsHTMLElement::FinishDecoderSetup() mDecoder=%p stream=%p src=%s\n",
|
||||
aDecoder, aDecoder->GetStream(), src.get());
|
||||
mDecoder = aDecoder;
|
||||
AddMediaElementToURITable();
|
||||
|
||||
@ -2490,15 +2486,7 @@ ImageContainer* nsHTMLMediaElement::GetImageContainer()
|
||||
if (!video)
|
||||
return nsnull;
|
||||
|
||||
nsRefPtr<LayerManager> manager =
|
||||
nsContentUtils::PersistentLayerManagerForDocument(OwnerDoc());
|
||||
if (!manager)
|
||||
return nsnull;
|
||||
|
||||
mImageContainer = manager->CreateImageContainer();
|
||||
if (manager->IsCompositingCheap()) {
|
||||
mImageContainer->SetDelayedConversion(true);
|
||||
}
|
||||
mImageContainer = LayerManager::CreateImageContainer();
|
||||
return mImageContainer;
|
||||
}
|
||||
|
||||
|
@ -60,6 +60,11 @@ extern "C" {
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#if defined(MOZ_CUBEB)
|
||||
#include "nsAutoRef.h"
|
||||
#include "cubeb/cubeb.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
@ -78,6 +83,10 @@ using mozilla::TimeStamp;
|
||||
PRLogModuleInfo* gAudioStreamLog = nsnull;
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_CUBEB)
|
||||
static cubeb* gCubebContext;
|
||||
#endif
|
||||
|
||||
static const PRUint32 FAKE_BUFFER_SIZE = 176400;
|
||||
|
||||
// Number of milliseconds per second.
|
||||
@ -170,9 +179,9 @@ class AudioInitEvent : public nsRunnable
|
||||
{
|
||||
ContentChild * cpc = ContentChild::GetSingleton();
|
||||
NS_ASSERTION(cpc, "Content Protocol is NULL!");
|
||||
mOwner->mAudioChild = static_cast<AudioChild*> (cpc->SendPAudioConstructor(mOwner->mChannels,
|
||||
mOwner->mRate,
|
||||
mOwner->mFormat));
|
||||
mOwner->mAudioChild = static_cast<AudioChild*>(cpc->SendPAudioConstructor(mOwner->mChannels,
|
||||
mOwner->mRate,
|
||||
mOwner->mFormat));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -316,42 +325,78 @@ class AudioShutdownEvent : public nsRunnable
|
||||
};
|
||||
#endif
|
||||
|
||||
static mozilla::Mutex* gVolumeScaleLock = nsnull;
|
||||
#define PREF_VOLUME_SCALE "media.volume_scale"
|
||||
#define PREF_USE_CUBEB "media.use_cubeb"
|
||||
|
||||
static mozilla::Mutex* gAudioPrefsLock = nsnull;
|
||||
static double gVolumeScale = 1.0;
|
||||
static bool gUseCubeb = false;
|
||||
|
||||
static int VolumeScaleChanged(const char* aPref, void *aClosure) {
|
||||
nsAdoptingString value = Preferences::GetString("media.volume_scale");
|
||||
mozilla::MutexAutoLock lock(*gVolumeScaleLock);
|
||||
if (value.IsEmpty()) {
|
||||
gVolumeScale = 1.0;
|
||||
} else {
|
||||
NS_ConvertUTF16toUTF8 utf8(value);
|
||||
gVolumeScale = NS_MAX<double>(0, PR_strtod(utf8.get(), nsnull));
|
||||
static int PrefChanged(const char* aPref, void* aClosure)
|
||||
{
|
||||
if (strcmp(aPref, PREF_VOLUME_SCALE) == 0) {
|
||||
nsAdoptingString value = Preferences::GetString(aPref);
|
||||
mozilla::MutexAutoLock lock(*gAudioPrefsLock);
|
||||
if (value.IsEmpty()) {
|
||||
gVolumeScale = 1.0;
|
||||
} else {
|
||||
NS_ConvertUTF16toUTF8 utf8(value);
|
||||
gVolumeScale = NS_MAX<double>(0, PR_strtod(utf8.get(), nsnull));
|
||||
}
|
||||
} else if (strcmp(aPref, PREF_USE_CUBEB) == 0) {
|
||||
bool value = Preferences::GetBool(aPref, true);
|
||||
mozilla::MutexAutoLock lock(*gAudioPrefsLock);
|
||||
gUseCubeb = value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static double GetVolumeScale() {
|
||||
mozilla::MutexAutoLock lock(*gVolumeScaleLock);
|
||||
static double GetVolumeScale()
|
||||
{
|
||||
mozilla::MutexAutoLock lock(*gAudioPrefsLock);
|
||||
return gVolumeScale;
|
||||
}
|
||||
|
||||
#if defined(MOZ_CUBEB)
|
||||
static bool GetUseCubeb()
|
||||
{
|
||||
mozilla::MutexAutoLock lock(*gAudioPrefsLock);
|
||||
return gUseCubeb;
|
||||
}
|
||||
#endif
|
||||
|
||||
void nsAudioStream::InitLibrary()
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
gAudioStreamLog = PR_NewLogModule("nsAudioStream");
|
||||
#endif
|
||||
gVolumeScaleLock = new mozilla::Mutex("nsAudioStream::gVolumeScaleLock");
|
||||
VolumeScaleChanged(nsnull, nsnull);
|
||||
Preferences::RegisterCallback(VolumeScaleChanged, "media.volume_scale");
|
||||
gAudioPrefsLock = new mozilla::Mutex("nsAudioStream::gAudioPrefsLock");
|
||||
PrefChanged(PREF_VOLUME_SCALE, nsnull);
|
||||
Preferences::RegisterCallback(PrefChanged, PREF_VOLUME_SCALE);
|
||||
#if defined(MOZ_CUBEB)
|
||||
PrefChanged(PREF_USE_CUBEB, nsnull);
|
||||
Preferences::RegisterCallback(PrefChanged, PREF_USE_CUBEB);
|
||||
if (cubeb_init(&gCubebContext, "nsAudioStream") != 0) {
|
||||
NS_WARNING("cubeb_init failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void nsAudioStream::ShutdownLibrary()
|
||||
{
|
||||
Preferences::UnregisterCallback(VolumeScaleChanged, "media.volume_scale");
|
||||
delete gVolumeScaleLock;
|
||||
gVolumeScaleLock = nsnull;
|
||||
Preferences::UnregisterCallback(PrefChanged, PREF_VOLUME_SCALE);
|
||||
#if defined(MOZ_CUBEB)
|
||||
Preferences::UnregisterCallback(PrefChanged, PREF_USE_CUBEB);
|
||||
#endif
|
||||
delete gAudioPrefsLock;
|
||||
gAudioPrefsLock = nsnull;
|
||||
|
||||
#if defined(MOZ_CUBEB)
|
||||
if (gCubebContext) {
|
||||
cubeb_destroy(gCubebContext);
|
||||
gCubebContext = nsnull;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
nsIThread *
|
||||
@ -365,16 +410,6 @@ nsAudioStream::GetThread()
|
||||
return mAudioPlaybackThread;
|
||||
}
|
||||
|
||||
nsAudioStream* nsAudioStream::AllocateStream()
|
||||
{
|
||||
#if defined(REMOTE_AUDIO)
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Content) {
|
||||
return new nsRemotedAudioStream();
|
||||
}
|
||||
#endif
|
||||
return new nsNativeAudioStream();
|
||||
}
|
||||
|
||||
class AsyncShutdownPlaybackThread : public nsRunnable
|
||||
{
|
||||
public:
|
||||
@ -770,3 +805,398 @@ nsRemotedAudioStream::IsPaused()
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_CUBEB)
|
||||
template <>
|
||||
class nsAutoRefTraits<cubeb_stream> : public nsPointerRefTraits<cubeb_stream>
|
||||
{
|
||||
public:
|
||||
static void Release(cubeb_stream* aStream) { cubeb_stream_destroy(aStream); }
|
||||
};
|
||||
|
||||
class nsBufferedAudioStream : public nsAudioStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsBufferedAudioStream();
|
||||
~nsBufferedAudioStream();
|
||||
|
||||
nsresult Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat aFormat);
|
||||
void Shutdown();
|
||||
nsresult Write(const void* aBuf, PRUint32 aFrames);
|
||||
PRUint32 Available();
|
||||
void SetVolume(double aVolume);
|
||||
void Drain();
|
||||
void Pause();
|
||||
void Resume();
|
||||
PRInt64 GetPosition();
|
||||
PRInt64 GetPositionInFrames();
|
||||
bool IsPaused();
|
||||
PRInt32 GetMinWriteSize();
|
||||
|
||||
private:
|
||||
static long DataCallback_S(cubeb_stream*, void* aThis, void* aBuffer, long aFrames)
|
||||
{
|
||||
return static_cast<nsBufferedAudioStream*>(aThis)->DataCallback(aBuffer, aFrames);
|
||||
}
|
||||
|
||||
static int StateCallback_S(cubeb_stream*, void* aThis, cubeb_state aState)
|
||||
{
|
||||
return static_cast<nsBufferedAudioStream*>(aThis)->StateCallback(aState);
|
||||
}
|
||||
|
||||
long DataCallback(void* aBuffer, long aFrames);
|
||||
int StateCallback(cubeb_state aState);
|
||||
|
||||
// Shared implementation of underflow adjusted position calculation.
|
||||
// Caller must own the monitor.
|
||||
PRInt64 GetPositionInFramesUnlocked();
|
||||
|
||||
// The monitor is held to protect all access to member variables. Write()
|
||||
// waits while mBuffer is full; DataCallback() notifies as it consumes
|
||||
// data from mBuffer. Drain() waits while mState is DRAINING;
|
||||
// StateCallback() notifies when mState is DRAINED.
|
||||
Monitor mMonitor;
|
||||
|
||||
// Sum of silent frames written when DataCallback requests more frames
|
||||
// than are available in mBuffer.
|
||||
PRUint64 mLostFrames;
|
||||
|
||||
// Temporary audio buffer. Filled by Write() and consumed by
|
||||
// DataCallback(). Once mBufferLimit is reached, Write() blocks until
|
||||
// sufficient space becomes available in mBuffer. The buffer and buffer
|
||||
// limit deal in bytes, not frames.
|
||||
nsTArray<PRUint8> mBuffer;
|
||||
PRUint32 mBufferLimit;
|
||||
|
||||
// Software volume level. Applied during the servicing of DataCallback().
|
||||
double mVolume;
|
||||
|
||||
// Owning reference to a cubeb_stream. cubeb_stream_destroy is called by
|
||||
// nsAutoRef's destructor.
|
||||
nsAutoRef<cubeb_stream> mCubebStream;
|
||||
|
||||
PRInt32 mRate;
|
||||
PRInt32 mChannels;
|
||||
SampleFormat mFormat;
|
||||
PRUint32 mBytesPerFrame;
|
||||
|
||||
enum StreamState {
|
||||
INITIALIZED, // Initialized, playback has not begun.
|
||||
STARTED, // Started by a call to Write() (iff INITIALIZED) or Resume().
|
||||
STOPPED, // Stopped by a call to Pause().
|
||||
DRAINING, // Drain requested. DataCallback will indicate end of stream
|
||||
// once the remaining contents of mBuffer are requested by
|
||||
// cubeb, after which StateCallback will indicate drain
|
||||
// completion.
|
||||
DRAINED // StateCallback has indicated that the drain is complete.
|
||||
};
|
||||
|
||||
StreamState mState;
|
||||
|
||||
// Arbitrary default stream latency. The higher this value, the longer stream
|
||||
// volume changes will take to become audible.
|
||||
static const unsigned int DEFAULT_LATENCY_MS = 100;
|
||||
};
|
||||
#endif
|
||||
|
||||
nsAudioStream* nsAudioStream::AllocateStream()
|
||||
{
|
||||
#if defined(REMOTE_AUDIO)
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Content) {
|
||||
return new nsRemotedAudioStream();
|
||||
}
|
||||
#endif
|
||||
#if defined(MOZ_CUBEB)
|
||||
if (GetUseCubeb()) {
|
||||
return new nsBufferedAudioStream();
|
||||
}
|
||||
#endif
|
||||
return new nsNativeAudioStream();
|
||||
}
|
||||
|
||||
#if defined(MOZ_CUBEB)
|
||||
nsBufferedAudioStream::nsBufferedAudioStream()
|
||||
: mMonitor("nsBufferedAudioStream"), mLostFrames(0), mVolume(1.0), mRate(0), mChannels(0),
|
||||
mBytesPerFrame(0), mState(INITIALIZED)
|
||||
{
|
||||
}
|
||||
|
||||
nsBufferedAudioStream::~nsBufferedAudioStream()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS0(nsBufferedAudioStream)
|
||||
|
||||
nsresult
|
||||
nsBufferedAudioStream::Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat aFormat)
|
||||
{
|
||||
if (!gCubebContext || aNumChannels < 0 || aRate < 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mRate = aRate;
|
||||
mChannels = aNumChannels;
|
||||
mFormat = aFormat;
|
||||
|
||||
cubeb_stream_params params;
|
||||
params.rate = aRate;
|
||||
params.channels = aNumChannels;
|
||||
switch (aFormat) {
|
||||
case FORMAT_S16_LE:
|
||||
params.format = CUBEB_SAMPLE_S16LE;
|
||||
mBytesPerFrame = sizeof(short) * aNumChannels;
|
||||
break;
|
||||
case FORMAT_FLOAT32:
|
||||
params.format = CUBEB_SAMPLE_FLOAT32LE;
|
||||
mBytesPerFrame = sizeof(float) * aNumChannels;
|
||||
break;
|
||||
default:
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
{
|
||||
cubeb_stream* stream;
|
||||
if (cubeb_stream_init(gCubebContext, &stream, "nsBufferedAudioStream", params,
|
||||
DEFAULT_LATENCY_MS, DataCallback_S, StateCallback_S, this) == CUBEB_OK) {
|
||||
mCubebStream.own(stream);
|
||||
}
|
||||
}
|
||||
|
||||
if (!mCubebStream) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Limit mBuffer to one second of audio. This value is arbitrary, and was
|
||||
// selected based on the observed behaviour of the existing nsAudioStream
|
||||
// implementations.
|
||||
mBufferLimit = aRate * mBytesPerFrame;
|
||||
NS_ABORT_IF_FALSE(mBufferLimit % mBytesPerFrame == 0, "Must buffer complete frames");
|
||||
|
||||
// Pre-allocate the buffer. nsTArray::RemoveElementsAt shrinks the buffer
|
||||
// only if its length reaches zero, so allocator thrashing should be
|
||||
// minimal.
|
||||
mBuffer.SetCapacity(mBufferLimit);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsBufferedAudioStream::Shutdown()
|
||||
{
|
||||
if (mCubebStream) {
|
||||
cubeb_stream_stop(mCubebStream);
|
||||
mCubebStream.reset();
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBufferedAudioStream::Write(const void* aBuf, PRUint32 aFrames)
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
if (!mCubebStream) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
NS_ASSERTION(mState == INITIALIZED || mState == STARTED, "Stream write in unexpected state.");
|
||||
|
||||
const PRUint8* src = static_cast<const PRUint8*>(aBuf);
|
||||
PRUint32 bytesToCopy = aFrames * mBytesPerFrame;
|
||||
|
||||
while (bytesToCopy > 0) {
|
||||
NS_ABORT_IF_FALSE(mBuffer.Length() <= mBufferLimit, "Buffer invariant violated.");
|
||||
|
||||
PRUint32 available = NS_MIN(bytesToCopy, mBufferLimit - mBuffer.Length());
|
||||
NS_ABORT_IF_FALSE(available % mBytesPerFrame == 0, "Must copy complete frames.");
|
||||
|
||||
mBuffer.AppendElements(src, available);
|
||||
src += available;
|
||||
bytesToCopy -= available;
|
||||
|
||||
if (mState != STARTED && cubeb_stream_start(mCubebStream) == CUBEB_OK) {
|
||||
mState = STARTED;
|
||||
}
|
||||
|
||||
if (bytesToCopy > 0) {
|
||||
mon.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsBufferedAudioStream::Available()
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
NS_ABORT_IF_FALSE(mBuffer.Length() <= mBufferLimit, "Buffer invariant violated.");
|
||||
NS_ABORT_IF_FALSE(mBuffer.Length() % mBytesPerFrame == 0, "Buffer invariant violated.");
|
||||
return (mBufferLimit - mBuffer.Length()) / mBytesPerFrame;
|
||||
}
|
||||
|
||||
PRInt32 nsBufferedAudioStream::GetMinWriteSize()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
nsBufferedAudioStream::SetVolume(double aVolume)
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
NS_ABORT_IF_FALSE(aVolume >= 0.0 && aVolume <= 1.0, "Invalid volume");
|
||||
mVolume = aVolume;
|
||||
}
|
||||
|
||||
void
|
||||
nsBufferedAudioStream::Drain()
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
if (mState != STARTED) {
|
||||
return;
|
||||
}
|
||||
mState = DRAINING;
|
||||
while (mState != DRAINED) {
|
||||
mon.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsBufferedAudioStream::Pause()
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
if (!mCubebStream || mState != STARTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cubeb_stream_stop(mCubebStream) == CUBEB_OK) {
|
||||
mState = STOPPED;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsBufferedAudioStream::Resume()
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
if (!mCubebStream || mState != STOPPED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cubeb_stream_start(mCubebStream) == CUBEB_OK) {
|
||||
mState = STARTED;
|
||||
}
|
||||
}
|
||||
|
||||
PRInt64 nsBufferedAudioStream::GetPosition()
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
PRInt64 frames = GetPositionInFramesUnlocked();
|
||||
if (frames >= 0) {
|
||||
return USECS_PER_S * frames / mRate;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
PRInt64
|
||||
nsBufferedAudioStream::GetPositionInFrames()
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
return GetPositionInFramesUnlocked();
|
||||
}
|
||||
|
||||
PRInt64
|
||||
nsBufferedAudioStream::GetPositionInFramesUnlocked()
|
||||
{
|
||||
mMonitor.AssertCurrentThreadOwns();
|
||||
|
||||
if (!mCubebStream) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint64_t position = 0;
|
||||
if (cubeb_stream_get_position(mCubebStream, &position) != CUBEB_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Adjust the reported position by the number of silent frames written
|
||||
// during stream underruns.
|
||||
PRInt64 adjustedPosition = 0;
|
||||
if (position >= mLostFrames) {
|
||||
adjustedPosition = position - mLostFrames;
|
||||
}
|
||||
return adjustedPosition;
|
||||
}
|
||||
|
||||
bool
|
||||
nsBufferedAudioStream::IsPaused()
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
return mState == STOPPED;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void
|
||||
SampleCopy(void* aDst, const PRUint8* aSrc, PRUint32 aSamples, double aVolume)
|
||||
{
|
||||
const T* src = reinterpret_cast<const T*>(aSrc);
|
||||
double scaled_volume = GetVolumeScale() * aVolume;
|
||||
T* dst = static_cast<T*>(aDst);
|
||||
for (PRUint32 i = 0; i < aSamples; ++i) {
|
||||
dst[i] = T(src[i] * scaled_volume);
|
||||
}
|
||||
}
|
||||
|
||||
long
|
||||
nsBufferedAudioStream::DataCallback(void* aBuffer, long aFrames)
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
PRUint32 bytesWanted = aFrames * mBytesPerFrame;
|
||||
|
||||
// Adjust bytesWanted to fit what is available in mBuffer.
|
||||
PRUint32 available = NS_MIN(bytesWanted, mBuffer.Length());
|
||||
NS_ABORT_IF_FALSE(available % mBytesPerFrame == 0, "Must copy complete frames");
|
||||
|
||||
// Copy each sample from mBuffer to aBuffer, adjusting the volume during the copy.
|
||||
PRUint32 samplesToCopy = available / mBytesPerFrame * mChannels;
|
||||
switch (mFormat) {
|
||||
case FORMAT_S16_LE:
|
||||
SampleCopy<PRInt16>(aBuffer, mBuffer.Elements(), samplesToCopy, mVolume);
|
||||
break;
|
||||
case FORMAT_FLOAT32:
|
||||
SampleCopy<float>(aBuffer, mBuffer.Elements(), samplesToCopy, mVolume);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Remove copied data from the temporary audio buffer.
|
||||
mBuffer.RemoveElementsAt(0, available);
|
||||
NS_ABORT_IF_FALSE(mBuffer.Length() % mBytesPerFrame == 0, "Must copy complete frames");
|
||||
|
||||
// Notify any blocked Write() call that more space is available in mBuffer.
|
||||
mon.NotifyAll();
|
||||
|
||||
// Calculate remaining bytes requested by caller. If the stream is not
|
||||
// draining an underrun has occurred, so fill the remaining buffer with
|
||||
// silence.
|
||||
bytesWanted -= available;
|
||||
if (mState != DRAINING) {
|
||||
memset(static_cast<PRUint8*>(aBuffer) + available, 0, bytesWanted);
|
||||
mLostFrames += bytesWanted / mBytesPerFrame;
|
||||
bytesWanted = 0;
|
||||
}
|
||||
|
||||
return aFrames - (bytesWanted / mBytesPerFrame);
|
||||
}
|
||||
|
||||
int
|
||||
nsBufferedAudioStream::StateCallback(cubeb_state aState)
|
||||
{
|
||||
if (aState == CUBEB_STATE_DRAINED) {
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
mState = DRAINED;
|
||||
mon.NotifyAll();
|
||||
}
|
||||
return CUBEB_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -233,7 +233,7 @@ const PRUint8 nsSMILTimedElement::sMaxNumInstanceTimes = 100;
|
||||
|
||||
// Detect if we arrive in some sort of undetected recursive syncbase dependency
|
||||
// relationship
|
||||
const PRUint16 nsSMILTimedElement::sMaxUpdateIntervalRecursionDepth = 20;
|
||||
const PRUint8 nsSMILTimedElement::sMaxUpdateIntervalRecursionDepth = 20;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Ctor, dtor
|
||||
@ -252,6 +252,7 @@ nsSMILTimedElement::nsSMILTimedElement()
|
||||
mSeekState(SEEK_NOT_SEEKING),
|
||||
mDeferIntervalUpdates(false),
|
||||
mDoDeferredUpdate(false),
|
||||
mDeleteCount(0),
|
||||
mUpdateIntervalRecursionDepth(0)
|
||||
{
|
||||
mSimpleDur.SetIndefinite();
|
||||
@ -1960,12 +1961,29 @@ nsSMILTimedElement::UpdateCurrentInterval(bool aForceChangeNotice)
|
||||
if (mElementState == STATE_STARTUP)
|
||||
return;
|
||||
|
||||
// Although SMIL gives rules for detecting cycles in change notifications,
|
||||
// some configurations can lead to create-delete-create-delete-etc. cycles
|
||||
// which SMIL does not consider.
|
||||
//
|
||||
// In order to provide consistent behavior in such cases, we detect two
|
||||
// deletes in a row and then refuse to create any further intervals. That is,
|
||||
// we say the configuration is invalid.
|
||||
if (mDeleteCount > 1) {
|
||||
// When we update the delete count we also set the state to post active, so
|
||||
// if we're not post active here then something other than
|
||||
// UpdateCurrentInterval has updated the element state in between and all
|
||||
// bets are off.
|
||||
NS_ABORT_IF_FALSE(mElementState == STATE_POSTACTIVE,
|
||||
"Expected to be in post-active state after performing double delete");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that we aren't stuck in infinite recursion updating some syncbase
|
||||
// dependencies. Generally such situations should be detected in advance and
|
||||
// the chain broken in a sensible and predictable manner, so if we're hitting
|
||||
// this assertion we need to work out how to detect the case that's causing
|
||||
// it. In release builds, just bail out before we overflow the stack.
|
||||
AutoRestore<PRUint16> depthRestorer(mUpdateIntervalRecursionDepth);
|
||||
AutoRestore<PRUint8> depthRestorer(mUpdateIntervalRecursionDepth);
|
||||
if (++mUpdateIntervalRecursionDepth > sMaxUpdateIntervalRecursionDepth) {
|
||||
NS_ABORT_IF_FALSE(false,
|
||||
"Update current interval recursion depth exceeded threshold");
|
||||
@ -2026,6 +2044,8 @@ nsSMILTimedElement::UpdateCurrentInterval(bool aForceChangeNotice)
|
||||
// sample (along with firing end events, clearing intervals etc.)
|
||||
RegisterMilestone();
|
||||
} else if (mElementState == STATE_WAITING) {
|
||||
AutoRestore<PRUint8> deleteCountRestorer(mDeleteCount);
|
||||
++mDeleteCount;
|
||||
mElementState = STATE_POSTACTIVE;
|
||||
ResetCurrentInterval();
|
||||
}
|
||||
|
@ -625,13 +625,13 @@ protected:
|
||||
// Used to batch updates to the timing model
|
||||
class AutoIntervalUpdateBatcher;
|
||||
bool mDeferIntervalUpdates;
|
||||
bool mDoDeferredUpdate; // Set if an update to the current interval
|
||||
// was requested while mDeferIntervalUpdates
|
||||
// was set
|
||||
bool mDoDeferredUpdate; // Set if an update to the current interval was
|
||||
// requested while mDeferIntervalUpdates was set
|
||||
|
||||
// Recursion depth checking
|
||||
PRUint16 mUpdateIntervalRecursionDepth;
|
||||
static const PRUint16 sMaxUpdateIntervalRecursionDepth;
|
||||
PRUint8 mDeleteCount;
|
||||
PRUint8 mUpdateIntervalRecursionDepth;
|
||||
static const PRUint8 sMaxUpdateIntervalRecursionDepth;
|
||||
};
|
||||
|
||||
#endif // NS_SMILTIMEDELEMENT_H_
|
||||
|
@ -4927,7 +4927,7 @@ GenerateNormal(float *N, const PRUint8 *data, PRInt32 stride,
|
||||
PRInt32 x, PRInt32 y, float surfaceScale)
|
||||
{
|
||||
// See this for source of constants:
|
||||
// http://www.w3.org/TR/SVG11/filters.html#feDiffuseLighting
|
||||
// http://www.w3.org/TR/SVG11/filters.html#feDiffuseLightingElement
|
||||
static const PRInt8 Kx[3][3][3][3] =
|
||||
{ { { { 0, 0, 0}, { 0, -2, 2}, { 0, -1, 1} },
|
||||
{ { 0, 0, 0}, {-2, 0, 2}, {-1, 0, 1} },
|
||||
|
@ -655,8 +655,16 @@ nsSHEntry::RemoveChild(nsISHEntry * aChild)
|
||||
childRemoved = mChildren.ReplaceObjectAt(nsnull, index);
|
||||
}
|
||||
}
|
||||
if (childRemoved)
|
||||
if (childRemoved) {
|
||||
aChild->SetParent(nsnull);
|
||||
|
||||
// reduce the child count, i.e. remove empty children at the end
|
||||
for (PRInt32 i = mChildren.Count() - 1; i >= 0 && !mChildren[i]; --i) {
|
||||
if (!mChildren.RemoveObjectAt(i)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
14
dom/base/crashtests/693811-1.html
Normal file
14
dom/base/crashtests/693811-1.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
|
||||
var collection = document.images;
|
||||
var other = document.embeds;
|
||||
var options = document.createElement("select").options;
|
||||
collection.toString;
|
||||
options.selectedIndex;
|
||||
Object.getPrototypeOf(collection).item = {};
|
||||
other.toString;
|
||||
collection.toString;
|
||||
options.selectedIndex;
|
||||
options.toString;
|
||||
</script>
|
16
dom/base/crashtests/693811-2.html
Normal file
16
dom/base/crashtests/693811-2.html
Normal file
@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
|
||||
var collection = document.images;
|
||||
var other = document.embeds;
|
||||
var options = document.createElement("select").options;
|
||||
collection.toString;
|
||||
options.selectedIndex;
|
||||
Object.defineProperty(Object.getPrototypeOf(collection),
|
||||
"item",
|
||||
{ value: {}, enumerable: true, configurable: true });
|
||||
other.toString;
|
||||
collection.toString;
|
||||
options.selectedIndex;
|
||||
options.toString;
|
||||
</script>
|
4
dom/base/crashtests/693811-3.html
Normal file
4
dom/base/crashtests/693811-3.html
Normal file
@ -0,0 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
document.createElement("p").constructor = function(){};
|
||||
</script>
|
@ -30,6 +30,9 @@ load 637116.html
|
||||
load 666869.html
|
||||
load 675621-1.html
|
||||
load 693894.html
|
||||
load 693811-1.html
|
||||
load 693811-2.html
|
||||
load 693811-3.html
|
||||
load 695867.html
|
||||
load 697643.html
|
||||
load 706283-1.html
|
||||
|
@ -88,14 +88,22 @@ AppendWindowURI(nsGlobalWindow *aWindow, nsACString& aStr)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
CollectWindowMemoryUsage(nsGlobalWindow *aWindow,
|
||||
nsIMemoryMultiReporterCallback *aCb,
|
||||
nsISupports *aClosure)
|
||||
struct WindowTotals
|
||||
{
|
||||
NS_NAMED_LITERAL_CSTRING(kWindowDesc,
|
||||
"Memory used by a window and the DOM within it.");
|
||||
WindowTotals() : mDom(0), mStyleSheets(0) {}
|
||||
size_t mDom;
|
||||
size_t mStyleSheets;
|
||||
};
|
||||
|
||||
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(WindowStyleSheetsMallocSizeOf,
|
||||
"window/style-sheets")
|
||||
|
||||
static void
|
||||
CollectWindowReports(nsGlobalWindow *aWindow,
|
||||
WindowTotals *aWindowTotals,
|
||||
nsIMemoryMultiReporterCallback *aCb,
|
||||
nsISupports *aClosure)
|
||||
{
|
||||
// DOM window objects fall into one of three categories:
|
||||
// - "active" windows are currently either displayed in an active
|
||||
// tab, or a child of such a window.
|
||||
@ -119,7 +127,7 @@ CollectWindowMemoryUsage(nsGlobalWindow *aWindow,
|
||||
// The path we give to the reporter callback for inner windows are
|
||||
// as follows:
|
||||
//
|
||||
// explicit/dom/window-objects/<category>/top=<top-outer-id> (inner=<top-inner-id>)/inner-window(id=<id>, uri=<uri>)
|
||||
// explicit/dom+style/window-objects/<category>/top=<top-outer-id> (inner=<top-inner-id>)/inner-window(id=<id>, uri=<uri>)
|
||||
//
|
||||
// Where:
|
||||
// - <category> is active, cached, or other, as described above.
|
||||
@ -138,62 +146,82 @@ CollectWindowMemoryUsage(nsGlobalWindow *aWindow,
|
||||
//
|
||||
// For outer windows we simply use:
|
||||
//
|
||||
// explicit/dom/window-objects/<category>/outer-windows
|
||||
// explicit/dom+style/window-objects/<category>/outer-windows
|
||||
//
|
||||
// Which gives us simple counts of how many outer windows (and their
|
||||
// combined sizes) per category.
|
||||
|
||||
nsCAutoString str("explicit/dom/window-objects/");
|
||||
nsCAutoString windowPath("explicit/dom+style/window-objects/");
|
||||
|
||||
nsIDocShell *docShell = aWindow->GetDocShell();
|
||||
|
||||
nsGlobalWindow *top = aWindow->GetTop();
|
||||
PRInt64 windowSize = aWindow->SizeOf();
|
||||
PRInt64 windowDOMSize = aWindow->SizeOf();
|
||||
PRInt64 styleSheetsSize = aWindow->SizeOfStyleSheets(WindowStyleSheetsMallocSizeOf);
|
||||
|
||||
if (docShell && aWindow->IsFrozen()) {
|
||||
str += NS_LITERAL_CSTRING("cached/");
|
||||
windowPath += NS_LITERAL_CSTRING("cached/");
|
||||
} else if (docShell) {
|
||||
str += NS_LITERAL_CSTRING("active/");
|
||||
windowPath += NS_LITERAL_CSTRING("active/");
|
||||
} else {
|
||||
str += NS_LITERAL_CSTRING("other/");
|
||||
windowPath += NS_LITERAL_CSTRING("other/");
|
||||
}
|
||||
|
||||
if (aWindow->IsInnerWindow()) {
|
||||
str += NS_LITERAL_CSTRING("top=");
|
||||
windowPath += NS_LITERAL_CSTRING("top=");
|
||||
|
||||
if (top) {
|
||||
str.AppendInt(top->WindowID());
|
||||
windowPath.AppendInt(top->WindowID());
|
||||
|
||||
nsGlobalWindow *topInner = top->GetCurrentInnerWindowInternal();
|
||||
if (topInner) {
|
||||
str += NS_LITERAL_CSTRING(" (inner=");
|
||||
str.AppendInt(topInner->WindowID());
|
||||
str += NS_LITERAL_CSTRING(")");
|
||||
windowPath += NS_LITERAL_CSTRING(" (inner=");
|
||||
windowPath.AppendInt(topInner->WindowID());
|
||||
windowPath += NS_LITERAL_CSTRING(")");
|
||||
}
|
||||
} else {
|
||||
str += NS_LITERAL_CSTRING("none");
|
||||
windowPath += NS_LITERAL_CSTRING("none");
|
||||
}
|
||||
|
||||
str += NS_LITERAL_CSTRING("/inner-window(id=");
|
||||
str.AppendInt(aWindow->WindowID());
|
||||
str += NS_LITERAL_CSTRING(", uri=");
|
||||
windowPath += NS_LITERAL_CSTRING("/inner-window(id=");
|
||||
windowPath.AppendInt(aWindow->WindowID());
|
||||
windowPath += NS_LITERAL_CSTRING(", uri=");
|
||||
|
||||
if (!AppendWindowURI(aWindow, str)) {
|
||||
str += NS_LITERAL_CSTRING("[system]");
|
||||
if (!AppendWindowURI(aWindow, windowPath)) {
|
||||
windowPath += NS_LITERAL_CSTRING("[system]");
|
||||
}
|
||||
|
||||
str += NS_LITERAL_CSTRING(")");
|
||||
windowPath += NS_LITERAL_CSTRING(")");
|
||||
} else {
|
||||
// Combine all outer windows per section (active/cached/other) as
|
||||
// they basically never contain anything of interest, and are
|
||||
// always pretty much the same size.
|
||||
|
||||
str += NS_LITERAL_CSTRING("outer-windows");
|
||||
windowPath += NS_LITERAL_CSTRING("outer-windows");
|
||||
}
|
||||
|
||||
aCb->Callback(EmptyCString(), str, nsIMemoryReporter::KIND_HEAP,
|
||||
nsIMemoryReporter::UNITS_BYTES, windowSize, kWindowDesc,
|
||||
aClosure);
|
||||
if (windowDOMSize > 0) {
|
||||
nsCAutoString domPath(windowPath);
|
||||
domPath += "/dom";
|
||||
NS_NAMED_LITERAL_CSTRING(kWindowDesc,
|
||||
"Memory used by a window and the DOM within it.");
|
||||
aCb->Callback(EmptyCString(), domPath, nsIMemoryReporter::KIND_HEAP,
|
||||
nsIMemoryReporter::UNITS_BYTES, windowDOMSize, kWindowDesc,
|
||||
aClosure);
|
||||
aWindowTotals->mDom += windowDOMSize;
|
||||
}
|
||||
|
||||
if (styleSheetsSize > 0) {
|
||||
nsCAutoString styleSheetsPath(windowPath);
|
||||
styleSheetsPath += "/style-sheets";
|
||||
NS_NAMED_LITERAL_CSTRING(kStyleSheetsDesc,
|
||||
"Memory used by style sheets within a window.");
|
||||
aCb->Callback(EmptyCString(), styleSheetsPath,
|
||||
nsIMemoryReporter::KIND_HEAP,
|
||||
nsIMemoryReporter::UNITS_BYTES, styleSheetsSize,
|
||||
kStyleSheetsDesc, aClosure);
|
||||
aWindowTotals->mStyleSheets += styleSheetsSize;
|
||||
}
|
||||
}
|
||||
|
||||
typedef nsTArray< nsRefPtr<nsGlobalWindow> > WindowArray;
|
||||
@ -223,10 +251,27 @@ nsDOMMemoryMultiReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb,
|
||||
// Collect window memory usage.
|
||||
nsRefPtr<nsGlobalWindow> *w = windows.Elements();
|
||||
nsRefPtr<nsGlobalWindow> *end = w + windows.Length();
|
||||
WindowTotals windowTotals;
|
||||
for (; w != end; ++w) {
|
||||
CollectWindowMemoryUsage(*w, aCb, aClosure);
|
||||
CollectWindowReports(*w, &windowTotals, aCb, aClosure);
|
||||
}
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(kDomTotalWindowsDesc,
|
||||
"Memory used for the DOM within windows. This is the sum of all windows' "
|
||||
"'dom' numbers.");
|
||||
aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING("dom-total-window"),
|
||||
nsIMemoryReporter::KIND_OTHER,
|
||||
nsIMemoryReporter::UNITS_BYTES, windowTotals.mDom,
|
||||
kDomTotalWindowsDesc, aClosure);
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(kLayoutTotalWindowStyleSheetsDesc,
|
||||
"Memory used for style sheets within windows. This is the sum of all windows' "
|
||||
"'style-sheets' numbers.");
|
||||
aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING("style-sheets-total-window"),
|
||||
nsIMemoryReporter::KIND_OTHER,
|
||||
nsIMemoryReporter::UNITS_BYTES, windowTotals.mStyleSheets,
|
||||
kLayoutTotalWindowStyleSheetsDesc, aClosure);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -817,7 +817,7 @@ nsDOMWindowUtils::GarbageCollect(nsICycleCollectorListener *aListener,
|
||||
}
|
||||
#endif
|
||||
|
||||
nsJSContext::GarbageCollectNow(js::gcreason::DOM_UTILS);
|
||||
nsJSContext::GarbageCollectNow(js::gcreason::DOM_UTILS, nsGCNormal, true);
|
||||
nsJSContext::CycleCollectNow(aListener, aExtraForgetSkippableCalls);
|
||||
|
||||
return NS_OK;
|
||||
|
@ -10296,6 +10296,16 @@ nsGlobalWindow::SizeOf() const
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t
|
||||
nsGlobalWindow::SizeOfStyleSheets(nsMallocSizeOfFun aMallocSizeOf) const
|
||||
{
|
||||
size_t n = 0;
|
||||
if (IsInnerWindow() && mDoc) {
|
||||
n += mDoc->SizeOfStyleSheets(aMallocSizeOf);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
// nsGlobalChromeWindow implementation
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalChromeWindow)
|
||||
|
@ -576,6 +576,7 @@ public:
|
||||
}
|
||||
|
||||
PRInt64 SizeOf() const;
|
||||
size_t SizeOfStyleSheets(nsMallocSizeOfFun aMallocSizeOf) const;
|
||||
|
||||
void UnmarkGrayTimers();
|
||||
private:
|
||||
|
@ -135,6 +135,8 @@ static PRLogModuleInfo* gJSDiagnostics;
|
||||
// doing the first GC.
|
||||
#define NS_FIRST_GC_DELAY 10000 // ms
|
||||
|
||||
#define NS_FULL_GC_DELAY 60000 // ms
|
||||
|
||||
// The amount of time we wait between a request to CC (after GC ran)
|
||||
// and doing the actual CC.
|
||||
#define NS_CC_DELAY 5000 // ms
|
||||
@ -148,6 +150,7 @@ static PRLogModuleInfo* gJSDiagnostics;
|
||||
// if you add statics here, add them to the list in nsJSRuntime::Startup
|
||||
|
||||
static nsITimer *sGCTimer;
|
||||
static nsITimer *sFullGCTimer;
|
||||
static nsITimer *sShrinkGCBuffersTimer;
|
||||
static nsITimer *sCCTimer;
|
||||
|
||||
@ -166,6 +169,7 @@ static bool sLoadingInProgress;
|
||||
|
||||
static PRUint32 sCCollectedWaitingForGC;
|
||||
static bool sPostGCEventsToConsole;
|
||||
static bool sDisableExplicitCompartmentGC;
|
||||
static PRUint32 sCCTimerFireCount = 0;
|
||||
static PRUint32 sMinForgetSkippableTime = PR_UINT32_MAX;
|
||||
static PRUint32 sMaxForgetSkippableTime = 0;
|
||||
@ -173,9 +177,15 @@ static PRUint32 sTotalForgetSkippableTime = 0;
|
||||
static PRUint32 sRemovedPurples = 0;
|
||||
static PRUint32 sForgetSkippableBeforeCC = 0;
|
||||
static PRUint32 sPreviousSuspectedCount = 0;
|
||||
static PRUint32 sCompartmentGCCount = 0;
|
||||
static nsJSContext* sTopEvaluator = nsnull;
|
||||
static bool sContextDeleted = false;
|
||||
static bool sPreviousWasChromeCompGC = false;
|
||||
|
||||
static bool sCleanupSinceLastGC = true;
|
||||
|
||||
PRUint32 nsJSContext::sGlobalGCEpoch = 0;
|
||||
|
||||
nsScriptNameSpaceManager *gNameSpaceManager;
|
||||
|
||||
static nsIJSRuntimeService *sRuntimeService;
|
||||
@ -216,7 +226,8 @@ nsMemoryPressureObserver::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
const PRUnichar* aData)
|
||||
{
|
||||
if (sGCOnMemoryPressure) {
|
||||
nsJSContext::GarbageCollectNow(js::gcreason::MEM_PRESSURE, nsGCShrinking);
|
||||
nsJSContext::GarbageCollectNow(js::gcreason::MEM_PRESSURE, nsGCShrinking,
|
||||
true);
|
||||
nsJSContext::CycleCollectNow();
|
||||
}
|
||||
return NS_OK;
|
||||
@ -938,6 +949,8 @@ static const char js_pccounts_content_str[] = JS_OPTIONS_DOT_STR "pccounts.con
|
||||
static const char js_pccounts_chrome_str[] = JS_OPTIONS_DOT_STR "pccounts.chrome";
|
||||
static const char js_jit_hardening_str[] = JS_OPTIONS_DOT_STR "jit_hardening";
|
||||
static const char js_memlog_option_str[] = JS_OPTIONS_DOT_STR "mem.log";
|
||||
static const char js_disable_explicit_compartment_gc[] =
|
||||
JS_OPTIONS_DOT_STR "disable_explicit_compartment_gc";
|
||||
|
||||
int
|
||||
nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
|
||||
@ -947,6 +960,8 @@ nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
|
||||
PRUint32 newDefaultJSOptions = oldDefaultJSOptions;
|
||||
|
||||
sPostGCEventsToConsole = Preferences::GetBool(js_memlog_option_str);
|
||||
sDisableExplicitCompartmentGC =
|
||||
Preferences::GetBool(js_disable_explicit_compartment_gc);
|
||||
|
||||
bool strict = Preferences::GetBool(js_strict_option_str);
|
||||
if (strict)
|
||||
@ -1048,6 +1063,9 @@ nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
|
||||
|
||||
nsJSContext::nsJSContext(JSRuntime *aRuntime)
|
||||
: mGCOnDestruction(true),
|
||||
mChromeComp(false),
|
||||
mGlobalGCEpoch(0),
|
||||
mEvaluationCount(0),
|
||||
mExecuteDepth(0)
|
||||
{
|
||||
|
||||
@ -1098,6 +1116,9 @@ nsJSContext::~nsJSContext()
|
||||
DestroyJSContext();
|
||||
|
||||
--sContextCount;
|
||||
if (sTopEvaluator == this) {
|
||||
sTopEvaluator = nsnull;
|
||||
}
|
||||
|
||||
if (!sContextCount && sDidShutdown) {
|
||||
// The last context is being deleted, and we're already in the
|
||||
@ -1124,6 +1145,7 @@ nsJSContext::DestroyJSContext()
|
||||
js_options_dot_str, this);
|
||||
|
||||
if (mGCOnDestruction) {
|
||||
sContextDeleted = true;
|
||||
PokeGC(js::gcreason::NSJSCONTEXT_DESTROY);
|
||||
}
|
||||
|
||||
@ -2237,6 +2259,7 @@ nsJSContext::CreateNativeGlobalForInner(
|
||||
{
|
||||
nsIXPConnect *xpc = nsContentUtils::XPConnect();
|
||||
PRUint32 flags = aIsChrome? nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT : 0;
|
||||
mChromeComp = aIsChrome;
|
||||
|
||||
nsCOMPtr<nsIPrincipal> systemPrincipal;
|
||||
if (aIsChrome) {
|
||||
@ -3159,6 +3182,12 @@ nsJSContext::ScriptEvaluated(bool aTerminated)
|
||||
if (aTerminated && mExecuteDepth == 0 && !JS_IsRunning(mContext)) {
|
||||
mOperationCallbackTime = 0;
|
||||
mModalStateTime = 0;
|
||||
|
||||
IncreaseEvaluationCount(this);
|
||||
if (EvaluationCount(sTopEvaluator) < EvaluationCount(this) &&
|
||||
(!mChromeComp || !sPreviousWasChromeCompGC)) {
|
||||
sTopEvaluator = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3231,9 +3260,20 @@ nsJSContext::ScriptExecuted()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
FullGCTimerFired(nsITimer* aTimer, void* aClosure)
|
||||
{
|
||||
NS_RELEASE(sFullGCTimer);
|
||||
|
||||
uintptr_t reason = reinterpret_cast<uintptr_t>(aClosure);
|
||||
nsJSContext::GarbageCollectNow(static_cast<js::gcreason::Reason>(reason),
|
||||
nsGCNormal, true);
|
||||
}
|
||||
|
||||
//static
|
||||
void
|
||||
nsJSContext::GarbageCollectNow(js::gcreason::Reason reason, PRUint32 gckind)
|
||||
nsJSContext::GarbageCollectNow(js::gcreason::Reason aReason, PRUint32 aGckind,
|
||||
bool aGlobal)
|
||||
{
|
||||
NS_TIME_FUNCTION_MIN(1.0);
|
||||
SAMPLE_LABEL("GC", "GarbageCollectNow");
|
||||
@ -3250,9 +3290,44 @@ nsJSContext::GarbageCollectNow(js::gcreason::Reason reason, PRUint32 gckind)
|
||||
sPendingLoadCount = 0;
|
||||
sLoadingInProgress = false;
|
||||
|
||||
if (nsContentUtils::XPConnect()) {
|
||||
nsContentUtils::XPConnect()->GarbageCollect(reason, gckind);
|
||||
if (!nsContentUtils::XPConnect()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use compartment GC when we're not asked to do a shrinking GC nor
|
||||
// global GC and compartment GC has been called less than 10 times after
|
||||
// the previous global GC. If a top level browsing context has been
|
||||
// deleted, we do a global GC.
|
||||
if (!sDisableExplicitCompartmentGC &&
|
||||
aGckind != nsGCShrinking && !aGlobal &&
|
||||
EvaluationCount(sTopEvaluator) > 0 &&
|
||||
!sContextDeleted && sCompartmentGCCount < 10) {
|
||||
nsJSContext* top = sTopEvaluator;
|
||||
sTopEvaluator = nsnull;
|
||||
ResetEvaluationCount(top);
|
||||
JSContext* cx = top->GetNativeContext();
|
||||
if (cx) {
|
||||
JSObject* global = top->GetNativeGlobal();
|
||||
if (global) {
|
||||
if (!sFullGCTimer) {
|
||||
CallCreateInstance("@mozilla.org/timer;1", &sFullGCTimer);
|
||||
}
|
||||
if (sFullGCTimer) {
|
||||
sFullGCTimer->Cancel();
|
||||
js::gcreason::Reason reason = js::gcreason::FULL_GC_TIMER;
|
||||
sFullGCTimer->InitWithFuncCallback(FullGCTimerFired,
|
||||
reinterpret_cast<void *>(reason),
|
||||
NS_FULL_GC_DELAY,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
JSCompartment* comp = js::GetObjectCompartment(global);
|
||||
js::CompartmentGCForReason(cx, comp, aReason);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsContentUtils::XPConnect()->GarbageCollect(aReason, aGckind);
|
||||
}
|
||||
|
||||
//static
|
||||
@ -3356,7 +3431,8 @@ GCTimerFired(nsITimer *aTimer, void *aClosure)
|
||||
NS_RELEASE(sGCTimer);
|
||||
|
||||
uintptr_t reason = reinterpret_cast<uintptr_t>(aClosure);
|
||||
nsJSContext::GarbageCollectNow(static_cast<js::gcreason::Reason>(reason), nsGCNormal);
|
||||
nsJSContext::GarbageCollectNow(static_cast<js::gcreason::Reason>(reason),
|
||||
nsGCNormal, false);
|
||||
}
|
||||
|
||||
void
|
||||
@ -3524,6 +3600,16 @@ nsJSContext::KillGCTimer()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsJSContext::KillFullGCTimer()
|
||||
{
|
||||
if (sFullGCTimer) {
|
||||
sFullGCTimer->Cancel();
|
||||
|
||||
NS_RELEASE(sFullGCTimer);
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void
|
||||
nsJSContext::KillShrinkGCBuffersTimer()
|
||||
@ -3552,8 +3638,8 @@ nsJSContext::GC(js::gcreason::Reason aReason)
|
||||
PokeGC(aReason);
|
||||
}
|
||||
|
||||
static void
|
||||
DOMGCFinishedCallback(JSRuntime *rt, JSCompartment *comp, const char *status)
|
||||
void
|
||||
nsJSContext::DOMGCFinishedCallback(JSRuntime *rt, JSCompartment *comp, const char *status)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "GCs must run on the main thread");
|
||||
|
||||
@ -3579,6 +3665,19 @@ DOMGCFinishedCallback(JSRuntime *rt, JSCompartment *comp, const char *status)
|
||||
sCCollectedWaitingForGC = 0;
|
||||
sCleanupSinceLastGC = false;
|
||||
|
||||
if (!comp) {
|
||||
sPreviousWasChromeCompGC = false;
|
||||
sContextDeleted = false;
|
||||
sCompartmentGCCount = 0;
|
||||
++sGlobalGCEpoch;
|
||||
KillFullGCTimer();
|
||||
} else {
|
||||
// Only every other compartment GC is allowed to collect a chrome
|
||||
// compartment. Otherwise we'd collect chrome compartment all the time.
|
||||
sPreviousWasChromeCompGC = xpc::AccessCheck::isChrome(comp);
|
||||
++sCompartmentGCCount;
|
||||
}
|
||||
|
||||
if (sGCTimer) {
|
||||
// If we were waiting for a GC to happen, kill the timer.
|
||||
nsJSContext::KillGCTimer();
|
||||
@ -3699,13 +3798,14 @@ void
|
||||
nsJSRuntime::Startup()
|
||||
{
|
||||
// initialize all our statics, so that we can restart XPCOM
|
||||
sGCTimer = sCCTimer = nsnull;
|
||||
sGCTimer = sFullGCTimer = sCCTimer = nsnull;
|
||||
sGCHasRun = false;
|
||||
sLastCCEndTime = 0;
|
||||
sPendingLoadCount = 0;
|
||||
sLoadingInProgress = false;
|
||||
sCCollectedWaitingForGC = 0;
|
||||
sPostGCEventsToConsole = false;
|
||||
sDisableExplicitCompartmentGC = false;
|
||||
gNameSpaceManager = nsnull;
|
||||
sRuntimeService = nsnull;
|
||||
sRuntime = nsnull;
|
||||
@ -3862,7 +3962,7 @@ nsJSRuntime::Init()
|
||||
// Let's make sure that our main thread is the same as the xpcom main thread.
|
||||
NS_ASSERTION(NS_IsMainThread(), "bad");
|
||||
|
||||
::JS_SetGCFinishedCallback(sRuntime, DOMGCFinishedCallback);
|
||||
::JS_SetGCFinishedCallback(sRuntime, nsJSContext::DOMGCFinishedCallback);
|
||||
|
||||
JSSecurityCallbacks *callbacks = JS_GetRuntimeSecurityCallbacks(sRuntime);
|
||||
NS_ASSERTION(callbacks, "SecMan should have set security callbacks!");
|
||||
@ -3947,6 +4047,7 @@ void
|
||||
nsJSRuntime::Shutdown()
|
||||
{
|
||||
nsJSContext::KillGCTimer();
|
||||
nsJSContext::KillFullGCTimer();
|
||||
nsJSContext::KillShrinkGCBuffersTimer();
|
||||
nsJSContext::KillCCTimer();
|
||||
|
||||
|
@ -181,7 +181,9 @@ public:
|
||||
static void LoadStart();
|
||||
static void LoadEnd();
|
||||
|
||||
static void GarbageCollectNow(js::gcreason::Reason reason, PRUint32 gckind = nsGCNormal);
|
||||
static void GarbageCollectNow(js::gcreason::Reason aReason,
|
||||
PRUint32 aGckind,
|
||||
bool aGlobal);
|
||||
static void ShrinkGCBuffersNow();
|
||||
// If aExtraForgetSkippableCalls is -1, forgetSkippable won't be
|
||||
// called even if the previous collection was GC.
|
||||
@ -190,6 +192,7 @@ public:
|
||||
|
||||
static void PokeGC(js::gcreason::Reason aReason);
|
||||
static void KillGCTimer();
|
||||
static void KillFullGCTimer();
|
||||
|
||||
static void PokeShrinkGCBuffers();
|
||||
static void KillShrinkGCBuffersTimer();
|
||||
@ -208,6 +211,29 @@ public:
|
||||
JSObject* global = JS_GetGlobalObject(mContext);
|
||||
return global ? mGlobalObjectRef.get() : nsnull;
|
||||
}
|
||||
|
||||
static PRUint32 EvaluationCount(nsJSContext* aCx)
|
||||
{
|
||||
return aCx && aCx->mGlobalGCEpoch == sGlobalGCEpoch ?
|
||||
aCx->mEvaluationCount : 0;
|
||||
}
|
||||
|
||||
static void IncreaseEvaluationCount(nsJSContext* aCx)
|
||||
{
|
||||
if (aCx->mGlobalGCEpoch != sGlobalGCEpoch) {
|
||||
aCx->mEvaluationCount = 0;
|
||||
aCx->mGlobalGCEpoch = sGlobalGCEpoch;
|
||||
}
|
||||
++(aCx->mEvaluationCount);
|
||||
}
|
||||
|
||||
static void ResetEvaluationCount(nsJSContext* aCx)
|
||||
{
|
||||
aCx->mEvaluationCount = 0;
|
||||
}
|
||||
|
||||
static void DOMGCFinishedCallback(JSRuntime* aRt, JSCompartment* aComp,
|
||||
const char* aStatus);
|
||||
protected:
|
||||
nsresult InitializeExternalClasses();
|
||||
|
||||
@ -296,7 +322,9 @@ private:
|
||||
bool mScriptsEnabled;
|
||||
bool mGCOnDestruction;
|
||||
bool mProcessingScriptTag;
|
||||
|
||||
bool mChromeComp;
|
||||
PRUint32 mGlobalGCEpoch;
|
||||
PRUint32 mEvaluationCount;
|
||||
PRUint32 mExecuteDepth;
|
||||
PRUint32 mDefaultJSOptions;
|
||||
PRTime mOperationCallbackTime;
|
||||
@ -308,6 +336,8 @@ private:
|
||||
// context does. It is eventually collected by the cycle collector.
|
||||
nsCOMPtr<nsIScriptGlobalObject> mGlobalObjectRef;
|
||||
|
||||
static PRUint32 sGlobalGCEpoch;
|
||||
|
||||
static int JSOptionChangedCallback(const char *pref, void *data);
|
||||
|
||||
static JSBool DOMOperationCallback(JSContext *cx);
|
||||
|
@ -54,6 +54,7 @@
|
||||
|
||||
interface nsIDOMFile;
|
||||
interface nsIVariant;
|
||||
interface nsIInputStreamCallback;
|
||||
|
||||
[scriptable, uuid(8cddbc86-f384-40ac-835b-fe3e00630cad)]
|
||||
interface nsIDOMHTMLCanvasElement : nsIDOMHTMLElement
|
||||
@ -82,5 +83,10 @@ interface nsIDOMHTMLCanvasElement : nsIDOMHTMLElement
|
||||
// A Mozilla-only extension to get a canvas context backed by double-buffered
|
||||
// shared memory. Only privileged callers can call this.
|
||||
nsISupports MozGetIPCContext(in DOMString contextId);
|
||||
|
||||
// A Mozilla-only extension that returns the canvas' image data as a data
|
||||
// stream in the desired image format.
|
||||
void mozFetchAsStream(in nsIInputStreamCallback callback,
|
||||
[optional] in DOMString type);
|
||||
};
|
||||
|
||||
|
@ -800,14 +800,14 @@ ContentChild::GetIndexedDBPath()
|
||||
bool
|
||||
ContentChild::RecvGarbageCollect()
|
||||
{
|
||||
nsJSContext::GarbageCollectNow(js::gcreason::DOM_IPC);
|
||||
nsJSContext::GarbageCollectNow(js::gcreason::DOM_IPC, nsGCNormal, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvCycleCollect()
|
||||
{
|
||||
nsJSContext::GarbageCollectNow(js::gcreason::DOM_IPC);
|
||||
nsJSContext::GarbageCollectNow(js::gcreason::DOM_IPC, nsGCNormal, true);
|
||||
nsJSContext::CycleCollectNow();
|
||||
return true;
|
||||
}
|
||||
|
@ -138,6 +138,7 @@ endif
|
||||
|
||||
LOCAL_INCLUDES += \
|
||||
-DSK_BUILD_FOR_ANDROID_NDK \
|
||||
-I$(topsrcdir)/widget/android \
|
||||
-I$(topsrcdir)/xpcom/base/ \
|
||||
-I$(topsrcdir)/gfx/skia/include/core \
|
||||
-I$(topsrcdir)/gfx/skia/include/config \
|
||||
|
@ -306,7 +306,6 @@ anp_audio_start(ANPAudioTrack* s)
|
||||
|
||||
if (s->keepGoing) {
|
||||
// we are already playing. Ignore.
|
||||
LOG("anp_audio_start called twice!");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -359,7 +358,14 @@ anp_audio_isStopped(ANPAudioTrack* s)
|
||||
return s->isStopped;
|
||||
}
|
||||
|
||||
void InitAudioTrackInterface(ANPAudioTrackInterfaceV0 *i) {
|
||||
uint32_t
|
||||
anp_audio_trackLatency(ANPAudioTrack* s) {
|
||||
// Bug 721835
|
||||
NOT_IMPLEMENTED();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void InitAudioTrackInterfaceV0(ANPAudioTrackInterfaceV0 *i) {
|
||||
_assert(i->inSize == sizeof(*i));
|
||||
ASSIGN(i, newTrack);
|
||||
ASSIGN(i, deleteTrack);
|
||||
@ -368,3 +374,14 @@ void InitAudioTrackInterface(ANPAudioTrackInterfaceV0 *i) {
|
||||
ASSIGN(i, stop);
|
||||
ASSIGN(i, isStopped);
|
||||
}
|
||||
|
||||
void InitAudioTrackInterfaceV1(ANPAudioTrackInterfaceV1 *i) {
|
||||
_assert(i->inSize == sizeof(*i));
|
||||
ASSIGN(i, newTrack);
|
||||
ASSIGN(i, deleteTrack);
|
||||
ASSIGN(i, start);
|
||||
ASSIGN(i, pause);
|
||||
ASSIGN(i, stop);
|
||||
ASSIGN(i, isStopped);
|
||||
ASSIGN(i, trackLatency);
|
||||
}
|
||||
|
@ -36,8 +36,8 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "android_npapi.h"
|
||||
#include <stdlib.h>
|
||||
#include "android_npapi.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
@ -53,7 +53,8 @@
|
||||
"!!!!!!!!!!!!!! %s not implemented %s, %d", \
|
||||
__PRETTY_FUNCTION__, __FILE__, __LINE__); \
|
||||
|
||||
void InitAudioTrackInterface(ANPAudioTrackInterfaceV0 *i);
|
||||
void InitAudioTrackInterfaceV0(ANPAudioTrackInterfaceV0 *i);
|
||||
void InitAudioTrackInterfaceV1(ANPAudioTrackInterfaceV1* i);
|
||||
void InitBitmapInterface(ANPBitmapInterfaceV0 *i);
|
||||
void InitCanvasInterface(ANPCanvasInterfaceV0 *i);
|
||||
void InitEventInterface(ANPEventInterfaceV0 *i);
|
||||
@ -63,5 +64,13 @@ void InitPaintInterface(ANPPaintInterfaceV0 *i);
|
||||
void InitPathInterface(ANPPathInterfaceV0 *i);
|
||||
void InitSurfaceInterface(ANPSurfaceInterfaceV0 *i);
|
||||
void InitSystemInterface(ANPSystemInterfaceV0 *i);
|
||||
void InitSystemInterfaceV1(ANPSystemInterfaceV1 *i);
|
||||
void InitSystemInterfaceV2(ANPSystemInterfaceV2 *i);
|
||||
void InitTypeFaceInterface(ANPTypefaceInterfaceV0 *i);
|
||||
void InitWindowInterface(ANPWindowInterfaceV0 *i);
|
||||
void InitWindowInterfaceV1(ANPWindowInterfaceV1 *i);
|
||||
void InitWindowInterfaceV2(ANPWindowInterfaceV2 *i);
|
||||
void InitVideoInterfaceV0(ANPVideoInterfaceV0 *i);
|
||||
void InitVideoInterfaceV1(ANPVideoInterfaceV1 *i);
|
||||
void InitOpenGLInterface(ANPOpenGLInterfaceV0 *i);
|
||||
void InitNativeWindowInterface(ANPNativeWindowInterfaceV0 *i);
|
||||
|
85
dom/plugins/base/android/ANPNativeWindow.cpp
Normal file
85
dom/plugins/base/android/ANPNativeWindow.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Android NPAPI support code
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* James Willcox <jwillcox@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
// must include config.h first for webkit to fiddle with new/delete
|
||||
#include <android/log.h>
|
||||
#include "AndroidBridge.h"
|
||||
#include "AndroidMediaLayer.h"
|
||||
#include "ANPBase.h"
|
||||
#include "nsIPluginInstanceOwner.h"
|
||||
#include "nsPluginInstanceOwner.h"
|
||||
#include "nsNPAPIPluginInstance.h"
|
||||
#include "gfxRect.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla;
|
||||
|
||||
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
|
||||
#define ASSIGN(obj, name) (obj)->name = anp_native_window_##name
|
||||
|
||||
static ANPNativeWindow anp_native_window_acquireNativeWindow(NPP instance) {
|
||||
nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
|
||||
|
||||
nsPluginInstanceOwner* owner;
|
||||
if (NS_FAILED(pinst->GetOwner((nsIPluginInstanceOwner**)&owner))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
ANPNativeWindow window = owner->Layer()->GetNativeWindowForContent();
|
||||
owner->Invalidate();
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
static void anp_native_window_invertPluginContent(NPP instance, bool isContentInverted) {
|
||||
nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
|
||||
|
||||
nsPluginInstanceOwner* owner;
|
||||
if (NS_FAILED(pinst->GetOwner((nsIPluginInstanceOwner**)&owner))) {
|
||||
return;
|
||||
}
|
||||
|
||||
owner->Layer()->SetInverted(isContentInverted);
|
||||
}
|
||||
|
||||
|
||||
void InitNativeWindowInterface(ANPNativeWindowInterfaceV0* i) {
|
||||
ASSIGN(i, acquireNativeWindow);
|
||||
ASSIGN(i, invertPluginContent);
|
||||
}
|
65
dom/plugins/base/android/ANPOpenGL.cpp
Normal file
65
dom/plugins/base/android/ANPOpenGL.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
/* The Original Code is Android NPAPI support code
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* James Willcox <jwillcox@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <android/log.h>
|
||||
#include "AndroidBridge.h"
|
||||
#include "ANPBase.h"
|
||||
#include "GLContextProvider.h"
|
||||
#include "nsNPAPIPluginInstance.h"
|
||||
|
||||
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
|
||||
#define ASSIGN(obj, name) (obj)->name = anp_opengl_##name
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gl;
|
||||
|
||||
static ANPEGLContext anp_opengl_acquireContext(NPP inst) {
|
||||
// Bug 687267
|
||||
NOT_IMPLEMENTED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ANPTextureInfo anp_opengl_lockTexture(NPP instance) {
|
||||
ANPTextureInfo info = { 0, 0, 0, 0 };
|
||||
NOT_IMPLEMENTED();
|
||||
return info;
|
||||
}
|
||||
|
||||
static void anp_opengl_releaseTexture(NPP instance, const ANPTextureInfo* info) {
|
||||
NOT_IMPLEMENTED();
|
||||
}
|
||||
|
||||
static void anp_opengl_invertPluginContent(NPP instance, bool isContentInverted) {
|
||||
NOT_IMPLEMENTED();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void InitOpenGLInterface(ANPOpenGLInterfaceV0* i) {
|
||||
ASSIGN(i, acquireContext);
|
||||
ASSIGN(i, lockTexture);
|
||||
ASSIGN(i, releaseTexture);
|
||||
ASSIGN(i, invertPluginContent);
|
||||
}
|
@ -62,6 +62,12 @@ anp_system_getApplicationDataDirectory()
|
||||
return dir;
|
||||
}
|
||||
|
||||
const char*
|
||||
anp_system_getApplicationDataDirectory(NPP instance)
|
||||
{
|
||||
return anp_system_getApplicationDataDirectory();
|
||||
}
|
||||
|
||||
jclass anp_system_loadJavaClass(NPP instance, const char* className)
|
||||
{
|
||||
LOG("%s", __PRETTY_FUNCTION__);
|
||||
@ -88,8 +94,27 @@ jclass anp_system_loadJavaClass(NPP instance, const char* className)
|
||||
return reinterpret_cast<jclass>(obj);
|
||||
}
|
||||
|
||||
void anp_system_setPowerState(NPP instance, ANPPowerState powerState)
|
||||
{
|
||||
NOT_IMPLEMENTED();
|
||||
}
|
||||
|
||||
void InitSystemInterface(ANPSystemInterfaceV0 *i) {
|
||||
_assert(i->inSize == sizeof(*i));
|
||||
ASSIGN(i, getApplicationDataDirectory);
|
||||
ASSIGN(i, loadJavaClass);
|
||||
}
|
||||
|
||||
void InitSystemInterfaceV1(ANPSystemInterfaceV1 *i) {
|
||||
_assert(i->inSize == sizeof(*i));
|
||||
ASSIGN(i, getApplicationDataDirectory);
|
||||
ASSIGN(i, loadJavaClass);
|
||||
ASSIGN(i, setPowerState);
|
||||
}
|
||||
|
||||
void InitSystemInterfaceV2(ANPSystemInterfaceV2 *i) {
|
||||
_assert(i->inSize == sizeof(*i));
|
||||
ASSIGN(i, getApplicationDataDirectory);
|
||||
ASSIGN(i, loadJavaClass);
|
||||
ASSIGN(i, setPowerState);
|
||||
}
|
||||
|
109
dom/plugins/base/android/ANPVideo.cpp
Normal file
109
dom/plugins/base/android/ANPVideo.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
/* The Original Code is Android NPAPI support code
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* James Willcox <jwillcox@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <android/log.h>
|
||||
#include "ANPBase.h"
|
||||
#include "AndroidMediaLayer.h"
|
||||
#include "nsIPluginInstanceOwner.h"
|
||||
#include "nsPluginInstanceOwner.h"
|
||||
#include "nsNPAPIPluginInstance.h"
|
||||
#include "gfxRect.h"
|
||||
|
||||
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
|
||||
#define ASSIGN(obj, name) (obj)->name = anp_video_##name
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
static AndroidMediaLayer* GetLayerForInstance(NPP instance) {
|
||||
nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
|
||||
|
||||
nsPluginInstanceOwner* owner;
|
||||
if (NS_FAILED(pinst->GetOwner((nsIPluginInstanceOwner**)&owner))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return owner->Layer();
|
||||
}
|
||||
|
||||
static void Invalidate(NPP instance) {
|
||||
nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
|
||||
|
||||
nsPluginInstanceOwner* owner;
|
||||
if (NS_FAILED(pinst->GetOwner((nsIPluginInstanceOwner**)&owner)))
|
||||
return;
|
||||
|
||||
owner->Invalidate();
|
||||
}
|
||||
|
||||
static ANPNativeWindow anp_video_acquireNativeWindow(NPP instance) {
|
||||
AndroidMediaLayer* layer = GetLayerForInstance(instance);
|
||||
if (!layer)
|
||||
return NULL;
|
||||
|
||||
return layer->RequestNativeWindowForVideo();
|
||||
}
|
||||
|
||||
static void anp_video_setWindowDimensions(NPP instance, const ANPNativeWindow window,
|
||||
const ANPRectF* dimensions) {
|
||||
AndroidMediaLayer* layer = GetLayerForInstance(instance);
|
||||
if (!layer)
|
||||
return;
|
||||
|
||||
gfxRect rect(dimensions->left, dimensions->top,
|
||||
dimensions->right - dimensions->left,
|
||||
dimensions->bottom - dimensions->top);
|
||||
|
||||
layer->SetNativeWindowDimensions(window, rect);
|
||||
Invalidate(instance);
|
||||
}
|
||||
|
||||
|
||||
static void anp_video_releaseNativeWindow(NPP instance, ANPNativeWindow window) {
|
||||
AndroidMediaLayer* layer = GetLayerForInstance(instance);
|
||||
if (!layer)
|
||||
return;
|
||||
|
||||
layer->ReleaseNativeWindowForVideo(window);
|
||||
Invalidate(instance);
|
||||
}
|
||||
|
||||
static void anp_video_setFramerateCallback(NPP instance, const ANPNativeWindow window, ANPVideoFrameCallbackProc callback) {
|
||||
// Bug 722682
|
||||
NOT_IMPLEMENTED();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void InitVideoInterfaceV0(ANPVideoInterfaceV0* i) {
|
||||
ASSIGN(i, acquireNativeWindow);
|
||||
ASSIGN(i, setWindowDimensions);
|
||||
ASSIGN(i, releaseNativeWindow);
|
||||
}
|
||||
|
||||
void InitVideoInterfaceV1(ANPVideoInterfaceV1* i) {
|
||||
ASSIGN(i, acquireNativeWindow);
|
||||
ASSIGN(i, setWindowDimensions);
|
||||
ASSIGN(i, releaseNativeWindow);
|
||||
ASSIGN(i, setFramerateCallback);
|
||||
}
|
@ -39,10 +39,16 @@
|
||||
#include "assert.h"
|
||||
#include "ANPBase.h"
|
||||
#include <android/log.h>
|
||||
#include "AndroidBridge.h"
|
||||
#include "nsNPAPIPluginInstance.h"
|
||||
#include "nsIPluginInstanceOwner.h"
|
||||
#include "nsPluginInstanceOwner.h"
|
||||
|
||||
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
|
||||
#define ASSIGN(obj, name) (obj)->name = anp_window_##name
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
void
|
||||
anp_window_setVisibleRects(NPP instance, const ANPRectI rects[], int32_t count)
|
||||
{
|
||||
@ -79,6 +85,32 @@ anp_window_requestCenterFitZoom(NPP instance)
|
||||
NOT_IMPLEMENTED();
|
||||
}
|
||||
|
||||
ANPRectI
|
||||
anp_window_visibleRect(NPP instance)
|
||||
{
|
||||
ANPRectI rect = { 0, 0, 0, 0 };
|
||||
|
||||
nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
|
||||
|
||||
nsPluginInstanceOwner* owner;
|
||||
if (NS_FAILED(pinst->GetOwner((nsIPluginInstanceOwner**)&owner))) {
|
||||
return rect;
|
||||
}
|
||||
|
||||
nsIntRect visibleRect = owner->GetVisibleRect();
|
||||
rect.left = visibleRect.x;
|
||||
rect.top = visibleRect.y;
|
||||
rect.right = visibleRect.x + visibleRect.width;
|
||||
rect.bottom = visibleRect.y + visibleRect.height;
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
void anp_window_requestFullScreenOrientation(NPP instance, ANPScreenOrientation orientation)
|
||||
{
|
||||
NOT_IMPLEMENTED();
|
||||
}
|
||||
|
||||
void InitWindowInterface(ANPWindowInterfaceV0 *i) {
|
||||
_assert(i->inSize == sizeof(*i));
|
||||
ASSIGN(i, setVisibleRects);
|
||||
@ -89,3 +121,26 @@ void InitWindowInterface(ANPWindowInterfaceV0 *i) {
|
||||
ASSIGN(i, requestCenterFitZoom);
|
||||
}
|
||||
|
||||
void InitWindowInterfaceV1(ANPWindowInterfaceV1 *i) {
|
||||
_assert(i->inSize == sizeof(*i));
|
||||
ASSIGN(i, setVisibleRects);
|
||||
ASSIGN(i, clearVisibleRects);
|
||||
ASSIGN(i, showKeyboard);
|
||||
ASSIGN(i, requestFullScreen);
|
||||
ASSIGN(i, exitFullScreen);
|
||||
ASSIGN(i, requestCenterFitZoom);
|
||||
ASSIGN(i, visibleRect);
|
||||
}
|
||||
|
||||
void InitWindowInterfaceV2(ANPWindowInterfaceV2 *i) {
|
||||
_assert(i->inSize == sizeof(*i));
|
||||
ASSIGN(i, setVisibleRects);
|
||||
ASSIGN(i, clearVisibleRects);
|
||||
ASSIGN(i, showKeyboard);
|
||||
ASSIGN(i, requestFullScreen);
|
||||
ASSIGN(i, exitFullScreen);
|
||||
ASSIGN(i, requestCenterFitZoom);
|
||||
ASSIGN(i, visibleRect);
|
||||
ASSIGN(i, requestFullScreenOrientation);
|
||||
}
|
||||
|
||||
|
@ -63,12 +63,17 @@ CPPSRCS += ANPAudio.cpp \
|
||||
ANPWindow.cpp \
|
||||
ANPBitmap.cpp \
|
||||
ANPLog.cpp \
|
||||
ANPNativeWindow.cpp \
|
||||
ANPSurface.cpp \
|
||||
ANPVideo.cpp \
|
||||
ANPOpenGL.cpp \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES += \
|
||||
-I$(topsrcdir)/widget/android \
|
||||
-I$(topsrcdir)/dom/plugins/base \
|
||||
-I$(topsrcdir)/dom/plugins/base/android/include \
|
||||
-I$(topsrcdir)/gfx/gl \
|
||||
$(MOZ_CAIRO_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
|
@ -36,8 +36,9 @@
|
||||
#define android_npapi_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "npapi.h"
|
||||
#include <jni.h>
|
||||
#include "npapi.h"
|
||||
#include "GLDefs.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// General types
|
||||
@ -120,6 +121,16 @@ typedef uint32_t ANPMatrixFlag;
|
||||
#define kSystemInterfaceV0_ANPGetValue ((NPNVariable)1010)
|
||||
#define kEventInterfaceV0_ANPGetValue ((NPNVariable)1011)
|
||||
|
||||
#define kAudioTrackInterfaceV1_ANPGetValue ((NPNVariable)1012)
|
||||
#define kOpenGLInterfaceV0_ANPGetValue ((NPNVariable)1013)
|
||||
#define kWindowInterfaceV1_ANPGetValue ((NPNVariable)1014)
|
||||
#define kVideoInterfaceV0_ANPGetValue ((NPNVariable)1015)
|
||||
#define kSystemInterfaceV1_ANPGetValue ((NPNVariable)1016)
|
||||
#define kSystemInterfaceV2_ANPGetValue ((NPNVariable)1017)
|
||||
#define kWindowInterfaceV2_ANPGetValue ((NPNVariable)1018)
|
||||
#define kNativeWindowInterfaceV0_ANPGetValue ((NPNVariable)1019)
|
||||
#define kVideoInterfaceV1_ANPGetValue ((NPNVariable)1020)
|
||||
|
||||
/** queries for the drawing models supported on this device.
|
||||
|
||||
NPN_GetValue(inst, kSupportedDrawingModel_ANPGetValue, uint32_t* bits)
|
||||
@ -180,6 +191,7 @@ enum ANPDrawingModels {
|
||||
surface object.
|
||||
*/
|
||||
kSurface_ANPDrawingModel = 1 << 1,
|
||||
kOpenGL_ANPDrawingModel = 1 << 2,
|
||||
};
|
||||
typedef int32_t ANPDrawingModel;
|
||||
|
||||
@ -678,6 +690,25 @@ struct ANPWindowInterfaceV0 : ANPInterface {
|
||||
void (*requestCenterFitZoom)(NPP instance);
|
||||
};
|
||||
|
||||
struct ANPWindowInterfaceV1 : ANPWindowInterfaceV0 {
|
||||
/** Returns a rectangle representing the visible area of the plugin on
|
||||
screen. The coordinates are relative to the size of the plugin in the
|
||||
document and therefore will never be negative or exceed the plugin's size.
|
||||
*/
|
||||
ANPRectI (*visibleRect)(NPP instance);
|
||||
};
|
||||
|
||||
typedef int32_t ANPScreenOrientation;
|
||||
|
||||
struct ANPWindowInterfaceV2 : ANPWindowInterfaceV1 {
|
||||
/** Called when the plugin wants to specify a particular screen orientation
|
||||
when entering into full screen mode. The orientation must be set prior
|
||||
to entering into full screen. After entering full screen any subsequent
|
||||
changes will be updated the next time the plugin goes full screen.
|
||||
*/
|
||||
void (*requestFullScreenOrientation)(NPP instance, ANPScreenOrientation orientation);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum ANPSampleFormats {
|
||||
@ -762,6 +793,12 @@ struct ANPAudioTrackInterfaceV0 : ANPInterface {
|
||||
bool (*isStopped)(ANPAudioTrack*);
|
||||
};
|
||||
|
||||
struct ANPAudioTrackInterfaceV1 : ANPAudioTrackInterfaceV0 {
|
||||
/** Returns the track's latency in milliseconds. */
|
||||
uint32_t (*trackLatency)(ANPAudioTrack*);
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// DEFINITION OF VALUES PASSED THROUGH NPP_HandleEvent
|
||||
|
||||
@ -922,12 +959,16 @@ struct ANPEvent {
|
||||
// use based on the value in model
|
||||
union {
|
||||
ANPBitmap bitmap;
|
||||
struct {
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
} surfaceSize;
|
||||
} data;
|
||||
} draw;
|
||||
int32_t other[8];
|
||||
} data;
|
||||
};
|
||||
|
||||
|
||||
struct ANPEventInterfaceV0 : ANPInterface {
|
||||
/** Post a copy of the specified event to the plugin. The event will be
|
||||
delivered to the plugin in its main thread (the thread that receives
|
||||
@ -976,4 +1017,117 @@ typedef uint32_t uint32;
|
||||
typedef int16_t int16;
|
||||
typedef uint16_t uint16;
|
||||
|
||||
/**
|
||||
* TODO should we not use EGL and GL data types for ABI safety?
|
||||
*/
|
||||
struct ANPTextureInfo {
|
||||
GLuint textureId;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
GLenum internalFormat;
|
||||
};
|
||||
|
||||
typedef void* ANPEGLContext;
|
||||
|
||||
struct ANPOpenGLInterfaceV0 : ANPInterface {
|
||||
ANPEGLContext (*acquireContext)(NPP instance);
|
||||
|
||||
ANPTextureInfo (*lockTexture)(NPP instance);
|
||||
|
||||
void (*releaseTexture)(NPP instance, const ANPTextureInfo*);
|
||||
|
||||
/**
|
||||
* Invert the contents of the plugin on the y-axis.
|
||||
* default is to not be inverted (i.e. use OpenGL coordinates)
|
||||
*/
|
||||
void (*invertPluginContent)(NPP instance, bool isContentInverted);
|
||||
};
|
||||
|
||||
enum ANPPowerStates {
|
||||
kDefault_ANPPowerState = 0,
|
||||
kScreenOn_ANPPowerState = 1
|
||||
};
|
||||
typedef int32_t ANPPowerState;
|
||||
|
||||
struct ANPSystemInterfaceV1 : ANPSystemInterfaceV0 {
|
||||
void (*setPowerState)(NPP instance, ANPPowerState powerState);
|
||||
};
|
||||
|
||||
struct ANPSystemInterfaceV2 : ANPInterface {
|
||||
/** Return the path name for the current Application's plugin data directory,
|
||||
or NULL if not supported. This directory will change depending on whether
|
||||
or not the plugin is found within an incognito tab.
|
||||
*/
|
||||
const char* (*getApplicationDataDirectory)(NPP instance);
|
||||
|
||||
// redeclaration of existing features
|
||||
jclass (*loadJavaClass)(NPP instance, const char* className);
|
||||
void (*setPowerState)(NPP instance, ANPPowerState powerState);
|
||||
};
|
||||
|
||||
typedef void* ANPNativeWindow;
|
||||
|
||||
struct ANPVideoInterfaceV0 : ANPInterface {
|
||||
|
||||
/**
|
||||
* Constructs a new native window to be used for rendering video content.
|
||||
*
|
||||
* Subsequent calls will produce new windows, but may also return NULL after
|
||||
* n attempts if the browser has reached it's limit. Further, if the browser
|
||||
* is unable to acquire the window quickly it may also return NULL in order
|
||||
* to not prevent the plugin from executing. A subsequent call will then
|
||||
* return the window if it is avaiable.
|
||||
*
|
||||
* NOTE: The hardware may fail if you try to decode more than the allowable
|
||||
* number of videos supported on that device.
|
||||
*/
|
||||
ANPNativeWindow (*acquireNativeWindow)(NPP instance);
|
||||
|
||||
/**
|
||||
* Sets the rectangle that specifies where the video content is to be drawn.
|
||||
* The dimensions are in document space. Further, if the rect is NULL the
|
||||
* browser will not attempt to draw the window, therefore do not set the
|
||||
* dimensions until you queue the first buffer in the window.
|
||||
*/
|
||||
void (*setWindowDimensions)(NPP instance, const ANPNativeWindow window, const ANPRectF* dimensions);
|
||||
|
||||
/**
|
||||
*/
|
||||
void (*releaseNativeWindow)(NPP instance, ANPNativeWindow window);
|
||||
};
|
||||
|
||||
/** Called to notify the plugin that a video frame has been composited by the
|
||||
* browser for display. This will be called in a separate thread and as such
|
||||
* you cannot call releaseNativeWindow from the callback.
|
||||
*
|
||||
* The timestamp is in nanoseconds, and is monotonically increasing.
|
||||
*/
|
||||
typedef void (*ANPVideoFrameCallbackProc)(ANPNativeWindow* window, int64_t timestamp);
|
||||
|
||||
struct ANPVideoInterfaceV1 : ANPVideoInterfaceV0 {
|
||||
/** Set a callback to be notified when an ANPNativeWindow is composited by
|
||||
* the browser.
|
||||
*/
|
||||
void (*setFramerateCallback)(NPP instance, const ANPNativeWindow window, ANPVideoFrameCallbackProc);
|
||||
};
|
||||
|
||||
struct ANPNativeWindowInterfaceV0 : ANPInterface {
|
||||
/**
|
||||
* Constructs a new native window to be used for rendering plugin content.
|
||||
*
|
||||
* Subsequent calls will return the original constructed window. Further, if
|
||||
* the browser is unable to acquire the window quickly it may return NULL in
|
||||
* order to not block the plugin indefinitely. A subsequent call will then
|
||||
* return the window if it is available.
|
||||
*/
|
||||
ANPNativeWindow (*acquireNativeWindow)(NPP instance);
|
||||
|
||||
/**
|
||||
* Invert the contents of the plugin on the y-axis.
|
||||
* default is to not be inverted (e.g. use OpenGL coordinates)
|
||||
*/
|
||||
void (*invertPluginContent)(NPP instance, bool isContentInverted);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -132,9 +132,10 @@ using mozilla::plugins::PluginModuleParent;
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
#include <android/log.h>
|
||||
#include "android_npapi.h"
|
||||
#include "ANPBase.h"
|
||||
#include "AndroidBridge.h"
|
||||
#include <android/log.h>
|
||||
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
|
||||
#endif
|
||||
|
||||
@ -2348,7 +2349,7 @@ _getvalue(NPP npp, NPNVariable variable, void *result)
|
||||
case kAudioTrackInterfaceV0_ANPGetValue: {
|
||||
LOG("get audio interface");
|
||||
ANPAudioTrackInterfaceV0 *i = (ANPAudioTrackInterfaceV0 *) result;
|
||||
InitAudioTrackInterface(i);
|
||||
InitAudioTrackInterfaceV0(i);
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
@ -2363,7 +2364,6 @@ _getvalue(NPP npp, NPNVariable variable, void *result)
|
||||
LOG("get system interface");
|
||||
ANPSystemInterfaceV0* i = reinterpret_cast<ANPSystemInterfaceV0*>(result);
|
||||
InitSystemInterface(i);
|
||||
LOG("done system interface");
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
@ -2395,6 +2395,71 @@ _getvalue(NPP npp, NPNVariable variable, void *result)
|
||||
*i = reinterpret_cast<int32_t>(ret);
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
case kAudioTrackInterfaceV1_ANPGetValue: {
|
||||
LOG("get audio interface v1");
|
||||
ANPAudioTrackInterfaceV1 *i = (ANPAudioTrackInterfaceV1 *) result;
|
||||
InitAudioTrackInterfaceV1(i);
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
case kNativeWindowInterfaceV0_ANPGetValue: {
|
||||
LOG("get native window interface v0");
|
||||
ANPNativeWindowInterfaceV0* i = (ANPNativeWindowInterfaceV0 *) result;
|
||||
InitNativeWindowInterface(i);
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
case kOpenGLInterfaceV0_ANPGetValue: {
|
||||
LOG("get openGL interface");
|
||||
ANPOpenGLInterfaceV0 *i = (ANPOpenGLInterfaceV0*) result;
|
||||
InitOpenGLInterface(i);
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
case kWindowInterfaceV1_ANPGetValue: {
|
||||
LOG("get Window interface V1");
|
||||
ANPWindowInterfaceV1 *i = (ANPWindowInterfaceV1 *) result;
|
||||
InitWindowInterfaceV1(i);
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
case kWindowInterfaceV2_ANPGetValue: {
|
||||
LOG("get Window interface V2");
|
||||
ANPWindowInterfaceV2 *i = (ANPWindowInterfaceV2 *) result;
|
||||
InitWindowInterfaceV2(i);
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
case kVideoInterfaceV0_ANPGetValue: {
|
||||
LOG("get video interface");
|
||||
ANPVideoInterfaceV0 *i = (ANPVideoInterfaceV0*) result;
|
||||
InitVideoInterfaceV0(i);
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
case kVideoInterfaceV1_ANPGetValue: {
|
||||
LOG("get video interface");
|
||||
ANPVideoInterfaceV1 *i = (ANPVideoInterfaceV1*) result;
|
||||
InitVideoInterfaceV1(i);
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
case kSystemInterfaceV1_ANPGetValue: {
|
||||
LOG("get system interface v1");
|
||||
ANPSystemInterfaceV1* i = reinterpret_cast<ANPSystemInterfaceV1*>(result);
|
||||
InitSystemInterfaceV1(i);
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
case kSystemInterfaceV2_ANPGetValue: {
|
||||
LOG("get system interface v2");
|
||||
ANPSystemInterfaceV2* i = reinterpret_cast<ANPSystemInterfaceV2*>(result);
|
||||
InitSystemInterfaceV2(i);
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// we no longer hand out any XPCOM objects
|
||||
|
@ -150,6 +150,8 @@ public:
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
PRUint32 GetANPDrawingModel() { return mANPDrawingModel; }
|
||||
void SetANPDrawingModel(PRUint32 aModel);
|
||||
|
||||
// This stuff is for kSurface_ANPDrawingModel
|
||||
void* GetJavaSurface();
|
||||
void SetJavaSurface(void* aSurface);
|
||||
void RequestJavaSurface();
|
||||
|
@ -122,6 +122,7 @@ static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
|
||||
#include "ANPBase.h"
|
||||
#include "android_npapi.h"
|
||||
#include "AndroidBridge.h"
|
||||
#include "AndroidMediaLayer.h"
|
||||
using namespace mozilla::dom;
|
||||
|
||||
#include <android/log.h>
|
||||
@ -262,23 +263,14 @@ nsPluginInstanceOwner::UseAsyncRendering()
|
||||
if (mUseAsyncRendering) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsRefPtr<ImageContainer> container;
|
||||
if (mObjectFrame) {
|
||||
container = mObjectFrame->GetImageContainer();
|
||||
}
|
||||
#endif
|
||||
|
||||
bool useAsyncRendering;
|
||||
bool result = (mInstance &&
|
||||
NS_SUCCEEDED(mInstance->UseAsyncPainting(&useAsyncRendering)) &&
|
||||
useAsyncRendering &&
|
||||
#ifdef XP_MACOSX
|
||||
container &&
|
||||
container->GetBackendType() ==
|
||||
LayerManager::LAYERS_OPENGL
|
||||
#else
|
||||
(!mPluginWindow ||
|
||||
useAsyncRendering
|
||||
#ifndef XP_MACOSX
|
||||
&& (!mPluginWindow ||
|
||||
mPluginWindow->type == NPWindowTypeDrawable)
|
||||
#endif
|
||||
);
|
||||
@ -348,8 +340,9 @@ nsPluginInstanceOwner::nsPluginInstanceOwner()
|
||||
mWaitingForPaint = false;
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
mPluginViewAdded = false;
|
||||
mLastPluginRect = gfxRect(0, 0, 0, 0);
|
||||
mOnScreen = false;
|
||||
mInverted = false;
|
||||
mLayer = new AndroidMediaLayer();
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -400,6 +393,13 @@ nsPluginInstanceOwner::~nsPluginInstanceOwner()
|
||||
PLUG_DeletePluginNativeWindow(mPluginWindow);
|
||||
mPluginWindow = nsnull;
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
if (mLayer) {
|
||||
delete mLayer;
|
||||
mLayer = nsnull;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mInstance) {
|
||||
mInstance->InvalidateOwner();
|
||||
}
|
||||
@ -1683,6 +1683,43 @@ void nsPluginInstanceOwner::ScrollPositionDidChange(nscoord aX, nscoord aY)
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
|
||||
void nsPluginInstanceOwner::SendSize(int width, int height)
|
||||
{
|
||||
if (!mInstance)
|
||||
return;
|
||||
|
||||
PRInt32 model = mInstance->GetANPDrawingModel();
|
||||
|
||||
if (model != kOpenGL_ANPDrawingModel)
|
||||
return;
|
||||
|
||||
ANPEvent event;
|
||||
event.inSize = sizeof(ANPEvent);
|
||||
event.eventType = kDraw_ANPEventType;
|
||||
event.data.draw.model = kOpenGL_ANPDrawingModel;
|
||||
event.data.draw.data.surfaceSize.width = width;
|
||||
event.data.draw.data.surfaceSize.height = height;
|
||||
|
||||
mInstance->HandleEvent(&event, nsnull);
|
||||
}
|
||||
|
||||
void nsPluginInstanceOwner::SendOnScreenEvent(bool onScreen)
|
||||
{
|
||||
if (!mInstance)
|
||||
return;
|
||||
|
||||
if ((onScreen && !mOnScreen) || (!onScreen && mOnScreen)) {
|
||||
ANPEvent event;
|
||||
event.inSize = sizeof(ANPEvent);
|
||||
event.eventType = kLifecycle_ANPEventType;
|
||||
event.data.lifecycle.action = onScreen ? kOnScreen_ANPLifecycleAction : kOffScreen_ANPLifecycleAction;
|
||||
mInstance->HandleEvent(&event, nsnull);
|
||||
|
||||
mOnScreen = onScreen;
|
||||
}
|
||||
}
|
||||
|
||||
bool nsPluginInstanceOwner::AddPluginView(const gfxRect& aRect)
|
||||
{
|
||||
void* javaSurface = mInstance->GetJavaSurface();
|
||||
@ -1691,11 +1728,6 @@ bool nsPluginInstanceOwner::AddPluginView(const gfxRect& aRect)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aRect.IsEqualEdges(mLastPluginRect)) {
|
||||
// Already added and in position, no work to do
|
||||
return true;
|
||||
}
|
||||
|
||||
JNIEnv* env = GetJNIForThread();
|
||||
if (!env)
|
||||
return false;
|
||||
@ -1738,26 +1770,16 @@ bool nsPluginInstanceOwner::AddPluginView(const gfxRect& aRect)
|
||||
aRect.height);
|
||||
#endif
|
||||
|
||||
if (!mPluginViewAdded) {
|
||||
ANPEvent event;
|
||||
event.inSize = sizeof(ANPEvent);
|
||||
event.eventType = kLifecycle_ANPEventType;
|
||||
event.data.lifecycle.action = kOnScreen_ANPLifecycleAction;
|
||||
mInstance->HandleEvent(&event, nsnull);
|
||||
|
||||
mPluginViewAdded = true;
|
||||
}
|
||||
SendOnScreenEvent(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void nsPluginInstanceOwner::RemovePluginView()
|
||||
{
|
||||
if (!mInstance || !mObjectFrame | !mPluginViewAdded)
|
||||
if (!mInstance || !mObjectFrame | !mOnScreen)
|
||||
return;
|
||||
|
||||
mPluginViewAdded = false;
|
||||
|
||||
void* surface = mInstance->GetJavaSurface();
|
||||
if (!surface)
|
||||
return;
|
||||
@ -1773,13 +1795,17 @@ void nsPluginInstanceOwner::RemovePluginView()
|
||||
"removePluginView",
|
||||
"(Landroid/view/View;)V");
|
||||
env->CallStaticVoidMethod(cls, method, surface);
|
||||
|
||||
ANPEvent event;
|
||||
event.inSize = sizeof(ANPEvent);
|
||||
event.eventType = kLifecycle_ANPEventType;
|
||||
event.data.lifecycle.action = kOffScreen_ANPLifecycleAction;
|
||||
mInstance->HandleEvent(&event, nsnull);
|
||||
SendOnScreenEvent(false);
|
||||
}
|
||||
|
||||
void nsPluginInstanceOwner::Invalidate() {
|
||||
NPRect rect;
|
||||
rect.left = rect.top = 0;
|
||||
rect.right = mPluginWindow->width;
|
||||
rect.bottom = mPluginWindow->height;
|
||||
InvalidateRect(&rect);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
nsresult nsPluginInstanceOwner::DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent)
|
||||
@ -2861,15 +2887,21 @@ void nsPluginInstanceOwner::Paint(gfxContext* aContext,
|
||||
|
||||
if (model == kSurface_ANPDrawingModel) {
|
||||
if (!AddPluginView(aFrameRect)) {
|
||||
NPRect rect;
|
||||
rect.left = rect.top = 0;
|
||||
rect.right = aFrameRect.width;
|
||||
rect.bottom = aFrameRect.height;
|
||||
InvalidateRect(&rect);
|
||||
Invalidate();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (model == kOpenGL_ANPDrawingModel) {
|
||||
// FIXME: this is gross
|
||||
float zoomLevel = aFrameRect.width / (float)mPluginWindow->width;
|
||||
mLayer->UpdatePosition(aFrameRect, zoomLevel);
|
||||
|
||||
SendOnScreenEvent(true);
|
||||
SendSize((int)aFrameRect.width, (int)aFrameRect.height);
|
||||
return;
|
||||
}
|
||||
|
||||
if (model != kBitmap_ANPDrawingModel)
|
||||
return;
|
||||
|
||||
@ -3566,8 +3598,16 @@ void nsPluginInstanceOwner::UpdateWindowPositionAndClipRect(bool aSetWindow)
|
||||
} else {
|
||||
mPluginWindow->clipRect.right = 0;
|
||||
mPluginWindow->clipRect.bottom = 0;
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
RemovePluginView();
|
||||
#if 0 //MOZ_WIDGET_ANDROID
|
||||
if (mInstance) {
|
||||
PRInt32 model = mInstance->GetANPDrawingModel();
|
||||
|
||||
if (model == kSurface_ANPDrawingModel) {
|
||||
RemovePluginView();
|
||||
} else if (model == kOpenGL_ANPDrawingModel) {
|
||||
HidePluginLayer();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -94,6 +94,12 @@ class gfxXlibSurface;
|
||||
#include <os2.h>
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
namespace mozilla {
|
||||
class AndroidMediaLayer;
|
||||
}
|
||||
#endif
|
||||
|
||||
// X.h defines KeyPress
|
||||
#ifdef KeyPress
|
||||
#undef KeyPress
|
||||
@ -286,6 +292,26 @@ public:
|
||||
void EndUpdateBackground(gfxContext* aContext, const nsIntRect& aRect);
|
||||
|
||||
bool UseAsyncRendering();
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
nsIntRect GetVisibleRect() {
|
||||
return nsIntRect(0, 0, mPluginWindow->width, mPluginWindow->height);
|
||||
}
|
||||
|
||||
void SetInverted(bool aInverted) {
|
||||
mInverted = aInverted;
|
||||
}
|
||||
|
||||
bool Inverted() {
|
||||
return mInverted;
|
||||
}
|
||||
|
||||
mozilla::AndroidMediaLayer* Layer() {
|
||||
return mLayer;
|
||||
}
|
||||
|
||||
void Invalidate();
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
@ -298,11 +324,18 @@ private:
|
||||
}
|
||||
|
||||
void FixUpURLS(const nsString &name, nsAString &value);
|
||||
#ifdef ANDROID
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
void SendSize(int width, int height);
|
||||
void SendOnScreenEvent(bool onScreen);
|
||||
|
||||
bool AddPluginView(const gfxRect& aRect);
|
||||
void RemovePluginView();
|
||||
bool mPluginViewAdded;
|
||||
gfxRect mLastPluginRect;
|
||||
|
||||
bool mOnScreen;
|
||||
bool mInverted;
|
||||
|
||||
// For kOpenGL_ANPDrawingModel
|
||||
mozilla::AndroidMediaLayer *mLayer;
|
||||
#endif
|
||||
|
||||
nsPluginNativeWindow *mPluginWindow;
|
||||
|
@ -647,9 +647,6 @@ PluginInstanceParent::GetImage(ImageContainer* aContainer, Image** aImage)
|
||||
#ifdef XP_MACOSX
|
||||
if (ioSurface) {
|
||||
format = Image::MAC_IO_SURFACE;
|
||||
if (!aContainer->Manager()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -83,6 +83,7 @@ EXTRA_COMPONENTS = \
|
||||
EXTRA_JS_MODULES = \
|
||||
ril_consts.js \
|
||||
ril_worker.js \
|
||||
systemlibs.js \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -47,7 +47,7 @@ Cu.import("resource://gre/modules/Services.jsm");
|
||||
var RIL = {};
|
||||
Cu.import("resource://gre/modules/ril_consts.js", RIL);
|
||||
|
||||
const DEBUG = true; // set to false to suppress debug messages
|
||||
const DEBUG = false; // set to true to see debug messages
|
||||
|
||||
const RADIOINTERFACELAYER_CID =
|
||||
Components.ID("{2d831c8d-6017-435b-a80c-e5d422810cea}");
|
||||
@ -241,7 +241,9 @@ RadioInterfaceLayer.prototype = {
|
||||
handleCallStateChange: function handleCallStateChange(call) {
|
||||
debug("handleCallStateChange: " + JSON.stringify(call));
|
||||
call.state = convertRILCallState(call.state);
|
||||
if (call.state == nsIRadioInterfaceLayer.CALL_STATE_CONNECTED) {
|
||||
if (call.state == nsIRadioInterfaceLayer.CALL_STATE_DIALING ||
|
||||
call.state == nsIRadioInterfaceLayer.CALL_STATE_RINGING ||
|
||||
call.state == nsIRadioInterfaceLayer.CALL_STATE_CONNECTED) {
|
||||
// This is now the active call.
|
||||
this._activeCall = call;
|
||||
}
|
||||
|
@ -62,7 +62,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
importScripts("ril_consts.js");
|
||||
importScripts("ril_consts.js", "systemlibs.js");
|
||||
|
||||
let DEBUG = false;
|
||||
|
||||
@ -72,6 +72,8 @@ const UINT16_SIZE = 2;
|
||||
const UINT32_SIZE = 4;
|
||||
const PARCEL_SIZE_SIZE = UINT32_SIZE;
|
||||
|
||||
let RILQUIRKS_CALLSTATE_EXTRA_UINT32 = false;
|
||||
|
||||
/**
|
||||
* This object contains helpers buffering incoming data & deconstructing it
|
||||
* into parcels as well as buffering outgoing data & constructing parcels.
|
||||
@ -432,7 +434,6 @@ let Buf = {
|
||||
/**
|
||||
* Process one parcel.
|
||||
*/
|
||||
|
||||
processParcel: function processParcel() {
|
||||
let response_type = this.readUint32();
|
||||
let length = this.readIncoming - UINT32_SIZE;
|
||||
@ -445,20 +446,24 @@ let Buf = {
|
||||
request_type = this.tokenRequestMap[token];
|
||||
if (error) {
|
||||
//TODO
|
||||
debug("Received error " + error + " for solicited parcel type " +
|
||||
request_type);
|
||||
if (DEBUG) {
|
||||
debug("Received error " + error + " for solicited parcel type " +
|
||||
request_type);
|
||||
}
|
||||
return;
|
||||
}
|
||||
debug("Solicited response for request type " + request_type +
|
||||
", token " + token);
|
||||
if (DEBUG) {
|
||||
debug("Solicited response for request type " + request_type +
|
||||
", token " + token);
|
||||
}
|
||||
delete this.tokenRequestMap[token];
|
||||
this.lastSolicitedToken = token;
|
||||
} else if (response_type == RESPONSE_TYPE_UNSOLICITED) {
|
||||
request_type = this.readUint32();
|
||||
length -= UINT32_SIZE;
|
||||
debug("Unsolicited response for request type " + request_type);
|
||||
if (DEBUG) debug("Unsolicited response for request type " + request_type);
|
||||
} else {
|
||||
debug("Unknown response type: " + response_type);
|
||||
if (DEBUG) debug("Unknown response type: " + response_type);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -483,9 +488,8 @@ let Buf = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Communication with the RIL IPC thread.
|
||||
* Communicate with the RIL IPC thread.
|
||||
*/
|
||||
|
||||
sendParcel: function sendParcel() {
|
||||
// Compute the size of the parcel and write it to the front of the parcel
|
||||
// where we left room for it. Note that he parcel size does not include
|
||||
@ -496,7 +500,7 @@ let Buf = {
|
||||
// This assumes that postRILMessage will make a copy of the ArrayBufferView
|
||||
// right away!
|
||||
let parcel = this.outgoingBytes.subarray(0, this.outgoingIndex);
|
||||
debug("Outgoing parcel: " + Array.slice(parcel));
|
||||
if (DEBUG) debug("Outgoing parcel: " + Array.slice(parcel));
|
||||
postRILMessage(parcel);
|
||||
this.outgoingIndex = PARCEL_SIZE_SIZE;
|
||||
},
|
||||
@ -516,6 +520,25 @@ let Buf = {
|
||||
*/
|
||||
let RIL = {
|
||||
|
||||
/**
|
||||
* Set quirk flags based on the RIL model detected. Note that this
|
||||
* requires the RIL being "warmed up" first, which happens when on
|
||||
* an incoming or outgoing call.
|
||||
*/
|
||||
rilQuirksInitialized: false,
|
||||
initRILQuirks: function initRILQuirks() {
|
||||
// The Samsung Galaxy S2 I-9100 radio sends an extra Uint32 in the
|
||||
// call state.
|
||||
let model_id = libcutils.property_get("ril.model_id");
|
||||
if (DEBUG) debug("Detected RIL model " + model_id);
|
||||
if (model_id == "I9100") {
|
||||
if (DEBUG) debug("Enabling RILQUIRKS_CALLSTATE_EXTRA_UINT32 for I9100.");
|
||||
RILQUIRKS_CALLSTATE_EXTRA_UINT32 = true;
|
||||
}
|
||||
|
||||
this.rilQuirksInitialized = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve the ICC's status.
|
||||
*
|
||||
@ -865,7 +888,7 @@ let RIL = {
|
||||
handleParcel: function handleParcel(request_type, length) {
|
||||
let method = this[request_type];
|
||||
if (typeof method == "function") {
|
||||
debug("Handling parcel as " + method.name);
|
||||
if (DEBUG) debug("Handling parcel as " + method.name);
|
||||
method.call(this, length);
|
||||
}
|
||||
}
|
||||
@ -915,6 +938,10 @@ RIL[REQUEST_CHANGE_SIM_PIN] = function REQUEST_CHANGE_SIM_PIN() {
|
||||
RIL[REQUEST_CHANGE_SIM_PIN2] = null;
|
||||
RIL[REQUEST_ENTER_NETWORK_DEPERSONALIZATION] = null;
|
||||
RIL[REQUEST_GET_CURRENT_CALLS] = function REQUEST_GET_CURRENT_CALLS(length) {
|
||||
if (!this.rilQuirksInitialized) {
|
||||
this.initRILQuirks();
|
||||
}
|
||||
|
||||
let calls_length = 0;
|
||||
// The RIL won't even send us the length integer if there are no active calls.
|
||||
// So only read this integer if the parcel actually has it.
|
||||
@ -928,22 +955,24 @@ RIL[REQUEST_GET_CURRENT_CALLS] = function REQUEST_GET_CURRENT_CALLS(length) {
|
||||
|
||||
let calls = {};
|
||||
for (let i = 0; i < calls_length; i++) {
|
||||
let call = {
|
||||
state: Buf.readUint32(), // CALL_STATE_*
|
||||
callIndex: Buf.readUint32(), // GSM index (1-based)
|
||||
toa: Buf.readUint32(),
|
||||
isMpty: Boolean(Buf.readUint32()),
|
||||
isMT: Boolean(Buf.readUint32()),
|
||||
als: Buf.readUint32(),
|
||||
isVoice: Boolean(Buf.readUint32()),
|
||||
isVoicePrivacy: Boolean(Buf.readUint32()),
|
||||
somethingOrOther: Buf.readUint32(), //XXX TODO whatziz? not in ril.h, but it's in the output...
|
||||
number: Buf.readString(), //TODO munge with TOA
|
||||
numberPresentation: Buf.readUint32(), // CALL_PRESENTATION_*
|
||||
name: Buf.readString(),
|
||||
namePresentation: Buf.readUint32(),
|
||||
uusInfo: null
|
||||
};
|
||||
let call = {};
|
||||
call.state = Buf.readUint32(); // CALL_STATE_*
|
||||
call.callIndex = Buf.readUint32(); // GSM index (1-based)
|
||||
call.toa = Buf.readUint32();
|
||||
call.isMpty = Boolean(Buf.readUint32());
|
||||
call.isMT = Boolean(Buf.readUint32());
|
||||
call.als = Buf.readUint32();
|
||||
call.isVoice = Boolean(Buf.readUint32());
|
||||
call.isVoicePrivacy = Boolean(Buf.readUint32());
|
||||
if (RILQUIRKS_CALLSTATE_EXTRA_UINT32) {
|
||||
Buf.readUint32();
|
||||
}
|
||||
call.number = Buf.readString(); //TODO munge with TOA
|
||||
call.numberPresentation = Buf.readUint32(); // CALL_PRESENTATION_*
|
||||
call.name = Buf.readString();
|
||||
call.namePresentation = Buf.readUint32();
|
||||
|
||||
call.uusInfo = null;
|
||||
let uusInfoPresent = Buf.readUint32();
|
||||
if (uusInfoPresent == 1) {
|
||||
call.uusInfo = {
|
||||
@ -952,6 +981,7 @@ RIL[REQUEST_GET_CURRENT_CALLS] = function REQUEST_GET_CURRENT_CALLS(length) {
|
||||
userData: null //XXX TODO byte array?!?
|
||||
};
|
||||
}
|
||||
|
||||
calls[call.callIndex] = call;
|
||||
}
|
||||
Phone.onCurrentCalls(calls);
|
||||
@ -1218,9 +1248,6 @@ RIL[UNSOLICITED_RESEND_INCALL_MUTE] = null;
|
||||
*/
|
||||
let Phone = {
|
||||
|
||||
//XXX TODO beware, this is just demo code. It's still missing
|
||||
// communication with the UI thread.
|
||||
|
||||
/**
|
||||
* One of the RADIO_STATE_* constants.
|
||||
*/
|
||||
@ -1313,7 +1340,9 @@ let Phone = {
|
||||
*/
|
||||
|
||||
onRadioStateChanged: function onRadioStateChanged(newState) {
|
||||
debug("Radio state changed from " + this.radioState + " to " + newState);
|
||||
if (DEBUG) {
|
||||
debug("Radio state changed from " + this.radioState + " to " + newState);
|
||||
}
|
||||
if (this.radioState == newState) {
|
||||
// No change in state, return.
|
||||
return;
|
||||
@ -1455,13 +1484,13 @@ let Phone = {
|
||||
},
|
||||
|
||||
onNetworkStateChanged: function onNetworkStateChanged() {
|
||||
debug("Network state changed, re-requesting phone state.");
|
||||
if (DEBUG) debug("Network state changed, re-requesting phone state.");
|
||||
this.requestNetworkInfo();
|
||||
},
|
||||
|
||||
onICCStatus: function onICCStatus(iccStatus) {
|
||||
if (DEBUG) {
|
||||
debug("iccStatus: " + JSON.stringify(iccStatus));
|
||||
debug("iccStatus: " + JSON.stringify(iccStatus));
|
||||
}
|
||||
this.iccStatus = iccStatus;
|
||||
|
||||
|
79
dom/system/b2g/systemlibs.js
Normal file
79
dom/system/b2g/systemlibs.js
Normal file
@ -0,0 +1,79 @@
|
||||
/* 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/. */
|
||||
|
||||
const SYSTEM_PROPERTY_KEY_MAX = 32;
|
||||
const SYSTEM_PROPERTY_VALUE_MAX = 92;
|
||||
|
||||
/**
|
||||
* Expose some system-level functions.
|
||||
*/
|
||||
let libcutils = (function() {
|
||||
let lib;
|
||||
try {
|
||||
lib = ctypes.open("libcutils.so");
|
||||
} catch(ex) {
|
||||
// Return a fallback option in case libcutils.so isn't present (e.g.
|
||||
// when building Firefox with MOZ_B2G_RIL.
|
||||
dump("Could not load libcutils.so. Using fake propdb.");
|
||||
let fake_propdb = Object.create(null);
|
||||
return {
|
||||
property_get: function fake_property_get(key, defaultValue) {
|
||||
if (key in fake_propdb) {
|
||||
return fake_propdb[key];
|
||||
}
|
||||
return defaultValue === undefined ? null : defaultValue;
|
||||
},
|
||||
property_set: function fake_property_set(key, value) {
|
||||
fake_propdb[key] = value;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let c_property_get = lib.declare("property_get", ctypes.default_abi,
|
||||
ctypes.int, // return value: length
|
||||
ctypes.char.ptr, // key
|
||||
ctypes.char.ptr, // value
|
||||
ctypes.char.ptr); // default
|
||||
let c_property_set = lib.declare("property_set", ctypes.default_abi,
|
||||
ctypes.int, // return value: success
|
||||
ctypes.char.ptr, // key
|
||||
ctypes.char.ptr); // value
|
||||
let c_value_buf = ctypes.char.array(SYSTEM_PROPERTY_VALUE_MAX)();
|
||||
|
||||
return {
|
||||
|
||||
/**
|
||||
* Get a system property.
|
||||
*
|
||||
* @param key
|
||||
* Name of the property
|
||||
* @param defaultValue [optional]
|
||||
* Default value to return if the property isn't set (default: null)
|
||||
*/
|
||||
property_get: function property_get(key, defaultValue) {
|
||||
if (defaultValue === undefined) {
|
||||
defaultValue = null;
|
||||
}
|
||||
c_property_get(key, c_value_buf, defaultValue);
|
||||
return c_value_buf.readString();
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a system property
|
||||
*
|
||||
* @param key
|
||||
* Name of the property
|
||||
* @param value
|
||||
* Value to set the property to.
|
||||
*/
|
||||
property_set: function property_set(key, value) {
|
||||
let rv = c_property_set(key, value);
|
||||
if (rv) {
|
||||
throw Error('libcutils.property_set("' + key + '", "' + value +
|
||||
'") failed with error ' + rv);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
})();
|
@ -293,6 +293,8 @@ CreateJSContextForWorker(WorkerPrivate* aWorkerPrivate)
|
||||
JS_SetGCParameter(runtime, JSGC_MAX_BYTES,
|
||||
aWorkerPrivate->GetJSRuntimeHeapSize());
|
||||
|
||||
JS_SetNativeStackQuota(runtime, WORKER_CONTEXT_NATIVE_STACK_LIMIT);
|
||||
|
||||
JSContext* workerCx = JS_NewContext(runtime, 0);
|
||||
if (!workerCx) {
|
||||
JS_DestroyRuntime(runtime);
|
||||
@ -306,8 +308,6 @@ CreateJSContextForWorker(WorkerPrivate* aWorkerPrivate)
|
||||
|
||||
JS_SetOperationCallback(workerCx, OperationCallback);
|
||||
|
||||
JS_SetNativeStackQuota(workerCx, WORKER_CONTEXT_NATIVE_STACK_LIMIT);
|
||||
|
||||
NS_ASSERTION((aWorkerPrivate->GetJSContextOptions() &
|
||||
kRequiredJSContextOptions) == kRequiredJSContextOptions,
|
||||
"Somehow we lost our required options!");
|
||||
|
@ -155,6 +155,8 @@ SwapToISupportsArray(SmartPtr<T>& aSrc,
|
||||
dest->swap(rawSupports);
|
||||
}
|
||||
|
||||
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(JsWorkerMallocSizeOf, "js-worker")
|
||||
|
||||
class WorkerMemoryReporter : public nsIMemoryMultiReporter
|
||||
{
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
@ -232,7 +234,7 @@ public:
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
JS::RuntimeStats rtStats(xpc::JsMallocSizeOf, xpc::GetCompartmentName,
|
||||
JS::RuntimeStats rtStats(JsWorkerMallocSizeOf, xpc::GetCompartmentName,
|
||||
xpc::DestroyCompartmentName);
|
||||
nsresult rv = CollectForRuntime(/* isQuick = */false, &rtStats);
|
||||
if (NS_FAILED(rv)) {
|
||||
@ -1523,7 +1525,7 @@ public:
|
||||
JSAutoSuspendRequest asr(aCx);
|
||||
|
||||
*mSucceeded = mIsQuick
|
||||
? JS::GetExplicitNonHeapForRuntime(JS_GetRuntime(aCx), static_cast<int64_t*>(mData), xpc::JsMallocSizeOf)
|
||||
? JS::GetExplicitNonHeapForRuntime(JS_GetRuntime(aCx), static_cast<int64_t*>(mData), JsWorkerMallocSizeOf)
|
||||
: JS::CollectRuntimeStats(JS_GetRuntime(aCx), static_cast<JS::RuntimeStats*>(mData));
|
||||
|
||||
{
|
||||
|
@ -9,9 +9,17 @@
|
||||
android:sharedUserId="@MOZ_ANDROID_SHARED_ID@"
|
||||
#endif
|
||||
>
|
||||
|
||||
<uses-sdk android:minSdkVersion="5"
|
||||
android:targetSdkVersion="11"/>
|
||||
|
||||
#ifdef MOZ_TABLETS_ONLY
|
||||
<supports-screens android:smallScreens="false"
|
||||
android:normalScreens="false"
|
||||
android:largeScreens="false"
|
||||
android:xlargeScreens="true" />
|
||||
#endif
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
@ -1792,5 +1792,5 @@ public class GeckoAppShell
|
||||
}
|
||||
|
||||
// This is only used in Native Fennec.
|
||||
public static void preventPanning() { }
|
||||
public static void setPreventPanning(final boolean aPreventPanning) { }
|
||||
}
|
||||
|
@ -79,7 +79,8 @@ MIN_CPU_VERSION=5
|
||||
endif
|
||||
|
||||
ifeq (,$(ANDROID_VERSION_CODE))
|
||||
ANDROID_VERSION_CODE=$(shell $(PYTHON) $(topsrcdir)/toolkit/xre/make-platformini.py --print-buildid | cut -c1-10)
|
||||
# increment the version code by 1 so xul fennec will win any compatability ties
|
||||
ANDROID_VERSION_CODE=$(shell echo `$(PYTHON) $(topsrcdir)/toolkit/xre/make-platformini.py --print-buildid | cut -c1-10` + 1 | bc)
|
||||
endif
|
||||
|
||||
DEFINES += \
|
||||
@ -94,6 +95,11 @@ DEFINES += \
|
||||
-DMOZILLA_OFFICIAL=$(MOZILLA_OFFICIAL) \
|
||||
$(NULL)
|
||||
|
||||
MOZ_MOBILE_COMPAT = @MOZ_MOBILE_COMPAT@
|
||||
ifeq (Tablets,$(MOZ_MOBILE_COMPAT))
|
||||
DEFINES += -DMOZ_TABLETS_ONLY=1
|
||||
endif
|
||||
|
||||
GARBAGE += \
|
||||
AndroidManifest.xml \
|
||||
classes.dex \
|
||||
|
@ -1108,8 +1108,6 @@ GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize, const bool aUseReadFBO, c
|
||||
return true;
|
||||
}
|
||||
|
||||
const bool firstTime = (mOffscreenDrawFBO == 0 && mOffscreenReadFBO == 0);
|
||||
|
||||
GLuint curBoundFramebufferDraw = 0;
|
||||
GLuint curBoundFramebufferRead = 0;
|
||||
GLuint curBoundRenderbuffer = 0;
|
||||
@ -1412,8 +1410,7 @@ GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize, const bool aUseReadFBO, c
|
||||
|
||||
#ifdef DEBUG
|
||||
if (DebugMode()) {
|
||||
printf_stderr("%s %dx%d offscreen FBO: r: %d g: %d b: %d a: %d depth: %d stencil: %d samples: %d\n",
|
||||
firstTime ? "Created" : "Resized",
|
||||
printf_stderr("Resized %dx%d offscreen FBO: r: %d g: %d b: %d a: %d depth: %d stencil: %d samples: %d\n",
|
||||
mOffscreenActualSize.width, mOffscreenActualSize.height,
|
||||
mActualFormat.red, mActualFormat.green, mActualFormat.blue, mActualFormat.alpha,
|
||||
mActualFormat.depth, mActualFormat.stencil, mActualFormat.samples);
|
||||
@ -1429,13 +1426,7 @@ GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize, const bool aUseReadFBO, c
|
||||
BindReadFBO(curBoundFramebufferRead);
|
||||
fBindTexture(LOCAL_GL_TEXTURE_2D, curBoundTexture);
|
||||
fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, curBoundRenderbuffer);
|
||||
|
||||
// -don't- restore the viewport the first time through this, since
|
||||
// the previous one isn't valid.
|
||||
if (firstTime)
|
||||
fViewport(0, 0, aSize.width, aSize.height); // XXX This is coming out in 711642
|
||||
else
|
||||
fViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
|
||||
fViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
275
gfx/layers/ImageLayers.cpp
Normal file
275
gfx/layers/ImageLayers.cpp
Normal file
@ -0,0 +1,275 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Corporation code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Bas Schouten <bschouten@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "mozilla/ipc/Shmem.h"
|
||||
#include "ImageLayers.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "yuv_convert.h"
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include "nsCoreAnimationSupport.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
already_AddRefed<Image>
|
||||
ImageFactory::CreateImage(const Image::Format *aFormats,
|
||||
PRUint32 aNumFormats,
|
||||
const gfxIntSize &,
|
||||
BufferRecycleBin *aRecycleBin)
|
||||
{
|
||||
if (!aNumFormats) {
|
||||
return nsnull;
|
||||
}
|
||||
nsRefPtr<Image> img;
|
||||
if (FormatInList(aFormats, aNumFormats, Image::PLANAR_YCBCR)) {
|
||||
img = new PlanarYCbCrImage(aRecycleBin);
|
||||
} else if (FormatInList(aFormats, aNumFormats, Image::CAIRO_SURFACE)) {
|
||||
img = new CairoImage();
|
||||
#ifdef XP_MACOSX
|
||||
} else if (FormatInList(aFormats, aNumFormats, Image::MAC_IO_SURFACE)) {
|
||||
img = new MacIOSurfaceImage();
|
||||
#endif
|
||||
}
|
||||
return img.forget();
|
||||
}
|
||||
|
||||
BufferRecycleBin::BufferRecycleBin()
|
||||
: mLock("mozilla.layers.BufferRecycleBin.mLock")
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BufferRecycleBin::RecycleBuffer(PRUint8* aBuffer, PRUint32 aSize)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
if (!mRecycledBuffers.IsEmpty() && aSize != mRecycledBufferSize) {
|
||||
mRecycledBuffers.Clear();
|
||||
}
|
||||
mRecycledBufferSize = aSize;
|
||||
mRecycledBuffers.AppendElement(aBuffer);
|
||||
}
|
||||
|
||||
PRUint8*
|
||||
BufferRecycleBin::GetBuffer(PRUint32 aSize)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
if (mRecycledBuffers.IsEmpty() || mRecycledBufferSize != aSize)
|
||||
return new PRUint8[aSize];
|
||||
|
||||
PRUint32 last = mRecycledBuffers.Length() - 1;
|
||||
PRUint8* result = mRecycledBuffers[last].forget();
|
||||
mRecycledBuffers.RemoveElementAt(last);
|
||||
return result;
|
||||
}
|
||||
|
||||
ImageContainer::~ImageContainer()
|
||||
{
|
||||
}
|
||||
|
||||
already_AddRefed<Image>
|
||||
ImageContainer::CreateImage(const Image::Format *aFormats,
|
||||
PRUint32 aNumFormats)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
return mImageFactory->CreateImage(aFormats, aNumFormats, mScaleHint, mRecycleBin);
|
||||
}
|
||||
|
||||
void
|
||||
ImageContainer::SetCurrentImage(Image *aImage)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
mActiveImage = aImage;
|
||||
CurrentImageChanged();
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
ImageContainer::GetCurrentAsSurface(gfxIntSize *aSize)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
if (!mActiveImage) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
*aSize = mActiveImage->GetSize();
|
||||
return mActiveImage->GetAsSurface();
|
||||
}
|
||||
|
||||
gfxIntSize
|
||||
ImageContainer::GetCurrentSize()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
if (!mActiveImage) {
|
||||
return gfxIntSize(0,0);
|
||||
}
|
||||
|
||||
return mActiveImage->GetSize();
|
||||
}
|
||||
|
||||
PlanarYCbCrImage::PlanarYCbCrImage(BufferRecycleBin *aRecycleBin)
|
||||
: Image(nsnull, PLANAR_YCBCR)
|
||||
, mBufferSize(0)
|
||||
, mRecycleBin(aRecycleBin)
|
||||
{
|
||||
}
|
||||
|
||||
PlanarYCbCrImage::~PlanarYCbCrImage()
|
||||
{
|
||||
if (mBuffer) {
|
||||
mRecycleBin->RecycleBuffer(mBuffer.forget(), mBufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
PRUint8*
|
||||
PlanarYCbCrImage::AllocateBuffer(PRUint32 aSize)
|
||||
{
|
||||
return mRecycleBin->GetBuffer(aSize);
|
||||
}
|
||||
|
||||
void
|
||||
PlanarYCbCrImage::CopyData(const Data& aData)
|
||||
{
|
||||
mData = aData;
|
||||
|
||||
mData.mYStride = mData.mYSize.width;
|
||||
mData.mCbCrStride = mData.mCbCrSize.width;
|
||||
|
||||
// update buffer size
|
||||
mBufferSize = mData.mCbCrStride * mData.mCbCrSize.height * 2 +
|
||||
mData.mYStride * mData.mYSize.height;
|
||||
|
||||
// get new buffer
|
||||
mBuffer = AllocateBuffer(mBufferSize);
|
||||
if (!mBuffer)
|
||||
return;
|
||||
|
||||
mData.mYChannel = mBuffer;
|
||||
mData.mCbChannel = mData.mYChannel + mData.mYStride * mData.mYSize.height;
|
||||
mData.mCrChannel = mData.mCbChannel + mData.mCbCrStride * mData.mCbCrSize.height;
|
||||
|
||||
for (int i = 0; i < mData.mYSize.height; i++) {
|
||||
memcpy(mData.mYChannel + i * mData.mYStride,
|
||||
aData.mYChannel + i * aData.mYStride,
|
||||
mData.mYStride);
|
||||
}
|
||||
for (int i = 0; i < mData.mCbCrSize.height; i++) {
|
||||
memcpy(mData.mCbChannel + i * mData.mCbCrStride,
|
||||
aData.mCbChannel + i * aData.mCbCrStride,
|
||||
mData.mCbCrStride);
|
||||
memcpy(mData.mCrChannel + i * mData.mCbCrStride,
|
||||
aData.mCrChannel + i * aData.mCbCrStride,
|
||||
mData.mCbCrStride);
|
||||
}
|
||||
|
||||
mSize = aData.mPicSize;
|
||||
}
|
||||
|
||||
void
|
||||
PlanarYCbCrImage::SetData(const Data &aData)
|
||||
{
|
||||
CopyData(aData);
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
PlanarYCbCrImage::GetAsSurface()
|
||||
{
|
||||
if (mSurface) {
|
||||
nsRefPtr<gfxASurface> result = mSurface.get();
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
nsRefPtr<gfxImageSurface> imageSurface =
|
||||
new gfxImageSurface(mSize, gfxASurface::ImageFormatRGB24);
|
||||
|
||||
gfx::YUVType type =
|
||||
gfx::TypeFromSize(mData.mYSize.width,
|
||||
mData.mYSize.height,
|
||||
mData.mCbCrSize.width,
|
||||
mData.mCbCrSize.height);
|
||||
|
||||
// Convert from YCbCr to RGB now
|
||||
gfx::ConvertYCbCrToRGB32(mData.mYChannel,
|
||||
mData.mCbChannel,
|
||||
mData.mCrChannel,
|
||||
imageSurface->Data(),
|
||||
mData.mPicX,
|
||||
mData.mPicY,
|
||||
mData.mPicSize.width,
|
||||
mData.mPicSize.height,
|
||||
mData.mYStride,
|
||||
mData.mCbCrStride,
|
||||
imageSurface->Stride(),
|
||||
type);
|
||||
|
||||
mSurface = imageSurface;
|
||||
|
||||
return imageSurface.forget().get();
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
void
|
||||
MacIOSurfaceImage::SetData(const Data& aData)
|
||||
{
|
||||
mIOSurface = nsIOSurface::LookupSurface(aData.mIOSurface->GetIOSurfaceID());
|
||||
mSize = gfxIntSize(mIOSurface->GetWidth(), mIOSurface->GetHeight());
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
MacIOSurfaceImage::GetAsSurface()
|
||||
{
|
||||
return mIOSurface->GetAsSurface();
|
||||
}
|
||||
|
||||
void
|
||||
MacIOSurfaceImage::Update(ImageContainer* aContainer)
|
||||
{
|
||||
if (mUpdateCallback) {
|
||||
mUpdateCallback(aContainer, mPluginInstanceOwner);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
@ -46,8 +46,12 @@
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "gfxPlatform.h"
|
||||
|
||||
class nsIOSurface;
|
||||
#ifdef XP_MACOSX
|
||||
#include "nsIOSurface.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
@ -60,6 +64,14 @@ enum StereoMode {
|
||||
STEREO_MODE_TOP_BOTTOM
|
||||
};
|
||||
|
||||
struct ImageBackendData
|
||||
{
|
||||
virtual ~ImageBackendData() {}
|
||||
|
||||
protected:
|
||||
ImageBackendData() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* A class representing a buffer of pixel data. The data can be in one
|
||||
* of various formats including YCbCr.
|
||||
@ -104,8 +116,7 @@ public:
|
||||
CAIRO_SURFACE,
|
||||
|
||||
/**
|
||||
* The MAC_IO_SURFACE format creates a MacIOSurfaceImage. This
|
||||
* is only supported on Mac with OpenGL layers.
|
||||
* The MAC_IO_SURFACE format creates a MacIOSurfaceImage.
|
||||
*
|
||||
* It wraps an IOSurface object and binds it directly to a GL texture.
|
||||
*/
|
||||
@ -115,16 +126,106 @@ public:
|
||||
Format GetFormat() { return mFormat; }
|
||||
void* GetImplData() { return mImplData; }
|
||||
|
||||
virtual already_AddRefed<gfxASurface> GetAsSurface() = 0;
|
||||
virtual gfxIntSize GetSize() = 0;
|
||||
|
||||
ImageBackendData* GetBackendData(LayerManager::LayersBackend aBackend)
|
||||
{ return mBackendData[aBackend]; }
|
||||
void SetBackendData(LayerManager::LayersBackend aBackend, ImageBackendData* aData)
|
||||
{ mBackendData[aBackend] = aData; }
|
||||
|
||||
protected:
|
||||
Image(void* aImplData, Format aFormat) :
|
||||
mImplData(aImplData),
|
||||
mFormat(aFormat)
|
||||
{}
|
||||
|
||||
nsAutoPtr<ImageBackendData> mBackendData[LayerManager::LAYERS_LAST];
|
||||
|
||||
void* mImplData;
|
||||
Format mFormat;
|
||||
};
|
||||
|
||||
/**
|
||||
* A RecycleBin is owned by an ImageContainer. We store buffers in it that we
|
||||
* want to recycle from one image to the next.It's a separate object from
|
||||
* ImageContainer because images need to store a strong ref to their RecycleBin
|
||||
* and we must avoid creating a reference loop between an ImageContainer and
|
||||
* its active image.
|
||||
*/
|
||||
class BufferRecycleBin {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RecycleBin)
|
||||
|
||||
typedef mozilla::gl::GLContext GLContext;
|
||||
|
||||
public:
|
||||
BufferRecycleBin();
|
||||
|
||||
void RecycleBuffer(PRUint8* aBuffer, PRUint32 aSize);
|
||||
// Returns a recycled buffer of the right size, or allocates a new buffer.
|
||||
PRUint8* GetBuffer(PRUint32 aSize);
|
||||
|
||||
private:
|
||||
typedef mozilla::Mutex Mutex;
|
||||
|
||||
// This protects mRecycledBuffers, mRecycledBufferSize, mRecycledTextures
|
||||
// and mRecycledTextureSizes
|
||||
Mutex mLock;
|
||||
|
||||
// We should probably do something to prune this list on a timer so we don't
|
||||
// eat excess memory while video is paused...
|
||||
nsTArray<nsAutoArrayPtr<PRUint8> > mRecycledBuffers;
|
||||
// This is only valid if mRecycledBuffers is non-empty
|
||||
PRUint32 mRecycledBufferSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if aFormat is in the given format array.
|
||||
*/
|
||||
static inline bool
|
||||
FormatInList(const Image::Format* aFormats, PRUint32 aNumFormats,
|
||||
Image::Format aFormat)
|
||||
{
|
||||
for (PRUint32 i = 0; i < aNumFormats; ++i) {
|
||||
if (aFormats[i] == aFormat) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that manages Image creation for a LayerManager. The only reason
|
||||
* we need a separate class here is that LayerMananers aren't threadsafe
|
||||
* (because layers can only be used on the main thread) and we want to
|
||||
* be able to create images from any thread, to facilitate video playback
|
||||
* without involving the main thread, for example.
|
||||
* Different layer managers can implement child classes of this making it
|
||||
* possible to create layer manager specific images.
|
||||
* This class is not meant to be used directly but rather can be set on an
|
||||
* image container. This is usually done by the layer system internally and
|
||||
* not explicitly by users. For PlanarYCbCr or Cairo images the default
|
||||
* implementation will creates images whose data lives in system memory, for
|
||||
* MacIOSurfaces the default implementation will be a simple nsIOSurface
|
||||
* wrapper.
|
||||
*/
|
||||
|
||||
class THEBES_API ImageFactory
|
||||
{
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageFactory)
|
||||
protected:
|
||||
friend class ImageContainer;
|
||||
|
||||
ImageFactory() {}
|
||||
virtual ~ImageFactory() {}
|
||||
|
||||
virtual already_AddRefed<Image> CreateImage(const Image::Format* aFormats,
|
||||
PRUint32 aNumFormats,
|
||||
const gfxIntSize &aScaleHint,
|
||||
BufferRecycleBin *aRecycleBin);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* A class that manages Images for an ImageLayer. The only reason
|
||||
* we need a separate class here is that ImageLayers aren't threadsafe
|
||||
@ -139,10 +240,12 @@ public:
|
||||
ImageContainer() :
|
||||
mReentrantMonitor("ImageContainer.mReentrantMonitor"),
|
||||
mPaintCount(0),
|
||||
mPreviousImagePainted(false)
|
||||
mPreviousImagePainted(false),
|
||||
mImageFactory(new ImageFactory()),
|
||||
mRecycleBin(new BufferRecycleBin())
|
||||
{}
|
||||
|
||||
virtual ~ImageContainer() {}
|
||||
~ImageContainer();
|
||||
|
||||
/**
|
||||
* Create an Image in one of the given formats.
|
||||
@ -152,8 +255,8 @@ public:
|
||||
* Can be called on any thread. This method takes mReentrantMonitor
|
||||
* when accessing thread-shared state.
|
||||
*/
|
||||
virtual already_AddRefed<Image> CreateImage(const Image::Format* aFormats,
|
||||
PRUint32 aNumFormats) = 0;
|
||||
already_AddRefed<Image> CreateImage(const Image::Format* aFormats,
|
||||
PRUint32 aNumFormats);
|
||||
|
||||
/**
|
||||
* Set an Image as the current image to display. The Image must have
|
||||
@ -163,13 +266,7 @@ public:
|
||||
*
|
||||
* The Image data must not be modified after this method is called!
|
||||
*/
|
||||
virtual void SetCurrentImage(Image* aImage) = 0;
|
||||
|
||||
/**
|
||||
* Ask any PlanarYCbCr images created by this container to delay
|
||||
* YUV -> RGB conversion until draw time. See PlanarYCbCrImage::SetDelayedConversion.
|
||||
*/
|
||||
virtual void SetDelayedConversion(bool aDelayed) {}
|
||||
void SetCurrentImage(Image* aImage);
|
||||
|
||||
/**
|
||||
* Get the current Image.
|
||||
@ -181,7 +278,13 @@ public:
|
||||
* Implementations must call CurrentImageChanged() while holding
|
||||
* mReentrantMonitor.
|
||||
*/
|
||||
virtual already_AddRefed<Image> GetCurrentImage() = 0;
|
||||
already_AddRefed<Image> GetCurrentImage()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
nsRefPtr<Image> retval = mActiveImage;
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current image as a gfxASurface. This is useful for fallback
|
||||
@ -198,32 +301,14 @@ public:
|
||||
* Can be called on any thread. This method takes mReentrantMonitor
|
||||
* when accessing thread-shared state.
|
||||
*/
|
||||
virtual already_AddRefed<gfxASurface> GetCurrentAsSurface(gfxIntSize* aSizeResult) = 0;
|
||||
|
||||
/**
|
||||
* Returns the layer manager for this container. This can only
|
||||
* be used on the main thread, since layer managers should only be
|
||||
* accessed on the main thread.
|
||||
*/
|
||||
LayerManager* Manager()
|
||||
{
|
||||
NS_PRECONDITION(NS_IsMainThread(), "Must be called on main thread");
|
||||
return mManager;
|
||||
}
|
||||
already_AddRefed<gfxASurface> GetCurrentAsSurface(gfxIntSize* aSizeResult);
|
||||
|
||||
/**
|
||||
* Returns the size of the image in pixels.
|
||||
* Can be called on any thread. This method takes mReentrantMonitor when accessing
|
||||
* thread-shared state.
|
||||
*/
|
||||
virtual gfxIntSize GetCurrentSize() = 0;
|
||||
|
||||
/**
|
||||
* Set a new layer manager for this image container. It must be
|
||||
* either of the same type as the container's current layer manager,
|
||||
* or null. TRUE is returned on success. Main thread only.
|
||||
*/
|
||||
virtual bool SetLayerManager(LayerManager *aManager) = 0;
|
||||
gfxIntSize GetCurrentSize();
|
||||
|
||||
/**
|
||||
* Sets a size that the image is expected to be rendered at.
|
||||
@ -232,14 +317,14 @@ public:
|
||||
* Can be called on any thread. This method takes mReentrantMonitor
|
||||
* when accessing thread-shared state.
|
||||
*/
|
||||
virtual void SetScaleHint(const gfxIntSize& /* aScaleHint */) { }
|
||||
void SetScaleHint(const gfxIntSize& aScaleHint)
|
||||
{ mScaleHint = aScaleHint; }
|
||||
|
||||
/**
|
||||
* Get the layer manager type this image container was created with,
|
||||
* presumably its users might want to do something special if types do not
|
||||
* match. Can be called on any thread.
|
||||
*/
|
||||
virtual LayerManager::LayersBackend GetBackendType() = 0;
|
||||
void SetImageFactory(ImageFactory *aFactory)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
mImageFactory = aFactory ? aFactory : new ImageFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time at which the currently contained image was first
|
||||
@ -285,19 +370,11 @@ public:
|
||||
|
||||
protected:
|
||||
typedef mozilla::ReentrantMonitor ReentrantMonitor;
|
||||
LayerManager* mManager;
|
||||
|
||||
// ReentrantMonitor to protect thread safe access to the "current
|
||||
// image", and any other state which is shared between threads.
|
||||
ReentrantMonitor mReentrantMonitor;
|
||||
|
||||
ImageContainer(LayerManager* aManager) :
|
||||
mManager(aManager),
|
||||
mReentrantMonitor("ImageContainer.mReentrantMonitor"),
|
||||
mPaintCount(0),
|
||||
mPreviousImagePainted(false)
|
||||
{}
|
||||
|
||||
// Performs necessary housekeeping to ensure the painted frame statistics
|
||||
// are accurate. Must be called by SetCurrentImage() implementations with
|
||||
// mReentrantMonitor held.
|
||||
@ -307,6 +384,8 @@ protected:
|
||||
mPaintTime = TimeStamp();
|
||||
}
|
||||
|
||||
nsRefPtr<Image> mActiveImage;
|
||||
|
||||
// Number of contained images that have been painted at least once. It's up
|
||||
// to the ImageContainer implementation to ensure accesses to this are
|
||||
// threadsafe.
|
||||
@ -318,6 +397,15 @@ protected:
|
||||
|
||||
// Denotes whether the previous image was painted.
|
||||
bool mPreviousImagePainted;
|
||||
|
||||
// This is the image factory used by this container, layer managers using
|
||||
// this container can set an alternative image factory that will be used to
|
||||
// create images for this container.
|
||||
nsRefPtr<ImageFactory> mImageFactory;
|
||||
|
||||
gfxIntSize mScaleHint;
|
||||
|
||||
nsRefPtr<BufferRecycleBin> mRecycleBin;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -332,8 +420,6 @@ public:
|
||||
*/
|
||||
void SetContainer(ImageContainer* aContainer)
|
||||
{
|
||||
NS_ASSERTION(!aContainer->Manager() || aContainer->Manager() == Manager(),
|
||||
"ImageContainer must have the same manager as the ImageLayer");
|
||||
mContainer = aContainer;
|
||||
}
|
||||
/**
|
||||
@ -422,13 +508,13 @@ public:
|
||||
MAX_DIMENSION = 16384
|
||||
};
|
||||
|
||||
~PlanarYCbCrImage();
|
||||
|
||||
/**
|
||||
* This makes a copy of the data buffers.
|
||||
* XXX Eventually we will change this to not make a copy of the data,
|
||||
* Right now it doesn't matter because the BasicLayer implementation
|
||||
* does YCbCr conversion here anyway.
|
||||
* This makes a copy of the data buffers, in order to support functioning
|
||||
* in all different layer managers.
|
||||
*/
|
||||
virtual void SetData(const Data& aData) = 0;
|
||||
virtual void SetData(const Data& aData);
|
||||
|
||||
/**
|
||||
* Ask this Image to not convert YUV to RGB during SetData, and make
|
||||
@ -440,19 +526,14 @@ public:
|
||||
/**
|
||||
* Grab the original YUV data. This is optional.
|
||||
*/
|
||||
virtual const Data* GetData() { return nsnull; }
|
||||
virtual const Data* GetData() { return &mData; }
|
||||
|
||||
/**
|
||||
* Make a copy of the YCbCr data.
|
||||
* Make a copy of the YCbCr data into local storage.
|
||||
*
|
||||
* @param aDest Data object to store the plane data in.
|
||||
* @param aDestSize Size of the Y plane that was copied.
|
||||
* @param aDestBufferSize Number of bytes allocated for storage.
|
||||
* @param aData Input image data.
|
||||
* @return Raw data pointer for the planes or nsnull on failure.
|
||||
*/
|
||||
PRUint8 *CopyData(Data& aDest, gfxIntSize& aDestSize,
|
||||
PRUint32& aDestBufferSize, const Data& aData);
|
||||
void CopyData(const Data& aData);
|
||||
|
||||
/**
|
||||
* Return a buffer to store image data in.
|
||||
@ -464,15 +545,31 @@ public:
|
||||
/**
|
||||
* Return the number of bytes of heap memory used to store this image.
|
||||
*/
|
||||
virtual PRUint32 GetDataSize() = 0;
|
||||
virtual PRUint32 GetDataSize() { return mBufferSize; }
|
||||
|
||||
protected:
|
||||
PlanarYCbCrImage(void* aImplData) : Image(aImplData, PLANAR_YCBCR) {}
|
||||
already_AddRefed<gfxASurface> GetAsSurface();
|
||||
|
||||
virtual gfxIntSize GetSize() { return mSize; }
|
||||
|
||||
void SetOffscreenFormat(gfxImageFormat aFormat) { mOffscreenFormat = aFormat; }
|
||||
gfxImageFormat GetOffscreenFormat() { return mOffscreenFormat; }
|
||||
|
||||
// XXX - not easy to protect these sadly.
|
||||
nsAutoArrayPtr<PRUint8> mBuffer;
|
||||
PRUint32 mBufferSize;
|
||||
Data mData;
|
||||
gfxIntSize mSize;
|
||||
gfxImageFormat mOffscreenFormat;
|
||||
nsCountedRef<nsMainThreadSurfaceRef> mSurface;
|
||||
nsRefPtr<BufferRecycleBin> mRecycleBin;
|
||||
|
||||
PlanarYCbCrImage(BufferRecycleBin *aRecycleBin);
|
||||
};
|
||||
|
||||
/**
|
||||
* Currently, the data in a CairoImage surface is treated as being in the
|
||||
* device output color space.
|
||||
* device output color space. This class is very simple as all backends
|
||||
* have to know about how to deal with drawing a cairo image.
|
||||
*/
|
||||
class THEBES_API CairoImage : public Image {
|
||||
public:
|
||||
@ -486,10 +583,26 @@ public:
|
||||
* to the surface (which will eventually be released on the main thread).
|
||||
* The surface must not be modified after this call!!!
|
||||
*/
|
||||
virtual void SetData(const Data& aData) = 0;
|
||||
void SetData(const Data& aData)
|
||||
{
|
||||
mSurface = aData.mSurface;
|
||||
mSize = aData.mSize;
|
||||
}
|
||||
|
||||
protected:
|
||||
CairoImage(void* aImplData) : Image(aImplData, CAIRO_SURFACE) {}
|
||||
|
||||
virtual already_AddRefed<gfxASurface> GetAsSurface()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Must be main thread");
|
||||
nsRefPtr<gfxASurface> surface = mSurface.get();
|
||||
return surface.forget();
|
||||
}
|
||||
|
||||
gfxIntSize GetSize() { return mSize; }
|
||||
|
||||
CairoImage() : Image(NULL, CAIRO_SURFACE) {}
|
||||
|
||||
nsCountedRef<nsMainThreadSurfaceRef> mSurface;
|
||||
gfxIntSize mSize;
|
||||
};
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
@ -499,12 +612,27 @@ public:
|
||||
nsIOSurface* mIOSurface;
|
||||
};
|
||||
|
||||
MacIOSurfaceImage()
|
||||
: Image(NULL, MAC_IO_SURFACE)
|
||||
, mSize(0, 0)
|
||||
, mPluginInstanceOwner(NULL)
|
||||
, mUpdateCallback(NULL)
|
||||
, mDestroyCallback(NULL)
|
||||
{}
|
||||
|
||||
virtual ~MacIOSurfaceImage()
|
||||
{
|
||||
if (mDestroyCallback) {
|
||||
mDestroyCallback(mPluginInstanceOwner);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This can only be called on the main thread. It may add a reference
|
||||
* to the surface (which will eventually be released on the main thread).
|
||||
* The surface must not be modified after this call!!!
|
||||
*/
|
||||
virtual void SetData(const Data& aData) = 0;
|
||||
virtual void SetData(const Data& aData);
|
||||
|
||||
/**
|
||||
* Temporary hacks to force plugin drawing during an empty transaction.
|
||||
@ -512,12 +640,38 @@ public:
|
||||
* when async plugin rendering is complete.
|
||||
*/
|
||||
typedef void (*UpdateSurfaceCallback)(ImageContainer* aContainer, void* aInstanceOwner);
|
||||
virtual void SetUpdateCallback(UpdateSurfaceCallback aCallback, void* aInstanceOwner) = 0;
|
||||
typedef void (*DestroyCallback)(void* aInstanceOwner);
|
||||
virtual void SetDestroyCallback(DestroyCallback aCallback) = 0;
|
||||
virtual void SetUpdateCallback(UpdateSurfaceCallback aCallback, void* aInstanceOwner)
|
||||
{
|
||||
mUpdateCallback = aCallback;
|
||||
mPluginInstanceOwner = aInstanceOwner;
|
||||
}
|
||||
|
||||
protected:
|
||||
MacIOSurfaceImage(void* aImplData) : Image(aImplData, MAC_IO_SURFACE) {}
|
||||
typedef void (*DestroyCallback)(void* aInstanceOwner);
|
||||
virtual void SetDestroyCallback(DestroyCallback aCallback)
|
||||
{
|
||||
mDestroyCallback = aCallback;
|
||||
}
|
||||
|
||||
virtual gfxIntSize GetSize()
|
||||
{
|
||||
return mSize;
|
||||
}
|
||||
|
||||
nsIOSurface* GetIOSurface()
|
||||
{
|
||||
return mIOSurface;
|
||||
}
|
||||
|
||||
void Update(ImageContainer* aContainer);
|
||||
|
||||
virtual already_AddRefed<gfxASurface> GetAsSurface();
|
||||
|
||||
private:
|
||||
gfxIntSize mSize;
|
||||
nsRefPtr<nsIOSurface> mIOSurface;
|
||||
void* mPluginInstanceOwner;
|
||||
UpdateSurfaceCallback mUpdateCallback;
|
||||
DestroyCallback mDestroyCallback;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -229,6 +229,13 @@ LayerManager::Mutated(Layer* aLayer)
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
already_AddRefed<ImageContainer>
|
||||
LayerManager::CreateImageContainer()
|
||||
{
|
||||
nsRefPtr<ImageContainer> container = new ImageContainer();
|
||||
return container.forget();
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// Layer
|
||||
|
||||
@ -513,54 +520,7 @@ ContainerLayer::DidInsertChild(Layer* aLayer)
|
||||
mMayHaveReadbackChild = true;
|
||||
}
|
||||
}
|
||||
|
||||
PRUint8*
|
||||
PlanarYCbCrImage::AllocateBuffer(PRUint32 aSize)
|
||||
{
|
||||
const fallible_t fallible = fallible_t();
|
||||
return new (fallible) PRUint8[aSize];
|
||||
}
|
||||
|
||||
PRUint8*
|
||||
PlanarYCbCrImage::CopyData(Data& aDest, gfxIntSize& aDestSize,
|
||||
PRUint32& aDestBufferSize, const Data& aData)
|
||||
{
|
||||
aDest = aData;
|
||||
|
||||
aDest.mYStride = aDest.mYSize.width;
|
||||
aDest.mCbCrStride = aDest.mCbCrSize.width;
|
||||
|
||||
// update buffer size
|
||||
aDestBufferSize = aDest.mCbCrStride * aDest.mCbCrSize.height * 2 +
|
||||
aDest.mYStride * aDest.mYSize.height;
|
||||
|
||||
// get new buffer
|
||||
PRUint8* buffer = AllocateBuffer(aDestBufferSize);
|
||||
if (!buffer)
|
||||
return nsnull;
|
||||
|
||||
aDest.mYChannel = buffer;
|
||||
aDest.mCbChannel = aDest.mYChannel + aDest.mYStride * aDest.mYSize.height;
|
||||
aDest.mCrChannel = aDest.mCbChannel + aDest.mCbCrStride * aDest.mCbCrSize.height;
|
||||
|
||||
for (int i = 0; i < aDest.mYSize.height; i++) {
|
||||
memcpy(aDest.mYChannel + i * aDest.mYStride,
|
||||
aData.mYChannel + i * aData.mYStride,
|
||||
aDest.mYStride);
|
||||
}
|
||||
for (int i = 0; i < aDest.mCbCrSize.height; i++) {
|
||||
memcpy(aDest.mCbChannel + i * aDest.mCbCrStride,
|
||||
aData.mCbChannel + i * aData.mCbCrStride,
|
||||
aDest.mCbCrStride);
|
||||
memcpy(aDest.mCrChannel + i * aDest.mCbCrStride,
|
||||
aData.mCrChannel + i * aData.mCbCrStride,
|
||||
aDest.mCbCrStride);
|
||||
}
|
||||
|
||||
aDestSize = aData.mPicSize;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LayerManager::StartFrameTimeRecording()
|
||||
{
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include "gfxColor.h"
|
||||
#include "gfxPattern.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
@ -428,9 +429,9 @@ public:
|
||||
virtual already_AddRefed<ReadbackLayer> CreateReadbackLayer() { return nsnull; }
|
||||
|
||||
/**
|
||||
* Can be called anytime
|
||||
* Can be called anytime, from any thread.
|
||||
*/
|
||||
virtual already_AddRefed<ImageContainer> CreateImageContainer() = 0;
|
||||
static already_AddRefed<ImageContainer> CreateImageContainer();
|
||||
|
||||
/**
|
||||
* Type of layer manager his is. This is to be used sparsely in order to
|
||||
|
@ -82,14 +82,9 @@ CPPSRCS = \
|
||||
LayerManagerOGL.cpp \
|
||||
ThebesLayerOGL.cpp \
|
||||
LayerSorter.cpp \
|
||||
ImageLayers.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
|
||||
CMMSRCS = \
|
||||
MacIOSurfaceImageOGL.mm \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
|
||||
ifdef MOZ_ENABLE_D3D9_LAYER
|
||||
EXPORTS += \
|
||||
|
@ -56,106 +56,70 @@ using mozilla::ReentrantMonitor;
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
/**
|
||||
* All our images can yield up a cairo surface and their size.
|
||||
*/
|
||||
class BasicImageImplData {
|
||||
class BasicPlanarYCbCrImage : public PlanarYCbCrImage
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This must be called on the main thread.
|
||||
*/
|
||||
virtual already_AddRefed<gfxASurface> GetAsSurface() = 0;
|
||||
BasicPlanarYCbCrImage(const gfxIntSize& aScaleHint, gfxImageFormat aOffscreenFormat, BufferRecycleBin *aRecycleBin)
|
||||
: PlanarYCbCrImage(aRecycleBin)
|
||||
, mScaleHint(aScaleHint)
|
||||
, mOffscreenFormat(aOffscreenFormat)
|
||||
{}
|
||||
|
||||
gfxIntSize GetSize() { return mSize; }
|
||||
|
||||
protected:
|
||||
gfxIntSize mSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* Since BasicLayers only paint on the main thread, handling a CairoImage
|
||||
* is extremely simple. We just hang on to a reference to the surface and
|
||||
* return that surface when BasicImageLayer::Paint asks for it via
|
||||
* BasicImageContainer::GetAsSurface.
|
||||
*/
|
||||
class BasicCairoImage : public CairoImage, public BasicImageImplData {
|
||||
public:
|
||||
BasicCairoImage() : CairoImage(static_cast<BasicImageImplData*>(this)) {}
|
||||
|
||||
virtual void SetData(const Data& aData)
|
||||
~BasicPlanarYCbCrImage()
|
||||
{
|
||||
mSurface = aData.mSurface;
|
||||
mSize = aData.mSize;
|
||||
if (mDecodedBuffer) {
|
||||
// Right now this only happens if the Image was never drawn, otherwise
|
||||
// this will have been tossed away at surface destruction.
|
||||
mRecycleBin->RecycleBuffer(mDecodedBuffer.forget(), mSize.height * mStride);
|
||||
}
|
||||
}
|
||||
|
||||
virtual already_AddRefed<gfxASurface> GetAsSurface()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Must be main thread");
|
||||
nsRefPtr<gfxASurface> surface = mSurface.get();
|
||||
return surface.forget();
|
||||
}
|
||||
|
||||
protected:
|
||||
nsCountedRef<nsMainThreadSurfaceRef> mSurface;
|
||||
};
|
||||
|
||||
/**
|
||||
* We handle YCbCr by converting to RGB when the image is initialized
|
||||
* (which should be done off the main thread). The RGB results are stored
|
||||
* in a memory buffer and converted to a cairo surface lazily.
|
||||
*/
|
||||
class BasicPlanarYCbCrImage : public PlanarYCbCrImage, public BasicImageImplData {
|
||||
typedef gfxASurface::gfxImageFormat gfxImageFormat;
|
||||
public:
|
||||
/**
|
||||
* aScaleHint is a size that the image is expected to be rendered at.
|
||||
* This is a hint for image backends to optimize scaling.
|
||||
*/
|
||||
BasicPlanarYCbCrImage(const gfxIntSize& aScaleHint) :
|
||||
PlanarYCbCrImage(static_cast<BasicImageImplData*>(this)),
|
||||
mScaleHint(aScaleHint),
|
||||
mOffscreenFormat(gfxASurface::ImageFormatUnknown),
|
||||
mDelayedConversion(false)
|
||||
{}
|
||||
|
||||
virtual void SetData(const Data& aData);
|
||||
virtual void SetDelayedConversion(bool aDelayed) { mDelayedConversion = aDelayed; }
|
||||
already_AddRefed<gfxASurface> GetAsSurface();
|
||||
|
||||
virtual already_AddRefed<gfxASurface> GetAsSurface();
|
||||
private:
|
||||
gfxIntSize mScaleHint;
|
||||
gfxImageFormat mOffscreenFormat;
|
||||
int mStride;
|
||||
nsAutoArrayPtr<PRUint8> mDecodedBuffer;
|
||||
};
|
||||
|
||||
const Data* GetData() { return &mData; }
|
||||
class BasicImageFactory : public ImageFactory
|
||||
{
|
||||
public:
|
||||
BasicImageFactory() {}
|
||||
|
||||
void SetOffscreenFormat(gfxImageFormat aFormat) { mOffscreenFormat = aFormat; }
|
||||
gfxImageFormat GetOffscreenFormat() { return mOffscreenFormat; }
|
||||
virtual already_AddRefed<Image> CreateImage(const Image::Format* aFormats,
|
||||
PRUint32 aNumFormats,
|
||||
const gfxIntSize &aScaleHint,
|
||||
BufferRecycleBin *aRecycleBin)
|
||||
{
|
||||
if (!aNumFormats) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
PRUint32 GetDataSize() { return mBuffer ? mDelayedConversion ? mBufferSize : mSize.height * mStride : 0; }
|
||||
nsRefPtr<Image> image;
|
||||
if (aFormats[0] == Image::PLANAR_YCBCR) {
|
||||
image = new BasicPlanarYCbCrImage(aScaleHint, gfxPlatform::GetPlatform()->GetOffscreenFormat(), aRecycleBin);
|
||||
return image.forget();
|
||||
}
|
||||
|
||||
protected:
|
||||
nsAutoArrayPtr<PRUint8> mBuffer;
|
||||
nsCountedRef<nsMainThreadSurfaceRef> mSurface;
|
||||
gfxIntSize mScaleHint;
|
||||
PRInt32 mStride;
|
||||
gfxImageFormat mOffscreenFormat;
|
||||
Data mData;
|
||||
PRUint32 mBufferSize;
|
||||
bool mDelayedConversion;
|
||||
return ImageFactory::CreateImage(aFormats, aNumFormats, aScaleHint, aRecycleBin);
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
BasicPlanarYCbCrImage::SetData(const Data& aData)
|
||||
{
|
||||
PlanarYCbCrImage::SetData(aData);
|
||||
|
||||
// Do some sanity checks to prevent integer overflow
|
||||
if (aData.mYSize.width > PlanarYCbCrImage::MAX_DIMENSION ||
|
||||
aData.mYSize.height > PlanarYCbCrImage::MAX_DIMENSION) {
|
||||
NS_ERROR("Illegal image source width or height");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mDelayedConversion) {
|
||||
mBuffer = CopyData(mData, mSize, mBufferSize, aData);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
gfxASurface::gfxImageFormat format = GetOffscreenFormat();
|
||||
|
||||
gfxIntSize size(mScaleHint);
|
||||
@ -167,13 +131,13 @@ BasicPlanarYCbCrImage::SetData(const Data& aData)
|
||||
}
|
||||
|
||||
mStride = gfxASurface::FormatStrideForWidth(format, size.width);
|
||||
mBuffer = AllocateBuffer(size.height * mStride);
|
||||
if (!mBuffer) {
|
||||
mDecodedBuffer = AllocateBuffer(size.height * mStride);
|
||||
if (!mDecodedBuffer) {
|
||||
// out of memory
|
||||
return;
|
||||
}
|
||||
|
||||
gfxUtils::ConvertYCbCrToRGB(aData, format, size, mBuffer, mStride);
|
||||
gfxUtils::ConvertYCbCrToRGB(aData, format, size, mDecodedBuffer, mStride);
|
||||
SetOffscreenFormat(format);
|
||||
mSize = size;
|
||||
}
|
||||
@ -196,22 +160,20 @@ BasicPlanarYCbCrImage::GetAsSurface()
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
// XXX: If we forced delayed conversion, are we ever going to hit this?
|
||||
// We may need to implement the conversion here.
|
||||
if (!mBuffer || mDelayedConversion) {
|
||||
return nsnull;
|
||||
if (!mDecodedBuffer) {
|
||||
return PlanarYCbCrImage::GetAsSurface();
|
||||
}
|
||||
|
||||
gfxASurface::gfxImageFormat format = GetOffscreenFormat();
|
||||
|
||||
nsRefPtr<gfxImageSurface> imgSurface =
|
||||
new gfxImageSurface(mBuffer, mSize, mStride, format);
|
||||
new gfxImageSurface(mDecodedBuffer, mSize, mStride, format);
|
||||
if (!imgSurface || imgSurface->CairoStatus() != 0) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// Pass ownership of the buffer to the surface
|
||||
imgSurface->SetData(&imageSurfaceDataKey, mBuffer.forget(), DestroyBuffer);
|
||||
imgSurface->SetData(&imageSurfaceDataKey, mDecodedBuffer.forget(), DestroyBuffer);
|
||||
|
||||
nsRefPtr<gfxASurface> result = imgSurface.get();
|
||||
#if defined(XP_MACOSX)
|
||||
@ -221,144 +183,20 @@ BasicPlanarYCbCrImage::GetAsSurface()
|
||||
result = quartzSurface.forget();
|
||||
}
|
||||
#endif
|
||||
mSurface = result.get();
|
||||
|
||||
mSurface = result;
|
||||
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Our image container is very simple. It's really just a factory
|
||||
* for the image objects. We use a ReentrantMonitor to synchronize access to
|
||||
* mImage.
|
||||
*/
|
||||
class BasicImageContainer : public ImageContainer {
|
||||
public:
|
||||
typedef gfxASurface::gfxImageFormat gfxImageFormat;
|
||||
|
||||
BasicImageContainer() :
|
||||
ImageContainer(nsnull),
|
||||
mScaleHint(-1, -1),
|
||||
mOffscreenFormat(gfxASurface::ImageFormatUnknown),
|
||||
mDelayed(false)
|
||||
{}
|
||||
virtual already_AddRefed<Image> CreateImage(const Image::Format* aFormats,
|
||||
PRUint32 aNumFormats);
|
||||
virtual void SetDelayedConversion(bool aDelayed) { mDelayed = aDelayed; }
|
||||
virtual void SetCurrentImage(Image* aImage);
|
||||
virtual already_AddRefed<Image> GetCurrentImage();
|
||||
virtual already_AddRefed<gfxASurface> GetCurrentAsSurface(gfxIntSize* aSize);
|
||||
virtual gfxIntSize GetCurrentSize();
|
||||
virtual bool SetLayerManager(LayerManager *aManager);
|
||||
virtual void SetScaleHint(const gfxIntSize& aScaleHint);
|
||||
void SetOffscreenFormat(gfxImageFormat aFormat) { mOffscreenFormat = aFormat; }
|
||||
virtual LayerManager::LayersBackend GetBackendType() { return LayerManager::LAYERS_BASIC; }
|
||||
|
||||
protected:
|
||||
nsRefPtr<Image> mImage;
|
||||
gfxIntSize mScaleHint;
|
||||
gfxImageFormat mOffscreenFormat;
|
||||
bool mDelayed;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if aFormat is in the given format array.
|
||||
*/
|
||||
static bool
|
||||
FormatInList(const Image::Format* aFormats, PRUint32 aNumFormats,
|
||||
Image::Format aFormat)
|
||||
ImageFactory*
|
||||
BasicLayerManager::GetImageFactory()
|
||||
{
|
||||
for (PRUint32 i = 0; i < aNumFormats; ++i) {
|
||||
if (aFormats[i] == aFormat) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
already_AddRefed<Image>
|
||||
BasicImageContainer::CreateImage(const Image::Format* aFormats,
|
||||
PRUint32 aNumFormats)
|
||||
{
|
||||
nsRefPtr<Image> image;
|
||||
// Prefer cairo surfaces because they're native for us
|
||||
if (FormatInList(aFormats, aNumFormats, Image::CAIRO_SURFACE)) {
|
||||
image = new BasicCairoImage();
|
||||
} else if (FormatInList(aFormats, aNumFormats, Image::PLANAR_YCBCR)) {
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
image = new BasicPlanarYCbCrImage(mScaleHint);
|
||||
static_cast<BasicPlanarYCbCrImage*>(image.get())->SetOffscreenFormat(mOffscreenFormat);
|
||||
static_cast<BasicPlanarYCbCrImage*>(image.get())->SetDelayedConversion(mDelayed);
|
||||
}
|
||||
return image.forget();
|
||||
}
|
||||
|
||||
void
|
||||
BasicImageContainer::SetCurrentImage(Image* aImage)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
mImage = aImage;
|
||||
CurrentImageChanged();
|
||||
}
|
||||
|
||||
already_AddRefed<Image>
|
||||
BasicImageContainer::GetCurrentImage()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
nsRefPtr<Image> image = mImage;
|
||||
return image.forget();
|
||||
}
|
||||
|
||||
static BasicImageImplData*
|
||||
ToImageData(Image* aImage)
|
||||
{
|
||||
return static_cast<BasicImageImplData*>(aImage->GetImplData());
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
BasicImageContainer::GetCurrentAsSurface(gfxIntSize* aSizeResult)
|
||||
{
|
||||
NS_PRECONDITION(NS_IsMainThread(), "Must be called on main thread");
|
||||
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
if (!mImage) {
|
||||
return nsnull;
|
||||
}
|
||||
*aSizeResult = ToImageData(mImage)->GetSize();
|
||||
return ToImageData(mImage)->GetAsSurface();
|
||||
}
|
||||
|
||||
gfxIntSize
|
||||
BasicImageContainer::GetCurrentSize()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
return !mImage ? gfxIntSize(0,0) : ToImageData(mImage)->GetSize();
|
||||
}
|
||||
|
||||
void BasicImageContainer::SetScaleHint(const gfxIntSize& aScaleHint)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
mScaleHint = aScaleHint;
|
||||
}
|
||||
|
||||
bool
|
||||
BasicImageContainer::SetLayerManager(LayerManager *aManager)
|
||||
{
|
||||
if (aManager &&
|
||||
aManager->GetBackendType() != LayerManager::LAYERS_BASIC)
|
||||
{
|
||||
return false;
|
||||
if (!mFactory) {
|
||||
mFactory = new BasicImageFactory();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
already_AddRefed<ImageContainer>
|
||||
BasicLayerManager::CreateImageContainer()
|
||||
{
|
||||
nsRefPtr<ImageContainer> container = new BasicImageContainer();
|
||||
static_cast<BasicImageContainer*>(container.get())->
|
||||
SetOffscreenFormat(gfxPlatform::GetPlatform()->GetOffscreenFormat());
|
||||
return container.forget();
|
||||
return mFactory.get();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -899,6 +899,8 @@ BasicImageLayer::GetAndPaintCurrentImage(gfxContext* aContext,
|
||||
if (!mContainer)
|
||||
return nsnull;
|
||||
|
||||
mContainer->SetImageFactory(mManager->IsCompositingCheap() ? nsnull : BasicManager()->GetImageFactory());
|
||||
|
||||
nsRefPtr<Image> image = mContainer->GetCurrentImage();
|
||||
|
||||
nsRefPtr<gfxASurface> surface = mContainer->GetCurrentAsSurface(&mSize);
|
||||
|
@ -131,9 +131,10 @@ public:
|
||||
virtual already_AddRefed<ContainerLayer> CreateContainerLayer();
|
||||
virtual already_AddRefed<ImageLayer> CreateImageLayer();
|
||||
virtual already_AddRefed<CanvasLayer> CreateCanvasLayer();
|
||||
virtual already_AddRefed<ImageContainer> CreateImageContainer();
|
||||
virtual already_AddRefed<ColorLayer> CreateColorLayer();
|
||||
virtual already_AddRefed<ReadbackLayer> CreateReadbackLayer();
|
||||
virtual ImageFactory *GetImageFactory();
|
||||
|
||||
virtual already_AddRefed<ShadowThebesLayer> CreateShadowThebesLayer()
|
||||
{ return nsnull; }
|
||||
virtual already_AddRefed<ShadowContainerLayer> CreateShadowContainerLayer()
|
||||
@ -207,6 +208,8 @@ protected:
|
||||
nsRefPtr<gfxContext> mDefaultTarget;
|
||||
// The context to draw into.
|
||||
nsRefPtr<gfxContext> mTarget;
|
||||
// Image factory we use.
|
||||
nsRefPtr<ImageFactory> mFactory;
|
||||
|
||||
// Cached surface for double buffering
|
||||
gfxCachedTempSurface mCachedSurface;
|
||||
@ -276,54 +279,4 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We need to be able to hold a reference to a gfxASurface from Image
|
||||
* subclasses. This is potentially a problem since Images can be addrefed
|
||||
* or released off the main thread. We can ensure that we never AddRef
|
||||
* a gfxASurface off the main thread, but we might want to Release due
|
||||
* to an Image being destroyed off the main thread.
|
||||
*
|
||||
* We use nsCountedRef<nsMainThreadSurfaceRef> to reference the
|
||||
* gfxASurface. When AddRefing, we assert that we're on the main thread.
|
||||
* When Releasing, if we're not on the main thread, we post an event to
|
||||
* the main thread to do the actual release.
|
||||
*/
|
||||
class nsMainThreadSurfaceRef;
|
||||
|
||||
template <>
|
||||
class nsAutoRefTraits<nsMainThreadSurfaceRef> {
|
||||
public:
|
||||
typedef gfxASurface* RawRef;
|
||||
|
||||
/**
|
||||
* The XPCOM event that will do the actual release on the main thread.
|
||||
*/
|
||||
class SurfaceReleaser : public nsRunnable {
|
||||
public:
|
||||
SurfaceReleaser(RawRef aRef) : mRef(aRef) {}
|
||||
NS_IMETHOD Run() {
|
||||
mRef->Release();
|
||||
return NS_OK;
|
||||
}
|
||||
RawRef mRef;
|
||||
};
|
||||
|
||||
static RawRef Void() { return nsnull; }
|
||||
static void Release(RawRef aRawRef)
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
aRawRef->Release();
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIRunnable> runnable = new SurfaceReleaser(aRawRef);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
static void AddRef(RawRef aRawRef)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(),
|
||||
"Can only add a reference on the main thread");
|
||||
aRawRef->AddRef();
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* GFX_BASICLAYERS_H */
|
||||
|
@ -100,102 +100,6 @@ SurfaceToTexture(ID3D10Device *aDevice,
|
||||
return texture.forget();
|
||||
}
|
||||
|
||||
ImageContainerD3D10::ImageContainerD3D10(ID3D10Device1 *aDevice)
|
||||
: ImageContainer(nsnull)
|
||||
, mDevice(aDevice)
|
||||
{
|
||||
}
|
||||
|
||||
already_AddRefed<Image>
|
||||
ImageContainerD3D10::CreateImage(const Image::Format *aFormats,
|
||||
PRUint32 aNumFormats)
|
||||
{
|
||||
if (!aNumFormats) {
|
||||
return nsnull;
|
||||
}
|
||||
nsRefPtr<Image> img;
|
||||
if (aFormats[0] == Image::PLANAR_YCBCR) {
|
||||
img = new PlanarYCbCrImageD3D10(mDevice);
|
||||
} else if (aFormats[0] == Image::CAIRO_SURFACE) {
|
||||
img = new CairoImageD3D10(mDevice);
|
||||
}
|
||||
return img.forget();
|
||||
}
|
||||
|
||||
void
|
||||
ImageContainerD3D10::SetCurrentImage(Image *aImage)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
mActiveImage = aImage;
|
||||
CurrentImageChanged();
|
||||
}
|
||||
|
||||
already_AddRefed<Image>
|
||||
ImageContainerD3D10::GetCurrentImage()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
nsRefPtr<Image> retval = mActiveImage;
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
ImageContainerD3D10::GetCurrentAsSurface(gfxIntSize *aSize)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
if (!mActiveImage) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
if (mActiveImage->GetFormat() == Image::PLANAR_YCBCR) {
|
||||
PlanarYCbCrImageD3D10 *yuvImage =
|
||||
static_cast<PlanarYCbCrImageD3D10*>(mActiveImage.get());
|
||||
if (yuvImage->HasData()) {
|
||||
*aSize = yuvImage->mSize;
|
||||
}
|
||||
} else if (mActiveImage->GetFormat() == Image::CAIRO_SURFACE) {
|
||||
CairoImageD3D10 *cairoImage =
|
||||
static_cast<CairoImageD3D10*>(mActiveImage.get());
|
||||
*aSize = cairoImage->mSize;
|
||||
}
|
||||
|
||||
return static_cast<ImageD3D10*>(mActiveImage->GetImplData())->GetAsSurface();
|
||||
}
|
||||
|
||||
gfxIntSize
|
||||
ImageContainerD3D10::GetCurrentSize()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
if (!mActiveImage) {
|
||||
return gfxIntSize(0,0);
|
||||
}
|
||||
if (mActiveImage->GetFormat() == Image::PLANAR_YCBCR) {
|
||||
PlanarYCbCrImageD3D10 *yuvImage =
|
||||
static_cast<PlanarYCbCrImageD3D10*>(mActiveImage.get());
|
||||
if (!yuvImage->HasData()) {
|
||||
return gfxIntSize(0,0);
|
||||
}
|
||||
return yuvImage->mSize;
|
||||
|
||||
} else if (mActiveImage->GetFormat() == Image::CAIRO_SURFACE) {
|
||||
CairoImageD3D10 *cairoImage =
|
||||
static_cast<CairoImageD3D10*>(mActiveImage.get());
|
||||
return cairoImage->mSize;
|
||||
}
|
||||
|
||||
return gfxIntSize(0,0);
|
||||
}
|
||||
|
||||
bool
|
||||
ImageContainerD3D10::SetLayerManager(LayerManager *aManager)
|
||||
{
|
||||
if (aManager->GetBackendType() == LayerManager::LAYERS_D3D10) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Layer*
|
||||
ImageLayerD3D10::GetLayer()
|
||||
{
|
||||
@ -218,51 +122,39 @@ ImageLayerD3D10::RenderLayer()
|
||||
|
||||
ID3D10EffectTechnique *technique;
|
||||
|
||||
if (GetContainer()->GetBackendType() != LayerManager::LAYERS_D3D10 ||
|
||||
image->GetFormat() == Image::CAIRO_SURFACE)
|
||||
if (image->GetFormat() == Image::CAIRO_SURFACE)
|
||||
{
|
||||
gfxIntSize size;
|
||||
bool hasAlpha;
|
||||
nsRefPtr<ID3D10ShaderResourceView> srView;
|
||||
CairoImage *cairoImage =
|
||||
static_cast<CairoImage*>(image.get());
|
||||
|
||||
if (GetContainer()->GetBackendType() != LayerManager::LAYERS_D3D10)
|
||||
{
|
||||
nsRefPtr<gfxASurface> surf = GetContainer()->GetCurrentAsSurface(&size);
|
||||
|
||||
nsRefPtr<ID3D10Texture2D> texture = SurfaceToTexture(device(), surf, size);
|
||||
|
||||
if (!texture) {
|
||||
NS_WARNING("Failed to create texture for surface.");
|
||||
return;
|
||||
}
|
||||
|
||||
hasAlpha = surf->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA;
|
||||
|
||||
device()->CreateShaderResourceView(texture, NULL, getter_AddRefs(srView));
|
||||
} else {
|
||||
ImageContainerD3D10 *container =
|
||||
static_cast<ImageContainerD3D10*>(GetContainer());
|
||||
|
||||
if (container->device() != device()) {
|
||||
container->SetDevice(device());
|
||||
}
|
||||
|
||||
// image->GetFormat() == Image::CAIRO_SURFACE
|
||||
CairoImageD3D10 *cairoImage =
|
||||
static_cast<CairoImageD3D10*>(image.get());
|
||||
|
||||
if (cairoImage->mDevice != device()) {
|
||||
// This shader resource view was for an old device! Can't draw that
|
||||
// now.
|
||||
return;
|
||||
}
|
||||
|
||||
srView = cairoImage->mSRView;
|
||||
hasAlpha = cairoImage->mHasAlpha;
|
||||
size = cairoImage->mSize;
|
||||
if (!cairoImage->mSurface) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasAlpha) {
|
||||
if (!cairoImage->GetBackendData(LayerManager::LAYERS_D3D10)) {
|
||||
nsAutoPtr<CairoD3D10BackendData> dat = new CairoD3D10BackendData();
|
||||
dat->mTexture = SurfaceToTexture(device(), cairoImage->mSurface, cairoImage->mSize);
|
||||
|
||||
if (dat->mTexture) {
|
||||
device()->CreateShaderResourceView(dat->mTexture, NULL, getter_AddRefs(dat->mSRView));
|
||||
cairoImage->SetBackendData(LayerManager::LAYERS_D3D10, dat.forget());
|
||||
}
|
||||
}
|
||||
|
||||
CairoD3D10BackendData *data =
|
||||
static_cast<CairoD3D10BackendData*>(cairoImage->GetBackendData(LayerManager::LAYERS_D3D10));
|
||||
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<ID3D10Device> dev;
|
||||
data->mTexture->GetDevice(getter_AddRefs(dev));
|
||||
if (dev != device()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cairoImage->mSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) {
|
||||
if (mFilter == gfxPattern::FILTER_NEAREST) {
|
||||
technique = effect()->GetTechniqueByName("RenderRGBALayerPremulPoint");
|
||||
} else {
|
||||
@ -276,29 +168,38 @@ ImageLayerD3D10::RenderLayer()
|
||||
}
|
||||
}
|
||||
|
||||
if (srView) {
|
||||
effect()->GetVariableByName("tRGB")->AsShaderResource()->SetResource(srView);
|
||||
}
|
||||
effect()->GetVariableByName("tRGB")->AsShaderResource()->SetResource(data->mSRView);
|
||||
|
||||
effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector(
|
||||
ShaderConstantRectD3D10(
|
||||
(float)0,
|
||||
(float)0,
|
||||
(float)size.width,
|
||||
(float)size.height)
|
||||
(float)cairoImage->mSize.width,
|
||||
(float)cairoImage->mSize.height)
|
||||
);
|
||||
} else if (image->GetFormat() == Image::PLANAR_YCBCR) {
|
||||
PlanarYCbCrImageD3D10 *yuvImage =
|
||||
static_cast<PlanarYCbCrImageD3D10*>(image.get());
|
||||
PlanarYCbCrImage *yuvImage =
|
||||
static_cast<PlanarYCbCrImage*>(image.get());
|
||||
|
||||
if (!yuvImage->HasData()) {
|
||||
if (!yuvImage->mBufferSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (yuvImage->mDevice != device()) {
|
||||
// These shader resources were created for an old device! Can't draw
|
||||
// that here.
|
||||
return;
|
||||
if (!yuvImage->GetBackendData(LayerManager::LAYERS_D3D10)) {
|
||||
AllocateTexturesYCbCr(yuvImage);
|
||||
}
|
||||
|
||||
PlanarYCbCrD3D10BackendData *data =
|
||||
static_cast<PlanarYCbCrD3D10BackendData*>(yuvImage->GetBackendData(LayerManager::LAYERS_D3D10));
|
||||
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<ID3D10Device> dev;
|
||||
data->mYTexture->GetDevice(getter_AddRefs(dev));
|
||||
if (dev != device()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: At some point we should try to deal with mFilter here, you don't
|
||||
@ -308,9 +209,9 @@ ImageLayerD3D10::RenderLayer()
|
||||
|
||||
technique = effect()->GetTechniqueByName("RenderYCbCrLayer");
|
||||
|
||||
effect()->GetVariableByName("tY")->AsShaderResource()->SetResource(yuvImage->mYView);
|
||||
effect()->GetVariableByName("tCb")->AsShaderResource()->SetResource(yuvImage->mCbView);
|
||||
effect()->GetVariableByName("tCr")->AsShaderResource()->SetResource(yuvImage->mCrView);
|
||||
effect()->GetVariableByName("tY")->AsShaderResource()->SetResource(data->mYView);
|
||||
effect()->GetVariableByName("tCb")->AsShaderResource()->SetResource(data->mCbView);
|
||||
effect()->GetVariableByName("tCr")->AsShaderResource()->SetResource(data->mCrView);
|
||||
|
||||
/*
|
||||
* Send 3d control data and metadata to NV3DVUtils
|
||||
@ -341,7 +242,7 @@ ImageLayerD3D10::RenderLayer()
|
||||
if (yuvImage->mData.mStereoMode != STEREO_MODE_MONO) {
|
||||
// Dst resource is optional
|
||||
GetNv3DVUtils()->SendNv3DVMetaData((unsigned int)yuvImage->mSize.width,
|
||||
(unsigned int)yuvImage->mSize.height, (HANDLE)(yuvImage->mYTexture), (HANDLE)(NULL));
|
||||
(unsigned int)yuvImage->mSize.height, (HANDLE)(data->mYTexture), (HANDLE)(NULL));
|
||||
}
|
||||
}
|
||||
|
||||
@ -373,146 +274,49 @@ ImageLayerD3D10::RenderLayer()
|
||||
GetContainer()->NotifyPaintedImage(image);
|
||||
}
|
||||
|
||||
PlanarYCbCrImageD3D10::PlanarYCbCrImageD3D10(ID3D10Device1 *aDevice)
|
||||
: PlanarYCbCrImage(static_cast<ImageD3D10*>(this))
|
||||
, mBufferSize(0)
|
||||
, mDevice(aDevice)
|
||||
, mHasData(false)
|
||||
void ImageLayerD3D10::AllocateTexturesYCbCr(PlanarYCbCrImage *aImage)
|
||||
{
|
||||
}
|
||||
nsAutoPtr<PlanarYCbCrD3D10BackendData> backendData =
|
||||
new PlanarYCbCrD3D10BackendData;
|
||||
|
||||
void
|
||||
PlanarYCbCrImageD3D10::SetData(const PlanarYCbCrImage::Data &aData)
|
||||
{
|
||||
mBuffer = CopyData(mData, mSize, mBufferSize, aData);
|
||||
PlanarYCbCrImage::Data &data = aImage->mData;
|
||||
|
||||
AllocateTextures();
|
||||
|
||||
mHasData = true;
|
||||
}
|
||||
|
||||
void
|
||||
PlanarYCbCrImageD3D10::AllocateTextures()
|
||||
{
|
||||
D3D10_SUBRESOURCE_DATA dataY;
|
||||
D3D10_SUBRESOURCE_DATA dataCb;
|
||||
D3D10_SUBRESOURCE_DATA dataCr;
|
||||
CD3D10_TEXTURE2D_DESC descY(DXGI_FORMAT_R8_UNORM,
|
||||
mData.mYSize.width,
|
||||
mData.mYSize.height, 1, 1);
|
||||
data.mYSize.width,
|
||||
data.mYSize.height, 1, 1);
|
||||
CD3D10_TEXTURE2D_DESC descCbCr(DXGI_FORMAT_R8_UNORM,
|
||||
mData.mCbCrSize.width,
|
||||
mData.mCbCrSize.height, 1, 1);
|
||||
data.mCbCrSize.width,
|
||||
data.mCbCrSize.height, 1, 1);
|
||||
|
||||
descY.Usage = descCbCr.Usage = D3D10_USAGE_IMMUTABLE;
|
||||
|
||||
dataY.pSysMem = mData.mYChannel;
|
||||
dataY.SysMemPitch = mData.mYStride;
|
||||
dataCb.pSysMem = mData.mCbChannel;
|
||||
dataCb.SysMemPitch = mData.mCbCrStride;
|
||||
dataCr.pSysMem = mData.mCrChannel;
|
||||
dataCr.SysMemPitch = mData.mCbCrStride;
|
||||
dataY.pSysMem = data.mYChannel;
|
||||
dataY.SysMemPitch = data.mYStride;
|
||||
dataCb.pSysMem = data.mCbChannel;
|
||||
dataCb.SysMemPitch = data.mCbCrStride;
|
||||
dataCr.pSysMem = data.mCrChannel;
|
||||
dataCr.SysMemPitch = data.mCbCrStride;
|
||||
|
||||
HRESULT hr = mDevice->CreateTexture2D(&descY, &dataY, getter_AddRefs(mYTexture));
|
||||
HRESULT hr = device()->CreateTexture2D(&descY, &dataY, getter_AddRefs(backendData->mYTexture));
|
||||
if (!FAILED(hr)) {
|
||||
hr = mDevice->CreateTexture2D(&descCbCr, &dataCb, getter_AddRefs(mCbTexture));
|
||||
hr = device()->CreateTexture2D(&descCbCr, &dataCb, getter_AddRefs(backendData->mCbTexture));
|
||||
}
|
||||
if (!FAILED(hr)) {
|
||||
hr = mDevice->CreateTexture2D(&descCbCr, &dataCr, getter_AddRefs(mCrTexture));
|
||||
hr = device()->CreateTexture2D(&descCbCr, &dataCr, getter_AddRefs(backendData->mCrTexture));
|
||||
}
|
||||
if (FAILED(hr)) {
|
||||
LayerManagerD3D10::ReportFailure(NS_LITERAL_CSTRING("PlanarYCbCrImageD3D10::AllocateTextures(): Failed to create texture"),
|
||||
hr);
|
||||
return;
|
||||
}
|
||||
mDevice->CreateShaderResourceView(mYTexture, NULL, getter_AddRefs(mYView));
|
||||
mDevice->CreateShaderResourceView(mCbTexture, NULL, getter_AddRefs(mCbView));
|
||||
mDevice->CreateShaderResourceView(mCrTexture, NULL, getter_AddRefs(mCrView));
|
||||
}
|
||||
device()->CreateShaderResourceView(backendData->mYTexture, NULL, getter_AddRefs(backendData->mYView));
|
||||
device()->CreateShaderResourceView(backendData->mCbTexture, NULL, getter_AddRefs(backendData->mCbView));
|
||||
device()->CreateShaderResourceView(backendData->mCrTexture, NULL, getter_AddRefs(backendData->mCrView));
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
PlanarYCbCrImageD3D10::GetAsSurface()
|
||||
{
|
||||
nsRefPtr<gfxImageSurface> imageSurface =
|
||||
new gfxImageSurface(mSize, gfxASurface::ImageFormatRGB24);
|
||||
|
||||
gfx::YUVType type =
|
||||
gfx::TypeFromSize(mData.mYSize.width,
|
||||
mData.mYSize.height,
|
||||
mData.mCbCrSize.width,
|
||||
mData.mCbCrSize.height);
|
||||
|
||||
// Convert from YCbCr to RGB now
|
||||
gfx::ConvertYCbCrToRGB32(mData.mYChannel,
|
||||
mData.mCbChannel,
|
||||
mData.mCrChannel,
|
||||
imageSurface->Data(),
|
||||
mData.mPicX,
|
||||
mData.mPicY,
|
||||
mData.mPicSize.width,
|
||||
mData.mPicSize.height,
|
||||
mData.mYStride,
|
||||
mData.mCbCrStride,
|
||||
imageSurface->Stride(),
|
||||
type);
|
||||
|
||||
return imageSurface.forget().get();
|
||||
}
|
||||
|
||||
CairoImageD3D10::~CairoImageD3D10()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CairoImageD3D10::SetData(const CairoImage::Data &aData)
|
||||
{
|
||||
mSize = aData.mSize;
|
||||
NS_ASSERTION(aData.mSurface->GetContentType() != gfxASurface::CONTENT_ALPHA,
|
||||
"Invalid content type passed to CairoImageD3D10.");
|
||||
|
||||
mTexture = SurfaceToTexture(mDevice, aData.mSurface, mSize);
|
||||
|
||||
if (!mTexture) {
|
||||
NS_WARNING("Failed to create texture for CairoImage.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (aData.mSurface->GetContentType() == gfxASurface::CONTENT_COLOR) {
|
||||
mHasAlpha = false;
|
||||
} else {
|
||||
mHasAlpha = true;
|
||||
}
|
||||
|
||||
mDevice->CreateShaderResourceView(mTexture, NULL, getter_AddRefs(mSRView));
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
CairoImageD3D10::GetAsSurface()
|
||||
{
|
||||
nsRefPtr<ID3D10Texture2D> surfTexture;
|
||||
|
||||
// Make a copy of the texture since our current texture is not suitable for
|
||||
// drawing with Direct2D because it is immutable and cannot be bound as a
|
||||
// render target.
|
||||
D3D10_TEXTURE2D_DESC texDesc;
|
||||
mTexture->GetDesc(&texDesc);
|
||||
texDesc.Usage = D3D10_USAGE_DEFAULT;
|
||||
texDesc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
|
||||
texDesc.MiscFlags = D3D10_RESOURCE_MISC_GDI_COMPATIBLE;
|
||||
|
||||
HRESULT hr = mDevice->CreateTexture2D(&texDesc, NULL, getter_AddRefs(surfTexture));
|
||||
if (FAILED(hr)) {
|
||||
LayerManagerD3D10::ReportFailure(NS_LITERAL_CSTRING("CairoImageD3D10::GetAsSurface(): Failed to create texture"),
|
||||
hr);
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
mDevice->CopyResource(surfTexture, mTexture);
|
||||
|
||||
nsRefPtr<gfxASurface> surf =
|
||||
new gfxD2DSurface(surfTexture, mHasAlpha ? gfxASurface::CONTENT_COLOR_ALPHA :
|
||||
gfxASurface::CONTENT_COLOR);
|
||||
return surf.forget();
|
||||
aImage->SetBackendData(LayerManager::LAYERS_D3D10, backendData.forget());
|
||||
}
|
||||
|
||||
} /* layers */
|
||||
|
@ -45,35 +45,6 @@
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class THEBES_API ImageContainerD3D10 : public ImageContainer
|
||||
{
|
||||
public:
|
||||
ImageContainerD3D10(ID3D10Device1 *aDevice);
|
||||
virtual ~ImageContainerD3D10() {}
|
||||
|
||||
virtual already_AddRefed<Image> CreateImage(const Image::Format* aFormats,
|
||||
PRUint32 aNumFormats);
|
||||
|
||||
virtual void SetCurrentImage(Image* aImage);
|
||||
|
||||
virtual already_AddRefed<Image> GetCurrentImage();
|
||||
|
||||
virtual already_AddRefed<gfxASurface> GetCurrentAsSurface(gfxIntSize* aSize);
|
||||
|
||||
virtual gfxIntSize GetCurrentSize();
|
||||
|
||||
virtual bool SetLayerManager(LayerManager *aManager);
|
||||
|
||||
virtual LayerManager::LayersBackend GetBackendType() { return LayerManager::LAYERS_D3D10; }
|
||||
|
||||
ID3D10Device1 *device() { return mDevice; }
|
||||
void SetDevice(ID3D10Device1 *aDevice) { mDevice = aDevice; }
|
||||
|
||||
private:
|
||||
nsRefPtr<Image> mActiveImage;
|
||||
nsRefPtr<ID3D10Device1> mDevice;
|
||||
};
|
||||
|
||||
class THEBES_API ImageLayerD3D10 : public ImageLayer,
|
||||
public LayerD3D10
|
||||
{
|
||||
@ -89,70 +60,24 @@ public:
|
||||
virtual Layer* GetLayer();
|
||||
|
||||
virtual void RenderLayer();
|
||||
|
||||
void AllocateTexturesYCbCr(PlanarYCbCrImage *aImage);
|
||||
};
|
||||
|
||||
class THEBES_API ImageD3D10
|
||||
struct PlanarYCbCrD3D10BackendData : public ImageBackendData
|
||||
{
|
||||
public:
|
||||
virtual already_AddRefed<gfxASurface> GetAsSurface() = 0;
|
||||
};
|
||||
|
||||
class THEBES_API PlanarYCbCrImageD3D10 : public PlanarYCbCrImage,
|
||||
public ImageD3D10
|
||||
{
|
||||
public:
|
||||
PlanarYCbCrImageD3D10(ID3D10Device1 *aDevice);
|
||||
~PlanarYCbCrImageD3D10() {}
|
||||
|
||||
virtual void SetData(const Data &aData);
|
||||
|
||||
/*
|
||||
* Upload the data from out mData into our textures. For now we use this to
|
||||
* make sure the textures are created and filled on the main thread.
|
||||
*/
|
||||
void AllocateTextures();
|
||||
|
||||
bool HasData() { return mHasData; }
|
||||
|
||||
PRUint32 GetDataSize() { return mBuffer ? mBufferSize : 0; }
|
||||
|
||||
virtual already_AddRefed<gfxASurface> GetAsSurface();
|
||||
|
||||
nsAutoArrayPtr<PRUint8> mBuffer;
|
||||
PRUint32 mBufferSize;
|
||||
nsRefPtr<ID3D10Device1> mDevice;
|
||||
Data mData;
|
||||
gfxIntSize mSize;
|
||||
nsRefPtr<ID3D10Texture2D> mYTexture;
|
||||
nsRefPtr<ID3D10Texture2D> mCrTexture;
|
||||
nsRefPtr<ID3D10Texture2D> mCbTexture;
|
||||
nsRefPtr<ID3D10ShaderResourceView> mYView;
|
||||
nsRefPtr<ID3D10ShaderResourceView> mCbView;
|
||||
nsRefPtr<ID3D10ShaderResourceView> mCrView;
|
||||
bool mHasData;
|
||||
};
|
||||
|
||||
|
||||
class THEBES_API CairoImageD3D10 : public CairoImage,
|
||||
public ImageD3D10
|
||||
struct CairoD3D10BackendData : public ImageBackendData
|
||||
{
|
||||
public:
|
||||
CairoImageD3D10(ID3D10Device1 *aDevice)
|
||||
: CairoImage(static_cast<ImageD3D10*>(this))
|
||||
, mDevice(aDevice)
|
||||
, mHasAlpha(true)
|
||||
{ }
|
||||
~CairoImageD3D10();
|
||||
|
||||
virtual void SetData(const Data &aData);
|
||||
|
||||
virtual already_AddRefed<gfxASurface> GetAsSurface();
|
||||
|
||||
nsRefPtr<ID3D10Device1> mDevice;
|
||||
nsRefPtr<ID3D10Texture2D> mTexture;
|
||||
nsRefPtr<ID3D10ShaderResourceView> mSRView;
|
||||
gfxIntSize mSize;
|
||||
bool mHasAlpha;
|
||||
};
|
||||
|
||||
} /* layers */
|
||||
|
@ -421,13 +421,6 @@ LayerManagerD3D10::CreateReadbackLayer()
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<ImageContainer>
|
||||
LayerManagerD3D10::CreateImageContainer()
|
||||
{
|
||||
nsRefPtr<ImageContainer> layer = new ImageContainerD3D10(mDevice);
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
static void ReleaseTexture(void *texture)
|
||||
{
|
||||
static_cast<ID3D10Texture2D*>(texture)->Release();
|
||||
|
@ -161,8 +161,6 @@ public:
|
||||
|
||||
virtual already_AddRefed<ReadbackLayer> CreateReadbackLayer();
|
||||
|
||||
virtual already_AddRefed<ImageContainer> CreateImageContainer();
|
||||
|
||||
virtual already_AddRefed<gfxASurface>
|
||||
CreateOptimalSurface(const gfxIntSize &aSize,
|
||||
gfxASurface::gfxImageFormat imageFormat);
|
||||
|
@ -137,101 +137,160 @@ SurfaceToTexture(IDirect3DDevice9 *aDevice,
|
||||
return texture.forget();
|
||||
}
|
||||
|
||||
ImageContainerD3D9::ImageContainerD3D9(IDirect3DDevice9 *aDevice)
|
||||
: ImageContainer(nsnull)
|
||||
, mDevice(aDevice)
|
||||
static void AllocateTexturesYCbCr(PlanarYCbCrImage *aImage,
|
||||
IDirect3DDevice9 *aDevice,
|
||||
LayerManagerD3D9 *aManager)
|
||||
{
|
||||
}
|
||||
nsAutoPtr<PlanarYCbCrD3D9BackendData> backendData =
|
||||
new PlanarYCbCrD3D9BackendData;
|
||||
|
||||
already_AddRefed<Image>
|
||||
ImageContainerD3D9::CreateImage(const Image::Format *aFormats,
|
||||
PRUint32 aNumFormats)
|
||||
{
|
||||
if (!aNumFormats) {
|
||||
return nsnull;
|
||||
}
|
||||
nsRefPtr<Image> img;
|
||||
if (aFormats[0] == Image::PLANAR_YCBCR) {
|
||||
img = new PlanarYCbCrImageD3D9();
|
||||
} else if (aFormats[0] == Image::CAIRO_SURFACE) {
|
||||
img = new CairoImageD3D9(mDevice);
|
||||
}
|
||||
return img.forget();
|
||||
}
|
||||
PlanarYCbCrImage::Data &data = aImage->mData;
|
||||
|
||||
void
|
||||
ImageContainerD3D9::SetCurrentImage(Image *aImage)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
D3DLOCKED_RECT lockrectY;
|
||||
D3DLOCKED_RECT lockrectCb;
|
||||
D3DLOCKED_RECT lockrectCr;
|
||||
PRUint8* src;
|
||||
PRUint8* dest;
|
||||
|
||||
mActiveImage = aImage;
|
||||
CurrentImageChanged();
|
||||
}
|
||||
nsRefPtr<IDirect3DSurface9> tmpSurfaceY;
|
||||
nsRefPtr<IDirect3DSurface9> tmpSurfaceCb;
|
||||
nsRefPtr<IDirect3DSurface9> tmpSurfaceCr;
|
||||
|
||||
already_AddRefed<Image>
|
||||
ImageContainerD3D9::GetCurrentImage()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
nsRefPtr<IDirect3DDevice9Ex> deviceEx;
|
||||
aDevice->QueryInterface(IID_IDirect3DDevice9Ex,
|
||||
getter_AddRefs(deviceEx));
|
||||
|
||||
nsRefPtr<Image> retval = mActiveImage;
|
||||
return retval.forget();
|
||||
}
|
||||
bool isD3D9Ex = deviceEx;
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
ImageContainerD3D9::GetCurrentAsSurface(gfxIntSize *aSize)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
if (!mActiveImage) {
|
||||
return nsnull;
|
||||
}
|
||||
if (isD3D9Ex) {
|
||||
nsRefPtr<IDirect3DTexture9> tmpYTexture;
|
||||
nsRefPtr<IDirect3DTexture9> tmpCbTexture;
|
||||
nsRefPtr<IDirect3DTexture9> tmpCrTexture;
|
||||
// D3D9Ex does not support the managed pool, could use dynamic textures
|
||||
// here. But since an Image is immutable static textures are probably a
|
||||
// better idea.
|
||||
|
||||
if (mActiveImage->GetFormat() == Image::PLANAR_YCBCR) {
|
||||
PlanarYCbCrImageD3D9 *yuvImage =
|
||||
static_cast<PlanarYCbCrImageD3D9*>(mActiveImage.get());
|
||||
if (yuvImage->HasData()) {
|
||||
*aSize = yuvImage->mSize;
|
||||
HRESULT hr;
|
||||
hr = aDevice->CreateTexture(data.mYSize.width, data.mYSize.height,
|
||||
1, 0, D3DFMT_L8, D3DPOOL_DEFAULT,
|
||||
getter_AddRefs(backendData->mYTexture), NULL);
|
||||
if (!FAILED(hr)) {
|
||||
hr = aDevice->CreateTexture(data.mCbCrSize.width, data.mCbCrSize.height,
|
||||
1, 0, D3DFMT_L8, D3DPOOL_DEFAULT,
|
||||
getter_AddRefs(backendData->mCbTexture), NULL);
|
||||
}
|
||||
} else if (mActiveImage->GetFormat() == Image::CAIRO_SURFACE) {
|
||||
CairoImageD3D9 *cairoImage =
|
||||
static_cast<CairoImageD3D9*>(mActiveImage.get());
|
||||
*aSize = cairoImage->GetSize();
|
||||
}
|
||||
|
||||
return static_cast<ImageD3D9*>(mActiveImage->GetImplData())->GetAsSurface();
|
||||
}
|
||||
|
||||
gfxIntSize
|
||||
ImageContainerD3D9::GetCurrentSize()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
if (!mActiveImage) {
|
||||
return gfxIntSize(0,0);
|
||||
}
|
||||
if (mActiveImage->GetFormat() == Image::PLANAR_YCBCR) {
|
||||
PlanarYCbCrImageD3D9 *yuvImage =
|
||||
static_cast<PlanarYCbCrImageD3D9*>(mActiveImage.get());
|
||||
if (!yuvImage->HasData()) {
|
||||
return gfxIntSize(0,0);
|
||||
if (!FAILED(hr)) {
|
||||
hr = aDevice->CreateTexture(data.mCbCrSize.width, data.mCbCrSize.height,
|
||||
1, 0, D3DFMT_L8, D3DPOOL_DEFAULT,
|
||||
getter_AddRefs(backendData->mCrTexture), NULL);
|
||||
}
|
||||
if (!FAILED(hr)) {
|
||||
hr = aDevice->CreateTexture(data.mYSize.width, data.mYSize.height,
|
||||
1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM,
|
||||
getter_AddRefs(tmpYTexture), NULL);
|
||||
}
|
||||
if (!FAILED(hr)) {
|
||||
hr = aDevice->CreateTexture(data.mCbCrSize.width, data.mCbCrSize.height,
|
||||
1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM,
|
||||
getter_AddRefs(tmpCbTexture), NULL);
|
||||
}
|
||||
if (!FAILED(hr)) {
|
||||
hr = aDevice->CreateTexture(data.mCbCrSize.width, data.mCbCrSize.height,
|
||||
1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM,
|
||||
getter_AddRefs(tmpCrTexture), NULL);
|
||||
}
|
||||
return yuvImage->mSize;
|
||||
|
||||
} else if (mActiveImage->GetFormat() == Image::CAIRO_SURFACE) {
|
||||
CairoImageD3D9 *cairoImage =
|
||||
static_cast<CairoImageD3D9*>(mActiveImage.get());
|
||||
return cairoImage->GetSize();
|
||||
if (FAILED(hr)) {
|
||||
aManager->ReportFailure(NS_LITERAL_CSTRING("PlanarYCbCrImageD3D9::AllocateTextures(): Failed to create texture (isD3D9Ex)"),
|
||||
hr);
|
||||
return;
|
||||
}
|
||||
|
||||
tmpYTexture->GetSurfaceLevel(0, getter_AddRefs(tmpSurfaceY));
|
||||
tmpCbTexture->GetSurfaceLevel(0, getter_AddRefs(tmpSurfaceCb));
|
||||
tmpCrTexture->GetSurfaceLevel(0, getter_AddRefs(tmpSurfaceCr));
|
||||
tmpSurfaceY->LockRect(&lockrectY, NULL, 0);
|
||||
tmpSurfaceCb->LockRect(&lockrectCb, NULL, 0);
|
||||
tmpSurfaceCr->LockRect(&lockrectCr, NULL, 0);
|
||||
} else {
|
||||
HRESULT hr;
|
||||
hr = aDevice->CreateTexture(data.mYSize.width, data.mYSize.height,
|
||||
1, 0, D3DFMT_L8, D3DPOOL_MANAGED,
|
||||
getter_AddRefs(backendData->mYTexture), NULL);
|
||||
if (!FAILED(hr)) {
|
||||
aDevice->CreateTexture(data.mCbCrSize.width, data.mCbCrSize.height,
|
||||
1, 0, D3DFMT_L8, D3DPOOL_MANAGED,
|
||||
getter_AddRefs(backendData->mCbTexture), NULL);
|
||||
}
|
||||
if (!FAILED(hr)) {
|
||||
aDevice->CreateTexture(data.mCbCrSize.width, data.mCbCrSize.height,
|
||||
1, 0, D3DFMT_L8, D3DPOOL_MANAGED,
|
||||
getter_AddRefs(backendData->mCrTexture), NULL);
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
aManager->ReportFailure(NS_LITERAL_CSTRING("PlanarYCbCrImageD3D9::AllocateTextures(): Failed to create texture (!isD3D9Ex)"),
|
||||
hr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* lock the entire texture */
|
||||
backendData->mYTexture->LockRect(0, &lockrectY, NULL, 0);
|
||||
backendData->mCbTexture->LockRect(0, &lockrectCb, NULL, 0);
|
||||
backendData->mCrTexture->LockRect(0, &lockrectCr, NULL, 0);
|
||||
}
|
||||
|
||||
return gfxIntSize(0,0);
|
||||
}
|
||||
src = data.mYChannel;
|
||||
//FIX cast
|
||||
dest = (PRUint8*)lockrectY.pBits;
|
||||
|
||||
bool
|
||||
ImageContainerD3D9::SetLayerManager(LayerManager *aManager)
|
||||
{
|
||||
if (aManager->GetBackendType() == LayerManager::LAYERS_D3D9) {
|
||||
return true;
|
||||
// copy over data
|
||||
for (int h=0; h<data.mYSize.height; h++) {
|
||||
memcpy(dest, src, data.mYSize.width);
|
||||
dest += lockrectY.Pitch;
|
||||
src += data.mYStride;
|
||||
}
|
||||
|
||||
return false;
|
||||
src = data.mCbChannel;
|
||||
//FIX cast
|
||||
dest = (PRUint8*)lockrectCb.pBits;
|
||||
|
||||
// copy over data
|
||||
for (int h=0; h<data.mCbCrSize.height; h++) {
|
||||
memcpy(dest, src, data.mCbCrSize.width);
|
||||
dest += lockrectCb.Pitch;
|
||||
src += data.mCbCrStride;
|
||||
}
|
||||
|
||||
src = data.mCrChannel;
|
||||
//FIX cast
|
||||
dest = (PRUint8*)lockrectCr.pBits;
|
||||
|
||||
// copy over data
|
||||
for (int h=0; h<data.mCbCrSize.height; h++) {
|
||||
memcpy(dest, src, data.mCbCrSize.width);
|
||||
dest += lockrectCr.Pitch;
|
||||
src += data.mCbCrStride;
|
||||
}
|
||||
|
||||
if (isD3D9Ex) {
|
||||
tmpSurfaceY->UnlockRect();
|
||||
tmpSurfaceCb->UnlockRect();
|
||||
tmpSurfaceCr->UnlockRect();
|
||||
nsRefPtr<IDirect3DSurface9> dstSurface;
|
||||
backendData->mYTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
|
||||
aDevice->UpdateSurface(tmpSurfaceY, NULL, dstSurface, NULL);
|
||||
backendData->mCbTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
|
||||
aDevice->UpdateSurface(tmpSurfaceCb, NULL, dstSurface, NULL);
|
||||
backendData->mCrTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
|
||||
aDevice->UpdateSurface(tmpSurfaceCr, NULL, dstSurface, NULL);
|
||||
} else {
|
||||
backendData->mYTexture->UnlockRect(0);
|
||||
backendData->mCbTexture->UnlockRect(0);
|
||||
backendData->mCrTexture->UnlockRect(0);
|
||||
}
|
||||
|
||||
aImage->SetBackendData(LayerManager::LAYERS_D3D9, backendData.forget());
|
||||
}
|
||||
|
||||
Layer*
|
||||
@ -254,8 +313,37 @@ ImageLayerD3D9::RenderLayer()
|
||||
|
||||
SetShaderTransformAndOpacity();
|
||||
|
||||
if (GetContainer()->GetBackendType() != LayerManager::LAYERS_D3D9)
|
||||
if (image->GetFormat() == Image::CAIRO_SURFACE)
|
||||
{
|
||||
CairoImage *cairoImage =
|
||||
static_cast<CairoImage*>(image.get());
|
||||
|
||||
if (!cairoImage->mSurface) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cairoImage->GetBackendData(LayerManager::LAYERS_D3D9)) {
|
||||
nsAutoPtr<CairoD3D9BackendData> dat = new CairoD3D9BackendData();
|
||||
dat->mTexture = SurfaceToTexture(device(), cairoImage->mSurface, cairoImage->mSize);
|
||||
|
||||
if (dat->mTexture) {
|
||||
cairoImage->SetBackendData(LayerManager::LAYERS_D3D9, dat.forget());
|
||||
}
|
||||
}
|
||||
|
||||
CairoD3D9BackendData *data =
|
||||
static_cast<CairoD3D9BackendData*>(cairoImage->GetBackendData(LayerManager::LAYERS_D3D9));
|
||||
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<IDirect3DDevice9> dev;
|
||||
data->mTexture->GetDevice(getter_AddRefs(dev));
|
||||
if (dev != device()) {
|
||||
return;
|
||||
}
|
||||
|
||||
gfxIntSize size;
|
||||
nsRefPtr<gfxASurface> surface =
|
||||
GetContainer()->GetCurrentAsSurface(&size);
|
||||
@ -275,16 +363,40 @@ ImageLayerD3D9::RenderLayer()
|
||||
mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBLAYER);
|
||||
}
|
||||
|
||||
if (mFilter == gfxPattern::FILTER_NEAREST) {
|
||||
device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
|
||||
device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
|
||||
}
|
||||
device()->SetTexture(0, texture);
|
||||
device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
|
||||
} else if (image->GetFormat() == Image::PLANAR_YCBCR) {
|
||||
PlanarYCbCrImageD3D9 *yuvImage =
|
||||
static_cast<PlanarYCbCrImageD3D9*>(image.get());
|
||||
if (mFilter == gfxPattern::FILTER_NEAREST) {
|
||||
device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
||||
device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
||||
}
|
||||
} else {
|
||||
PlanarYCbCrImage *yuvImage =
|
||||
static_cast<PlanarYCbCrImage*>(image.get());
|
||||
|
||||
if (!yuvImage->HasData()) {
|
||||
if (!yuvImage->mBufferSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!yuvImage->GetBackendData(LayerManager::LAYERS_D3D9)) {
|
||||
AllocateTexturesYCbCr(yuvImage, device(), mD3DManager);
|
||||
}
|
||||
|
||||
PlanarYCbCrD3D9BackendData *data =
|
||||
static_cast<PlanarYCbCrD3D9BackendData*>(yuvImage->GetBackendData(LayerManager::LAYERS_D3D9));
|
||||
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<IDirect3DDevice9> dev;
|
||||
data->mYTexture->GetDevice(getter_AddRefs(dev));
|
||||
if (dev != device()) {
|
||||
return;
|
||||
}
|
||||
yuvImage->AllocateTextures(device());
|
||||
|
||||
device()->SetVertexShaderConstantF(CBvLayerQuad,
|
||||
ShaderConstantRect(0,
|
||||
@ -336,300 +448,26 @@ ImageLayerD3D9::RenderLayer()
|
||||
nsRefPtr<IDirect3DSurface9> renderTarget;
|
||||
device()->GetRenderTarget(0, getter_AddRefs(renderTarget));
|
||||
mD3DManager->GetNv3DVUtils()->SendNv3DVMetaData((unsigned int)yuvImage->mSize.width,
|
||||
(unsigned int)yuvImage->mSize.height, (HANDLE)(yuvImage->mYTexture), (HANDLE)(renderTarget));
|
||||
(unsigned int)yuvImage->mSize.height, (HANDLE)(data->mYTexture), (HANDLE)(renderTarget));
|
||||
}
|
||||
}
|
||||
|
||||
// Linear scaling is default here, adhering to mFilter is difficult since
|
||||
// presumably even with point filtering we'll still want chroma upsampling
|
||||
// to be linear. In the current approach we can't.
|
||||
device()->SetTexture(0, yuvImage->mYTexture);
|
||||
device()->SetTexture(1, yuvImage->mCbTexture);
|
||||
device()->SetTexture(2, yuvImage->mCrTexture);
|
||||
device()->SetTexture(0, data->mYTexture);
|
||||
device()->SetTexture(1, data->mCbTexture);
|
||||
device()->SetTexture(2, data->mCrTexture);
|
||||
|
||||
device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
|
||||
|
||||
device()->SetVertexShaderConstantF(CBvTextureCoords,
|
||||
ShaderConstantRect(0, 0, 1.0f, 1.0f), 1);
|
||||
|
||||
} else if (image->GetFormat() == Image::CAIRO_SURFACE) {
|
||||
CairoImageD3D9 *cairoImage =
|
||||
static_cast<CairoImageD3D9*>(image.get());
|
||||
ImageContainerD3D9 *container =
|
||||
static_cast<ImageContainerD3D9*>(GetContainer());
|
||||
|
||||
if (container->device() != device()) {
|
||||
// Ensure future images get created with the right device.
|
||||
container->SetDevice(device());
|
||||
}
|
||||
|
||||
if (cairoImage->device() != device()) {
|
||||
cairoImage->SetDevice(device());
|
||||
}
|
||||
|
||||
device()->SetVertexShaderConstantF(CBvLayerQuad,
|
||||
ShaderConstantRect(0,
|
||||
0,
|
||||
cairoImage->GetSize().width,
|
||||
cairoImage->GetSize().height),
|
||||
1);
|
||||
|
||||
if (cairoImage->HasAlpha()) {
|
||||
mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBALAYER);
|
||||
} else {
|
||||
mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBLAYER);
|
||||
}
|
||||
|
||||
if (mFilter == gfxPattern::FILTER_NEAREST) {
|
||||
device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
|
||||
device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
|
||||
}
|
||||
device()->SetTexture(0, cairoImage->GetOrCreateTexture());
|
||||
device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
|
||||
if (mFilter == gfxPattern::FILTER_NEAREST) {
|
||||
device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
||||
device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
||||
}
|
||||
}
|
||||
|
||||
GetContainer()->NotifyPaintedImage(image);
|
||||
}
|
||||
|
||||
PlanarYCbCrImageD3D9::PlanarYCbCrImageD3D9()
|
||||
: PlanarYCbCrImage(static_cast<ImageD3D9*>(this))
|
||||
, mBufferSize(0)
|
||||
, mHasData(false)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
PlanarYCbCrImageD3D9::SetData(const PlanarYCbCrImage::Data &aData)
|
||||
{
|
||||
mBuffer = CopyData(mData, mSize, mBufferSize, aData);
|
||||
|
||||
mHasData = true;
|
||||
}
|
||||
|
||||
void
|
||||
PlanarYCbCrImageD3D9::AllocateTextures(IDirect3DDevice9 *aDevice)
|
||||
{
|
||||
D3DLOCKED_RECT lockrectY;
|
||||
D3DLOCKED_RECT lockrectCb;
|
||||
D3DLOCKED_RECT lockrectCr;
|
||||
PRUint8* src;
|
||||
PRUint8* dest;
|
||||
|
||||
nsRefPtr<IDirect3DSurface9> tmpSurfaceY;
|
||||
nsRefPtr<IDirect3DSurface9> tmpSurfaceCb;
|
||||
nsRefPtr<IDirect3DSurface9> tmpSurfaceCr;
|
||||
|
||||
nsRefPtr<IDirect3DDevice9Ex> deviceEx;
|
||||
aDevice->QueryInterface(IID_IDirect3DDevice9Ex,
|
||||
getter_AddRefs(deviceEx));
|
||||
|
||||
bool isD3D9Ex = deviceEx;
|
||||
|
||||
if (isD3D9Ex) {
|
||||
nsRefPtr<IDirect3DTexture9> tmpYTexture;
|
||||
nsRefPtr<IDirect3DTexture9> tmpCbTexture;
|
||||
nsRefPtr<IDirect3DTexture9> tmpCrTexture;
|
||||
// D3D9Ex does not support the managed pool, could use dynamic textures
|
||||
// here. But since an Image is immutable static textures are probably a
|
||||
// better idea.
|
||||
|
||||
HRESULT hr;
|
||||
hr = aDevice->CreateTexture(mData.mYSize.width, mData.mYSize.height,
|
||||
1, 0, D3DFMT_L8, D3DPOOL_DEFAULT,
|
||||
getter_AddRefs(mYTexture), NULL);
|
||||
if (!FAILED(hr)) {
|
||||
hr = aDevice->CreateTexture(mData.mCbCrSize.width, mData.mCbCrSize.height,
|
||||
1, 0, D3DFMT_L8, D3DPOOL_DEFAULT,
|
||||
getter_AddRefs(mCbTexture), NULL);
|
||||
}
|
||||
if (!FAILED(hr)) {
|
||||
hr = aDevice->CreateTexture(mData.mCbCrSize.width, mData.mCbCrSize.height,
|
||||
1, 0, D3DFMT_L8, D3DPOOL_DEFAULT,
|
||||
getter_AddRefs(mCrTexture), NULL);
|
||||
}
|
||||
if (!FAILED(hr)) {
|
||||
hr = aDevice->CreateTexture(mData.mYSize.width, mData.mYSize.height,
|
||||
1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM,
|
||||
getter_AddRefs(tmpYTexture), NULL);
|
||||
}
|
||||
if (!FAILED(hr)) {
|
||||
hr = aDevice->CreateTexture(mData.mCbCrSize.width, mData.mCbCrSize.height,
|
||||
1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM,
|
||||
getter_AddRefs(tmpCbTexture), NULL);
|
||||
}
|
||||
if (!FAILED(hr)) {
|
||||
hr = aDevice->CreateTexture(mData.mCbCrSize.width, mData.mCbCrSize.height,
|
||||
1, 0, D3DFMT_L8, D3DPOOL_SYSTEMMEM,
|
||||
getter_AddRefs(tmpCrTexture), NULL);
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
mManager->ReportFailure(NS_LITERAL_CSTRING("PlanarYCbCrImageD3D9::AllocateTextures(): Failed to create texture (isD3D9Ex)"),
|
||||
hr);
|
||||
return;
|
||||
}
|
||||
|
||||
tmpYTexture->GetSurfaceLevel(0, getter_AddRefs(tmpSurfaceY));
|
||||
tmpCbTexture->GetSurfaceLevel(0, getter_AddRefs(tmpSurfaceCb));
|
||||
tmpCrTexture->GetSurfaceLevel(0, getter_AddRefs(tmpSurfaceCr));
|
||||
tmpSurfaceY->LockRect(&lockrectY, NULL, 0);
|
||||
tmpSurfaceCb->LockRect(&lockrectCb, NULL, 0);
|
||||
tmpSurfaceCr->LockRect(&lockrectCr, NULL, 0);
|
||||
} else {
|
||||
HRESULT hr;
|
||||
hr = aDevice->CreateTexture(mData.mYSize.width, mData.mYSize.height,
|
||||
1, 0, D3DFMT_L8, D3DPOOL_MANAGED,
|
||||
getter_AddRefs(mYTexture), NULL);
|
||||
if (!FAILED(hr)) {
|
||||
aDevice->CreateTexture(mData.mCbCrSize.width, mData.mCbCrSize.height,
|
||||
1, 0, D3DFMT_L8, D3DPOOL_MANAGED,
|
||||
getter_AddRefs(mCbTexture), NULL);
|
||||
}
|
||||
if (!FAILED(hr)) {
|
||||
aDevice->CreateTexture(mData.mCbCrSize.width, mData.mCbCrSize.height,
|
||||
1, 0, D3DFMT_L8, D3DPOOL_MANAGED,
|
||||
getter_AddRefs(mCrTexture), NULL);
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
mManager->ReportFailure(NS_LITERAL_CSTRING("PlanarYCbCrImageD3D9::AllocateTextures(): Failed to create texture (!isD3D9Ex)"),
|
||||
hr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* lock the entire texture */
|
||||
mYTexture->LockRect(0, &lockrectY, NULL, 0);
|
||||
mCbTexture->LockRect(0, &lockrectCb, NULL, 0);
|
||||
mCrTexture->LockRect(0, &lockrectCr, NULL, 0);
|
||||
}
|
||||
|
||||
src = mData.mYChannel;
|
||||
//FIX cast
|
||||
dest = (PRUint8*)lockrectY.pBits;
|
||||
|
||||
// copy over data
|
||||
for (int h=0; h<mData.mYSize.height; h++) {
|
||||
memcpy(dest, src, mData.mYSize.width);
|
||||
dest += lockrectY.Pitch;
|
||||
src += mData.mYStride;
|
||||
}
|
||||
|
||||
src = mData.mCbChannel;
|
||||
//FIX cast
|
||||
dest = (PRUint8*)lockrectCb.pBits;
|
||||
|
||||
// copy over data
|
||||
for (int h=0; h<mData.mCbCrSize.height; h++) {
|
||||
memcpy(dest, src, mData.mCbCrSize.width);
|
||||
dest += lockrectCb.Pitch;
|
||||
src += mData.mCbCrStride;
|
||||
}
|
||||
|
||||
src = mData.mCrChannel;
|
||||
//FIX cast
|
||||
dest = (PRUint8*)lockrectCr.pBits;
|
||||
|
||||
// copy over data
|
||||
for (int h=0; h<mData.mCbCrSize.height; h++) {
|
||||
memcpy(dest, src, mData.mCbCrSize.width);
|
||||
dest += lockrectCr.Pitch;
|
||||
src += mData.mCbCrStride;
|
||||
}
|
||||
|
||||
if (isD3D9Ex) {
|
||||
tmpSurfaceY->UnlockRect();
|
||||
tmpSurfaceCb->UnlockRect();
|
||||
tmpSurfaceCr->UnlockRect();
|
||||
nsRefPtr<IDirect3DSurface9> dstSurface;
|
||||
mYTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
|
||||
aDevice->UpdateSurface(tmpSurfaceY, NULL, dstSurface, NULL);
|
||||
mCbTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
|
||||
aDevice->UpdateSurface(tmpSurfaceCb, NULL, dstSurface, NULL);
|
||||
mCrTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
|
||||
aDevice->UpdateSurface(tmpSurfaceCr, NULL, dstSurface, NULL);
|
||||
} else {
|
||||
mYTexture->UnlockRect(0);
|
||||
mCbTexture->UnlockRect(0);
|
||||
mCrTexture->UnlockRect(0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PlanarYCbCrImageD3D9::FreeTextures()
|
||||
{
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
PlanarYCbCrImageD3D9::GetAsSurface()
|
||||
{
|
||||
nsRefPtr<gfxImageSurface> imageSurface =
|
||||
new gfxImageSurface(mSize, gfxASurface::ImageFormatRGB24);
|
||||
|
||||
gfx::YUVType type =
|
||||
gfx::TypeFromSize(mData.mYSize.width,
|
||||
mData.mYSize.height,
|
||||
mData.mCbCrSize.width,
|
||||
mData.mCbCrSize.height);
|
||||
|
||||
// Convert from YCbCr to RGB now
|
||||
gfx::ConvertYCbCrToRGB32(mData.mYChannel,
|
||||
mData.mCbChannel,
|
||||
mData.mCrChannel,
|
||||
imageSurface->Data(),
|
||||
mData.mPicX,
|
||||
mData.mPicY,
|
||||
mData.mPicSize.width,
|
||||
mData.mPicSize.height,
|
||||
mData.mYStride,
|
||||
mData.mCbCrStride,
|
||||
imageSurface->Stride(),
|
||||
type);
|
||||
|
||||
return imageSurface.forget().get();
|
||||
}
|
||||
|
||||
CairoImageD3D9::~CairoImageD3D9()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CairoImageD3D9::SetDevice(IDirect3DDevice9 *aDevice)
|
||||
{
|
||||
mTexture = NULL;
|
||||
mDevice = aDevice;
|
||||
}
|
||||
|
||||
void
|
||||
CairoImageD3D9::SetData(const CairoImage::Data &aData)
|
||||
{
|
||||
mSize = aData.mSize;
|
||||
mCachedSurface = aData.mSurface;
|
||||
mTexture = NULL;
|
||||
}
|
||||
|
||||
IDirect3DTexture9*
|
||||
CairoImageD3D9::GetOrCreateTexture()
|
||||
{
|
||||
if (mTexture)
|
||||
return mTexture;
|
||||
|
||||
mTexture = SurfaceToTexture(mDevice, mCachedSurface, mSize);
|
||||
|
||||
// We need to keep our cached surface around in case the device changes.
|
||||
return mTexture;
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
CairoImageD3D9::GetAsSurface()
|
||||
{
|
||||
nsRefPtr<gfxASurface> surface = mCachedSurface;
|
||||
return surface.forget();
|
||||
}
|
||||
|
||||
ShadowImageLayerD3D9::ShadowImageLayerD3D9(LayerManagerD3D9* aManager)
|
||||
: ShadowImageLayer(aManager, nsnull)
|
||||
, LayerD3D9(aManager)
|
||||
@ -675,7 +513,7 @@ ShadowImageLayerD3D9::Swap(const SharedImage& aNewFront,
|
||||
data.mPicY = 0;
|
||||
|
||||
if (!mYCbCrImage) {
|
||||
mYCbCrImage = new PlanarYCbCrImageD3D9();
|
||||
mYCbCrImage = new PlanarYCbCrImage(new BufferRecycleBin());
|
||||
}
|
||||
|
||||
mYCbCrImage->SetData(data);
|
||||
@ -710,12 +548,25 @@ ShadowImageLayerD3D9::RenderLayer()
|
||||
if (mBuffer) {
|
||||
mBuffer->RenderTo(mD3DManager, GetEffectiveVisibleRegion());
|
||||
} else if (mYCbCrImage) {
|
||||
if (!mYCbCrImage->HasData()) {
|
||||
if (!mYCbCrImage->mBufferSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mYCbCrImage->GetBackendData(LayerManager::LAYERS_D3D9)) {
|
||||
AllocateTexturesYCbCr(mYCbCrImage, device(), mD3DManager);
|
||||
}
|
||||
|
||||
PlanarYCbCrD3D9BackendData *data =
|
||||
static_cast<PlanarYCbCrD3D9BackendData*>(mYCbCrImage->GetBackendData(LayerManager::LAYERS_D3D9));
|
||||
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mYCbCrImage->mBufferSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
mYCbCrImage->AllocateTextures(device());
|
||||
|
||||
SetShaderTransformAndOpacity();
|
||||
|
||||
device()->SetVertexShaderConstantF(CBvLayerQuad,
|
||||
@ -737,9 +588,9 @@ ShadowImageLayerD3D9::RenderLayer()
|
||||
// Linear scaling is default here, adhering to mFilter is difficult since
|
||||
// presumably even with point filtering we'll still want chroma upsampling
|
||||
// to be linear. In the current approach we can't.
|
||||
device()->SetTexture(0, mYCbCrImage->mYTexture);
|
||||
device()->SetTexture(1, mYCbCrImage->mCbTexture);
|
||||
device()->SetTexture(2, mYCbCrImage->mCrTexture);
|
||||
device()->SetTexture(0, data->mYTexture);
|
||||
device()->SetTexture(1, data->mCbTexture);
|
||||
device()->SetTexture(2, data->mCrTexture);
|
||||
|
||||
device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
|
||||
} else {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user