зеркало из https://github.com/mozilla/gecko-dev.git
Merge last PGO-green changeset of mozilla-inbound to mozilla-central
This commit is contained in:
Коммит
20833ba752
|
@ -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,38 @@ 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;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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} },
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -47,36 +47,6 @@ namespace layers {
|
|||
|
||||
class ShadowBufferD3D9;
|
||||
|
||||
class THEBES_API ImageContainerD3D9 : public ImageContainer
|
||||
{
|
||||
public:
|
||||
ImageContainerD3D9(IDirect3DDevice9 *aDevice);
|
||||
virtual ~ImageContainerD3D9() {}
|
||||
|
||||
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_D3D9; }
|
||||
|
||||
IDirect3DDevice9 *device() { return mDevice; }
|
||||
void SetDevice(IDirect3DDevice9 *aDevice) { mDevice = aDevice; }
|
||||
|
||||
private:
|
||||
nsRefPtr<Image> mActiveImage;
|
||||
|
||||
nsRefPtr<IDirect3DDevice9> mDevice;
|
||||
};
|
||||
|
||||
class THEBES_API ImageLayerD3D9 : public ImageLayer,
|
||||
public LayerD3D9
|
||||
{
|
||||
|
@ -100,81 +70,17 @@ public:
|
|||
virtual already_AddRefed<gfxASurface> GetAsSurface() = 0;
|
||||
};
|
||||
|
||||
class THEBES_API PlanarYCbCrImageD3D9 : public PlanarYCbCrImage,
|
||||
public ImageD3D9
|
||||
|
||||
struct CairoD3D9BackendData : public ImageBackendData
|
||||
{
|
||||
public:
|
||||
PlanarYCbCrImageD3D9();
|
||||
~PlanarYCbCrImageD3D9() {}
|
||||
nsRefPtr<IDirect3DTexture9> mTexture;
|
||||
};
|
||||
|
||||
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(IDirect3DDevice9 *aDevice);
|
||||
/*
|
||||
* XXX
|
||||
* Free the textures, we call this from the main thread when we're done
|
||||
* drawing this frame. We cannot free this from the constructor since it may
|
||||
* be destroyed off the main-thread and might not be able to properly clean
|
||||
* up its textures
|
||||
*/
|
||||
void FreeTextures();
|
||||
bool HasData() { return mHasData; }
|
||||
|
||||
PRUint32 GetDataSize() { return mBuffer ? mBufferSize : 0; }
|
||||
|
||||
virtual already_AddRefed<gfxASurface> GetAsSurface();
|
||||
|
||||
nsAutoArrayPtr<PRUint8> mBuffer;
|
||||
PRUint32 mBufferSize;
|
||||
LayerManagerD3D9 *mManager;
|
||||
Data mData;
|
||||
gfxIntSize mSize;
|
||||
struct PlanarYCbCrD3D9BackendData : public ImageBackendData
|
||||
{
|
||||
nsRefPtr<IDirect3DTexture9> mYTexture;
|
||||
nsRefPtr<IDirect3DTexture9> mCrTexture;
|
||||
nsRefPtr<IDirect3DTexture9> mCbTexture;
|
||||
bool mHasData;
|
||||
};
|
||||
|
||||
|
||||
class THEBES_API CairoImageD3D9 : public CairoImage,
|
||||
public ImageD3D9
|
||||
{
|
||||
public:
|
||||
CairoImageD3D9(IDirect3DDevice9 *aDevice)
|
||||
: CairoImage(static_cast<ImageD3D9*>(this))
|
||||
, mDevice(aDevice)
|
||||
{ }
|
||||
~CairoImageD3D9();
|
||||
|
||||
virtual void SetData(const Data &aData);
|
||||
|
||||
virtual already_AddRefed<gfxASurface> GetAsSurface();
|
||||
|
||||
IDirect3DDevice9 *device() { return mDevice; }
|
||||
void SetDevice(IDirect3DDevice9 *aDevice);
|
||||
|
||||
/**
|
||||
* Uploading a texture may fail if the screen is locked. If this happens,
|
||||
* we need to save the backing surface and retry when we are asked to paint.
|
||||
*/
|
||||
virtual IDirect3DTexture9* GetOrCreateTexture();
|
||||
const gfxIntSize& GetSize() { return mSize; }
|
||||
|
||||
bool HasAlpha() {
|
||||
return mCachedSurface->GetContentType() ==
|
||||
gfxASurface::CONTENT_COLOR_ALPHA;
|
||||
}
|
||||
|
||||
private:
|
||||
gfxIntSize mSize;
|
||||
nsRefPtr<gfxASurface> mCachedSurface;
|
||||
nsRefPtr<IDirect3DDevice9> mDevice;
|
||||
nsRefPtr<IDirect3DTexture9> mTexture;
|
||||
LayerManagerD3D9 *mManager;
|
||||
};
|
||||
|
||||
class ShadowImageLayerD3D9 : public ShadowImageLayer,
|
||||
|
@ -199,7 +105,7 @@ public:
|
|||
|
||||
private:
|
||||
nsRefPtr<ShadowBufferD3D9> mBuffer;
|
||||
nsRefPtr<PlanarYCbCrImageD3D9> mYCbCrImage;
|
||||
nsRefPtr<PlanarYCbCrImage> mYCbCrImage;
|
||||
};
|
||||
|
||||
} /* layers */
|
||||
|
|
|
@ -239,13 +239,6 @@ LayerManagerD3D9::CreateReadbackLayer()
|
|||
return layer.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<ImageContainer>
|
||||
LayerManagerD3D9::CreateImageContainer()
|
||||
{
|
||||
nsRefPtr<ImageContainer> container = new ImageContainerD3D9(device());
|
||||
return container.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<ShadowThebesLayer>
|
||||
LayerManagerD3D9::CreateShadowThebesLayer()
|
||||
{
|
||||
|
|
|
@ -165,8 +165,6 @@ public:
|
|||
|
||||
virtual already_AddRefed<ReadbackLayer> CreateReadbackLayer();
|
||||
|
||||
virtual already_AddRefed<ImageContainer> CreateImageContainer();
|
||||
|
||||
virtual already_AddRefed<ShadowThebesLayer> CreateShadowThebesLayer();
|
||||
virtual already_AddRefed<ShadowContainerLayer> CreateShadowContainerLayer();
|
||||
virtual already_AddRefed<ShadowImageLayer> CreateShadowImageLayer();
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
#include "gfxImageSurface.h"
|
||||
#include "yuv_convert.h"
|
||||
#include "GLContextProvider.h"
|
||||
#include "MacIOSurfaceImageOGL.h"
|
||||
#if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
|
||||
# include "GLXLibrary.h"
|
||||
# include "mozilla/X11Util.h"
|
||||
|
@ -136,39 +135,13 @@ GLTexture::Release()
|
|||
mContext = nsnull;
|
||||
}
|
||||
|
||||
RecycleBin::RecycleBin()
|
||||
: mLock("mozilla.layers.RecycleBin.mLock")
|
||||
TextureRecycleBin::TextureRecycleBin()
|
||||
: mLock("mozilla.layers.TextureRecycleBin.mLock")
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
RecycleBin::RecycleBuffer(PRUint8* aBuffer, PRUint32 aSize)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
if (!mRecycledBuffers.IsEmpty() && aSize != mRecycledBufferSize) {
|
||||
mRecycledBuffers.Clear();
|
||||
}
|
||||
mRecycledBufferSize = aSize;
|
||||
mRecycledBuffers.AppendElement(aBuffer);
|
||||
}
|
||||
|
||||
PRUint8*
|
||||
RecycleBin::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;
|
||||
}
|
||||
|
||||
void
|
||||
RecycleBin::RecycleTexture(GLTexture *aTexture, TextureType aType,
|
||||
TextureRecycleBin::RecycleTexture(GLTexture *aTexture, TextureType aType,
|
||||
const gfxIntSize& aSize)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
|
@ -184,7 +157,7 @@ RecycleBin::RecycleTexture(GLTexture *aTexture, TextureType aType,
|
|||
}
|
||||
|
||||
void
|
||||
RecycleBin::GetTexture(TextureType aType, const gfxIntSize& aSize,
|
||||
TextureRecycleBin::GetTexture(TextureType aType, const gfxIntSize& aSize,
|
||||
GLContext *aContext, GLTexture *aOutTexture)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
|
@ -198,204 +171,40 @@ RecycleBin::GetTexture(TextureType aType, const gfxIntSize& aSize,
|
|||
mRecycledTextures[aType].RemoveElementAt(last);
|
||||
}
|
||||
|
||||
ImageContainerOGL::ImageContainerOGL(LayerManagerOGL *aManager)
|
||||
: ImageContainer(aManager)
|
||||
, mRecycleBin(new RecycleBin())
|
||||
struct THEBES_API MacIOSurfaceImageOGLBackendData : public ImageBackendData
|
||||
{
|
||||
}
|
||||
GLTexture mTexture;
|
||||
};
|
||||
|
||||
ImageContainerOGL::~ImageContainerOGL()
|
||||
{
|
||||
if (mManager) {
|
||||
NS_ASSERTION(mManager->GetBackendType() == LayerManager::LAYERS_OPENGL, "Wrong layer manager got assigned to ImageContainerOGL!");
|
||||
|
||||
static_cast<LayerManagerOGL*>(mManager)->ForgetImageContainer(this);
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<Image>
|
||||
ImageContainerOGL::CreateImage(const Image::Format *aFormats,
|
||||
PRUint32 aNumFormats)
|
||||
{
|
||||
if (!aNumFormats) {
|
||||
return nsnull;
|
||||
}
|
||||
nsRefPtr<Image> img;
|
||||
if (aFormats[0] == Image::PLANAR_YCBCR) {
|
||||
img = new PlanarYCbCrImageOGL(static_cast<LayerManagerOGL*>(mManager),
|
||||
mRecycleBin);
|
||||
} else if (aFormats[0] == Image::CAIRO_SURFACE) {
|
||||
img = new CairoImageOGL(static_cast<LayerManagerOGL*>(mManager));
|
||||
}
|
||||
#ifdef XP_MACOSX
|
||||
else if (aFormats[0] == Image::MAC_IO_SURFACE) {
|
||||
img = new MacIOSurfaceImageOGL(static_cast<LayerManagerOGL*>(mManager));
|
||||
}
|
||||
#endif
|
||||
|
||||
return img.forget();
|
||||
}
|
||||
|
||||
void
|
||||
ImageContainerOGL::SetCurrentImage(Image *aImage)
|
||||
AllocateTextureIOSurface(MacIOSurfaceImage *aIOImage, mozilla::gl::GLContext* aGL)
|
||||
{
|
||||
nsRefPtr<Image> oldImage;
|
||||
nsAutoPtr<MacIOSurfaceImageOGLBackendData> backendData(
|
||||
new MacIOSurfaceImageOGLBackendData);
|
||||
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
backendData->mTexture.Allocate(aGL);
|
||||
aGL->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, backendData->mTexture.GetTextureID());
|
||||
aGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
|
||||
LOCAL_GL_TEXTURE_MIN_FILTER,
|
||||
LOCAL_GL_NEAREST);
|
||||
aGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
|
||||
LOCAL_GL_TEXTURE_MAG_FILTER,
|
||||
LOCAL_GL_NEAREST);
|
||||
|
||||
oldImage = mActiveImage.forget();
|
||||
mActiveImage = aImage;
|
||||
CurrentImageChanged();
|
||||
}
|
||||
void *nativeCtx = aGL->GetNativeData(GLContext::NativeGLContext);
|
||||
NSOpenGLContext* nsCtx = (NSOpenGLContext*)nativeCtx;
|
||||
|
||||
// Make sure oldImage is released outside the lock, so it can take our
|
||||
// lock in RecycleBuffer
|
||||
aIOImage->GetIOSurface()->CGLTexImageIOSurface2D(nsCtx,
|
||||
LOCAL_GL_RGBA, LOCAL_GL_BGRA,
|
||||
LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV, 0);
|
||||
|
||||
aGL->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
|
||||
aIOImage->SetBackendData(LayerManager::LAYERS_OPENGL, backendData.forget());
|
||||
}
|
||||
|
||||
already_AddRefed<Image>
|
||||
ImageContainerOGL::GetCurrentImage()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
nsRefPtr<Image> retval = mActiveImage;
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
ImageContainerOGL::GetCurrentAsSurface(gfxIntSize *aSize)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
if (!mActiveImage) {
|
||||
*aSize = gfxIntSize(0,0);
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
GLContext *gl = nsnull;
|
||||
// tex1 will be RGBA or Y, tex2 will Cb, tex3 will be Cr
|
||||
GLuint tex1 = 0;
|
||||
gfxIntSize size;
|
||||
|
||||
if (mActiveImage->GetFormat() == Image::PLANAR_YCBCR) {
|
||||
PlanarYCbCrImageOGL *yuvImage =
|
||||
static_cast<PlanarYCbCrImageOGL*>(mActiveImage.get());
|
||||
if (!yuvImage->HasData()) {
|
||||
*aSize = gfxIntSize(0, 0);
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
size = yuvImage->mData.mPicSize;
|
||||
|
||||
nsRefPtr<gfxImageSurface> imageSurface =
|
||||
new gfxImageSurface(size, gfxASurface::ImageFormatRGB24);
|
||||
|
||||
gfx::YUVType type =
|
||||
gfx::TypeFromSize(yuvImage->mData.mYSize.width,
|
||||
yuvImage->mData.mYSize.height,
|
||||
yuvImage->mData.mCbCrSize.width,
|
||||
yuvImage->mData.mCbCrSize.height);
|
||||
|
||||
gfx::ConvertYCbCrToRGB32(yuvImage->mData.mYChannel,
|
||||
yuvImage->mData.mCbChannel,
|
||||
yuvImage->mData.mCrChannel,
|
||||
imageSurface->Data(),
|
||||
yuvImage->mData.mPicX,
|
||||
yuvImage->mData.mPicY,
|
||||
size.width,
|
||||
size.height,
|
||||
yuvImage->mData.mYStride,
|
||||
yuvImage->mData.mCbCrStride,
|
||||
imageSurface->Stride(),
|
||||
type);
|
||||
|
||||
*aSize = size;
|
||||
return imageSurface.forget().get();
|
||||
}
|
||||
|
||||
if (mActiveImage->GetFormat() != Image::CAIRO_SURFACE)
|
||||
{
|
||||
*aSize = gfxIntSize(0, 0);
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
CairoImageOGL *cairoImage =
|
||||
static_cast<CairoImageOGL*>(mActiveImage.get());
|
||||
size = cairoImage->mSize;
|
||||
gl = cairoImage->mTexture.GetGLContext();
|
||||
tex1 = cairoImage->mTexture.GetTextureID();
|
||||
|
||||
nsRefPtr<gfxImageSurface> s = gl->ReadTextureImage(tex1, size, LOCAL_GL_RGBA);
|
||||
*aSize = size;
|
||||
return s.forget();
|
||||
}
|
||||
|
||||
gfxIntSize
|
||||
ImageContainerOGL::GetCurrentSize()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
if (!mActiveImage) {
|
||||
return gfxIntSize(0,0);
|
||||
}
|
||||
|
||||
if (mActiveImage->GetFormat() == Image::PLANAR_YCBCR) {
|
||||
PlanarYCbCrImageOGL *yuvImage =
|
||||
static_cast<PlanarYCbCrImageOGL*>(mActiveImage.get());
|
||||
if (!yuvImage->HasData()) {
|
||||
return gfxIntSize(0,0);
|
||||
}
|
||||
return yuvImage->mSize;
|
||||
}
|
||||
|
||||
if (mActiveImage->GetFormat() == Image::CAIRO_SURFACE) {
|
||||
CairoImageOGL *cairoImage =
|
||||
static_cast<CairoImageOGL*>(mActiveImage.get());
|
||||
return cairoImage->mSize;
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
if (mActiveImage->GetFormat() == Image::MAC_IO_SURFACE) {
|
||||
MacIOSurfaceImageOGL *ioImage =
|
||||
static_cast<MacIOSurfaceImageOGL*>(mActiveImage.get());
|
||||
return ioImage->mSize;
|
||||
}
|
||||
#endif
|
||||
|
||||
return gfxIntSize(0,0);
|
||||
}
|
||||
|
||||
bool
|
||||
ImageContainerOGL::SetLayerManager(LayerManager *aManager)
|
||||
{
|
||||
if (!aManager) {
|
||||
// the layer manager just entirely went away
|
||||
|
||||
// XXX if we don't have context sharing, we should tell our images
|
||||
// that their textures are no longer valid.
|
||||
mManager = nsnull;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aManager->GetBackendType() != LayerManager::LAYERS_OPENGL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LayerManagerOGL* lmOld = static_cast<LayerManagerOGL*>(mManager);
|
||||
LayerManagerOGL* lmNew = static_cast<LayerManagerOGL*>(aManager);
|
||||
|
||||
if (lmOld) {
|
||||
NS_ASSERTION(lmNew->glForResources() == lmOld->glForResources(),
|
||||
"We require GL context sharing here!");
|
||||
lmOld->ForgetImageContainer(this);
|
||||
}
|
||||
|
||||
mManager = aManager;
|
||||
|
||||
lmNew->RememberImageContainer(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Layer*
|
||||
ImageLayerOGL::GetLayer()
|
||||
{
|
||||
|
@ -417,27 +226,34 @@ ImageLayerOGL::RenderLayer(int,
|
|||
}
|
||||
|
||||
if (image->GetFormat() == Image::PLANAR_YCBCR) {
|
||||
PlanarYCbCrImageOGL *yuvImage =
|
||||
static_cast<PlanarYCbCrImageOGL*>(image.get());
|
||||
PlanarYCbCrImage *yuvImage =
|
||||
static_cast<PlanarYCbCrImage*>(image.get());
|
||||
|
||||
if (!yuvImage->HasData()) {
|
||||
if (!yuvImage->mBufferSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!yuvImage->HasTextures()) {
|
||||
yuvImage->AllocateTextures(gl());
|
||||
|
||||
if (!yuvImage->GetBackendData(LayerManager::LAYERS_OPENGL)) {
|
||||
AllocateTexturesYCbCr(yuvImage);
|
||||
}
|
||||
|
||||
yuvImage->UpdateTextures(gl());
|
||||
PlanarYCbCrOGLBackendData *data =
|
||||
static_cast<PlanarYCbCrOGLBackendData*>(yuvImage->GetBackendData(LayerManager::LAYERS_OPENGL));
|
||||
|
||||
if (!data || data->mTextures->GetGLContext() != mOGLManager->glForResources()) {
|
||||
// XXX - Can this ever happen? If so I need to fix this!
|
||||
return;
|
||||
}
|
||||
|
||||
gl()->MakeCurrent();
|
||||
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, yuvImage->mTextures[0].GetTextureID());
|
||||
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTextures[0].GetTextureID());
|
||||
gl()->ApplyFilterToBoundTexture(mFilter);
|
||||
gl()->fActiveTexture(LOCAL_GL_TEXTURE1);
|
||||
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, yuvImage->mTextures[1].GetTextureID());
|
||||
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTextures[1].GetTextureID());
|
||||
gl()->ApplyFilterToBoundTexture(mFilter);
|
||||
gl()->fActiveTexture(LOCAL_GL_TEXTURE2);
|
||||
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, yuvImage->mTextures[2].GetTextureID());
|
||||
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTextures[2].GetTextureID());
|
||||
gl()->ApplyFilterToBoundTexture(mFilter);
|
||||
|
||||
YCbCrTextureLayerProgram *program = mOGLManager->GetYCbCrLayerProgram();
|
||||
|
@ -460,16 +276,32 @@ ImageLayerOGL::RenderLayer(int,
|
|||
// someone else forgets.
|
||||
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
} else if (image->GetFormat() == Image::CAIRO_SURFACE) {
|
||||
CairoImageOGL *cairoImage =
|
||||
static_cast<CairoImageOGL*>(image.get());
|
||||
CairoImage *cairoImage =
|
||||
static_cast<CairoImage*>(image.get());
|
||||
|
||||
cairoImage->SetTiling(mUseTileSourceRect);
|
||||
if (!cairoImage->mSurface) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cairoImage->GetBackendData(LayerManager::LAYERS_OPENGL)) {
|
||||
AllocateTexturesCairo(cairoImage);
|
||||
}
|
||||
|
||||
CairoOGLBackendData *data =
|
||||
static_cast<CairoOGLBackendData*>(cairoImage->GetBackendData(LayerManager::LAYERS_OPENGL));
|
||||
|
||||
if (!data || data->mTexture.GetGLContext() != mOGLManager->glForResources()) {
|
||||
// XXX - Can this ever happen? If so I need to fix this!
|
||||
return;
|
||||
}
|
||||
|
||||
data->SetTiling(mUseTileSourceRect);
|
||||
gl()->MakeCurrent();
|
||||
unsigned int iwidth = cairoImage->mSize.width;
|
||||
unsigned int iheight = cairoImage->mSize.height;
|
||||
|
||||
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, cairoImage->mTexture.GetTextureID());
|
||||
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTexture.GetTextureID());
|
||||
|
||||
#if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
|
||||
GLXPixmap pixmap;
|
||||
|
@ -484,7 +316,7 @@ ImageLayerOGL::RenderLayer(int,
|
|||
#endif
|
||||
|
||||
ColorTextureLayerProgram *program =
|
||||
mOGLManager->GetColorTextureLayerProgram(cairoImage->mLayerProgram);
|
||||
mOGLManager->GetColorTextureLayerProgram(data->mLayerProgram);
|
||||
|
||||
gl()->ApplyFilterToBoundTexture(mFilter);
|
||||
|
||||
|
@ -592,8 +424,8 @@ ImageLayerOGL::RenderLayer(int,
|
|||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
} else if (image->GetFormat() == Image::MAC_IO_SURFACE) {
|
||||
MacIOSurfaceImageOGL *ioImage =
|
||||
static_cast<MacIOSurfaceImageOGL*>(image.get());
|
||||
MacIOSurfaceImage *ioImage =
|
||||
static_cast<MacIOSurfaceImage*>(image.get());
|
||||
|
||||
if (!mOGLManager->GetThebesLayerCallback()) {
|
||||
// If its an empty transaction we still need to update
|
||||
|
@ -602,15 +434,24 @@ ImageLayerOGL::RenderLayer(int,
|
|||
ioImage->Update(GetContainer());
|
||||
image = GetContainer()->GetCurrentImage();
|
||||
gl()->MakeCurrent();
|
||||
ioImage = static_cast<MacIOSurfaceImageOGL*>(image.get());
|
||||
ioImage = static_cast<MacIOSurfaceImage*>(image.get());
|
||||
}
|
||||
|
||||
if (!ioImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, ioImage->mTexture.GetTextureID());
|
||||
|
||||
if (!ioImage->GetBackendData(LayerManager::LAYERS_OPENGL)) {
|
||||
AllocateTextureIOSurface(ioImage, gl());
|
||||
}
|
||||
|
||||
MacIOSurfaceImageOGLBackendData *data =
|
||||
static_cast<MacIOSurfaceImageOGLBackendData*>(ioImage->GetBackendData(LayerManager::LAYERS_OPENGL));
|
||||
|
||||
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, data->mTexture.GetTextureID());
|
||||
|
||||
ColorTextureLayerProgram *program =
|
||||
mOGLManager->GetRGBARectLayerProgram();
|
||||
|
@ -618,7 +459,7 @@ ImageLayerOGL::RenderLayer(int,
|
|||
program->Activate();
|
||||
if (program->GetTexCoordMultiplierUniformLocation() != -1) {
|
||||
// 2DRect case, get the multiplier right for a sampler2DRect
|
||||
float f[] = { float(ioImage->mSize.width), float(ioImage->mSize.height) };
|
||||
float f[] = { float(ioImage->GetSize().width), float(ioImage->GetSize().height) };
|
||||
program->SetUniform(program->GetTexCoordMultiplierUniformLocation(),
|
||||
2, f);
|
||||
} else {
|
||||
|
@ -626,8 +467,8 @@ ImageLayerOGL::RenderLayer(int,
|
|||
}
|
||||
|
||||
program->SetLayerQuadRect(nsIntRect(0, 0,
|
||||
ioImage->mSize.width,
|
||||
ioImage->mSize.height));
|
||||
ioImage->GetSize().width,
|
||||
ioImage->GetSize().height));
|
||||
program->SetLayerTransform(GetEffectiveTransform());
|
||||
program->SetLayerOpacity(GetEffectiveOpacity());
|
||||
program->SetRenderOffset(aOffset);
|
||||
|
@ -660,61 +501,6 @@ InitTexture(GLContext* aGL, GLuint aTexture, GLenum aFormat, const gfxIntSize& a
|
|||
NULL);
|
||||
}
|
||||
|
||||
PlanarYCbCrImageOGL::PlanarYCbCrImageOGL(LayerManagerOGL *aManager,
|
||||
RecycleBin *aRecycleBin)
|
||||
: PlanarYCbCrImage(nsnull), mRecycleBin(aRecycleBin), mHasData(false)
|
||||
{
|
||||
#if 0
|
||||
// We really want to allocate this on the decode thread -- but to do that,
|
||||
// we need to create a per-thread shared GL context, and it will only work
|
||||
// if we have context sharing. For now, create the textures on the main
|
||||
// thread the first time we render.
|
||||
if (aManager) {
|
||||
AllocateTextures(aManager->glForResources());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
PlanarYCbCrImageOGL::~PlanarYCbCrImageOGL()
|
||||
{
|
||||
if (mBuffer) {
|
||||
mRecycleBin->RecycleBuffer(mBuffer.forget(), mBufferSize);
|
||||
}
|
||||
|
||||
if (HasTextures()) {
|
||||
mRecycleBin->RecycleTexture(&mTextures[0], RecycleBin::TEXTURE_Y, mData.mYSize);
|
||||
mRecycleBin->RecycleTexture(&mTextures[1], RecycleBin::TEXTURE_C, mData.mCbCrSize);
|
||||
mRecycleBin->RecycleTexture(&mTextures[2], RecycleBin::TEXTURE_C, mData.mCbCrSize);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PlanarYCbCrImageOGL::SetData(const PlanarYCbCrImage::Data &aData)
|
||||
{
|
||||
// Recycle the previous image main-memory buffer now that we're about to get a new buffer
|
||||
if (mBuffer)
|
||||
mRecycleBin->RecycleBuffer(mBuffer.forget(), mBufferSize);
|
||||
|
||||
mBuffer = CopyData(mData, mSize, mBufferSize, aData);
|
||||
|
||||
mHasData = true;
|
||||
}
|
||||
|
||||
void
|
||||
PlanarYCbCrImageOGL::AllocateTextures(mozilla::gl::GLContext *gl)
|
||||
{
|
||||
gl->MakeCurrent();
|
||||
|
||||
mRecycleBin->GetTexture(RecycleBin::TEXTURE_Y, mData.mYSize, gl, &mTextures[0]);
|
||||
InitTexture(gl, mTextures[0].GetTextureID(), LOCAL_GL_LUMINANCE, mData.mYSize);
|
||||
|
||||
mRecycleBin->GetTexture(RecycleBin::TEXTURE_C, mData.mCbCrSize, gl, &mTextures[1]);
|
||||
InitTexture(gl, mTextures[1].GetTextureID(), LOCAL_GL_LUMINANCE, mData.mCbCrSize);
|
||||
|
||||
mRecycleBin->GetTexture(RecycleBin::TEXTURE_C, mData.mCbCrSize, gl, &mTextures[2]);
|
||||
InitTexture(gl, mTextures[2].GetTextureID(), LOCAL_GL_LUMINANCE, mData.mCbCrSize);
|
||||
}
|
||||
|
||||
static void
|
||||
UploadYUVToTexture(GLContext* gl, const PlanarYCbCrImage::Data& aData,
|
||||
GLTexture* aYTexture,
|
||||
|
@ -745,62 +531,91 @@ UploadYUVToTexture(GLContext* gl, const PlanarYCbCrImage::Data& aData,
|
|||
gl->UploadSurfaceToTexture(surf, size, texture, true);
|
||||
}
|
||||
|
||||
void
|
||||
PlanarYCbCrImageOGL::UpdateTextures(GLContext *gl)
|
||||
{
|
||||
if (!mBuffer || !mHasData)
|
||||
return;
|
||||
|
||||
UploadYUVToTexture(gl, mData, &mTextures[0], &mTextures[1], &mTextures[2]);
|
||||
ImageLayerOGL::ImageLayerOGL(LayerManagerOGL *aManager)
|
||||
: ImageLayer(aManager, NULL)
|
||||
, LayerOGL(aManager)
|
||||
, mTextureRecycleBin(new TextureRecycleBin())
|
||||
{
|
||||
mImplData = static_cast<LayerOGL*>(this);
|
||||
}
|
||||
|
||||
CairoImageOGL::CairoImageOGL(LayerManagerOGL *aManager)
|
||||
: CairoImage(nsnull), mSize(0, 0), mTiling(false)
|
||||
void
|
||||
ImageLayerOGL::AllocateTexturesYCbCr(PlanarYCbCrImage *aImage)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread to create a cairo image");
|
||||
if (!aImage->mBufferSize)
|
||||
return;
|
||||
|
||||
if (aManager) {
|
||||
// Allocate texture now to grab a reference to the GLContext
|
||||
mTexture.Allocate(aManager->glForResources());
|
||||
nsAutoPtr<PlanarYCbCrOGLBackendData> backendData(
|
||||
new PlanarYCbCrOGLBackendData);
|
||||
|
||||
PlanarYCbCrImage::Data &data = aImage->mData;
|
||||
|
||||
GLContext *gl = mOGLManager->glForResources();
|
||||
|
||||
gl->MakeCurrent();
|
||||
|
||||
mTextureRecycleBin->GetTexture(TextureRecycleBin::TEXTURE_Y, data.mYSize, gl, &backendData->mTextures[0]);
|
||||
InitTexture(gl, backendData->mTextures[0].GetTextureID(), LOCAL_GL_LUMINANCE, data.mYSize);
|
||||
|
||||
mTextureRecycleBin->GetTexture(TextureRecycleBin::TEXTURE_C, data.mCbCrSize, gl, &backendData->mTextures[1]);
|
||||
InitTexture(gl, backendData->mTextures[1].GetTextureID(), LOCAL_GL_LUMINANCE, data.mCbCrSize);
|
||||
|
||||
mTextureRecycleBin->GetTexture(TextureRecycleBin::TEXTURE_C, data.mCbCrSize, gl, &backendData->mTextures[2]);
|
||||
InitTexture(gl, backendData->mTextures[2].GetTextureID(), LOCAL_GL_LUMINANCE, data.mCbCrSize);
|
||||
|
||||
UploadYUVToTexture(gl, aImage->mData,
|
||||
&backendData->mTextures[0],
|
||||
&backendData->mTextures[1],
|
||||
&backendData->mTextures[2]);
|
||||
|
||||
backendData->mYSize = aImage->mData.mYSize;
|
||||
backendData->mCbCrSize = aImage->mData.mCbCrSize;
|
||||
backendData->mTextureRecycleBin = mTextureRecycleBin;
|
||||
|
||||
aImage->SetBackendData(LayerManager::LAYERS_OPENGL, backendData.forget());
|
||||
}
|
||||
|
||||
void
|
||||
ImageLayerOGL::AllocateTexturesCairo(CairoImage *aImage)
|
||||
{
|
||||
nsAutoPtr<CairoOGLBackendData> backendData(
|
||||
new CairoOGLBackendData);
|
||||
|
||||
GLTexture &texture = backendData->mTexture;
|
||||
|
||||
texture.Allocate(mOGLManager->glForResources());
|
||||
|
||||
if (!texture.IsAllocated()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CairoImageOGL::SetData(const CairoImage::Data &aData)
|
||||
{
|
||||
#if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
|
||||
mSurface = nsnull;
|
||||
#endif
|
||||
|
||||
if (!mTexture.IsAllocated())
|
||||
return;
|
||||
|
||||
mozilla::gl::GLContext *gl = mTexture.GetGLContext();
|
||||
mozilla::gl::GLContext *gl = texture.GetGLContext();
|
||||
gl->MakeCurrent();
|
||||
|
||||
GLuint tex = mTexture.GetTextureID();
|
||||
GLuint tex = texture.GetTextureID();
|
||||
gl->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
mSize = aData.mSize;
|
||||
|
||||
#if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
|
||||
if (sGLXLibrary.SupportsTextureFromPixmap(aData.mSurface)) {
|
||||
mSurface = aData.mSurface;
|
||||
if (mSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) {
|
||||
mLayerProgram = gl::RGBALayerProgramType;
|
||||
if (sGLXLibrary.SupportsTextureFromPixmap(aImage->mSurface)) {
|
||||
if (aImage->mSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) {
|
||||
backendData->mLayerProgram = gl::RGBALayerProgramType;
|
||||
} else {
|
||||
mLayerProgram = gl::RGBXLayerProgramType;
|
||||
backendData->mLayerProgram = gl::RGBXLayerProgramType;
|
||||
}
|
||||
|
||||
aImage->SetBackendData(LayerManager::LAYERS_OPENGL, backendData.forget());
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
mLayerProgram =
|
||||
gl->UploadSurfaceToTexture(aData.mSurface,
|
||||
nsIntRect(0,0, mSize.width, mSize.height),
|
||||
backendData->mLayerProgram =
|
||||
gl->UploadSurfaceToTexture(aImage->mSurface,
|
||||
nsIntRect(0,0, aImage->mSize.width, aImage->mSize.height),
|
||||
tex, true);
|
||||
|
||||
aImage->SetBackendData(LayerManager::LAYERS_OPENGL, backendData.forget());
|
||||
}
|
||||
|
||||
void CairoImageOGL::SetTiling(bool aTiling)
|
||||
void CairoOGLBackendData::SetTiling(bool aTiling)
|
||||
{
|
||||
if (aTiling == mTiling)
|
||||
return;
|
||||
|
|
|
@ -90,23 +90,19 @@ private:
|
|||
};
|
||||
|
||||
/**
|
||||
* A RecycleBin is owned by an ImageContainerOGL. We store buffers
|
||||
* and textures in it that we want to recycle from one image to the next.
|
||||
* It's a separate object from ImageContainerOGL because images need to store
|
||||
* a strong ref to their RecycleBin and we must avoid creating a
|
||||
* reference loop between an ImageContainerOGL and its active image.
|
||||
* A RecycleBin is owned by an ImageLayer. We store textures 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 RecycleBin {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RecycleBin)
|
||||
class TextureRecycleBin {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureRecycleBin)
|
||||
|
||||
typedef mozilla::gl::GLContext GLContext;
|
||||
|
||||
public:
|
||||
RecycleBin();
|
||||
|
||||
void RecycleBuffer(PRUint8* aBuffer, PRUint32 aSize);
|
||||
// Returns a recycled buffer of the right size, or allocates a new buffer.
|
||||
PRUint8* GetBuffer(PRUint32 aSize);
|
||||
TextureRecycleBin();
|
||||
|
||||
enum TextureType {
|
||||
TEXTURE_Y,
|
||||
|
@ -125,53 +121,15 @@ private:
|
|||
// 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;
|
||||
|
||||
nsTArray<GLTexture> mRecycledTextures[2];
|
||||
gfxIntSize mRecycledTextureSizes[2];
|
||||
};
|
||||
|
||||
class THEBES_API ImageContainerOGL : public ImageContainer
|
||||
{
|
||||
public:
|
||||
ImageContainerOGL(LayerManagerOGL *aManager);
|
||||
virtual ~ImageContainerOGL();
|
||||
|
||||
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_OPENGL; }
|
||||
|
||||
private:
|
||||
|
||||
nsRefPtr<RecycleBin> mRecycleBin;
|
||||
nsRefPtr<Image> mActiveImage;
|
||||
};
|
||||
|
||||
class THEBES_API ImageLayerOGL : public ImageLayer,
|
||||
public LayerOGL
|
||||
{
|
||||
public:
|
||||
ImageLayerOGL(LayerManagerOGL *aManager)
|
||||
: ImageLayer(aManager, NULL)
|
||||
, LayerOGL(aManager)
|
||||
{
|
||||
mImplData = static_cast<LayerOGL*>(this);
|
||||
}
|
||||
ImageLayerOGL(LayerManagerOGL *aManager);
|
||||
~ImageLayerOGL() { Destroy(); }
|
||||
|
||||
// LayerOGL Implementation
|
||||
|
@ -181,66 +139,43 @@ public:
|
|||
virtual void RenderLayer(int aPreviousFrameBuffer,
|
||||
const nsIntPoint& aOffset);
|
||||
virtual void CleanupResources() {}
|
||||
|
||||
void AllocateTexturesYCbCr(PlanarYCbCrImage *aImage);
|
||||
void AllocateTexturesCairo(CairoImage *aImage);
|
||||
|
||||
protected:
|
||||
nsRefPtr<TextureRecycleBin> mTextureRecycleBin;
|
||||
};
|
||||
|
||||
class THEBES_API PlanarYCbCrImageOGL : public PlanarYCbCrImage
|
||||
struct THEBES_API PlanarYCbCrOGLBackendData : public ImageBackendData
|
||||
{
|
||||
typedef mozilla::gl::GLContext GLContext;
|
||||
~PlanarYCbCrOGLBackendData()
|
||||
{
|
||||
if (HasTextures()) {
|
||||
mTextureRecycleBin->RecycleTexture(&mTextures[0], TextureRecycleBin::TEXTURE_Y, mYSize);
|
||||
mTextureRecycleBin->RecycleTexture(&mTextures[1], TextureRecycleBin::TEXTURE_C, mCbCrSize);
|
||||
mTextureRecycleBin->RecycleTexture(&mTextures[2], TextureRecycleBin::TEXTURE_C, mCbCrSize);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
PlanarYCbCrImageOGL(LayerManagerOGL *aManager,
|
||||
RecycleBin *aRecycleBin);
|
||||
~PlanarYCbCrImageOGL();
|
||||
|
||||
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(GLContext *gl);
|
||||
void UpdateTextures(GLContext *gl);
|
||||
|
||||
bool HasData() { return mHasData; }
|
||||
bool HasTextures()
|
||||
{
|
||||
return mTextures[0].IsAllocated() && mTextures[1].IsAllocated() &&
|
||||
mTextures[2].IsAllocated();
|
||||
}
|
||||
|
||||
PRUint8* AllocateBuffer(PRUint32 aSize) {
|
||||
return mRecycleBin->GetBuffer(aSize);
|
||||
}
|
||||
|
||||
PRUint32 GetDataSize() { return mBuffer ? mBufferSize : 0; }
|
||||
|
||||
nsAutoArrayPtr<PRUint8> mBuffer;
|
||||
PRUint32 mBufferSize;
|
||||
nsRefPtr<RecycleBin> mRecycleBin;
|
||||
GLTexture mTextures[3];
|
||||
Data mData;
|
||||
gfxIntSize mSize;
|
||||
bool mHasData;
|
||||
gfxIntSize mYSize, mCbCrSize;
|
||||
nsRefPtr<TextureRecycleBin> mTextureRecycleBin;
|
||||
};
|
||||
|
||||
|
||||
class THEBES_API CairoImageOGL : public CairoImage
|
||||
struct CairoOGLBackendData : public ImageBackendData
|
||||
{
|
||||
typedef mozilla::gl::GLContext GLContext;
|
||||
|
||||
public:
|
||||
CairoImageOGL(LayerManagerOGL *aManager);
|
||||
|
||||
void SetData(const Data &aData);
|
||||
|
||||
GLTexture mTexture;
|
||||
gfxIntSize mSize;
|
||||
gl::ShaderProgramType mLayerProgram;
|
||||
#if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
|
||||
nsRefPtr<gfxASurface> mSurface;
|
||||
#endif
|
||||
CairoOGLBackendData() : mLayerProgram(gl::RGBALayerProgramType), mTiling(false) {}
|
||||
void SetTiling(bool aTiling);
|
||||
private:
|
||||
GLTexture mTexture;
|
||||
gl::ShaderProgramType mLayerProgram;
|
||||
bool mTiling;
|
||||
};
|
||||
|
||||
|
|
|
@ -102,14 +102,6 @@ LayerManagerOGL::Destroy()
|
|||
}
|
||||
mRoot = nsnull;
|
||||
|
||||
// Make a copy, since SetLayerManager will cause mImageContainers
|
||||
// to get mutated.
|
||||
nsTArray<ImageContainer*> imageContainers(mImageContainers);
|
||||
for (PRUint32 i = 0; i < imageContainers.Length(); ++i) {
|
||||
ImageContainer *c = imageContainers[i];
|
||||
c->SetLayerManager(nsnull);
|
||||
}
|
||||
|
||||
CleanupResources();
|
||||
|
||||
mDestroyed = true;
|
||||
|
@ -477,19 +469,6 @@ LayerManagerOGL::CreateContainerLayer()
|
|||
return layer.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<ImageContainer>
|
||||
LayerManagerOGL::CreateImageContainer()
|
||||
{
|
||||
if (mDestroyed) {
|
||||
NS_WARNING("Call on destroyed layer manager");
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsRefPtr<ImageContainer> container = new ImageContainerOGL(this);
|
||||
RememberImageContainer(container);
|
||||
return container.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<ImageLayer>
|
||||
LayerManagerOGL::CreateImageLayer()
|
||||
{
|
||||
|
@ -526,26 +505,6 @@ LayerManagerOGL::CreateCanvasLayer()
|
|||
return layer.forget();
|
||||
}
|
||||
|
||||
void
|
||||
LayerManagerOGL::ForgetImageContainer(ImageContainer *aContainer)
|
||||
{
|
||||
NS_ASSERTION(aContainer->Manager() == this,
|
||||
"ForgetImageContainer called on non-owned container!");
|
||||
|
||||
if (!mImageContainers.RemoveElement(aContainer)) {
|
||||
NS_WARNING("ForgetImageContainer couldn't find container it was supposed to forget!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LayerManagerOGL::RememberImageContainer(ImageContainer *aContainer)
|
||||
{
|
||||
NS_ASSERTION(aContainer->Manager() == this,
|
||||
"RememberImageContainer called on non-owned container!");
|
||||
mImageContainers.AppendElement(aContainer);
|
||||
}
|
||||
|
||||
LayerOGL*
|
||||
LayerManagerOGL::RootLayer() const
|
||||
{
|
||||
|
|
|
@ -162,8 +162,6 @@ public:
|
|||
|
||||
virtual already_AddRefed<CanvasLayer> CreateCanvasLayer();
|
||||
|
||||
virtual already_AddRefed<ImageContainer> CreateImageContainer();
|
||||
|
||||
virtual already_AddRefed<ShadowThebesLayer> CreateShadowThebesLayer();
|
||||
virtual already_AddRefed<ShadowContainerLayer> CreateShadowContainerLayer();
|
||||
virtual already_AddRefed<ShadowImageLayer> CreateShadowImageLayer();
|
||||
|
@ -173,16 +171,6 @@ public:
|
|||
virtual LayersBackend GetBackendType() { return LAYERS_OPENGL; }
|
||||
virtual void GetBackendName(nsAString& name) { name.AssignLiteral("OpenGL"); }
|
||||
|
||||
/**
|
||||
* Image Container management.
|
||||
*/
|
||||
|
||||
/* Forget this image container. Should be called by ImageContainerOGL
|
||||
* on its current layer manager before switching to a new one.
|
||||
*/
|
||||
void ForgetImageContainer(ImageContainer* aContainer);
|
||||
void RememberImageContainer(ImageContainer* aContainer);
|
||||
|
||||
/**
|
||||
* Helper methods.
|
||||
*/
|
||||
|
@ -423,11 +411,6 @@ private:
|
|||
|
||||
already_AddRefed<mozilla::gl::GLContext> CreateContext();
|
||||
|
||||
// The image containers that this layer manager has created.
|
||||
// The destructor will tell the layer manager to remove
|
||||
// it from the list.
|
||||
nsTArray<ImageContainer*> mImageContainers;
|
||||
|
||||
static ProgramType sLayerProgramTypes[];
|
||||
|
||||
/** Backbuffer */
|
||||
|
|
|
@ -1,120 +0,0 @@
|
|||
/* -*- 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):
|
||||
* Matt Woodrow <mwoodrow@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 "ImageLayerOGL.h"
|
||||
#include "MacIOSurfaceImageOGL.h"
|
||||
#include <AppKit/NSOpenGL.h>
|
||||
#include "OpenGL/OpenGL.h"
|
||||
|
||||
using namespace mozilla::gl;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
MacIOSurfaceImageOGL::MacIOSurfaceImageOGL(LayerManagerOGL *aManager)
|
||||
: MacIOSurfaceImage(nsnull), mSize(0, 0), mPluginInstanceOwner(nsnull),
|
||||
mUpdateCallback(nsnull), mDestroyCallback(nsnull)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread to create a cairo image");
|
||||
|
||||
if (aManager) {
|
||||
// Allocate texture now to grab a reference to the GLContext
|
||||
GLContext *gl = aManager->glForResources();
|
||||
mTexture.Allocate(gl);
|
||||
gl->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, mTexture.GetTextureID());
|
||||
gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
|
||||
LOCAL_GL_TEXTURE_MIN_FILTER,
|
||||
LOCAL_GL_NEAREST);
|
||||
gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
|
||||
LOCAL_GL_TEXTURE_MAG_FILTER,
|
||||
LOCAL_GL_NEAREST);
|
||||
gl->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
}
|
||||
}
|
||||
|
||||
MacIOSurfaceImageOGL::~MacIOSurfaceImageOGL()
|
||||
{
|
||||
if (mDestroyCallback) {
|
||||
mDestroyCallback(mPluginInstanceOwner);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacIOSurfaceImageOGL::SetData(const MacIOSurfaceImage::Data &aData)
|
||||
{
|
||||
mIOSurface = nsIOSurface::LookupSurface(aData.mIOSurface->GetIOSurfaceID());
|
||||
mSize = gfxIntSize(mIOSurface->GetWidth(), mIOSurface->GetHeight());
|
||||
|
||||
GLContext *gl = mTexture.GetGLContext();
|
||||
gl->MakeCurrent();
|
||||
|
||||
gl->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
gl->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, mTexture.GetTextureID());
|
||||
|
||||
void *nativeCtx = gl->GetNativeData(GLContext::NativeGLContext);
|
||||
NSOpenGLContext* nsCtx = (NSOpenGLContext*)nativeCtx;
|
||||
|
||||
mIOSurface->CGLTexImageIOSurface2D((CGLContextObj)[nsCtx CGLContextObj],
|
||||
LOCAL_GL_RGBA, LOCAL_GL_BGRA,
|
||||
LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV, 0);
|
||||
|
||||
gl->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
}
|
||||
|
||||
void
|
||||
MacIOSurfaceImageOGL::SetUpdateCallback(UpdateSurfaceCallback aCallback, void* aPluginInstanceOwner)
|
||||
{
|
||||
mUpdateCallback = aCallback;
|
||||
mPluginInstanceOwner = aPluginInstanceOwner;
|
||||
}
|
||||
|
||||
void
|
||||
MacIOSurfaceImageOGL::SetDestroyCallback(DestroyCallback aCallback)
|
||||
{
|
||||
mDestroyCallback = aCallback;
|
||||
}
|
||||
|
||||
void
|
||||
MacIOSurfaceImageOGL::Update(ImageContainer* aContainer)
|
||||
{
|
||||
if (mUpdateCallback) {
|
||||
mUpdateCallback(aContainer, mPluginInstanceOwner);
|
||||
}
|
||||
}
|
||||
|
||||
} /* layers */
|
||||
} /* mozilla */
|
|
@ -79,6 +79,7 @@ EXPORTS = \
|
|||
gfxUtils.h \
|
||||
gfxUserFontSet.h \
|
||||
nsCoreAnimationSupport.h \
|
||||
nsIOSurface.h \
|
||||
gfxSharedImageSurface.h \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
@ -41,6 +41,9 @@
|
|||
#include "gfxTypes.h"
|
||||
#include "gfxRect.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsAutoRef.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
|
||||
typedef struct _cairo_surface cairo_surface_t;
|
||||
typedef struct _cairo_user_data_key cairo_user_data_key_t;
|
||||
|
@ -358,4 +361,56 @@ public:
|
|||
virtual ~gfxUnknownSurface() { }
|
||||
};
|
||||
|
||||
#ifndef XPCOM_GLUE_AVOID_NSPR
|
||||
/**
|
||||
* 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
|
||||
#endif /* GFX_ASURFACE_H */
|
||||
|
|
|
@ -58,16 +58,16 @@ gfxAlphaBoxBlur::Init(const gfxRect& aRect,
|
|||
const gfxRect* aDirtyRect,
|
||||
const gfxRect* aSkipRect)
|
||||
{
|
||||
Rect rect(aRect.x, aRect.y, aRect.width, aRect.height);
|
||||
mozilla::gfx::Rect rect(aRect.x, aRect.y, aRect.width, aRect.height);
|
||||
IntSize spreadRadius(aSpreadRadius.width, aSpreadRadius.height);
|
||||
IntSize blurRadius(aBlurRadius.width, aBlurRadius.height);
|
||||
nsAutoPtr<Rect> dirtyRect;
|
||||
nsAutoPtr<mozilla::gfx::Rect> dirtyRect;
|
||||
if (aDirtyRect) {
|
||||
dirtyRect = new Rect(aDirtyRect->x, aDirtyRect->y, aDirtyRect->width, aDirtyRect->height);
|
||||
dirtyRect = new mozilla::gfx::Rect(aDirtyRect->x, aDirtyRect->y, aDirtyRect->width, aDirtyRect->height);
|
||||
}
|
||||
nsAutoPtr<Rect> skipRect;
|
||||
nsAutoPtr<mozilla::gfx::Rect> skipRect;
|
||||
if (aSkipRect) {
|
||||
skipRect = new Rect(aSkipRect->x, aSkipRect->y, aSkipRect->width, aSkipRect->height);
|
||||
skipRect = new mozilla::gfx::Rect(aSkipRect->x, aSkipRect->y, aSkipRect->width, aSkipRect->height);
|
||||
}
|
||||
|
||||
mBlur = new AlphaBoxBlur(rect, spreadRadius, blurRadius, dirtyRect, skipRect);
|
||||
|
@ -106,7 +106,7 @@ gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx, const gfxPoint& offset)
|
|||
|
||||
mBlur->Blur();
|
||||
|
||||
Rect* dirtyrect = mBlur->GetDirtyRect();
|
||||
mozilla::gfx::Rect* dirtyrect = mBlur->GetDirtyRect();
|
||||
|
||||
// Avoid a semi-expensive clip operation if we can, otherwise
|
||||
// clip to the dirty rect
|
||||
|
@ -125,7 +125,7 @@ gfxAlphaBoxBlur::Paint(gfxContext* aDestinationCtx, const gfxPoint& offset)
|
|||
|
||||
gfxIntSize gfxAlphaBoxBlur::CalculateBlurRadius(const gfxPoint& aStd)
|
||||
{
|
||||
Point std(aStd.x, aStd.y);
|
||||
mozilla::gfx::Point std(aStd.x, aStd.y);
|
||||
IntSize size = AlphaBoxBlur::CalculateBlurRadius(std);
|
||||
return gfxIntSize(size.width, size.height);
|
||||
}
|
||||
|
|
|
@ -41,11 +41,12 @@
|
|||
#define nsCoreAnimationSupport_h__
|
||||
#ifdef XP_MACOSX
|
||||
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import <OpenGL/OpenGL.h>
|
||||
#import "ApplicationServices/ApplicationServices.h"
|
||||
#include "nscore.h"
|
||||
#include "gfxTypes.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIOSurface.h"
|
||||
|
||||
// Get the system color space.
|
||||
CGColorSpaceRef THEBES_API CreateSystemColorSpace();
|
||||
|
@ -53,12 +54,9 @@ CGColorSpaceRef THEBES_API CreateSystemColorSpace();
|
|||
// Manages a CARenderer
|
||||
struct _CGLPBufferObject;
|
||||
struct _CGLContextObject;
|
||||
class nsIOSurface;
|
||||
|
||||
enum AllowOfflineRendererEnum { ALLOW_OFFLINE_RENDERER, DISALLOW_OFFLINE_RENDERER };
|
||||
|
||||
typedef uint32_t IOSurfaceID;
|
||||
|
||||
class THEBES_API nsCARenderer {
|
||||
NS_INLINE_DECL_REFCOUNTING(nsCARenderer)
|
||||
public:
|
||||
|
@ -110,30 +108,6 @@ private:
|
|||
AllowOfflineRendererEnum mAllowOfflineRenderer;
|
||||
};
|
||||
|
||||
class THEBES_API nsIOSurface {
|
||||
NS_INLINE_DECL_REFCOUNTING(nsIOSurface)
|
||||
public:
|
||||
static already_AddRefed<nsIOSurface> CreateIOSurface(int aWidth, int aHeight);
|
||||
static void ReleaseIOSurface(nsIOSurface *aIOSurface);
|
||||
static already_AddRefed<nsIOSurface> LookupSurface(IOSurfaceID aSurfaceID);
|
||||
|
||||
nsIOSurface(CFTypeRef aIOSurfacePtr) : mIOSurfacePtr(aIOSurfacePtr) {}
|
||||
~nsIOSurface() { CFRelease(mIOSurfacePtr); }
|
||||
IOSurfaceID GetIOSurfaceID();
|
||||
void *GetBaseAddress();
|
||||
size_t GetWidth();
|
||||
size_t GetHeight();
|
||||
size_t GetBytesPerRow();
|
||||
void Lock();
|
||||
void Unlock();
|
||||
CGLError CGLTexImageIOSurface2D(CGLContextObj ctxt,
|
||||
GLenum internalFormat, GLenum format,
|
||||
GLenum type, GLuint plane);
|
||||
private:
|
||||
friend class nsCARenderer;
|
||||
CFTypeRef mIOSurfacePtr;
|
||||
};
|
||||
|
||||
#endif // XP_MACOSX
|
||||
#endif // nsCoreAnimationSupport_h__
|
||||
|
||||
|
|
|
@ -202,7 +202,7 @@ CGLError nsIOSurfaceLib::CGLTexImageIOSurface2D(CGLContextObj ctxt,
|
|||
GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type,
|
||||
IOSurfacePtr ioSurface, GLuint plane) {
|
||||
return sTexImage(ctxt, target, internalFormat, width, height,
|
||||
return sTexImage(ctxt, target, internalFormat, width, height,
|
||||
format, type, ioSurface, plane);
|
||||
}
|
||||
|
||||
|
@ -267,6 +267,10 @@ void nsIOSurfaceLib::CloseLibrary() {
|
|||
sOpenGLFramework = nsnull;
|
||||
}
|
||||
|
||||
nsIOSurface::~nsIOSurface() {
|
||||
CFRelease(mIOSurfacePtr);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIOSurface> nsIOSurface::CreateIOSurface(int aWidth, int aHeight) {
|
||||
if (!nsIOSurfaceLib::isInit())
|
||||
return nsnull;
|
||||
|
@ -354,13 +358,37 @@ void nsIOSurface::Unlock() {
|
|||
nsIOSurfaceLib::IOSurfaceUnlock(mIOSurfacePtr, READ_ONLY, NULL);
|
||||
}
|
||||
|
||||
#include "gfxImageSurface.h"
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
nsIOSurface::GetAsSurface() {
|
||||
Lock();
|
||||
size_t bytesPerRow = GetBytesPerRow();
|
||||
size_t ioWidth = GetWidth();
|
||||
size_t ioHeight = GetHeight();
|
||||
|
||||
unsigned char* ioData = (unsigned char*)GetBaseAddress();
|
||||
|
||||
nsRefPtr<gfxImageSurface> imgSurface =
|
||||
new gfxImageSurface(gfxIntSize(ioWidth, ioHeight), gfxASurface::ImageFormatARGB32);
|
||||
|
||||
for (int i = 0; i < ioHeight; i++) {
|
||||
memcpy(imgSurface->Data() + i * imgSurface->Stride(),
|
||||
ioData + i * bytesPerRow, ioWidth * 4);
|
||||
}
|
||||
|
||||
Unlock();
|
||||
|
||||
return imgSurface.forget();
|
||||
}
|
||||
|
||||
CGLError
|
||||
nsIOSurface::CGLTexImageIOSurface2D(CGLContextObj ctxt,
|
||||
nsIOSurface::CGLTexImageIOSurface2D(NSOpenGLContext *ctxt,
|
||||
GLenum internalFormat, GLenum format,
|
||||
GLenum type, GLuint plane)
|
||||
{
|
||||
return nsIOSurfaceLib::CGLTexImageIOSurface2D(ctxt,
|
||||
GL_TEXTURE_RECTANGLE_ARB,
|
||||
return nsIOSurfaceLib::CGLTexImageIOSurface2D((CGLContextObj)[ctxt CGLContextObj],
|
||||
GL_TEXTURE_RECTANGLE_ARB,
|
||||
internalFormat,
|
||||
GetWidth(), GetHeight(),
|
||||
format, type,
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
// vim:set ts=2 sts=2 sw=2 et cin:
|
||||
/* ***** 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.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* bgirard <b56girard@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of 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 ***** */
|
||||
|
||||
#ifndef nsIOSurface_h__
|
||||
#define nsIOSurface_h__
|
||||
#ifdef XP_MACOSX
|
||||
|
||||
#import <OpenGL/OpenGL.h>
|
||||
|
||||
class gfxASurface;
|
||||
class _CGLContextObject;
|
||||
class NSOpenGLContext;
|
||||
|
||||
typedef _CGLContextObject* CGLContextObj;
|
||||
typedef uint32_t IOSurfaceID;
|
||||
|
||||
class THEBES_API nsIOSurface {
|
||||
NS_INLINE_DECL_REFCOUNTING(nsIOSurface)
|
||||
public:
|
||||
static already_AddRefed<nsIOSurface> CreateIOSurface(int aWidth, int aHeight);
|
||||
static void ReleaseIOSurface(nsIOSurface *aIOSurface);
|
||||
static already_AddRefed<nsIOSurface> LookupSurface(IOSurfaceID aSurfaceID);
|
||||
|
||||
nsIOSurface(const void *aIOSurfacePtr) : mIOSurfacePtr(aIOSurfacePtr) {}
|
||||
~nsIOSurface();
|
||||
IOSurfaceID GetIOSurfaceID();
|
||||
void *GetBaseAddress();
|
||||
size_t GetWidth();
|
||||
size_t GetHeight();
|
||||
size_t GetBytesPerRow();
|
||||
void Lock();
|
||||
void Unlock();
|
||||
CGLError CGLTexImageIOSurface2D(NSOpenGLContext *ctxt,
|
||||
GLenum internalFormat, GLenum format,
|
||||
GLenum type, GLuint plane);
|
||||
already_AddRefed<gfxASurface> GetAsSurface();
|
||||
private:
|
||||
friend class nsCARenderer;
|
||||
const void* mIOSurfacePtr;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -184,16 +184,20 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
#define LOG_SCOPE_APPEND_LINE_NUMBER_PASTE(id, line) id ## line
|
||||
#define LOG_SCOPE_APPEND_LINE_NUMBER_EXPAND(id, line) LOG_SCOPE_APPEND_LINE_NUMBER_PASTE(id, line)
|
||||
#define LOG_SCOPE_APPEND_LINE_NUMBER(id) LOG_SCOPE_APPEND_LINE_NUMBER_EXPAND(id, __LINE__)
|
||||
|
||||
#define LOG_SCOPE(l, s) \
|
||||
LogScope LOG_SCOPE_TMP_VAR ##__LINE__ (l, \
|
||||
static_cast<void *>(this), \
|
||||
NS_LITERAL_CSTRING(s))
|
||||
LogScope LOG_SCOPE_APPEND_LINE_NUMBER(LOG_SCOPE_TMP_VAR) (l, \
|
||||
static_cast<void *>(this), \
|
||||
NS_LITERAL_CSTRING(s))
|
||||
|
||||
#define LOG_SCOPE_WITH_PARAM(l, s, pn, pv) \
|
||||
LogScope LOG_SCOPE_TMP_VAR ##__LINE__ (l, \
|
||||
static_cast<void *>(this), \
|
||||
NS_LITERAL_CSTRING(s), \
|
||||
NS_LITERAL_CSTRING(pn), pv)
|
||||
LogScope LOG_SCOPE_APPEND_LINE_NUMBER(LOG_SCOPE_TMP_VAR) (l, \
|
||||
static_cast<void *>(this), \
|
||||
NS_LITERAL_CSTRING(s), \
|
||||
NS_LITERAL_CSTRING(pn), pv)
|
||||
|
||||
#define LOG_FUNC(l, s) \
|
||||
LogFunc(l, \
|
||||
|
|
|
@ -93,7 +93,7 @@ native gfxGraphicsFilter(gfxPattern::GraphicsFilter);
|
|||
*
|
||||
* Internally, imgIContainer also manages animation of images.
|
||||
*/
|
||||
[scriptable, uuid(8c82b89f-f90c-4a31-a544-6e1f759673d4)]
|
||||
[scriptable, uuid(2506249c-e0a1-4d8f-846c-2d478247f8d8)]
|
||||
interface imgIContainer : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -189,10 +189,8 @@ interface imgIContainer : nsISupports
|
|||
/**
|
||||
* Attempts to create an ImageContainer (and Image) containing the current
|
||||
* frame. Only valid for RASTER type images.
|
||||
*
|
||||
* @param aManager The layer manager to use to create the ImageContainer.
|
||||
*/
|
||||
[noscript] ImageContainer getImageContainer(in LayerManager aManager);
|
||||
[noscript] ImageContainer getImageContainer();
|
||||
|
||||
/**
|
||||
* Create and return a new copy of the given frame that you can write to
|
||||
|
|
|
@ -945,13 +945,9 @@ RasterImage::GetFrame(PRUint32 aWhichFrame,
|
|||
|
||||
|
||||
NS_IMETHODIMP
|
||||
RasterImage::GetImageContainer(LayerManager* aManager,
|
||||
ImageContainer **_retval)
|
||||
RasterImage::GetImageContainer(ImageContainer **_retval)
|
||||
{
|
||||
if (mImageContainer &&
|
||||
(mImageContainer->Manager() == aManager ||
|
||||
(!mImageContainer->Manager() &&
|
||||
(mImageContainer->GetBackendType() == aManager->GetBackendType())))) {
|
||||
if (mImageContainer) {
|
||||
*_retval = mImageContainer;
|
||||
NS_ADDREF(*_retval);
|
||||
return NS_OK;
|
||||
|
@ -966,8 +962,7 @@ RasterImage::GetImageContainer(LayerManager* aManager,
|
|||
GetWidth(&cairoData.mSize.width);
|
||||
GetHeight(&cairoData.mSize.height);
|
||||
|
||||
mImageContainer = aManager->CreateImageContainer();
|
||||
NS_ASSERTION(mImageContainer, "Failed to create ImageContainer!");
|
||||
mImageContainer = LayerManager::CreateImageContainer();
|
||||
|
||||
// Now create a CairoImage to display the surface.
|
||||
layers::Image::Format cairoFormat = layers::Image::CAIRO_SURFACE;
|
||||
|
|
|
@ -190,7 +190,7 @@ public:
|
|||
NS_SCRIPTABLE NS_IMETHOD GetAnimated(bool *aAnimated);
|
||||
NS_SCRIPTABLE NS_IMETHOD GetCurrentFrameIsOpaque(bool *aCurrentFrameIsOpaque);
|
||||
NS_IMETHOD GetFrame(PRUint32 aWhichFrame, PRUint32 aFlags, gfxASurface **_retval NS_OUTPARAM);
|
||||
NS_IMETHOD GetImageContainer(mozilla::layers::LayerManager* aManager, mozilla::layers::ImageContainer **_retval NS_OUTPARAM);
|
||||
NS_IMETHOD GetImageContainer(mozilla::layers::ImageContainer **_retval NS_OUTPARAM);
|
||||
NS_IMETHOD CopyFrame(PRUint32 aWhichFrame, PRUint32 aFlags, gfxImageSurface **_retval NS_OUTPARAM);
|
||||
NS_IMETHOD ExtractFrame(PRUint32 aWhichFrame, const nsIntRect & aRect, PRUint32 aFlags, imgIContainer **_retval NS_OUTPARAM);
|
||||
NS_IMETHOD Draw(gfxContext *aContext, gfxPattern::GraphicsFilter aFilter, const gfxMatrix & aUserSpaceToImageSpace, const gfxRect & aFill, const nsIntRect & aSubimage, const nsIntSize & aViewportSize, PRUint32 aFlags);
|
||||
|
|
|
@ -73,7 +73,7 @@ public:
|
|||
NS_SCRIPTABLE NS_IMETHOD GetAnimated(bool *aAnimated);
|
||||
NS_SCRIPTABLE NS_IMETHOD GetCurrentFrameIsOpaque(bool *aCurrentFrameIsOpaque);
|
||||
NS_IMETHOD GetFrame(PRUint32 aWhichFrame, PRUint32 aFlags, gfxASurface **_retval NS_OUTPARAM);
|
||||
NS_IMETHOD GetImageContainer(mozilla::layers::LayerManager* aManager, mozilla::layers::ImageContainer **_retval NS_OUTPARAM) { *_retval = NULL; return NS_OK; }
|
||||
NS_IMETHOD GetImageContainer(mozilla::layers::ImageContainer **_retval NS_OUTPARAM) { *_retval = NULL; return NS_OK; }
|
||||
NS_IMETHOD CopyFrame(PRUint32 aWhichFrame, PRUint32 aFlags, gfxImageSurface **_retval NS_OUTPARAM);
|
||||
NS_IMETHOD ExtractFrame(PRUint32 aWhichFrame, const nsIntRect & aRect, PRUint32 aFlags, imgIContainer **_retval NS_OUTPARAM);
|
||||
NS_IMETHOD Draw(gfxContext *aContext, gfxPattern::GraphicsFilter aFilter, const gfxMatrix & aUserSpaceToImageSpace, const gfxRect & aFill, const nsIntRect & aSubimage, const nsIntSize & aViewportSize, PRUint32 aFlags);
|
||||
|
|
|
@ -90,14 +90,10 @@ HashableValue::setValue(JSContext *cx, const Value &v)
|
|||
if (JSDOUBLE_IS_INT32(d, &i)) {
|
||||
/* Normalize int32-valued doubles to int32 for faster hashing and testing. */
|
||||
value = Int32Value(i);
|
||||
} else if (JSDOUBLE_IS_NaN(d)) {
|
||||
/* NaNs with different bits must hash and test identically. */
|
||||
value = DoubleValue(js_NaN);
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
/* All NaN values are the same. The bit-pattern must reflect this. */
|
||||
jsval_layout a, b;
|
||||
a.asDouble = d;
|
||||
b.asDouble = JS_CANONICALIZE_NAN(d);
|
||||
JS_ASSERT(a.asBits == b.asBits);
|
||||
#endif
|
||||
value = v;
|
||||
}
|
||||
} else {
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче