mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-01 00:32:11 +00:00
Merge m-c to fx-team.
This commit is contained in:
commit
a30c6ca187
@ -55,6 +55,7 @@ enum AccType {
|
||||
eProgressType,
|
||||
eRootType,
|
||||
eXULLabelType,
|
||||
eXULListItemType,
|
||||
eXULTabpanelsType,
|
||||
eXULTreeType,
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "nsEventShell.h"
|
||||
#include "DocAccessible.h"
|
||||
#include "nsAccessibilityService.h"
|
||||
#include "nsTextEquivUtils.h"
|
||||
#ifdef A11Y_LOG
|
||||
#include "Logging.h"
|
||||
#endif
|
||||
@ -37,6 +38,38 @@ EventQueue::PushEvent(AccEvent* aEvent)
|
||||
// Filter events.
|
||||
CoalesceEvents();
|
||||
|
||||
// Fire name change event on parent given that this event hasn't been
|
||||
// coalesced, the parent's name was calculated from its subtree, and the
|
||||
// subtree was changed.
|
||||
Accessible* target = aEvent->mAccessible;
|
||||
if (aEvent->mEventRule != AccEvent::eDoNotEmit &&
|
||||
target->HasNameDependentParent() &&
|
||||
(aEvent->mEventType == nsIAccessibleEvent::EVENT_NAME_CHANGE ||
|
||||
aEvent->mEventType == nsIAccessibleEvent::EVENT_TEXT_REMOVED ||
|
||||
aEvent->mEventType == nsIAccessibleEvent::EVENT_TEXT_INSERTED ||
|
||||
aEvent->mEventType == nsIAccessibleEvent::EVENT_SHOW ||
|
||||
aEvent->mEventType == nsIAccessibleEvent::EVENT_HIDE)) {
|
||||
// Only continue traversing up the tree if it's possible that the parent
|
||||
// accessible's name can depend on this accessible's name.
|
||||
Accessible* parent = target->Parent();
|
||||
while (parent &&
|
||||
nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeIfReqRule)) {
|
||||
// Test possible name dependent parent.
|
||||
if (nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeRule)) {
|
||||
nsAutoString name;
|
||||
ENameValueFlag nameFlag = parent->Name(name);
|
||||
// If name is obtained from subtree, fire name change event.
|
||||
if (nameFlag == eNameFromSubtree) {
|
||||
nsRefPtr<AccEvent> nameChangeEvent =
|
||||
new AccEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, parent);
|
||||
PushEvent(nameChangeEvent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
parent = parent->Parent();
|
||||
}
|
||||
}
|
||||
|
||||
// Associate text change with hide event if it wasn't stolen from hiding
|
||||
// siblings during coalescence.
|
||||
AccMutationEvent* showOrHideEvent = downcast_accEvent(aEvent);
|
||||
|
@ -344,7 +344,7 @@ nsTextEquivUtils::AppendString(nsAString *aString,
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
uint32_t
|
||||
nsTextEquivUtils::GetRoleRule(role aRole)
|
||||
{
|
||||
#define ROLE(geckoRole, stringRole, atkRole, \
|
||||
@ -360,4 +360,3 @@ nsTextEquivUtils::GetRoleRule(role aRole)
|
||||
|
||||
#undef ROLE
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,18 @@ class nsTextEquivUtils
|
||||
public:
|
||||
typedef mozilla::a11y::Accessible Accessible;
|
||||
|
||||
/**
|
||||
* Determines if the accessible has a given name rule.
|
||||
*
|
||||
* @param aAccessible [in] the given accessible
|
||||
* @param aRule [in] a given name rule
|
||||
* @return true if the accessible has the rule
|
||||
*/
|
||||
static inline bool HasNameRule(Accessible* aAccessible, ETextEquivRule aRule)
|
||||
{
|
||||
return (GetRoleRule(aAccessible->Role()) & aRule) == aRule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the name from accessible subtree if allowed.
|
||||
*
|
||||
|
@ -111,8 +111,8 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(Accessible, LastRelease())
|
||||
Accessible::Accessible(nsIContent* aContent, DocAccessible* aDoc) :
|
||||
mContent(aContent), mDoc(aDoc),
|
||||
mParent(nullptr), mIndexInParent(-1), mChildrenFlags(eChildrenUninitialized),
|
||||
mStateFlags(0), mType(0), mGenericTypes(0), mIndexOfEmbeddedChild(-1),
|
||||
mRoleMapEntry(nullptr)
|
||||
mStateFlags(0), mContextFlags(0), mType(0), mGenericTypes(0),
|
||||
mIndexOfEmbeddedChild(-1), mRoleMapEntry(nullptr)
|
||||
{
|
||||
#ifdef NS_DEBUG_X
|
||||
{
|
||||
@ -2533,6 +2533,12 @@ Accessible::BindToParent(Accessible* aParent, uint32_t aIndexInParent)
|
||||
mIndexInParent = aIndexInParent;
|
||||
|
||||
mParent->InvalidateChildrenGroupInfo();
|
||||
|
||||
// Note: this is currently only used for richlistitems and their children.
|
||||
if (mParent->HasNameDependentParent() || mParent->IsXULListItem())
|
||||
mContextFlags |= eHasNameDependentParent;
|
||||
else
|
||||
mContextFlags &= ~eHasNameDependentParent;
|
||||
}
|
||||
|
||||
// Accessible protected
|
||||
@ -2544,6 +2550,7 @@ Accessible::UnbindFromParent()
|
||||
mIndexInParent = -1;
|
||||
mIndexOfEmbeddedChild = -1;
|
||||
mGroupInfo = nullptr;
|
||||
mContextFlags &= ~eHasNameDependentParent;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -3241,6 +3248,8 @@ Accessible::StaticAsserts() const
|
||||
"Accessible::mStateFlags was oversized by eLastStateFlag!");
|
||||
static_assert(eLastAccType <= (1 << kTypeBits) - 1,
|
||||
"Accessible::mType was oversized by eLastAccType!");
|
||||
static_assert(eLastContextFlag <= (1 << kContextFlagsBits) - 1,
|
||||
"Accessible::mContextFlags was oversized by eLastContextFlag!");
|
||||
static_assert(eLastAccGenericType <= (1 << kGenericTypesBits) - 1,
|
||||
"Accessible::mGenericType was oversized by eLastAccGenericType!");
|
||||
}
|
||||
|
@ -579,6 +579,8 @@ public:
|
||||
bool IsXULLabel() const { return mType == eXULLabelType; }
|
||||
XULLabelAccessible* AsXULLabel();
|
||||
|
||||
bool IsXULListItem() const { return mType == eXULListItemType; }
|
||||
|
||||
bool IsXULTabpanels() const { return mType == eXULTabpanelsType; }
|
||||
|
||||
bool IsXULTree() const { return mType == eXULTreeType; }
|
||||
@ -790,6 +792,13 @@ public:
|
||||
bool NeedsDOMUIEvent() const
|
||||
{ return !(mStateFlags & eIgnoreDOMUIEvent); }
|
||||
|
||||
/**
|
||||
* Return true if this accessible has a parent whose name depends on this
|
||||
* accessible.
|
||||
*/
|
||||
bool HasNameDependentParent() const
|
||||
{ return mContextFlags & eHasNameDependentParent; }
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
@ -867,6 +876,15 @@ protected:
|
||||
eLastStateFlag = eGroupInfoDirty
|
||||
};
|
||||
|
||||
/**
|
||||
* Flags used for contextual information about the accessible.
|
||||
*/
|
||||
enum ContextFlags {
|
||||
eHasNameDependentParent = 1 << 0, // Parent's name depends on this accessible.
|
||||
|
||||
eLastContextFlag = eHasNameDependentParent
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@ -970,14 +988,16 @@ protected:
|
||||
|
||||
static const uint8_t kChildrenFlagsBits = 2;
|
||||
static const uint8_t kStateFlagsBits = 6;
|
||||
static const uint8_t kContextFlagsBits = 1;
|
||||
static const uint8_t kTypeBits = 6;
|
||||
static const uint8_t kGenericTypesBits = 12;
|
||||
|
||||
/**
|
||||
* Keep in sync with ChildrenFlags, StateFlags and AccTypes.
|
||||
* Keep in sync with ChildrenFlags, StateFlags, ContextFlags, and AccTypes.
|
||||
*/
|
||||
uint32_t mChildrenFlags : kChildrenFlagsBits;
|
||||
uint32_t mStateFlags : kStateFlagsBits;
|
||||
uint32_t mContextFlags : kContextFlagsBits;
|
||||
uint32_t mType : kTypeBits;
|
||||
uint32_t mGenericTypes : kGenericTypesBits;
|
||||
|
||||
|
@ -582,6 +582,7 @@ XULListitemAccessible::
|
||||
nsGkAtoms::type,
|
||||
nsGkAtoms::checkbox,
|
||||
eCaseMatters);
|
||||
mType = eXULListItemType;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(XULListitemAccessible, Accessible)
|
||||
|
@ -41,6 +41,7 @@ skip-if = os == 'win' || os == 'linux'
|
||||
[test_menu.xul]
|
||||
[test_mutation.html]
|
||||
[test_mutation.xhtml]
|
||||
[test_name.xul]
|
||||
[test_scroll.xul]
|
||||
[test_selection.html]
|
||||
[test_selection.xul]
|
||||
|
92
accessible/tests/mochitest/events/test_name.xul
Normal file
92
accessible/tests/mochitest/events/test_name.xul
Normal file
@ -0,0 +1,92 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/chrome-harness.js"/>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="../common.js" />
|
||||
<script type="application/javascript"
|
||||
src="../events.js" />
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
/**
|
||||
* Check name changed a11y event.
|
||||
*/
|
||||
function nameChangeChecker(aMsg, aID)
|
||||
{
|
||||
this.type = EVENT_NAME_CHANGE;
|
||||
|
||||
function targetGetter()
|
||||
{
|
||||
return getAccessible(aID);
|
||||
}
|
||||
Object.defineProperty(this, "target", { get: targetGetter });
|
||||
|
||||
this.getID = function getID()
|
||||
{
|
||||
return aMsg + " name changed";
|
||||
}
|
||||
}
|
||||
|
||||
function changeRichListItemChild()
|
||||
{
|
||||
this.invoke = function changeRichListItemChild_invoke()
|
||||
{
|
||||
getNode('childcontent').setAttribute('value', 'Changed.');
|
||||
}
|
||||
|
||||
this.eventSeq =
|
||||
[
|
||||
new nameChangeChecker("changeRichListItemChild: ", "listitem")
|
||||
];
|
||||
|
||||
this.getID = function changeRichListItemChild_getID()
|
||||
{
|
||||
return "changeRichListItemChild";
|
||||
}
|
||||
}
|
||||
|
||||
function doTest()
|
||||
{
|
||||
var queue = new eventQueue();
|
||||
queue.push(new changeRichListItemChild());
|
||||
queue.invoke();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<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=986054"
|
||||
title="Propagate name change events">
|
||||
Mozilla Bug 986054
|
||||
</a>
|
||||
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
<richlistbox>
|
||||
<richlistitem id="listitem">
|
||||
<description id="childcontent" value="This will be changed."/>
|
||||
</richlistitem>
|
||||
</richlistbox>
|
||||
</vbox>
|
||||
</window>
|
@ -596,10 +596,9 @@ var shell = {
|
||||
},
|
||||
|
||||
openAppForSystemMessage: function shell_openAppForSystemMessage(msg) {
|
||||
let origin = Services.io.newURI(msg.manifest, null, null).prePath;
|
||||
let payload = {
|
||||
url: msg.uri,
|
||||
manifestURL: msg.manifest,
|
||||
url: msg.pageURL,
|
||||
manifestURL: msg.manifestURL,
|
||||
isActivity: (msg.type == 'activity'),
|
||||
onlyShowApp: msg.onlyShowApp,
|
||||
showApp: msg.showApp,
|
||||
@ -877,7 +876,7 @@ var AlertsHelper = {
|
||||
});
|
||||
},
|
||||
|
||||
showNotification: function alert_showNotification(imageUrl,
|
||||
showNotification: function alert_showNotification(imageURL,
|
||||
title,
|
||||
text,
|
||||
textClickable,
|
||||
@ -885,37 +884,37 @@ var AlertsHelper = {
|
||||
uid,
|
||||
bidi,
|
||||
lang,
|
||||
manifestUrl) {
|
||||
manifestURL) {
|
||||
function send(appName, appIcon) {
|
||||
shell.sendChromeEvent({
|
||||
type: "desktop-notification",
|
||||
id: uid,
|
||||
icon: imageUrl,
|
||||
icon: imageURL,
|
||||
title: title,
|
||||
text: text,
|
||||
bidi: bidi,
|
||||
lang: lang,
|
||||
appName: appName,
|
||||
appIcon: appIcon,
|
||||
manifestURL: manifestUrl
|
||||
manifestURL: manifestURL
|
||||
});
|
||||
}
|
||||
|
||||
if (!manifestUrl || !manifestUrl.length) {
|
||||
if (!manifestURL || !manifestURL.length) {
|
||||
send(null, null);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have a manifest URL, get the icon and title from the manifest
|
||||
// to prevent spoofing.
|
||||
let app = DOMApplicationRegistry.getAppByManifestURL(manifestUrl);
|
||||
DOMApplicationRegistry.getManifestFor(manifestUrl).then((aManifest) => {
|
||||
let app = DOMApplicationRegistry.getAppByManifestURL(manifestURL);
|
||||
DOMApplicationRegistry.getManifestFor(manifestURL).then((aManifest) => {
|
||||
let helper = new ManifestHelper(aManifest, app.origin);
|
||||
send(helper.name, helper.iconURLForSize(128));
|
||||
});
|
||||
},
|
||||
|
||||
showAlertNotification: function alert_showAlertNotification(imageUrl,
|
||||
showAlertNotification: function alert_showAlertNotification(imageURL,
|
||||
title,
|
||||
text,
|
||||
textClickable,
|
||||
@ -930,7 +929,7 @@ var AlertsHelper = {
|
||||
}
|
||||
|
||||
this.registerListener(name, cookie, alertListener);
|
||||
this.showNotification(imageUrl, title, text, textClickable, cookie,
|
||||
this.showNotification(imageURL, title, text, textClickable, cookie,
|
||||
name, bidi, lang, null);
|
||||
},
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="26839cb46f856d610b192f5655a8c38a6bfe0829"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="eee8caa81a368f0feace718201ed15a423812c18"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="26839cb46f856d610b192f5655a8c38a6bfe0829"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="eee8caa81a368f0feace718201ed15a423812c18"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="5b93c7150acac5f657675b91889d828cc2b532e3"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="89c5816399e71bda92a8959b5b771c04d6672ea3"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="a9e08b91e9cd1f0930f16cfc49ec72f63575d5fe">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="26839cb46f856d610b192f5655a8c38a6bfe0829"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="eee8caa81a368f0feace718201ed15a423812c18"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="5b93c7150acac5f657675b91889d828cc2b532e3"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="26839cb46f856d610b192f5655a8c38a6bfe0829"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="eee8caa81a368f0feace718201ed15a423812c18"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
|
||||
|
@ -4,6 +4,6 @@
|
||||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "5f0660e48c2689c6de19a50aebfabf29e01a144e",
|
||||
"revision": "6c593455e3d1292120a6f3d41ec5d06bc91019f1",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="26839cb46f856d610b192f5655a8c38a6bfe0829"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="eee8caa81a368f0feace718201ed15a423812c18"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="26839cb46f856d610b192f5655a8c38a6bfe0829"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="eee8caa81a368f0feace718201ed15a423812c18"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="26839cb46f856d610b192f5655a8c38a6bfe0829"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="eee8caa81a368f0feace718201ed15a423812c18"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="26839cb46f856d610b192f5655a8c38a6bfe0829"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="eee8caa81a368f0feace718201ed15a423812c18"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="26839cb46f856d610b192f5655a8c38a6bfe0829"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="eee8caa81a368f0feace718201ed15a423812c18"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="5b93c7150acac5f657675b91889d828cc2b532e3"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="89c5816399e71bda92a8959b5b771c04d6672ea3"/>
|
||||
|
31
b2g/config/mozconfigs/macosx64_gecko/debug
Normal file
31
b2g/config/mozconfigs/macosx64_gecko/debug
Normal file
@ -0,0 +1,31 @@
|
||||
. $topsrcdir/build/macosx/mozconfig.common
|
||||
|
||||
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
|
||||
ac_add_options --enable-update-packaging
|
||||
ac_add_options --enable-signmar
|
||||
|
||||
# Nightlies only since this has a cost in performance
|
||||
ac_add_options --enable-js-diagnostics
|
||||
|
||||
# Needed to enable breakpad in application.ini
|
||||
export MOZILLA_OFFICIAL=1
|
||||
|
||||
export MOZ_TELEMETRY_REPORTING=1
|
||||
|
||||
#ac_add_options --with-macbundlename-prefix=Firefox
|
||||
|
||||
# Treat warnings as errors in directories with FAIL_ON_WARNINGS.
|
||||
ac_add_options --enable-warnings-as-errors
|
||||
|
||||
# B2G Stuff
|
||||
ac_add_options --enable-application=b2g
|
||||
ac_add_options --enable-debug-symbols
|
||||
ac_add_options --enable-debug
|
||||
ac_add_options --with-ccache
|
||||
ENABLE_MARIONETTE=1
|
||||
|
||||
export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
|
||||
|
||||
GAIADIR=$topsrcdir/gaia
|
||||
|
||||
. "$topsrcdir/b2g/config/mozconfigs/common.override"
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="26839cb46f856d610b192f5655a8c38a6bfe0829"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="eee8caa81a368f0feace718201ed15a423812c18"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
@ -5840,6 +5840,10 @@ if test "$OS_TARGET" = "WINNT" -a -z "$CROSS_COMPILE"; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# On mingw, check if headers are provided by toolchain.
|
||||
if test "$OS_TARGET" = "WINNT" -a -n "$GNU_CC"; then
|
||||
MOZ_CHECK_HEADER(d3d10.h, MOZ_HAS_WINSDK_WITH_D3D=1)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl D3D compiler DLL
|
||||
@ -5914,7 +5918,7 @@ if test -n "$MOZ_ANGLE_RENDERER"; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$MOZ_D3DCOMPILER_DLL_PATH" -a -z "$MOZ_D3DCOMPILER_CAB"; then
|
||||
if test -z "$MOZ_D3DCOMPILER_DLL_PATH" -a -z "$MOZ_D3DCOMPILER_CAB" -a -z "$CROSS_COMPILE"; then
|
||||
AC_MSG_ERROR([Couldn't find an acceptable D3D compiler DLL. Either install Windows SDK 8.0+ and reconfigure with --enable-winsdk-directx, install DirectX SDK (June 2010 version or newer), or reconfigure with --disable-webgl.])
|
||||
fi
|
||||
fi
|
||||
|
@ -7,8 +7,9 @@
|
||||
#include "base/basictypes.h"
|
||||
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "gfxPattern.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIDocShell.h"
|
||||
@ -26,6 +27,7 @@
|
||||
#include "mozilla/gfx/Matrix.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
DocumentRendererChild::DocumentRendererChild()
|
||||
@ -72,12 +74,13 @@ DocumentRendererChild::RenderDocument(nsIDOMWindow *window,
|
||||
// Draw directly into the output array.
|
||||
data.SetLength(renderSize.width * renderSize.height * 4);
|
||||
|
||||
nsRefPtr<gfxImageSurface> surf =
|
||||
new gfxImageSurface(reinterpret_cast<uint8_t*>(data.BeginWriting()),
|
||||
gfxIntSize(renderSize.width, renderSize.height),
|
||||
4 * renderSize.width,
|
||||
gfxImageFormat::ARGB32);
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(surf);
|
||||
RefPtr<DrawTarget> dt =
|
||||
Factory::CreateDrawTargetForData(BackendType::CAIRO,
|
||||
reinterpret_cast<uint8_t*>(data.BeginWriting()),
|
||||
IntSize(renderSize.width, renderSize.height),
|
||||
4 * renderSize.width,
|
||||
SurfaceFormat::B8G8R8A8);
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(dt);
|
||||
ctx->SetMatrix(mozilla::gfx::ThebesMatrix(transform));
|
||||
|
||||
nsCOMPtr<nsIPresShell> shell = presContext->PresShell();
|
||||
|
@ -816,7 +816,6 @@ protected:
|
||||
WebGLVertexAttrib0Status WhatDoesVertexAttrib0Need();
|
||||
bool DoFakeVertexAttrib0(GLuint vertexCount);
|
||||
void UndoFakeVertexAttrib0();
|
||||
void InvalidateFakeVertexAttrib0();
|
||||
|
||||
static CheckedUint32 GetImageSize(GLsizei height,
|
||||
GLsizei width,
|
||||
|
@ -60,7 +60,7 @@ WebGLContext::CreateQuery()
|
||||
if (IsContextLost())
|
||||
return nullptr;
|
||||
|
||||
if (mActiveOcclusionQuery && !gl->IsGLES2()) {
|
||||
if (mActiveOcclusionQuery && !gl->IsGLES()) {
|
||||
/* http://www.opengl.org/registry/specs/ARB/occlusion_query.txt
|
||||
* Calling either GenQueriesARB or DeleteQueriesARB while any query of
|
||||
* any target is active causes an INVALID_OPERATION error to be
|
||||
@ -95,7 +95,7 @@ WebGLContext::DeleteQuery(WebGLQuery *query)
|
||||
EndQuery(query->mType);
|
||||
}
|
||||
|
||||
if (mActiveOcclusionQuery && !gl->IsGLES2()) {
|
||||
if (mActiveOcclusionQuery && !gl->IsGLES()) {
|
||||
/* http://www.opengl.org/registry/specs/ARB/occlusion_query.txt
|
||||
* Calling either GenQueriesARB or DeleteQueriesARB while any query of
|
||||
* any target is active causes an INVALID_OPERATION error to be
|
||||
|
726
content/canvas/src/WebGLContextDraw.cpp
Normal file
726
content/canvas/src/WebGLContextDraw.cpp
Normal file
@ -0,0 +1,726 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WebGLContext.h"
|
||||
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "WebGLBuffer.h"
|
||||
#include "WebGLFramebuffer.h"
|
||||
#include "WebGLProgram.h"
|
||||
#include "WebGLRenderbuffer.h"
|
||||
#include "WebGLShader.h"
|
||||
#include "WebGLTexture.h"
|
||||
#include "WebGLUniformInfo.h"
|
||||
#include "WebGLVertexArray.h"
|
||||
#include "WebGLVertexAttribData.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::gl;
|
||||
|
||||
// For a Tegra workaround.
|
||||
static const int MAX_DRAW_CALLS_SINCE_FLUSH = 100;
|
||||
|
||||
bool
|
||||
WebGLContext::DrawInstanced_check(const char* info)
|
||||
{
|
||||
// This restriction was removed in GLES3, so WebGL2 shouldn't have it.
|
||||
if (!IsWebGL2() &&
|
||||
IsExtensionEnabled(ANGLE_instanced_arrays) &&
|
||||
!mBufferFetchingHasPerVertex)
|
||||
{
|
||||
/* http://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_instanced_arrays.txt
|
||||
* If all of the enabled vertex attribute arrays that are bound to active
|
||||
* generic attributes in the program have a non-zero divisor, the draw
|
||||
* call should return INVALID_OPERATION.
|
||||
*
|
||||
* NB: This also appears to apply to NV_instanced_arrays, though the
|
||||
* INVALID_OPERATION emission is not explicitly stated.
|
||||
* ARB_instanced_arrays does not have this restriction.
|
||||
*/
|
||||
ErrorInvalidOperation("%s: at least one vertex attribute divisor should be 0", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcount, const char* info)
|
||||
{
|
||||
if (first < 0 || count < 0) {
|
||||
ErrorInvalidValue("%s: negative first or count", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (primcount < 0) {
|
||||
ErrorInvalidValue("%s: negative primcount", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ValidateStencilParamsForDrawCall()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If count is 0, there's nothing to do.
|
||||
if (count == 0 || primcount == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there is no current program, this is silently ignored.
|
||||
// Any checks below this depend on a program being available.
|
||||
if (!mCurrentProgram) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ValidateBufferFetching(info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CheckedInt<GLsizei> checked_firstPlusCount = CheckedInt<GLsizei>(first) + count;
|
||||
|
||||
if (!checked_firstPlusCount.isValid()) {
|
||||
ErrorInvalidOperation("%s: overflow in first+count", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (uint32_t(checked_firstPlusCount.value()) > mMaxFetchedVertices) {
|
||||
ErrorInvalidOperation("%s: bound vertex attribute buffers do not have sufficient size for given first and count", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (uint32_t(primcount) > mMaxFetchedInstances) {
|
||||
ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
if (mBoundFramebuffer) {
|
||||
if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
|
||||
ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!DoFakeVertexAttrib0(checked_firstPlusCount.value())) {
|
||||
return false;
|
||||
}
|
||||
BindFakeBlackTextures();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei count)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateDrawModeEnum(mode, "drawArrays: mode"))
|
||||
return;
|
||||
|
||||
if (!DrawArrays_check(first, count, 1, "drawArrays"))
|
||||
return;
|
||||
|
||||
SetupContextLossTimer();
|
||||
gl->fDrawArrays(mode, first, count);
|
||||
|
||||
Draw_cleanup();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateDrawModeEnum(mode, "drawArraysInstanced: mode"))
|
||||
return;
|
||||
|
||||
if (!DrawArrays_check(first, count, primcount, "drawArraysInstanced"))
|
||||
return;
|
||||
|
||||
if (!DrawInstanced_check("drawArraysInstanced"))
|
||||
return;
|
||||
|
||||
SetupContextLossTimer();
|
||||
gl->fDrawArraysInstanced(mode, first, count, primcount);
|
||||
|
||||
Draw_cleanup();
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::DrawElements_check(GLsizei count, GLenum type,
|
||||
WebGLintptr byteOffset, GLsizei primcount,
|
||||
const char* info, GLuint* out_upperBound)
|
||||
{
|
||||
if (count < 0 || byteOffset < 0) {
|
||||
ErrorInvalidValue("%s: negative count or offset", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (primcount < 0) {
|
||||
ErrorInvalidValue("%s: negative primcount", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ValidateStencilParamsForDrawCall()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If count is 0, there's nothing to do.
|
||||
if (count == 0 || primcount == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CheckedUint32 checked_byteCount;
|
||||
|
||||
GLsizei first = 0;
|
||||
|
||||
if (type == LOCAL_GL_UNSIGNED_SHORT) {
|
||||
checked_byteCount = 2 * CheckedUint32(count);
|
||||
if (byteOffset % 2 != 0) {
|
||||
ErrorInvalidOperation("%s: invalid byteOffset for UNSIGNED_SHORT (must be a multiple of 2)", info);
|
||||
return false;
|
||||
}
|
||||
first = byteOffset / 2;
|
||||
}
|
||||
else if (type == LOCAL_GL_UNSIGNED_BYTE) {
|
||||
checked_byteCount = count;
|
||||
first = byteOffset;
|
||||
}
|
||||
else if (type == LOCAL_GL_UNSIGNED_INT && IsExtensionEnabled(OES_element_index_uint)) {
|
||||
checked_byteCount = 4 * CheckedUint32(count);
|
||||
if (byteOffset % 4 != 0) {
|
||||
ErrorInvalidOperation("%s: invalid byteOffset for UNSIGNED_INT (must be a multiple of 4)", info);
|
||||
return false;
|
||||
}
|
||||
first = byteOffset / 4;
|
||||
}
|
||||
else {
|
||||
ErrorInvalidEnum("%s: type must be UNSIGNED_SHORT or UNSIGNED_BYTE", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!checked_byteCount.isValid()) {
|
||||
ErrorInvalidValue("%s: overflow in byteCount", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there is no current program, this is silently ignored.
|
||||
// Any checks below this depend on a program being available.
|
||||
if (!mCurrentProgram) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mBoundVertexArray->mBoundElementArrayBuffer) {
|
||||
ErrorInvalidOperation("%s: must have element array buffer binding", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
WebGLBuffer& elemArrayBuffer = *mBoundVertexArray->mBoundElementArrayBuffer;
|
||||
|
||||
if (!elemArrayBuffer.ByteLength()) {
|
||||
ErrorInvalidOperation("%s: bound element array buffer doesn't have any data", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
CheckedInt<GLsizei> checked_neededByteCount = checked_byteCount.toChecked<GLsizei>() + byteOffset;
|
||||
|
||||
if (!checked_neededByteCount.isValid()) {
|
||||
ErrorInvalidOperation("%s: overflow in byteOffset+byteCount", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (uint32_t(checked_neededByteCount.value()) > elemArrayBuffer.ByteLength()) {
|
||||
ErrorInvalidOperation("%s: bound element array buffer is too small for given count and offset", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ValidateBufferFetching(info))
|
||||
return false;
|
||||
|
||||
if (!mMaxFetchedVertices ||
|
||||
!elemArrayBuffer.Validate(type, mMaxFetchedVertices - 1, first, count, out_upperBound))
|
||||
{
|
||||
ErrorInvalidOperation(
|
||||
"%s: bound vertex attribute buffers do not have sufficient "
|
||||
"size for given indices from the bound element array", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (uint32_t(primcount) > mMaxFetchedInstances) {
|
||||
ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
if (mBoundFramebuffer) {
|
||||
if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
|
||||
ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!DoFakeVertexAttrib0(mMaxFetchedVertices)) {
|
||||
return false;
|
||||
}
|
||||
BindFakeBlackTextures();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::DrawElements(GLenum mode, GLsizei count, GLenum type,
|
||||
WebGLintptr byteOffset)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateDrawModeEnum(mode, "drawElements: mode"))
|
||||
return;
|
||||
|
||||
GLuint upperBound = UINT_MAX;
|
||||
if (!DrawElements_check(count, type, byteOffset, 1, "drawElements",
|
||||
&upperBound))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SetupContextLossTimer();
|
||||
|
||||
if (gl->IsSupported(gl::GLFeature::draw_range_elements)) {
|
||||
gl->fDrawRangeElements(mode, 0, upperBound,
|
||||
count, type, reinterpret_cast<GLvoid*>(byteOffset));
|
||||
} else {
|
||||
gl->fDrawElements(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset));
|
||||
}
|
||||
|
||||
Draw_cleanup();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
|
||||
WebGLintptr byteOffset, GLsizei primcount)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateDrawModeEnum(mode, "drawElementsInstanced: mode"))
|
||||
return;
|
||||
|
||||
if (!DrawElements_check(count, type, byteOffset, primcount, "drawElementsInstanced"))
|
||||
return;
|
||||
|
||||
if (!DrawInstanced_check("drawElementsInstanced"))
|
||||
return;
|
||||
|
||||
SetupContextLossTimer();
|
||||
gl->fDrawElementsInstanced(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset), primcount);
|
||||
|
||||
Draw_cleanup();
|
||||
}
|
||||
|
||||
void WebGLContext::Draw_cleanup()
|
||||
{
|
||||
UndoFakeVertexAttrib0();
|
||||
UnbindFakeBlackTextures();
|
||||
|
||||
if (!mBoundFramebuffer) {
|
||||
Invalidate();
|
||||
mShouldPresent = true;
|
||||
mIsScreenCleared = false;
|
||||
}
|
||||
|
||||
if (gl->WorkAroundDriverBugs()) {
|
||||
if (gl->Renderer() == gl::GLRenderer::Tegra) {
|
||||
mDrawCallsSinceLastFlush++;
|
||||
|
||||
if (mDrawCallsSinceLastFlush >= MAX_DRAW_CALLS_SINCE_FLUSH) {
|
||||
gl->fFlush();
|
||||
mDrawCallsSinceLastFlush = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Let's check the viewport
|
||||
const WebGLRectangleObject* rect = CurValidFBRectObject();
|
||||
if (rect) {
|
||||
if (mViewportWidth > rect->Width() ||
|
||||
mViewportHeight > rect->Height())
|
||||
{
|
||||
if (!mAlreadyWarnedAboutViewportLargerThanDest) {
|
||||
GenerateWarning("Drawing to a destination rect smaller than the viewport rect. "
|
||||
"(This warning will only be given once)");
|
||||
mAlreadyWarnedAboutViewportLargerThanDest = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that state is consistent for drawing, and compute max number of elements (maxAllowedCount)
|
||||
* that will be legal to be read from bound VBOs.
|
||||
*/
|
||||
|
||||
bool
|
||||
WebGLContext::ValidateBufferFetching(const char *info)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
GLint currentProgram = 0;
|
||||
MakeContextCurrent();
|
||||
gl->fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, ¤tProgram);
|
||||
MOZ_ASSERT(GLuint(currentProgram) == mCurrentProgram->GLName(),
|
||||
"WebGL: current program doesn't agree with GL state");
|
||||
#endif
|
||||
|
||||
if (mBufferFetchingIsVerified) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hasPerVertex = false;
|
||||
uint32_t maxVertices = UINT32_MAX;
|
||||
uint32_t maxInstances = UINT32_MAX;
|
||||
uint32_t attribs = mBoundVertexArray->mAttribs.Length();
|
||||
|
||||
for (uint32_t i = 0; i < attribs; ++i) {
|
||||
const WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[i];
|
||||
|
||||
// If the attrib array isn't enabled, there's nothing to check;
|
||||
// it's a static value.
|
||||
if (!vd.enabled)
|
||||
continue;
|
||||
|
||||
if (vd.buf == nullptr) {
|
||||
ErrorInvalidOperation("%s: no VBO bound to enabled vertex attrib index %d!", info, i);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the attrib is not in use, then we don't have to validate
|
||||
// it, just need to make sure that the binding is non-null.
|
||||
if (!mCurrentProgram->IsAttribInUse(i))
|
||||
continue;
|
||||
|
||||
// the base offset
|
||||
CheckedUint32 checked_byteLength = CheckedUint32(vd.buf->ByteLength()) - vd.byteOffset;
|
||||
CheckedUint32 checked_sizeOfLastElement = CheckedUint32(vd.componentSize()) * vd.size;
|
||||
|
||||
if (!checked_byteLength.isValid() ||
|
||||
!checked_sizeOfLastElement.isValid())
|
||||
{
|
||||
ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (checked_byteLength.value() < checked_sizeOfLastElement.value()) {
|
||||
maxVertices = 0;
|
||||
maxInstances = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
CheckedUint32 checked_maxAllowedCount = ((checked_byteLength - checked_sizeOfLastElement) / vd.actualStride()) + 1;
|
||||
|
||||
if (!checked_maxAllowedCount.isValid()) {
|
||||
ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vd.divisor == 0) {
|
||||
maxVertices = std::min(maxVertices, checked_maxAllowedCount.value());
|
||||
hasPerVertex = true;
|
||||
} else {
|
||||
maxInstances = std::min(maxInstances, checked_maxAllowedCount.value() / vd.divisor);
|
||||
}
|
||||
}
|
||||
|
||||
mBufferFetchingIsVerified = true;
|
||||
mBufferFetchingHasPerVertex = hasPerVertex;
|
||||
mMaxFetchedVertices = maxVertices;
|
||||
mMaxFetchedInstances = maxInstances;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
WebGLVertexAttrib0Status
|
||||
WebGLContext::WhatDoesVertexAttrib0Need()
|
||||
{
|
||||
MOZ_ASSERT(mCurrentProgram);
|
||||
|
||||
// work around Mac OSX crash, see bug 631420
|
||||
#ifdef XP_MACOSX
|
||||
if (gl->WorkAroundDriverBugs() &&
|
||||
mBoundVertexArray->IsAttribArrayEnabled(0) &&
|
||||
!mCurrentProgram->IsAttribInUse(0))
|
||||
{
|
||||
return WebGLVertexAttrib0Status::EmulatedUninitializedArray;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (MOZ_LIKELY(gl->IsGLES() ||
|
||||
mBoundVertexArray->IsAttribArrayEnabled(0)))
|
||||
{
|
||||
return WebGLVertexAttrib0Status::Default;
|
||||
}
|
||||
|
||||
return mCurrentProgram->IsAttribInUse(0)
|
||||
? WebGLVertexAttrib0Status::EmulatedInitializedArray
|
||||
: WebGLVertexAttrib0Status::EmulatedUninitializedArray;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::DoFakeVertexAttrib0(GLuint vertexCount)
|
||||
{
|
||||
WebGLVertexAttrib0Status whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
|
||||
|
||||
if (MOZ_LIKELY(whatDoesAttrib0Need == WebGLVertexAttrib0Status::Default))
|
||||
return true;
|
||||
|
||||
if (!mAlreadyWarnedAboutFakeVertexAttrib0) {
|
||||
GenerateWarning("Drawing without vertex attrib 0 array enabled forces the browser "
|
||||
"to do expensive emulation work when running on desktop OpenGL "
|
||||
"platforms, for example on Mac. It is preferable to always draw "
|
||||
"with vertex attrib 0 array enabled, by using bindAttribLocation "
|
||||
"to bind some always-used attribute to location 0.");
|
||||
mAlreadyWarnedAboutFakeVertexAttrib0 = true;
|
||||
}
|
||||
|
||||
CheckedUint32 checked_dataSize = CheckedUint32(vertexCount) * 4 * sizeof(GLfloat);
|
||||
|
||||
if (!checked_dataSize.isValid()) {
|
||||
ErrorOutOfMemory("Integer overflow trying to construct a fake vertex attrib 0 array for a draw-operation "
|
||||
"with %d vertices. Try reducing the number of vertices.", vertexCount);
|
||||
return false;
|
||||
}
|
||||
|
||||
GLuint dataSize = checked_dataSize.value();
|
||||
|
||||
if (!mFakeVertexAttrib0BufferObject) {
|
||||
gl->fGenBuffers(1, &mFakeVertexAttrib0BufferObject);
|
||||
}
|
||||
|
||||
// if the VBO status is already exactly what we need, or if the only difference is that it's initialized and
|
||||
// we don't need it to be, then consider it OK
|
||||
bool vertexAttrib0BufferStatusOK =
|
||||
mFakeVertexAttrib0BufferStatus == whatDoesAttrib0Need ||
|
||||
(mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray &&
|
||||
whatDoesAttrib0Need == WebGLVertexAttrib0Status::EmulatedUninitializedArray);
|
||||
|
||||
if (!vertexAttrib0BufferStatusOK ||
|
||||
mFakeVertexAttrib0BufferObjectSize < dataSize ||
|
||||
mFakeVertexAttrib0BufferObjectVector[0] != mVertexAttrib0Vector[0] ||
|
||||
mFakeVertexAttrib0BufferObjectVector[1] != mVertexAttrib0Vector[1] ||
|
||||
mFakeVertexAttrib0BufferObjectVector[2] != mVertexAttrib0Vector[2] ||
|
||||
mFakeVertexAttrib0BufferObjectVector[3] != mVertexAttrib0Vector[3])
|
||||
{
|
||||
mFakeVertexAttrib0BufferStatus = whatDoesAttrib0Need;
|
||||
mFakeVertexAttrib0BufferObjectSize = dataSize;
|
||||
mFakeVertexAttrib0BufferObjectVector[0] = mVertexAttrib0Vector[0];
|
||||
mFakeVertexAttrib0BufferObjectVector[1] = mVertexAttrib0Vector[1];
|
||||
mFakeVertexAttrib0BufferObjectVector[2] = mVertexAttrib0Vector[2];
|
||||
mFakeVertexAttrib0BufferObjectVector[3] = mVertexAttrib0Vector[3];
|
||||
|
||||
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);
|
||||
|
||||
GetAndFlushUnderlyingGLErrors();
|
||||
|
||||
if (mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray) {
|
||||
nsAutoArrayPtr<GLfloat> array(new GLfloat[4 * vertexCount]);
|
||||
for(size_t i = 0; i < vertexCount; ++i) {
|
||||
array[4 * i + 0] = mVertexAttrib0Vector[0];
|
||||
array[4 * i + 1] = mVertexAttrib0Vector[1];
|
||||
array[4 * i + 2] = mVertexAttrib0Vector[2];
|
||||
array[4 * i + 3] = mVertexAttrib0Vector[3];
|
||||
}
|
||||
gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, array, LOCAL_GL_DYNAMIC_DRAW);
|
||||
} else {
|
||||
gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, nullptr, LOCAL_GL_DYNAMIC_DRAW);
|
||||
}
|
||||
GLenum error = GetAndFlushUnderlyingGLErrors();
|
||||
|
||||
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0);
|
||||
|
||||
// note that we do this error checking and early return AFTER having restored the buffer binding above
|
||||
if (error) {
|
||||
ErrorOutOfMemory("Ran out of memory trying to construct a fake vertex attrib 0 array for a draw-operation "
|
||||
"with %d vertices. Try reducing the number of vertices.", vertexCount);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);
|
||||
gl->fVertexAttribPointer(0, 4, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::UndoFakeVertexAttrib0()
|
||||
{
|
||||
WebGLVertexAttrib0Status whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
|
||||
|
||||
if (MOZ_LIKELY(whatDoesAttrib0Need == WebGLVertexAttrib0Status::Default))
|
||||
return;
|
||||
|
||||
if (mBoundVertexArray->HasAttrib(0) && mBoundVertexArray->mAttribs[0].buf) {
|
||||
const WebGLVertexAttribData& attrib0 = mBoundVertexArray->mAttribs[0];
|
||||
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, attrib0.buf->GLName());
|
||||
gl->fVertexAttribPointer(0,
|
||||
attrib0.size,
|
||||
attrib0.type,
|
||||
attrib0.normalized,
|
||||
attrib0.stride,
|
||||
reinterpret_cast<const GLvoid *>(attrib0.byteOffset));
|
||||
} else {
|
||||
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0);
|
||||
}
|
||||
|
||||
WebGLContextFakeBlackStatus
|
||||
WebGLContext::ResolvedFakeBlackStatus()
|
||||
{
|
||||
// handle this case first, it's the generic case
|
||||
if (MOZ_LIKELY(mFakeBlackStatus == WebGLContextFakeBlackStatus::NotNeeded))
|
||||
return mFakeBlackStatus;
|
||||
|
||||
if (mFakeBlackStatus == WebGLContextFakeBlackStatus::Needed)
|
||||
return mFakeBlackStatus;
|
||||
|
||||
for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
|
||||
if ((mBound2DTextures[i] && mBound2DTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) ||
|
||||
(mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded))
|
||||
{
|
||||
mFakeBlackStatus = WebGLContextFakeBlackStatus::Needed;
|
||||
return mFakeBlackStatus;
|
||||
}
|
||||
}
|
||||
|
||||
// we have exhausted all cases where we do need fakeblack, so if the status is still unknown,
|
||||
// that means that we do NOT need it.
|
||||
mFakeBlackStatus = WebGLContextFakeBlackStatus::NotNeeded;
|
||||
return mFakeBlackStatus;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::BindFakeBlackTexturesHelper(
|
||||
GLenum target,
|
||||
const nsTArray<WebGLRefPtr<WebGLTexture> > & boundTexturesArray,
|
||||
ScopedDeletePtr<FakeBlackTexture> & opaqueTextureScopedPtr,
|
||||
ScopedDeletePtr<FakeBlackTexture> & transparentTextureScopedPtr)
|
||||
{
|
||||
for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
|
||||
if (!boundTexturesArray[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
WebGLTextureFakeBlackStatus s = boundTexturesArray[i]->ResolvedFakeBlackStatus();
|
||||
MOZ_ASSERT(s != WebGLTextureFakeBlackStatus::Unknown);
|
||||
|
||||
if (MOZ_LIKELY(s == WebGLTextureFakeBlackStatus::NotNeeded)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool alpha = s == WebGLTextureFakeBlackStatus::UninitializedImageData &&
|
||||
FormatHasAlpha(boundTexturesArray[i]->ImageInfoBase().InternalFormat());
|
||||
ScopedDeletePtr<FakeBlackTexture>&
|
||||
blackTexturePtr = alpha
|
||||
? transparentTextureScopedPtr
|
||||
: opaqueTextureScopedPtr;
|
||||
|
||||
if (!blackTexturePtr) {
|
||||
GLenum format = alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
|
||||
blackTexturePtr
|
||||
= new FakeBlackTexture(gl, target, format);
|
||||
}
|
||||
|
||||
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
|
||||
gl->fBindTexture(target,
|
||||
blackTexturePtr->GLName());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::BindFakeBlackTextures()
|
||||
{
|
||||
// this is the generic case: try to return early
|
||||
if (MOZ_LIKELY(ResolvedFakeBlackStatus() == WebGLContextFakeBlackStatus::NotNeeded))
|
||||
return;
|
||||
|
||||
BindFakeBlackTexturesHelper(LOCAL_GL_TEXTURE_2D,
|
||||
mBound2DTextures,
|
||||
mBlackOpaqueTexture2D,
|
||||
mBlackTransparentTexture2D);
|
||||
BindFakeBlackTexturesHelper(LOCAL_GL_TEXTURE_CUBE_MAP,
|
||||
mBoundCubeMapTextures,
|
||||
mBlackOpaqueTextureCubeMap,
|
||||
mBlackTransparentTextureCubeMap);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::UnbindFakeBlackTextures()
|
||||
{
|
||||
// this is the generic case: try to return early
|
||||
if (MOZ_LIKELY(ResolvedFakeBlackStatus() == WebGLContextFakeBlackStatus::NotNeeded))
|
||||
return;
|
||||
|
||||
for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
|
||||
if (mBound2DTextures[i] && mBound2DTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) {
|
||||
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
|
||||
gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mBound2DTextures[i]->GLName());
|
||||
}
|
||||
if (mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) {
|
||||
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
|
||||
gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, mBoundCubeMapTextures[i]->GLName());
|
||||
}
|
||||
}
|
||||
|
||||
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + mActiveTexture);
|
||||
}
|
||||
|
||||
WebGLContext::FakeBlackTexture::FakeBlackTexture(GLContext *gl, GLenum target, GLenum format)
|
||||
: mGL(gl)
|
||||
, mGLName(0)
|
||||
{
|
||||
MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D || target == LOCAL_GL_TEXTURE_CUBE_MAP);
|
||||
MOZ_ASSERT(format == LOCAL_GL_RGB || format == LOCAL_GL_RGBA);
|
||||
|
||||
mGL->MakeCurrent();
|
||||
GLuint formerBinding = 0;
|
||||
gl->GetUIntegerv(target == LOCAL_GL_TEXTURE_2D
|
||||
? LOCAL_GL_TEXTURE_BINDING_2D
|
||||
: LOCAL_GL_TEXTURE_BINDING_CUBE_MAP,
|
||||
&formerBinding);
|
||||
gl->fGenTextures(1, &mGLName);
|
||||
gl->fBindTexture(target, mGLName);
|
||||
|
||||
// we allocate our zeros on the heap, and we overallocate (16 bytes instead of 4)
|
||||
// to minimize the risk of running into a driver bug in texImage2D, as it is
|
||||
// a bit unusual maybe to create 1x1 textures, and the stack may not have the alignment
|
||||
// that texImage2D expects.
|
||||
void* zeros = calloc(1, 16);
|
||||
if (target == LOCAL_GL_TEXTURE_2D) {
|
||||
gl->fTexImage2D(target, 0, format, 1, 1,
|
||||
0, format, LOCAL_GL_UNSIGNED_BYTE, zeros);
|
||||
} else {
|
||||
for (GLuint i = 0; i < 6; ++i) {
|
||||
gl->fTexImage2D(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format, 1, 1,
|
||||
0, format, LOCAL_GL_UNSIGNED_BYTE, zeros);
|
||||
}
|
||||
}
|
||||
free(zeros);
|
||||
|
||||
gl->fBindTexture(target, formerBinding);
|
||||
}
|
||||
|
||||
WebGLContext::FakeBlackTexture::~FakeBlackTexture()
|
||||
{
|
||||
if (mGL) {
|
||||
mGL->MakeCurrent();
|
||||
mGL->fDeleteTextures(1, &mGLName);
|
||||
}
|
||||
}
|
@ -72,49 +72,6 @@ WebGLContext::CurValidFBRectObject() const
|
||||
return rect;
|
||||
}
|
||||
|
||||
WebGLContext::FakeBlackTexture::FakeBlackTexture(GLContext *gl, GLenum target, GLenum format)
|
||||
: mGL(gl)
|
||||
, mGLName(0)
|
||||
{
|
||||
MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D || target == LOCAL_GL_TEXTURE_CUBE_MAP);
|
||||
MOZ_ASSERT(format == LOCAL_GL_RGB || format == LOCAL_GL_RGBA);
|
||||
|
||||
mGL->MakeCurrent();
|
||||
GLuint formerBinding = 0;
|
||||
gl->GetUIntegerv(target == LOCAL_GL_TEXTURE_2D
|
||||
? LOCAL_GL_TEXTURE_BINDING_2D
|
||||
: LOCAL_GL_TEXTURE_BINDING_CUBE_MAP,
|
||||
&formerBinding);
|
||||
gl->fGenTextures(1, &mGLName);
|
||||
gl->fBindTexture(target, mGLName);
|
||||
|
||||
// we allocate our zeros on the heap, and we overallocate (16 bytes instead of 4)
|
||||
// to minimize the risk of running into a driver bug in texImage2D, as it is
|
||||
// a bit unusual maybe to create 1x1 textures, and the stack may not have the alignment
|
||||
// that texImage2D expects.
|
||||
void* zeros = calloc(1, 16);
|
||||
if (target == LOCAL_GL_TEXTURE_2D) {
|
||||
gl->fTexImage2D(target, 0, format, 1, 1,
|
||||
0, format, LOCAL_GL_UNSIGNED_BYTE, zeros);
|
||||
} else {
|
||||
for (GLuint i = 0; i < 6; ++i) {
|
||||
gl->fTexImage2D(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format, 1, 1,
|
||||
0, format, LOCAL_GL_UNSIGNED_BYTE, zeros);
|
||||
}
|
||||
}
|
||||
free(zeros);
|
||||
|
||||
gl->fBindTexture(target, formerBinding);
|
||||
}
|
||||
|
||||
WebGLContext::FakeBlackTexture::~FakeBlackTexture()
|
||||
{
|
||||
if (mGL) {
|
||||
mGL->MakeCurrent();
|
||||
mGL->fDeleteTextures(1, &mGLName);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// WebGL API
|
||||
//
|
||||
@ -834,237 +791,6 @@ WebGLContext::DepthRange(GLfloat zNear, GLfloat zFar)
|
||||
gl->fDepthRange(zNear, zFar);
|
||||
}
|
||||
|
||||
WebGLVertexAttrib0Status
|
||||
WebGLContext::WhatDoesVertexAttrib0Need()
|
||||
{
|
||||
// here we may assume that mCurrentProgram != null
|
||||
|
||||
// work around Mac OSX crash, see bug 631420
|
||||
#ifdef XP_MACOSX
|
||||
if (gl->WorkAroundDriverBugs() &&
|
||||
mBoundVertexArray->IsAttribArrayEnabled(0) &&
|
||||
!mCurrentProgram->IsAttribInUse(0))
|
||||
{
|
||||
return WebGLVertexAttrib0Status::EmulatedUninitializedArray;
|
||||
}
|
||||
#endif
|
||||
|
||||
return (gl->IsGLES2() || mBoundVertexArray->IsAttribArrayEnabled(0)) ? WebGLVertexAttrib0Status::Default
|
||||
: mCurrentProgram->IsAttribInUse(0) ? WebGLVertexAttrib0Status::EmulatedInitializedArray
|
||||
: WebGLVertexAttrib0Status::EmulatedUninitializedArray;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::DoFakeVertexAttrib0(GLuint vertexCount)
|
||||
{
|
||||
WebGLVertexAttrib0Status whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
|
||||
|
||||
if (whatDoesAttrib0Need == WebGLVertexAttrib0Status::Default)
|
||||
return true;
|
||||
|
||||
if (!mAlreadyWarnedAboutFakeVertexAttrib0) {
|
||||
GenerateWarning("Drawing without vertex attrib 0 array enabled forces the browser "
|
||||
"to do expensive emulation work when running on desktop OpenGL "
|
||||
"platforms, for example on Mac. It is preferable to always draw "
|
||||
"with vertex attrib 0 array enabled, by using bindAttribLocation "
|
||||
"to bind some always-used attribute to location 0.");
|
||||
mAlreadyWarnedAboutFakeVertexAttrib0 = true;
|
||||
}
|
||||
|
||||
CheckedUint32 checked_dataSize = CheckedUint32(vertexCount) * 4 * sizeof(GLfloat);
|
||||
|
||||
if (!checked_dataSize.isValid()) {
|
||||
ErrorOutOfMemory("Integer overflow trying to construct a fake vertex attrib 0 array for a draw-operation "
|
||||
"with %d vertices. Try reducing the number of vertices.", vertexCount);
|
||||
return false;
|
||||
}
|
||||
|
||||
GLuint dataSize = checked_dataSize.value();
|
||||
|
||||
if (!mFakeVertexAttrib0BufferObject) {
|
||||
gl->fGenBuffers(1, &mFakeVertexAttrib0BufferObject);
|
||||
}
|
||||
|
||||
// if the VBO status is already exactly what we need, or if the only difference is that it's initialized and
|
||||
// we don't need it to be, then consider it OK
|
||||
bool vertexAttrib0BufferStatusOK =
|
||||
mFakeVertexAttrib0BufferStatus == whatDoesAttrib0Need ||
|
||||
(mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray &&
|
||||
whatDoesAttrib0Need == WebGLVertexAttrib0Status::EmulatedUninitializedArray);
|
||||
|
||||
if (!vertexAttrib0BufferStatusOK ||
|
||||
mFakeVertexAttrib0BufferObjectSize < dataSize ||
|
||||
mFakeVertexAttrib0BufferObjectVector[0] != mVertexAttrib0Vector[0] ||
|
||||
mFakeVertexAttrib0BufferObjectVector[1] != mVertexAttrib0Vector[1] ||
|
||||
mFakeVertexAttrib0BufferObjectVector[2] != mVertexAttrib0Vector[2] ||
|
||||
mFakeVertexAttrib0BufferObjectVector[3] != mVertexAttrib0Vector[3])
|
||||
{
|
||||
mFakeVertexAttrib0BufferStatus = whatDoesAttrib0Need;
|
||||
mFakeVertexAttrib0BufferObjectSize = dataSize;
|
||||
mFakeVertexAttrib0BufferObjectVector[0] = mVertexAttrib0Vector[0];
|
||||
mFakeVertexAttrib0BufferObjectVector[1] = mVertexAttrib0Vector[1];
|
||||
mFakeVertexAttrib0BufferObjectVector[2] = mVertexAttrib0Vector[2];
|
||||
mFakeVertexAttrib0BufferObjectVector[3] = mVertexAttrib0Vector[3];
|
||||
|
||||
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);
|
||||
|
||||
GetAndFlushUnderlyingGLErrors();
|
||||
|
||||
if (mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray) {
|
||||
nsAutoArrayPtr<GLfloat> array(new GLfloat[4 * vertexCount]);
|
||||
for(size_t i = 0; i < vertexCount; ++i) {
|
||||
array[4 * i + 0] = mVertexAttrib0Vector[0];
|
||||
array[4 * i + 1] = mVertexAttrib0Vector[1];
|
||||
array[4 * i + 2] = mVertexAttrib0Vector[2];
|
||||
array[4 * i + 3] = mVertexAttrib0Vector[3];
|
||||
}
|
||||
gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, array, LOCAL_GL_DYNAMIC_DRAW);
|
||||
} else {
|
||||
gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, nullptr, LOCAL_GL_DYNAMIC_DRAW);
|
||||
}
|
||||
GLenum error = GetAndFlushUnderlyingGLErrors();
|
||||
|
||||
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0);
|
||||
|
||||
// note that we do this error checking and early return AFTER having restored the buffer binding above
|
||||
if (error) {
|
||||
ErrorOutOfMemory("Ran out of memory trying to construct a fake vertex attrib 0 array for a draw-operation "
|
||||
"with %d vertices. Try reducing the number of vertices.", vertexCount);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);
|
||||
gl->fVertexAttribPointer(0, 4, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::UndoFakeVertexAttrib0()
|
||||
{
|
||||
WebGLVertexAttrib0Status whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
|
||||
|
||||
if (whatDoesAttrib0Need == WebGLVertexAttrib0Status::Default)
|
||||
return;
|
||||
|
||||
if (mBoundVertexArray->HasAttrib(0) && mBoundVertexArray->mAttribs[0].buf) {
|
||||
const WebGLVertexAttribData& attrib0 = mBoundVertexArray->mAttribs[0];
|
||||
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, attrib0.buf->GLName());
|
||||
gl->fVertexAttribPointer(0,
|
||||
attrib0.size,
|
||||
attrib0.type,
|
||||
attrib0.normalized,
|
||||
attrib0.stride,
|
||||
reinterpret_cast<const GLvoid *>(attrib0.byteOffset));
|
||||
} else {
|
||||
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0);
|
||||
}
|
||||
|
||||
WebGLContextFakeBlackStatus
|
||||
WebGLContext::ResolvedFakeBlackStatus()
|
||||
{
|
||||
// handle this case first, it's the generic case
|
||||
if (MOZ_LIKELY(mFakeBlackStatus == WebGLContextFakeBlackStatus::NotNeeded))
|
||||
return mFakeBlackStatus;
|
||||
|
||||
if (mFakeBlackStatus == WebGLContextFakeBlackStatus::Needed)
|
||||
return mFakeBlackStatus;
|
||||
|
||||
for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
|
||||
if ((mBound2DTextures[i] && mBound2DTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) ||
|
||||
(mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded))
|
||||
{
|
||||
mFakeBlackStatus = WebGLContextFakeBlackStatus::Needed;
|
||||
return mFakeBlackStatus;
|
||||
}
|
||||
}
|
||||
|
||||
// we have exhausted all cases where we do need fakeblack, so if the status is still unknown,
|
||||
// that means that we do NOT need it.
|
||||
mFakeBlackStatus = WebGLContextFakeBlackStatus::NotNeeded;
|
||||
return mFakeBlackStatus;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::BindFakeBlackTexturesHelper(
|
||||
GLenum target,
|
||||
const nsTArray<WebGLRefPtr<WebGLTexture> > & boundTexturesArray,
|
||||
ScopedDeletePtr<FakeBlackTexture> & opaqueTextureScopedPtr,
|
||||
ScopedDeletePtr<FakeBlackTexture> & transparentTextureScopedPtr)
|
||||
{
|
||||
for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
|
||||
if (!boundTexturesArray[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
WebGLTextureFakeBlackStatus s = boundTexturesArray[i]->ResolvedFakeBlackStatus();
|
||||
MOZ_ASSERT(s != WebGLTextureFakeBlackStatus::Unknown);
|
||||
|
||||
if (MOZ_LIKELY(s == WebGLTextureFakeBlackStatus::NotNeeded)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool alpha = s == WebGLTextureFakeBlackStatus::UninitializedImageData &&
|
||||
FormatHasAlpha(boundTexturesArray[i]->ImageInfoBase().InternalFormat());
|
||||
ScopedDeletePtr<FakeBlackTexture>&
|
||||
blackTexturePtr = alpha
|
||||
? transparentTextureScopedPtr
|
||||
: opaqueTextureScopedPtr;
|
||||
|
||||
if (!blackTexturePtr) {
|
||||
GLenum format = alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
|
||||
blackTexturePtr
|
||||
= new FakeBlackTexture(gl, target, format);
|
||||
}
|
||||
|
||||
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
|
||||
gl->fBindTexture(target,
|
||||
blackTexturePtr->GLName());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::BindFakeBlackTextures()
|
||||
{
|
||||
// this is the generic case: try to return early
|
||||
if (MOZ_LIKELY(ResolvedFakeBlackStatus() == WebGLContextFakeBlackStatus::NotNeeded))
|
||||
return;
|
||||
|
||||
BindFakeBlackTexturesHelper(LOCAL_GL_TEXTURE_2D,
|
||||
mBound2DTextures,
|
||||
mBlackOpaqueTexture2D,
|
||||
mBlackTransparentTexture2D);
|
||||
BindFakeBlackTexturesHelper(LOCAL_GL_TEXTURE_CUBE_MAP,
|
||||
mBoundCubeMapTextures,
|
||||
mBlackOpaqueTextureCubeMap,
|
||||
mBlackTransparentTextureCubeMap);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::UnbindFakeBlackTextures()
|
||||
{
|
||||
// this is the generic case: try to return early
|
||||
if (MOZ_LIKELY(ResolvedFakeBlackStatus() == WebGLContextFakeBlackStatus::NotNeeded))
|
||||
return;
|
||||
|
||||
for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
|
||||
if (mBound2DTextures[i] && mBound2DTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) {
|
||||
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
|
||||
gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mBound2DTextures[i]->GLName());
|
||||
}
|
||||
if (mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) {
|
||||
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
|
||||
gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, mBoundCubeMapTextures[i]->GLName());
|
||||
}
|
||||
}
|
||||
|
||||
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + mActiveTexture);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum rbtarget, WebGLRenderbuffer *wrb)
|
||||
{
|
||||
@ -2622,14 +2348,14 @@ WebGLContext::RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei
|
||||
case LOCAL_GL_RGBA4:
|
||||
case LOCAL_GL_RGB5_A1:
|
||||
// 16-bit RGBA formats are not supported on desktop GL
|
||||
if (!gl->IsGLES2()) internalformatForGL = LOCAL_GL_RGBA8;
|
||||
if (!gl->IsGLES()) internalformatForGL = LOCAL_GL_RGBA8;
|
||||
break;
|
||||
case LOCAL_GL_RGB565:
|
||||
// the RGB565 format is not supported on desktop GL
|
||||
if (!gl->IsGLES2()) internalformatForGL = LOCAL_GL_RGB8;
|
||||
if (!gl->IsGLES()) internalformatForGL = LOCAL_GL_RGB8;
|
||||
break;
|
||||
case LOCAL_GL_DEPTH_COMPONENT16:
|
||||
if (!gl->IsGLES2() || gl->IsExtensionSupported(gl::GLContext::OES_depth24))
|
||||
if (!gl->IsGLES() || gl->IsExtensionSupported(gl::GLContext::OES_depth24))
|
||||
internalformatForGL = LOCAL_GL_DEPTH_COMPONENT24;
|
||||
else if (gl->IsExtensionSupported(gl::GLContext::OES_packed_depth_stencil))
|
||||
internalformatForGL = LOCAL_GL_DEPTH24_STENCIL8;
|
||||
@ -3230,7 +2956,7 @@ WebGLContext::CompileShader(WebGLShader *shader)
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
ShShaderOutput targetShaderSourceLanguage = gl->IsGLES2() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT;
|
||||
ShShaderOutput targetShaderSourceLanguage = gl->IsGLES() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT;
|
||||
bool useShaderSourceTranslation = true;
|
||||
|
||||
if (shader->NeedsTranslation() && mShaderValidation) {
|
||||
@ -3800,7 +3526,7 @@ GLenum WebGLContext::CheckedTexImage2D(GLenum target,
|
||||
|
||||
// convert type for half float if not on GLES2
|
||||
GLenum realType = type;
|
||||
if (realType == LOCAL_GL_HALF_FLOAT_OES && !gl->IsGLES2()) {
|
||||
if (realType == LOCAL_GL_HALF_FLOAT_OES && !gl->IsGLES()) {
|
||||
realType = LOCAL_GL_HALF_FLOAT;
|
||||
}
|
||||
|
||||
@ -3882,7 +3608,7 @@ WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat,
|
||||
|
||||
// Handle ES2 and GL differences in floating point internal formats. Note that
|
||||
// format == internalformat, as checked above and as required by ES.
|
||||
internalformat = InternalFormatForFormatAndType(format, type, gl->IsGLES2());
|
||||
internalformat = InternalFormatForFormatAndType(format, type, gl->IsGLES());
|
||||
|
||||
// Handle ES2 and GL differences when supporting sRGB internal formats. GL ES
|
||||
// requires that format == internalformat, but GL will fail in this case.
|
||||
@ -3890,7 +3616,7 @@ WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat,
|
||||
// format -> internalformat
|
||||
// GL_RGB GL_SRGB_EXT
|
||||
// GL_RGBA GL_SRGB_ALPHA_EXT
|
||||
if (!gl->IsGLES2()) {
|
||||
if (!gl->IsGLES()) {
|
||||
switch (internalformat) {
|
||||
case LOCAL_GL_SRGB_EXT:
|
||||
format = LOCAL_GL_RGB;
|
||||
|
@ -1631,7 +1631,7 @@ WebGLContext::InitAndValidateGL()
|
||||
MakeContextCurrent();
|
||||
|
||||
// on desktop OpenGL, we always keep vertex attrib 0 array enabled
|
||||
if (!gl->IsGLES2()) {
|
||||
if (!gl->IsGLES()) {
|
||||
gl->fEnableVertexAttribArray(0);
|
||||
}
|
||||
|
||||
@ -1729,7 +1729,7 @@ WebGLContext::InitAndValidateGL()
|
||||
// Always 1 for GLES2
|
||||
mMaxFramebufferColorAttachments = 1;
|
||||
|
||||
if (!gl->IsGLES2()) {
|
||||
if (!gl->IsGLES()) {
|
||||
// gl_PointSize is always available in ES2 GLSL, but has to be
|
||||
// specifically enabled on desktop GLSL.
|
||||
gl->fEnable(LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE);
|
||||
|
@ -20,9 +20,6 @@
|
||||
using namespace mozilla;
|
||||
using namespace dom;
|
||||
|
||||
// For a Tegra workaround.
|
||||
static const int MAX_DRAW_CALLS_SINCE_FLUSH = 100;
|
||||
|
||||
void
|
||||
WebGLContext::VertexAttrib1f(GLuint index, GLfloat x0)
|
||||
{
|
||||
@ -38,7 +35,7 @@ WebGLContext::VertexAttrib1f(GLuint index, GLfloat x0)
|
||||
mVertexAttrib0Vector[1] = 0;
|
||||
mVertexAttrib0Vector[2] = 0;
|
||||
mVertexAttrib0Vector[3] = 1;
|
||||
if (gl->IsGLES2())
|
||||
if (gl->IsGLES())
|
||||
gl->fVertexAttrib1f(index, x0);
|
||||
}
|
||||
}
|
||||
@ -58,7 +55,7 @@ WebGLContext::VertexAttrib2f(GLuint index, GLfloat x0, GLfloat x1)
|
||||
mVertexAttrib0Vector[1] = x1;
|
||||
mVertexAttrib0Vector[2] = 0;
|
||||
mVertexAttrib0Vector[3] = 1;
|
||||
if (gl->IsGLES2())
|
||||
if (gl->IsGLES())
|
||||
gl->fVertexAttrib2f(index, x0, x1);
|
||||
}
|
||||
}
|
||||
@ -78,7 +75,7 @@ WebGLContext::VertexAttrib3f(GLuint index, GLfloat x0, GLfloat x1, GLfloat x2)
|
||||
mVertexAttrib0Vector[1] = x1;
|
||||
mVertexAttrib0Vector[2] = x2;
|
||||
mVertexAttrib0Vector[3] = 1;
|
||||
if (gl->IsGLES2())
|
||||
if (gl->IsGLES())
|
||||
gl->fVertexAttrib3f(index, x0, x1, x2);
|
||||
}
|
||||
}
|
||||
@ -99,7 +96,7 @@ WebGLContext::VertexAttrib4f(GLuint index, GLfloat x0, GLfloat x1,
|
||||
mVertexAttrib0Vector[1] = x1;
|
||||
mVertexAttrib0Vector[2] = x2;
|
||||
mVertexAttrib0Vector[3] = x3;
|
||||
if (gl->IsGLES2())
|
||||
if (gl->IsGLES())
|
||||
gl->fVertexAttrib4f(index, x0, x1, x2, x3);
|
||||
}
|
||||
}
|
||||
@ -120,7 +117,7 @@ WebGLContext::VertexAttrib1fv_base(GLuint idx, uint32_t arrayLength,
|
||||
mVertexAttrib0Vector[1] = GLfloat(0);
|
||||
mVertexAttrib0Vector[2] = GLfloat(0);
|
||||
mVertexAttrib0Vector[3] = GLfloat(1);
|
||||
if (gl->IsGLES2())
|
||||
if (gl->IsGLES())
|
||||
gl->fVertexAttrib1fv(idx, ptr);
|
||||
}
|
||||
}
|
||||
@ -140,7 +137,7 @@ WebGLContext::VertexAttrib2fv_base(GLuint idx, uint32_t arrayLength,
|
||||
mVertexAttrib0Vector[1] = ptr[1];
|
||||
mVertexAttrib0Vector[2] = GLfloat(0);
|
||||
mVertexAttrib0Vector[3] = GLfloat(1);
|
||||
if (gl->IsGLES2())
|
||||
if (gl->IsGLES())
|
||||
gl->fVertexAttrib2fv(idx, ptr);
|
||||
}
|
||||
}
|
||||
@ -160,7 +157,7 @@ WebGLContext::VertexAttrib3fv_base(GLuint idx, uint32_t arrayLength,
|
||||
mVertexAttrib0Vector[1] = ptr[1];
|
||||
mVertexAttrib0Vector[2] = ptr[2];
|
||||
mVertexAttrib0Vector[3] = GLfloat(1);
|
||||
if (gl->IsGLES2())
|
||||
if (gl->IsGLES())
|
||||
gl->fVertexAttrib3fv(idx, ptr);
|
||||
}
|
||||
}
|
||||
@ -180,7 +177,7 @@ WebGLContext::VertexAttrib4fv_base(GLuint idx, uint32_t arrayLength,
|
||||
mVertexAttrib0Vector[1] = ptr[1];
|
||||
mVertexAttrib0Vector[2] = ptr[2];
|
||||
mVertexAttrib0Vector[3] = ptr[3];
|
||||
if (gl->IsGLES2())
|
||||
if (gl->IsGLES())
|
||||
gl->fVertexAttrib4fv(idx, ptr);
|
||||
}
|
||||
}
|
||||
@ -214,7 +211,7 @@ WebGLContext::DisableVertexAttribArray(GLuint index)
|
||||
MakeContextCurrent();
|
||||
InvalidateBufferFetching();
|
||||
|
||||
if (index || gl->IsGLES2())
|
||||
if (index || gl->IsGLES())
|
||||
gl->fDisableVertexAttribArray(index);
|
||||
|
||||
MOZ_ASSERT(mBoundVertexArray->HasAttrib(index)); // should have been validated earlier
|
||||
@ -426,425 +423,3 @@ WebGLContext::VertexAttribDivisor(GLuint index, GLuint divisor)
|
||||
|
||||
gl->fVertexAttribDivisor(index, divisor);
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::DrawInstanced_check(const char* info)
|
||||
{
|
||||
// This restriction was removed in GLES3, so WebGL2 shouldn't have it.
|
||||
if (!IsWebGL2() &&
|
||||
IsExtensionEnabled(ANGLE_instanced_arrays) &&
|
||||
!mBufferFetchingHasPerVertex)
|
||||
{
|
||||
/* http://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_instanced_arrays.txt
|
||||
* If all of the enabled vertex attribute arrays that are bound to active
|
||||
* generic attributes in the program have a non-zero divisor, the draw
|
||||
* call should return INVALID_OPERATION.
|
||||
*
|
||||
* NB: This also appears to apply to NV_instanced_arrays, though the
|
||||
* INVALID_OPERATION emission is not explicitly stated.
|
||||
* ARB_instanced_arrays does not have this restriction.
|
||||
*/
|
||||
ErrorInvalidOperation("%s: at least one vertex attribute divisor should be 0", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcount, const char* info)
|
||||
{
|
||||
if (first < 0 || count < 0) {
|
||||
ErrorInvalidValue("%s: negative first or count", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (primcount < 0) {
|
||||
ErrorInvalidValue("%s: negative primcount", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ValidateStencilParamsForDrawCall()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If count is 0, there's nothing to do.
|
||||
if (count == 0 || primcount == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there is no current program, this is silently ignored.
|
||||
// Any checks below this depend on a program being available.
|
||||
if (!mCurrentProgram) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ValidateBufferFetching(info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CheckedInt<GLsizei> checked_firstPlusCount = CheckedInt<GLsizei>(first) + count;
|
||||
|
||||
if (!checked_firstPlusCount.isValid()) {
|
||||
ErrorInvalidOperation("%s: overflow in first+count", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (uint32_t(checked_firstPlusCount.value()) > mMaxFetchedVertices) {
|
||||
ErrorInvalidOperation("%s: bound vertex attribute buffers do not have sufficient size for given first and count", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (uint32_t(primcount) > mMaxFetchedInstances) {
|
||||
ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
if (mBoundFramebuffer) {
|
||||
if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
|
||||
ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!DoFakeVertexAttrib0(checked_firstPlusCount.value())) {
|
||||
return false;
|
||||
}
|
||||
BindFakeBlackTextures();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei count)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateDrawModeEnum(mode, "drawArrays: mode"))
|
||||
return;
|
||||
|
||||
if (!DrawArrays_check(first, count, 1, "drawArrays"))
|
||||
return;
|
||||
|
||||
SetupContextLossTimer();
|
||||
gl->fDrawArrays(mode, first, count);
|
||||
|
||||
Draw_cleanup();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateDrawModeEnum(mode, "drawArraysInstanced: mode"))
|
||||
return;
|
||||
|
||||
if (!DrawArrays_check(first, count, primcount, "drawArraysInstanced"))
|
||||
return;
|
||||
|
||||
if (!DrawInstanced_check("drawArraysInstanced"))
|
||||
return;
|
||||
|
||||
SetupContextLossTimer();
|
||||
gl->fDrawArraysInstanced(mode, first, count, primcount);
|
||||
|
||||
Draw_cleanup();
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::DrawElements_check(GLsizei count, GLenum type,
|
||||
WebGLintptr byteOffset, GLsizei primcount,
|
||||
const char* info, GLuint* out_upperBound)
|
||||
{
|
||||
if (count < 0 || byteOffset < 0) {
|
||||
ErrorInvalidValue("%s: negative count or offset", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (primcount < 0) {
|
||||
ErrorInvalidValue("%s: negative primcount", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ValidateStencilParamsForDrawCall()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If count is 0, there's nothing to do.
|
||||
if (count == 0 || primcount == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CheckedUint32 checked_byteCount;
|
||||
|
||||
GLsizei first = 0;
|
||||
|
||||
if (type == LOCAL_GL_UNSIGNED_SHORT) {
|
||||
checked_byteCount = 2 * CheckedUint32(count);
|
||||
if (byteOffset % 2 != 0) {
|
||||
ErrorInvalidOperation("%s: invalid byteOffset for UNSIGNED_SHORT (must be a multiple of 2)", info);
|
||||
return false;
|
||||
}
|
||||
first = byteOffset / 2;
|
||||
}
|
||||
else if (type == LOCAL_GL_UNSIGNED_BYTE) {
|
||||
checked_byteCount = count;
|
||||
first = byteOffset;
|
||||
}
|
||||
else if (type == LOCAL_GL_UNSIGNED_INT && IsExtensionEnabled(OES_element_index_uint)) {
|
||||
checked_byteCount = 4 * CheckedUint32(count);
|
||||
if (byteOffset % 4 != 0) {
|
||||
ErrorInvalidOperation("%s: invalid byteOffset for UNSIGNED_INT (must be a multiple of 4)", info);
|
||||
return false;
|
||||
}
|
||||
first = byteOffset / 4;
|
||||
}
|
||||
else {
|
||||
ErrorInvalidEnum("%s: type must be UNSIGNED_SHORT or UNSIGNED_BYTE", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!checked_byteCount.isValid()) {
|
||||
ErrorInvalidValue("%s: overflow in byteCount", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there is no current program, this is silently ignored.
|
||||
// Any checks below this depend on a program being available.
|
||||
if (!mCurrentProgram) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mBoundVertexArray->mBoundElementArrayBuffer) {
|
||||
ErrorInvalidOperation("%s: must have element array buffer binding", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
WebGLBuffer& elemArrayBuffer = *mBoundVertexArray->mBoundElementArrayBuffer;
|
||||
|
||||
if (!elemArrayBuffer.ByteLength()) {
|
||||
ErrorInvalidOperation("%s: bound element array buffer doesn't have any data", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
CheckedInt<GLsizei> checked_neededByteCount = checked_byteCount.toChecked<GLsizei>() + byteOffset;
|
||||
|
||||
if (!checked_neededByteCount.isValid()) {
|
||||
ErrorInvalidOperation("%s: overflow in byteOffset+byteCount", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (uint32_t(checked_neededByteCount.value()) > elemArrayBuffer.ByteLength()) {
|
||||
ErrorInvalidOperation("%s: bound element array buffer is too small for given count and offset", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ValidateBufferFetching(info))
|
||||
return false;
|
||||
|
||||
if (!mMaxFetchedVertices ||
|
||||
!elemArrayBuffer.Validate(type, mMaxFetchedVertices - 1, first, count, out_upperBound))
|
||||
{
|
||||
ErrorInvalidOperation(
|
||||
"%s: bound vertex attribute buffers do not have sufficient "
|
||||
"size for given indices from the bound element array", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (uint32_t(primcount) > mMaxFetchedInstances) {
|
||||
ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
if (mBoundFramebuffer) {
|
||||
if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
|
||||
ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!DoFakeVertexAttrib0(mMaxFetchedVertices)) {
|
||||
return false;
|
||||
}
|
||||
BindFakeBlackTextures();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::DrawElements(GLenum mode, GLsizei count, GLenum type,
|
||||
WebGLintptr byteOffset)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateDrawModeEnum(mode, "drawElements: mode"))
|
||||
return;
|
||||
|
||||
GLuint upperBound = UINT_MAX;
|
||||
if (!DrawElements_check(count, type, byteOffset, 1, "drawElements",
|
||||
&upperBound))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SetupContextLossTimer();
|
||||
|
||||
if (gl->IsSupported(gl::GLFeature::draw_range_elements)) {
|
||||
gl->fDrawRangeElements(mode, 0, upperBound,
|
||||
count, type, reinterpret_cast<GLvoid*>(byteOffset));
|
||||
} else {
|
||||
gl->fDrawElements(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset));
|
||||
}
|
||||
|
||||
Draw_cleanup();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
|
||||
WebGLintptr byteOffset, GLsizei primcount)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateDrawModeEnum(mode, "drawElementsInstanced: mode"))
|
||||
return;
|
||||
|
||||
if (!DrawElements_check(count, type, byteOffset, primcount, "drawElementsInstanced"))
|
||||
return;
|
||||
|
||||
if (!DrawInstanced_check("drawElementsInstanced"))
|
||||
return;
|
||||
|
||||
SetupContextLossTimer();
|
||||
gl->fDrawElementsInstanced(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset), primcount);
|
||||
|
||||
Draw_cleanup();
|
||||
}
|
||||
|
||||
void WebGLContext::Draw_cleanup()
|
||||
{
|
||||
UndoFakeVertexAttrib0();
|
||||
UnbindFakeBlackTextures();
|
||||
|
||||
if (!mBoundFramebuffer) {
|
||||
Invalidate();
|
||||
mShouldPresent = true;
|
||||
mIsScreenCleared = false;
|
||||
}
|
||||
|
||||
if (gl->WorkAroundDriverBugs()) {
|
||||
if (gl->Renderer() == gl::GLRenderer::Tegra) {
|
||||
mDrawCallsSinceLastFlush++;
|
||||
|
||||
if (mDrawCallsSinceLastFlush >= MAX_DRAW_CALLS_SINCE_FLUSH) {
|
||||
gl->fFlush();
|
||||
mDrawCallsSinceLastFlush = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Let's check the viewport
|
||||
const WebGLRectangleObject* rect = CurValidFBRectObject();
|
||||
if (rect) {
|
||||
if (mViewportWidth > rect->Width() ||
|
||||
mViewportHeight > rect->Height())
|
||||
{
|
||||
if (!mAlreadyWarnedAboutViewportLargerThanDest) {
|
||||
GenerateWarning("Drawing to a destination rect smaller than the viewport rect. "
|
||||
"(This warning will only be given once)");
|
||||
mAlreadyWarnedAboutViewportLargerThanDest = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that state is consistent for drawing, and compute max number of elements (maxAllowedCount)
|
||||
* that will be legal to be read from bound VBOs.
|
||||
*/
|
||||
|
||||
bool
|
||||
WebGLContext::ValidateBufferFetching(const char *info)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
GLint currentProgram = 0;
|
||||
MakeContextCurrent();
|
||||
gl->fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, ¤tProgram);
|
||||
MOZ_ASSERT(GLuint(currentProgram) == mCurrentProgram->GLName(),
|
||||
"WebGL: current program doesn't agree with GL state");
|
||||
#endif
|
||||
|
||||
if (mBufferFetchingIsVerified) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hasPerVertex = false;
|
||||
uint32_t maxVertices = UINT32_MAX;
|
||||
uint32_t maxInstances = UINT32_MAX;
|
||||
uint32_t attribs = mBoundVertexArray->mAttribs.Length();
|
||||
|
||||
for (uint32_t i = 0; i < attribs; ++i) {
|
||||
const WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[i];
|
||||
|
||||
// If the attrib array isn't enabled, there's nothing to check;
|
||||
// it's a static value.
|
||||
if (!vd.enabled)
|
||||
continue;
|
||||
|
||||
if (vd.buf == nullptr) {
|
||||
ErrorInvalidOperation("%s: no VBO bound to enabled vertex attrib index %d!", info, i);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the attrib is not in use, then we don't have to validate
|
||||
// it, just need to make sure that the binding is non-null.
|
||||
if (!mCurrentProgram->IsAttribInUse(i))
|
||||
continue;
|
||||
|
||||
// the base offset
|
||||
CheckedUint32 checked_byteLength = CheckedUint32(vd.buf->ByteLength()) - vd.byteOffset;
|
||||
CheckedUint32 checked_sizeOfLastElement = CheckedUint32(vd.componentSize()) * vd.size;
|
||||
|
||||
if (!checked_byteLength.isValid() ||
|
||||
!checked_sizeOfLastElement.isValid())
|
||||
{
|
||||
ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (checked_byteLength.value() < checked_sizeOfLastElement.value()) {
|
||||
maxVertices = 0;
|
||||
maxInstances = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
CheckedUint32 checked_maxAllowedCount = ((checked_byteLength - checked_sizeOfLastElement) / vd.actualStride()) + 1;
|
||||
|
||||
if (!checked_maxAllowedCount.isValid()) {
|
||||
ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vd.divisor == 0) {
|
||||
maxVertices = std::min(maxVertices, checked_maxAllowedCount.value());
|
||||
hasPerVertex = true;
|
||||
} else {
|
||||
maxInstances = std::min(maxInstances, checked_maxAllowedCount.value() / vd.divisor);
|
||||
}
|
||||
}
|
||||
|
||||
mBufferFetchingIsVerified = true;
|
||||
mBufferFetchingHasPerVertex = hasPerVertex;
|
||||
mMaxFetchedVertices = maxVertices;
|
||||
mMaxFetchedInstances = maxInstances;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -890,7 +890,7 @@ FinalizeDrawAndReadBuffers(GLContext* aGL, bool aColorBufferDefined)
|
||||
//
|
||||
// Note that this test is not performed if OpenGL 4.2 or ARB_ES2_compatibility is
|
||||
// available.
|
||||
if (aGL->IsGLES2() ||
|
||||
if (aGL->IsGLES() ||
|
||||
aGL->IsSupported(GLFeature::ES2_compatibility) ||
|
||||
aGL->IsAtLeast(ContextProfile::OpenGL, 420))
|
||||
{
|
||||
|
@ -16,7 +16,7 @@ using namespace mozilla::gl;
|
||||
static GLenum
|
||||
DepthStencilDepthFormat(GLContext* gl) {
|
||||
// We might not be able to get 24-bit, so let's pretend!
|
||||
if (gl->IsGLES2() && !gl->IsExtensionSupported(gl::GLContext::OES_depth24))
|
||||
if (gl->IsGLES() && !gl->IsExtensionSupported(gl::GLContext::OES_depth24))
|
||||
return LOCAL_GL_DEPTH_COMPONENT16;
|
||||
|
||||
return LOCAL_GL_DEPTH_COMPONENT24;
|
||||
|
@ -125,7 +125,7 @@ WebGLTexture::Bind(GLenum aTarget) {
|
||||
// thanks to the WebKit people for finding this out: GL_TEXTURE_WRAP_R is not
|
||||
// present in GLES 2, but is present in GL and it seems as if for cube maps
|
||||
// we need to set it to GL_CLAMP_TO_EDGE to get the expected GLES behavior.
|
||||
if (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP && !mContext->gl->IsGLES2())
|
||||
if (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP && !mContext->gl->IsGLES())
|
||||
mContext->gl->fTexParameteri(mTarget, LOCAL_GL_TEXTURE_WRAP_R, LOCAL_GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ if CONFIG['MOZ_WEBGL']:
|
||||
'WebGLContext.cpp',
|
||||
'WebGLContextAsyncQueries.cpp',
|
||||
'WebGLContextBuffers.cpp',
|
||||
'WebGLContextDraw.cpp',
|
||||
'WebGLContextExtensions.cpp',
|
||||
'WebGLContextFramebufferOperations.cpp',
|
||||
'WebGLContextGL.cpp',
|
||||
|
@ -7,10 +7,15 @@
|
||||
#include "MediaInfo.h"
|
||||
#ifdef MOZ_OMX_DECODER
|
||||
#include "GrallocImages.h"
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#endif
|
||||
#include "VideoUtils.h"
|
||||
#include "ImageContainer.h"
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include <cutils/properties.h>
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
@ -56,6 +61,15 @@ IsYV12Format(const VideoData::YCbCrBuffer::Plane& aYPlane,
|
||||
aCbPlane.mWidth == aCrPlane.mWidth &&
|
||||
aCbPlane.mHeight == aCrPlane.mHeight;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsInEmulator()
|
||||
{
|
||||
char propQemu[PROPERTY_VALUE_MAX];
|
||||
property_get("ro.kernel.qemu", propQemu, "");
|
||||
return !strncmp(propQemu, "1", 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
VideoData::VideoData(int64_t aOffset, int64_t aTime, int64_t aDuration, int64_t aTimecode)
|
||||
@ -229,7 +243,7 @@ VideoData* VideoData::Create(VideoInfo& aInfo,
|
||||
// Currently our decoder only knows how to output to ImageFormat::PLANAR_YCBCR
|
||||
// format.
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
if (IsYV12Format(Y, Cb, Cr)) {
|
||||
if (IsYV12Format(Y, Cb, Cr) && !IsInEmulator()) {
|
||||
v->mImage = aContainer->CreateImage(ImageFormat::GRALLOC_PLANAR_YCBCR);
|
||||
}
|
||||
#endif
|
||||
@ -329,7 +343,7 @@ VideoData* VideoData::Create(VideoInfo& aInfo,
|
||||
int64_t aOffset,
|
||||
int64_t aTime,
|
||||
int64_t aDuration,
|
||||
mozilla::layers::GraphicBufferLocked* aBuffer,
|
||||
mozilla::layers::TextureClient* aBuffer,
|
||||
bool aKeyframe,
|
||||
int64_t aTimecode,
|
||||
const IntRect& aPicture)
|
||||
|
@ -101,7 +101,7 @@ public:
|
||||
};
|
||||
|
||||
namespace layers {
|
||||
class GraphicBufferLocked;
|
||||
class TextureClient;
|
||||
class PlanarYCbCrImage;
|
||||
}
|
||||
|
||||
@ -179,7 +179,7 @@ public:
|
||||
int64_t aOffset,
|
||||
int64_t aTime,
|
||||
int64_t aDuration,
|
||||
layers::GraphicBufferLocked* aBuffer,
|
||||
layers::TextureClient* aBuffer,
|
||||
bool aKeyframe,
|
||||
int64_t aTimecode,
|
||||
const IntRect& aPicture);
|
||||
|
@ -1505,7 +1505,10 @@ MediaDecoderStateMachine::EnsureActive()
|
||||
return;
|
||||
}
|
||||
mIsReaderIdle = false;
|
||||
SetReaderActive();
|
||||
{
|
||||
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
|
||||
SetReaderActive();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -7,7 +7,7 @@
|
||||
#define MPAPI_h_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "GrallocImages.h"
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
|
||||
namespace MPAPI {
|
||||
|
||||
@ -41,7 +41,7 @@ struct VideoFrame {
|
||||
VideoPlane Y;
|
||||
VideoPlane Cb;
|
||||
VideoPlane Cr;
|
||||
nsRefPtr<mozilla::layers::GraphicBufferLocked> mGraphicBuffer;
|
||||
mozilla::RefPtr<mozilla::layers::TextureClient> mGraphicBuffer;
|
||||
|
||||
VideoFrame() :
|
||||
mTimeUs(0),
|
||||
|
@ -19,6 +19,8 @@
|
||||
#include <ui/Fence.h>
|
||||
#endif
|
||||
|
||||
#include "mozilla/layers/GrallocTextureClient.h"
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Types.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
@ -42,6 +44,7 @@ PRLogModuleInfo *gOmxDecoderLog;
|
||||
using namespace MPAPI;
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::layers;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -190,43 +193,6 @@ private:
|
||||
bool mCompleted;
|
||||
};
|
||||
|
||||
namespace layers {
|
||||
|
||||
VideoGraphicBuffer::VideoGraphicBuffer(const android::wp<android::OmxDecoder> aOmxDecoder,
|
||||
android::MediaBuffer *aBuffer,
|
||||
SurfaceDescriptor& aDescriptor)
|
||||
: GraphicBufferLocked(aDescriptor),
|
||||
mMediaBuffer(aBuffer),
|
||||
mOmxDecoder(aOmxDecoder)
|
||||
{
|
||||
mMediaBuffer->add_ref();
|
||||
}
|
||||
|
||||
VideoGraphicBuffer::~VideoGraphicBuffer()
|
||||
{
|
||||
MOZ_ASSERT(!mMediaBuffer);
|
||||
}
|
||||
|
||||
void
|
||||
VideoGraphicBuffer::Unlock()
|
||||
{
|
||||
android::sp<android::OmxDecoder> omxDecoder = mOmxDecoder.promote();
|
||||
if (omxDecoder.get()) {
|
||||
// Post kNotifyPostReleaseVideoBuffer message to OmxDecoder via ALooper.
|
||||
// The message is delivered to OmxDecoder on ALooper thread.
|
||||
// MediaBuffer::release() could take a very long time.
|
||||
// PostReleaseVideoBuffer() prevents long time locking.
|
||||
omxDecoder->PostReleaseVideoBuffer(mMediaBuffer, mReleaseFenceHandle);
|
||||
} else {
|
||||
NS_WARNING("OmxDecoder is not present");
|
||||
if (mMediaBuffer) {
|
||||
mMediaBuffer->release();
|
||||
}
|
||||
}
|
||||
mMediaBuffer = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace android {
|
||||
@ -837,20 +803,21 @@ bool OmxDecoder::ReadVideo(VideoFrame *aFrame, int64_t aTimeUs,
|
||||
unreadable = 0;
|
||||
}
|
||||
|
||||
mozilla::layers::SurfaceDescriptor *descriptor = nullptr;
|
||||
RefPtr<mozilla::layers::TextureClient> textureClient;
|
||||
if ((mVideoBuffer->graphicBuffer().get())) {
|
||||
descriptor = mNativeWindow->getSurfaceDescriptorFromBuffer(mVideoBuffer->graphicBuffer().get());
|
||||
textureClient = mNativeWindow->getTextureClientFromBuffer(mVideoBuffer->graphicBuffer().get());
|
||||
}
|
||||
|
||||
if (descriptor) {
|
||||
// Change the descriptor's size to video's size. There are cases that
|
||||
// GraphicBuffer's size and actual video size is different.
|
||||
// See Bug 850566.
|
||||
mozilla::layers::SurfaceDescriptorGralloc newDescriptor = descriptor->get_SurfaceDescriptorGralloc();
|
||||
newDescriptor.size() = IntSize(mVideoWidth, mVideoHeight);
|
||||
if (textureClient) {
|
||||
// Manually increment reference count to keep MediaBuffer alive
|
||||
// during TextureClient is in use.
|
||||
mVideoBuffer->add_ref();
|
||||
GrallocTextureClientOGL* grallocClient = static_cast<GrallocTextureClientOGL*>(textureClient.get());
|
||||
grallocClient->SetMediaBuffer(mVideoBuffer);
|
||||
// Set recycle callback for TextureClient
|
||||
textureClient->SetRecycleCallback(OmxDecoder::RecycleCallback, this);
|
||||
|
||||
mozilla::layers::SurfaceDescriptor descWrapper(newDescriptor);
|
||||
aFrame->mGraphicBuffer = new mozilla::layers::VideoGraphicBuffer(this, mVideoBuffer, descWrapper);
|
||||
aFrame->mGraphicBuffer = textureClient;
|
||||
aFrame->mRotation = mVideoRotation;
|
||||
aFrame->mTimeUs = timeUs;
|
||||
aFrame->mKeyFrame = keyFrame;
|
||||
@ -1099,6 +1066,16 @@ void OmxDecoder::ReleaseAllPendingVideoBuffersLocked()
|
||||
releasingVideoBuffers.clear();
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
OmxDecoder::RecycleCallback(TextureClient* aClient, void* aClosure)
|
||||
{
|
||||
OmxDecoder* decoder = static_cast<OmxDecoder*>(aClosure);
|
||||
GrallocTextureClientOGL* client = static_cast<GrallocTextureClientOGL*>(aClient);
|
||||
|
||||
aClient->ClearRecycleCallback();
|
||||
decoder->PostReleaseVideoBuffer(client->GetMediaBuffer(), client->GetReleaseFenceHandle());
|
||||
}
|
||||
|
||||
int64_t OmxDecoder::ProcessCachedData(int64_t aOffset, bool aWaitForCompletion)
|
||||
{
|
||||
// We read data in chunks of 32 KiB. We can reduce this
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "GonkNativeWindow.h"
|
||||
#include "GonkNativeWindowClient.h"
|
||||
#include "GrallocImages.h"
|
||||
#include "mozilla/layers/FenceUtils.h"
|
||||
#include "MP3FrameParser.h"
|
||||
#include "MPAPI.h"
|
||||
@ -21,26 +20,6 @@ namespace android {
|
||||
class OmxDecoder;
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class VideoGraphicBuffer : public GraphicBufferLocked {
|
||||
// XXX change this to an actual smart pointer at some point
|
||||
android::MediaBuffer *mMediaBuffer;
|
||||
android::wp<android::OmxDecoder> mOmxDecoder;
|
||||
public:
|
||||
VideoGraphicBuffer(const android::wp<android::OmxDecoder> aOmxDecoder,
|
||||
android::MediaBuffer *aBuffer,
|
||||
SurfaceDescriptor& aDescriptor);
|
||||
~VideoGraphicBuffer();
|
||||
|
||||
protected:
|
||||
void Unlock();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace android {
|
||||
|
||||
// MediaStreamSource is a DataSource that reads from a MPAPI media stream.
|
||||
@ -85,6 +64,7 @@ class OmxDecoder : public OMXCodecProxy::EventListener {
|
||||
typedef mozilla::MediaResource MediaResource;
|
||||
typedef mozilla::AbstractMediaDecoder AbstractMediaDecoder;
|
||||
typedef mozilla::layers::FenceHandle FenceHandle;
|
||||
typedef mozilla::layers::TextureClient TextureClient;
|
||||
|
||||
enum {
|
||||
kPreferSoftwareCodecs = 1,
|
||||
@ -263,6 +243,8 @@ public:
|
||||
void onMessageReceived(const sp<AMessage> &msg);
|
||||
|
||||
int64_t ProcessCachedData(int64_t aOffset, bool aWaitForCompletion);
|
||||
|
||||
static void RecycleCallback(TextureClient* aClient, void* aClosure);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -312,6 +312,9 @@ RtspOmxReader::ReadMetadata(MediaInfo* aInfo,
|
||||
}
|
||||
|
||||
void RtspOmxReader::SetIdle() {
|
||||
// Call parent class to set OMXCodec idle.
|
||||
MediaOmxReader::SetIdle();
|
||||
|
||||
// Need to pause RTSP streaming OMXCodec decoding.
|
||||
if (mRtspResource) {
|
||||
nsIStreamingProtocolController* controller =
|
||||
@ -320,9 +323,6 @@ void RtspOmxReader::SetIdle() {
|
||||
controller->Pause();
|
||||
}
|
||||
}
|
||||
|
||||
// Call parent class to set OMXCodec idle.
|
||||
MediaOmxReader::SetIdle();
|
||||
}
|
||||
|
||||
void RtspOmxReader::SetActive() {
|
||||
|
@ -669,6 +669,22 @@ CouldBeDOMBinding(nsWrapperCache* aCache)
|
||||
return aCache->IsDOMBinding();
|
||||
}
|
||||
|
||||
inline bool
|
||||
TryToOuterize(JSContext* cx, JS::MutableHandle<JS::Value> rval)
|
||||
{
|
||||
if (js::IsInnerObject(&rval.toObject())) {
|
||||
JS::Rooted<JSObject*> obj(cx, &rval.toObject());
|
||||
obj = JS_ObjectToOuterObject(cx, obj);
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rval.set(JS::ObjectValue(*obj));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Make sure to wrap the given string value into the right compartment, as
|
||||
// needed.
|
||||
MOZ_ALWAYS_INLINE
|
||||
@ -697,10 +713,10 @@ MaybeWrapObjectValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
|
||||
return JS_WrapValue(cx, rval);
|
||||
}
|
||||
|
||||
// We're same-compartment. If we're a WebIDL object, we're done.
|
||||
// We're same-compartment, but even then we might need to wrap
|
||||
// objects specially. Check for that.
|
||||
if (IsDOMObject(obj)) {
|
||||
rval.set(JS::ObjectValue(*obj));
|
||||
return true;
|
||||
return TryToOuterize(cx, rval);
|
||||
}
|
||||
|
||||
// It's not a WebIDL object. But it might be an XPConnect one, in which case
|
||||
@ -821,14 +837,17 @@ WrapNewBindingObject(JSContext* cx, JS::Handle<JSObject*> scope, T* value,
|
||||
MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
|
||||
#endif
|
||||
|
||||
rval.set(JS::ObjectValue(*obj));
|
||||
|
||||
bool sameCompartment =
|
||||
js::GetObjectCompartment(obj) == js::GetContextCompartment(cx);
|
||||
if (sameCompartment && couldBeDOMBinding) {
|
||||
rval.set(JS::ObjectValue(*obj));
|
||||
return true;
|
||||
// We only need to outerize Window objects, so anything inheriting from
|
||||
// nsGlobalWindow (which inherits from EventTarget itself).
|
||||
return IsBaseOf<nsGlobalWindow, T>::value || IsSame<EventTarget, T>::value ?
|
||||
TryToOuterize(cx, rval) : true;
|
||||
}
|
||||
|
||||
rval.set(JS::ObjectValue(*obj));
|
||||
return JS_WrapValue(cx, rval);
|
||||
}
|
||||
|
||||
|
@ -1365,14 +1365,14 @@ nsGonkCameraControl::GetRecorderProfileManagerImpl()
|
||||
}
|
||||
|
||||
void
|
||||
nsGonkCameraControl::OnNewPreviewFrame(layers::GraphicBufferLocked* aBuffer)
|
||||
nsGonkCameraControl::OnNewPreviewFrame(layers::TextureClient* aBuffer)
|
||||
{
|
||||
nsRefPtr<Image> frame = mImageContainer->CreateImage(ImageFormat::GRALLOC_PLANAR_YCBCR);
|
||||
|
||||
GrallocImage* videoImage = static_cast<GrallocImage*>(frame.get());
|
||||
|
||||
GrallocImage::GrallocData data;
|
||||
data.mGraphicBuffer = static_cast<layers::GraphicBufferLocked*>(aBuffer);
|
||||
data.mGraphicBuffer = aBuffer;
|
||||
data.mPicSize = IntSize(mCurrentConfiguration.mPreviewSize.width,
|
||||
mCurrentConfiguration.mPreviewSize.height);
|
||||
videoImage->SetData(data);
|
||||
@ -1415,7 +1415,7 @@ OnAutoFocusComplete(nsGonkCameraControl* gc, bool aSuccess)
|
||||
}
|
||||
|
||||
void
|
||||
OnNewPreviewFrame(nsGonkCameraControl* gc, layers::GraphicBufferLocked* aBuffer)
|
||||
OnNewPreviewFrame(nsGonkCameraControl* gc, layers::TextureClient* aBuffer)
|
||||
{
|
||||
gc->OnNewPreviewFrame(aBuffer);
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ namespace android {
|
||||
namespace mozilla {
|
||||
|
||||
namespace layers {
|
||||
class GraphicBufferLocked;
|
||||
class TextureClient;
|
||||
class ImageContainer;
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ public:
|
||||
void OnAutoFocusComplete(bool aSuccess);
|
||||
void OnTakePictureComplete(uint8_t* aData, uint32_t aLength);
|
||||
void OnTakePictureError();
|
||||
void OnNewPreviewFrame(layers::GraphicBufferLocked* aBuffer);
|
||||
void OnNewPreviewFrame(layers::TextureClient* aBuffer);
|
||||
void OnRecorderEvent(int msg, int ext1, int ext2);
|
||||
void OnError(CameraControlListener::CameraErrorContext aWhere,
|
||||
CameraControlListener::CameraError aError);
|
||||
@ -163,7 +163,7 @@ private:
|
||||
void OnTakePictureComplete(nsGonkCameraControl* gc, uint8_t* aData, uint32_t aLength);
|
||||
void OnTakePictureError(nsGonkCameraControl* gc);
|
||||
void OnAutoFocusComplete(nsGonkCameraControl* gc, bool aSuccess);
|
||||
void OnNewPreviewFrame(nsGonkCameraControl* gc, layers::GraphicBufferLocked* aBuffer);
|
||||
void OnNewPreviewFrame(nsGonkCameraControl* gc, layers::TextureClient* aBuffer);
|
||||
void OnShutter(nsGonkCameraControl* gc);
|
||||
void OnClosed(nsGonkCameraControl* gc);
|
||||
void OnError(nsGonkCameraControl* gc, CameraControlListener::CameraError aError,
|
||||
|
@ -22,7 +22,9 @@
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "nsDebug.h"
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "GonkCameraControl.h"
|
||||
#include "GonkNativeWindow.h"
|
||||
#include "CameraCommon.h"
|
||||
@ -48,7 +50,7 @@ GonkCameraHardware::OnNewFrame()
|
||||
if (mClosing) {
|
||||
return;
|
||||
}
|
||||
nsRefPtr<GraphicBufferLocked> buffer = mNativeWindow->getCurrentBuffer();
|
||||
RefPtr<TextureClient> buffer = mNativeWindow->getCurrentBuffer();
|
||||
if (!buffer) {
|
||||
DOM_CAMERA_LOGW("received null frame");
|
||||
return;
|
||||
|
@ -14,18 +14,19 @@ Cu.import("resource://gre/modules/ContactService.jsm", imports);
|
||||
Cu.import("resource://gre/modules/Promise.jsm", imports);
|
||||
Cu.importGlobalProperties(["indexedDB"]);
|
||||
|
||||
// |const| will not work because
|
||||
// it will make the Promise object immutable before assigning.
|
||||
// Using |let| and Object.freeze() instead.
|
||||
let {
|
||||
const {
|
||||
STORE_NAME,
|
||||
SAVED_GETALL_STORE_NAME,
|
||||
REVISION_STORE,
|
||||
DB_NAME,
|
||||
ContactService,
|
||||
Promise
|
||||
} = imports;
|
||||
Object.freeze(imports);
|
||||
// |const| will not work because
|
||||
// it will make the Promise object immutable before assigning.
|
||||
// Using Object.defineProperty() instead.
|
||||
Object.defineProperty(this, "Promise", {
|
||||
value: imports.Promise, writable: false, configurable: false
|
||||
});
|
||||
|
||||
let DEBUG = false;
|
||||
function debug(str) {
|
||||
|
@ -28,7 +28,8 @@ XPCOMUtils.defineLazyServiceGetter(this, "powerManagerService",
|
||||
// Limit the number of pending messages for a given page.
|
||||
let kMaxPendingMessages;
|
||||
try {
|
||||
kMaxPendingMessages = Services.prefs.getIntPref("dom.messages.maxPendingMessages");
|
||||
kMaxPendingMessages =
|
||||
Services.prefs.getIntPref("dom.messages.maxPendingMessages");
|
||||
} catch(e) {
|
||||
// getIntPref throws when the pref is not set.
|
||||
kMaxPendingMessages = 5;
|
||||
@ -66,7 +67,7 @@ function SystemMessageInternal() {
|
||||
this._pages = [];
|
||||
|
||||
// The set of listeners. This is a multi-dimensional object. The _listeners
|
||||
// object itself is a map from manifest ID -> an array mapping proccesses to
|
||||
// object itself is a map from manifest URL -> an array mapping proccesses to
|
||||
// windows. We do this so that we can track both what processes we have to
|
||||
// send system messages to as well as supporting the single-process case
|
||||
// where we track windows instead.
|
||||
@ -91,10 +92,11 @@ function SystemMessageInternal() {
|
||||
|
||||
SystemMessageInternal.prototype = {
|
||||
|
||||
_getMessageConfigurator: function _getMessageConfigurator(aType) {
|
||||
_getMessageConfigurator: function(aType) {
|
||||
debug("_getMessageConfigurator for type: " + aType);
|
||||
if (this._configurators[aType] === undefined) {
|
||||
let contractID = "@mozilla.org/dom/system-messages/configurator/" + aType + ";1";
|
||||
let contractID =
|
||||
"@mozilla.org/dom/system-messages/configurator/" + aType + ";1";
|
||||
if (contractID in Cc) {
|
||||
debug(contractID + " is registered, creating an instance");
|
||||
this._configurators[aType] =
|
||||
@ -107,7 +109,7 @@ SystemMessageInternal.prototype = {
|
||||
return this._configurators[aType] || defaultMessageConfigurator;
|
||||
},
|
||||
|
||||
_cancelCpuWakeLock: function _cancelCpuWakeLock(aPageKey) {
|
||||
_cancelCpuWakeLock: function(aPageKey) {
|
||||
let cpuWakeLock = this._cpuWakeLocks[aPageKey];
|
||||
if (cpuWakeLock) {
|
||||
debug("Releasing the CPU wake lock for page key = " + aPageKey);
|
||||
@ -117,7 +119,7 @@ SystemMessageInternal.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_acquireCpuWakeLock: function _acquireCpuWakeLock(aPageKey) {
|
||||
_acquireCpuWakeLock: function(aPageKey) {
|
||||
let cpuWakeLock = this._cpuWakeLocks[aPageKey];
|
||||
if (!cpuWakeLock) {
|
||||
// We have to ensure the CPU doesn't sleep during the process of the page
|
||||
@ -157,7 +159,7 @@ SystemMessageInternal.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_findPage: function _findPage(aType, aPageURL, aManifestURL) {
|
||||
_findPage: function(aType, aPageURL, aManifestURL) {
|
||||
let page = null;
|
||||
this._pages.some(function(aPage) {
|
||||
if (this._isPageMatched(aPage, aType, aPageURL, aManifestURL)) {
|
||||
@ -168,7 +170,7 @@ SystemMessageInternal.prototype = {
|
||||
return page;
|
||||
},
|
||||
|
||||
sendMessage: function sendMessage(aType, aMessage, aPageURI, aManifestURI, aExtra) {
|
||||
sendMessage: function(aType, aMessage, aPageURI, aManifestURI, aExtra) {
|
||||
// Buffer system messages until the webapps' registration is ready,
|
||||
// so that we can know the correct pages registered to be sent.
|
||||
if (!this._webappsRegistryReady) {
|
||||
@ -212,7 +214,7 @@ SystemMessageInternal.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
broadcastMessage: function broadcastMessage(aType, aMessage, aExtra) {
|
||||
broadcastMessage: function(aType, aMessage, aExtra) {
|
||||
// Buffer system messages until the webapps' registration is ready,
|
||||
// so that we can know the correct pages registered to be broadcasted.
|
||||
if (!this._webappsRegistryReady) {
|
||||
@ -235,8 +237,8 @@ SystemMessageInternal.prototype = {
|
||||
let result = this._sendMessageCommon(aType,
|
||||
aMessage,
|
||||
messageID,
|
||||
aPage.uri,
|
||||
aPage.manifest,
|
||||
aPage.pageURL,
|
||||
aPage.manifestURL,
|
||||
aExtra);
|
||||
debug("Returned status of sending message: " + result);
|
||||
|
||||
@ -255,7 +257,7 @@ SystemMessageInternal.prototype = {
|
||||
}, this);
|
||||
},
|
||||
|
||||
registerPage: function registerPage(aType, aPageURI, aManifestURI) {
|
||||
registerPage: function(aType, aPageURI, aManifestURI) {
|
||||
if (!aPageURI || !aManifestURI) {
|
||||
throw Cr.NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
@ -272,12 +274,12 @@ SystemMessageInternal.prototype = {
|
||||
}
|
||||
|
||||
this._pages.push({ type: aType,
|
||||
uri: pageURL,
|
||||
manifest: manifestURL,
|
||||
pageURL: pageURL,
|
||||
manifestURL: manifestURL,
|
||||
pendingMessages: [] });
|
||||
},
|
||||
|
||||
_findTargetIndex: function _findTargetIndex(aTargets, aTarget) {
|
||||
_findTargetIndex: function(aTargets, aTarget) {
|
||||
if (!aTargets || !aTarget) {
|
||||
return -1;
|
||||
}
|
||||
@ -290,18 +292,18 @@ SystemMessageInternal.prototype = {
|
||||
return -1;
|
||||
},
|
||||
|
||||
_isEmptyObject: function _isEmptyObject(aObj) {
|
||||
_isEmptyObject: function(aObj) {
|
||||
for (let name in aObj) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
_removeTargetFromListener: function _removeTargetFromListener(aTarget,
|
||||
aManifest,
|
||||
aRemoveListener,
|
||||
aUri) {
|
||||
let targets = this._listeners[aManifest];
|
||||
_removeTargetFromListener: function(aTarget,
|
||||
aManifestURL,
|
||||
aRemoveListener,
|
||||
aPageURL) {
|
||||
let targets = this._listeners[aManifestURL];
|
||||
if (!targets) {
|
||||
return false;
|
||||
}
|
||||
@ -312,22 +314,22 @@ SystemMessageInternal.prototype = {
|
||||
}
|
||||
|
||||
if (aRemoveListener) {
|
||||
debug("remove the listener for " + aManifest);
|
||||
delete this._listeners[aManifest];
|
||||
debug("remove the listener for " + aManifestURL);
|
||||
delete this._listeners[aManifestURL];
|
||||
return true;
|
||||
}
|
||||
|
||||
let target = targets[index];
|
||||
if (aUri && target.winCounts[aUri] !== undefined &&
|
||||
--target.winCounts[aUri] === 0) {
|
||||
delete target.winCounts[aUri];
|
||||
if (aPageURL && target.winCounts[aPageURL] !== undefined &&
|
||||
--target.winCounts[aPageURL] === 0) {
|
||||
delete target.winCounts[aPageURL];
|
||||
}
|
||||
|
||||
if (this._isEmptyObject(target.winCounts)) {
|
||||
if (targets.length === 1) {
|
||||
// If it's the only one, get rid of this manifest entirely.
|
||||
debug("remove the listener for " + aManifest);
|
||||
delete this._listeners[aManifest];
|
||||
// If it's the only one, get rid of the entry of manifest URL entirely.
|
||||
debug("remove the listener for " + aManifestURL);
|
||||
delete this._listeners[aManifestURL];
|
||||
} else {
|
||||
// If more than one left, remove this one and leave the rest.
|
||||
targets.splice(index, 1);
|
||||
@ -336,7 +338,7 @@ SystemMessageInternal.prototype = {
|
||||
return true;
|
||||
},
|
||||
|
||||
receiveMessage: function receiveMessage(aMessage) {
|
||||
receiveMessage: function(aMessage) {
|
||||
let msg = aMessage.json;
|
||||
|
||||
// To prevent the hacked child process from sending commands to parent
|
||||
@ -348,7 +350,7 @@ SystemMessageInternal.prototype = {
|
||||
"SystemMessageManager:HasPendingMessages",
|
||||
"SystemMessageManager:Message:Return:OK",
|
||||
"SystemMessageManager:HandleMessagesDone"].indexOf(aMessage.name) != -1) {
|
||||
if (!aMessage.target.assertContainApp(msg.manifest)) {
|
||||
if (!aMessage.target.assertContainApp(msg.manifestURL)) {
|
||||
debug("Got message from a child process containing illegal manifest URL.");
|
||||
return null;
|
||||
}
|
||||
@ -360,37 +362,42 @@ SystemMessageInternal.prototype = {
|
||||
break;
|
||||
case "SystemMessageManager:Register":
|
||||
{
|
||||
debug("Got Register from " + msg.uri + " @ " + msg.manifest);
|
||||
let uri = msg.uri;
|
||||
debug("Got Register from " + msg.pageURL + " @ " + msg.manifestURL);
|
||||
let pageURL = msg.pageURL;
|
||||
let targets, index;
|
||||
if (!(targets = this._listeners[msg.manifest])) {
|
||||
if (!(targets = this._listeners[msg.manifestURL])) {
|
||||
let winCounts = {};
|
||||
winCounts[uri] = 1;
|
||||
this._listeners[msg.manifest] = [{ target: aMessage.target,
|
||||
winCounts: winCounts }];
|
||||
} else if ((index = this._findTargetIndex(targets, aMessage.target)) === -1) {
|
||||
winCounts[pageURL] = 1;
|
||||
this._listeners[msg.manifestURL] = [{ target: aMessage.target,
|
||||
winCounts: winCounts }];
|
||||
} else if ((index = this._findTargetIndex(targets,
|
||||
aMessage.target)) === -1) {
|
||||
let winCounts = {};
|
||||
winCounts[uri] = 1;
|
||||
winCounts[pageURL] = 1;
|
||||
targets.push({ target: aMessage.target,
|
||||
winCounts: winCounts });
|
||||
} else {
|
||||
let winCounts = targets[index].winCounts;
|
||||
if (winCounts[uri] === undefined) {
|
||||
winCounts[uri] = 1;
|
||||
if (winCounts[pageURL] === undefined) {
|
||||
winCounts[pageURL] = 1;
|
||||
} else {
|
||||
winCounts[uri]++;
|
||||
winCounts[pageURL]++;
|
||||
}
|
||||
}
|
||||
|
||||
debug("listeners for " + msg.manifest + " innerWinID " + msg.innerWindowID);
|
||||
debug("listeners for " + msg.manifestURL +
|
||||
" innerWinID " + msg.innerWindowID);
|
||||
break;
|
||||
}
|
||||
case "child-process-shutdown":
|
||||
{
|
||||
debug("Got child-process-shutdown from " + aMessage.target);
|
||||
for (let manifest in this._listeners) {
|
||||
// See if any processes in this manifest have this target.
|
||||
if (this._removeTargetFromListener(aMessage.target, manifest, true, null)) {
|
||||
for (let manifestURL in this._listeners) {
|
||||
// See if any processes in this manifest URL have this target.
|
||||
if (this._removeTargetFromListener(aMessage.target,
|
||||
manifestURL,
|
||||
true,
|
||||
null)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -398,18 +405,22 @@ SystemMessageInternal.prototype = {
|
||||
}
|
||||
case "SystemMessageManager:Unregister":
|
||||
{
|
||||
debug("Got Unregister from " + aMessage.target + "innerWinID " + msg.innerWindowID);
|
||||
this._removeTargetFromListener(aMessage.target, msg.manifest, false, msg.uri);
|
||||
debug("Got Unregister from " + aMessage.target +
|
||||
" innerWinID " + msg.innerWindowID);
|
||||
this._removeTargetFromListener(aMessage.target,
|
||||
msg.manifestURL,
|
||||
false,
|
||||
msg.pageURL);
|
||||
break;
|
||||
}
|
||||
case "SystemMessageManager:GetPendingMessages":
|
||||
{
|
||||
debug("received SystemMessageManager:GetPendingMessages " + msg.type +
|
||||
" for " + msg.uri + " @ " + msg.manifest);
|
||||
" for " + msg.pageURL + " @ " + msg.manifestURL);
|
||||
|
||||
// This is a sync call used to return the pending messages for a page.
|
||||
// Find the right page to get its corresponding pending messages.
|
||||
let page = this._findPage(msg.type, msg.uri, msg.manifest);
|
||||
let page = this._findPage(msg.type, msg.pageURL, msg.manifestURL);
|
||||
if (!page) {
|
||||
return;
|
||||
}
|
||||
@ -428,19 +439,19 @@ SystemMessageInternal.prototype = {
|
||||
aMessage.target
|
||||
.sendAsyncMessage("SystemMessageManager:GetPendingMessages:Return",
|
||||
{ type: msg.type,
|
||||
manifest: msg.manifest,
|
||||
uri: msg.uri,
|
||||
manifestURL: msg.manifestURL,
|
||||
pageURL: msg.pageURL,
|
||||
msgQueue: pendingMessages });
|
||||
break;
|
||||
}
|
||||
case "SystemMessageManager:HasPendingMessages":
|
||||
{
|
||||
debug("received SystemMessageManager:HasPendingMessages " + msg.type +
|
||||
" for " + msg.uri + " @ " + msg.manifest);
|
||||
" for " + msg.pageURL + " @ " + msg.manifestURL);
|
||||
|
||||
// This is a sync call used to return if a page has pending messages.
|
||||
// Find the right page to get its corresponding pending messages.
|
||||
let page = this._findPage(msg.type, msg.uri, msg.manifest);
|
||||
let page = this._findPage(msg.type, msg.pageURL, msg.manifestURL);
|
||||
if (!page) {
|
||||
return false;
|
||||
}
|
||||
@ -451,11 +462,11 @@ SystemMessageInternal.prototype = {
|
||||
case "SystemMessageManager:Message:Return:OK":
|
||||
{
|
||||
debug("received SystemMessageManager:Message:Return:OK " + msg.type +
|
||||
" for " + msg.uri + " @ " + msg.manifest);
|
||||
" for " + msg.pageURL + " @ " + msg.manifestURL);
|
||||
|
||||
// We need to clean up the pending message since the app has already
|
||||
// received it, thus avoiding the re-lanunched app handling it again.
|
||||
let page = this._findPage(msg.type, msg.uri, msg.manifest);
|
||||
let page = this._findPage(msg.type, msg.pageURL, msg.manifestURL);
|
||||
if (page) {
|
||||
let pendingMessages = page.pendingMessages;
|
||||
for (let i = 0; i < pendingMessages.length; i++) {
|
||||
@ -470,7 +481,8 @@ SystemMessageInternal.prototype = {
|
||||
case "SystemMessageManager:HandleMessagesDone":
|
||||
{
|
||||
debug("received SystemMessageManager:HandleMessagesDone " + msg.type +
|
||||
" with " + msg.handledCount + " for " + msg.uri + " @ " + msg.manifest);
|
||||
" with " + msg.handledCount + " for " + msg.pageURL +
|
||||
" @ " + msg.manifestURL);
|
||||
|
||||
// A page has finished handling some of its system messages, so we try
|
||||
// to release the CPU wake lock we acquired on behalf of that page.
|
||||
@ -480,7 +492,7 @@ SystemMessageInternal.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
observe: function observe(aSubject, aTopic, aData) {
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case "xpcom-shutdown":
|
||||
kMessages.forEach(function(aMsg) {
|
||||
@ -504,7 +516,8 @@ SystemMessageInternal.prototype = {
|
||||
switch (aSysMsg.how) {
|
||||
case "send":
|
||||
this.sendMessage(
|
||||
aSysMsg.type, aSysMsg.msg, aSysMsg.pageURI, aSysMsg.manifestURI, aSysMsg.extra);
|
||||
aSysMsg.type, aSysMsg.msg,
|
||||
aSysMsg.pageURI, aSysMsg.manifestURI, aSysMsg.extra);
|
||||
break;
|
||||
case "broadcast":
|
||||
this.broadcastMessage(aSysMsg.type, aSysMsg.msg, aSysMsg.extra);
|
||||
@ -516,7 +529,7 @@ SystemMessageInternal.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_queueMessage: function _queueMessage(aPage, aMessage, aMessageID) {
|
||||
_queueMessage: function(aPage, aMessage, aMessageID) {
|
||||
// Queue the message for this page because we've never known if an app is
|
||||
// opened or not. We'll clean it up when the app has already received it.
|
||||
aPage.pendingMessages.push({ msg: aMessage, msgID: aMessageID });
|
||||
@ -525,7 +538,7 @@ SystemMessageInternal.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_openAppPage: function _openAppPage(aPage, aMessage, aExtra, aMsgSentStatus) {
|
||||
_openAppPage: function(aPage, aMessage, aExtra, aMsgSentStatus) {
|
||||
// This means the app must be brought to the foreground.
|
||||
let showApp = this._getMessageConfigurator(aPage.type).mustShowRunningApp;
|
||||
|
||||
@ -540,21 +553,23 @@ SystemMessageInternal.prototype = {
|
||||
let onlyShowApp = (aMsgSentStatus === MSG_SENT_SUCCESS) && showApp;
|
||||
|
||||
// We don't need to send the full object to observers.
|
||||
let page = { uri: aPage.uri,
|
||||
manifest: aPage.manifest,
|
||||
let page = { pageURL: aPage.pageURL,
|
||||
manifestURL: aPage.manifestURL,
|
||||
type: aPage.type,
|
||||
extra: aExtra,
|
||||
target: aMessage.target,
|
||||
onlyShowApp: onlyShowApp,
|
||||
showApp: showApp };
|
||||
debug("Asking to open " + JSON.stringify(page));
|
||||
Services.obs.notifyObservers(this, "system-messages-open-app", JSON.stringify(page));
|
||||
Services.obs.notifyObservers(this,
|
||||
"system-messages-open-app",
|
||||
JSON.stringify(page));
|
||||
},
|
||||
|
||||
_isPageMatched: function _isPageMatched(aPage, aType, aPageURI, aManifestURI) {
|
||||
_isPageMatched: function(aPage, aType, aPageURL, aManifestURL) {
|
||||
return (aPage.type === aType &&
|
||||
aPage.manifest === aManifestURI &&
|
||||
aPage.uri === aPageURI)
|
||||
aPage.manifestURL === aManifestURL &&
|
||||
aPage.pageURL === aPageURL)
|
||||
},
|
||||
|
||||
_createKeyForPage: function _createKeyForPage(aPage) {
|
||||
@ -566,8 +581,8 @@ SystemMessageInternal.prototype = {
|
||||
.createInstance(Ci.nsICryptoHash);
|
||||
hasher.init(hasher.SHA1);
|
||||
|
||||
// add uri and action to the hash
|
||||
["type", "manifest", "uri"].forEach(function(aProp) {
|
||||
// add manifest/page URL and action to the hash
|
||||
["type", "manifestURL", "pageURL"].forEach(function(aProp) {
|
||||
let data = converter.convertToByteArray(aPage[aProp], {});
|
||||
hasher.update(data, data.length);
|
||||
});
|
||||
@ -575,29 +590,29 @@ SystemMessageInternal.prototype = {
|
||||
return hasher.finish(true);
|
||||
},
|
||||
|
||||
_sendMessageCommon:
|
||||
function _sendMessageCommon(aType, aMessage, aMessageID, aPageURI, aManifestURI, aExtra) {
|
||||
_sendMessageCommon: function(aType, aMessage, aMessageID,
|
||||
aPageURL, aManifestURL, aExtra) {
|
||||
// Don't send the system message not granted by the app's permissions.
|
||||
if (!SystemMessagePermissionsChecker
|
||||
.isSystemMessagePermittedToSend(aType,
|
||||
aPageURI,
|
||||
aManifestURI)) {
|
||||
aPageURL,
|
||||
aManifestURL)) {
|
||||
return MSG_SENT_FAILURE_PERM_DENIED;
|
||||
}
|
||||
|
||||
let appPageIsRunning = false;
|
||||
let pageKey = this._createKeyForPage({ type: aType,
|
||||
manifest: aManifestURI,
|
||||
uri: aPageURI });
|
||||
manifestURL: aManifestURL,
|
||||
pageURL: aPageURL });
|
||||
|
||||
let targets = this._listeners[aManifestURI];
|
||||
let targets = this._listeners[aManifestURL];
|
||||
if (targets) {
|
||||
for (let index = 0; index < targets.length; ++index) {
|
||||
let target = targets[index];
|
||||
// We only need to send the system message to the targets (processes)
|
||||
// which contain the window page that matches the manifest/page URL of
|
||||
// the destination of system message.
|
||||
if (target.winCounts[aPageURI] === undefined) {
|
||||
if (target.winCounts[aPageURL] === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -615,8 +630,8 @@ SystemMessageInternal.prototype = {
|
||||
manager.sendAsyncMessage("SystemMessageManager:Message",
|
||||
{ type: aType,
|
||||
msg: aMessage,
|
||||
manifest: aManifestURI,
|
||||
uri: aPageURI,
|
||||
manifestURL: aManifestURL,
|
||||
pageURL: aPageURL,
|
||||
msgID: aMessageID });
|
||||
}
|
||||
}
|
||||
@ -637,7 +652,8 @@ SystemMessageInternal.prototype = {
|
||||
|
||||
classID: Components.ID("{70589ca5-91ac-4b9e-b839-d6a88167d714}"),
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISystemMessagesInternal, Ci.nsIObserver])
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISystemMessagesInternal,
|
||||
Ci.nsIObserver])
|
||||
}
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SystemMessageInternal]);
|
||||
|
@ -39,8 +39,8 @@ function SystemMessageManager() {
|
||||
// Pending messages for this page, keyed by message type.
|
||||
this._pendings = {};
|
||||
|
||||
// Flag to specify if this process has already registered manifest.
|
||||
this._registerManifestReady = false;
|
||||
// Flag to specify if this process has already registered the manifest URL.
|
||||
this._registerManifestURLReady = false;
|
||||
|
||||
// Flag to determine this process is a parent or child process.
|
||||
let appInfo = Cc["@mozilla.org/xre/app-info;1"];
|
||||
@ -57,7 +57,7 @@ function SystemMessageManager() {
|
||||
SystemMessageManager.prototype = {
|
||||
__proto__: DOMRequestIpcHelper.prototype,
|
||||
|
||||
_dispatchMessage: function sysMessMgr_dispatchMessage(aType, aDispatcher, aMessage) {
|
||||
_dispatchMessage: function(aType, aDispatcher, aMessage) {
|
||||
if (aDispatcher.isHandling) {
|
||||
// Queue up the incomming message if we're currently dispatching a
|
||||
// message; we'll send the message once we finish with the current one.
|
||||
@ -73,8 +73,7 @@ SystemMessageManager.prototype = {
|
||||
aDispatcher.isHandling = true;
|
||||
|
||||
// We get a json blob, but in some cases we want another kind of object
|
||||
// to be dispatched.
|
||||
// To do so, we check if we have a with a contract ID of
|
||||
// to be dispatched. To do so, we check if we have a valid contract ID of
|
||||
// "@mozilla.org/dom/system-messages/wrapper/TYPE;1" component implementing
|
||||
// nsISystemMessageWrapper.
|
||||
debug("Dispatching " + JSON.stringify(aMessage) + "\n");
|
||||
@ -99,17 +98,27 @@ SystemMessageManager.prototype = {
|
||||
// so the parent can release the CPU wake lock it took on our behalf.
|
||||
cpmm.sendAsyncMessage("SystemMessageManager:HandleMessagesDone",
|
||||
{ type: aType,
|
||||
manifest: this._manifest,
|
||||
uri: this._uri,
|
||||
manifestURL: this._manifestURL,
|
||||
pageURL: this._pageURL,
|
||||
handledCount: 1 });
|
||||
|
||||
aDispatcher.isHandling = false;
|
||||
|
||||
if (aDispatcher.messages.length > 0) {
|
||||
this._dispatchMessage(aType, aDispatcher, aDispatcher.messages.shift());
|
||||
} else {
|
||||
// No more messages that need to be handled, we can notify the
|
||||
// ContentChild to release the CPU wake lock grabbed by the ContentParent
|
||||
// (i.e. NewWakeLockOnBehalfOfProcess()) and reset the process's priority.
|
||||
//
|
||||
// TODO: Bug 874353 - Remove SystemMessageHandledListener in ContentParent
|
||||
Services.obs.notifyObservers(/* aSubject */ null,
|
||||
"handle-system-messages-done",
|
||||
/* aData */ null);
|
||||
}
|
||||
},
|
||||
|
||||
mozSetMessageHandler: function sysMessMgr_setMessageHandler(aType, aHandler) {
|
||||
mozSetMessageHandler: function(aType, aHandler) {
|
||||
debug("set message handler for [" + aType + "] " + aHandler);
|
||||
|
||||
if (this._isInBrowserElement) {
|
||||
@ -137,11 +146,11 @@ SystemMessageManager.prototype = {
|
||||
// Ask for the list of currently pending messages.
|
||||
cpmm.sendAsyncMessage("SystemMessageManager:GetPendingMessages",
|
||||
{ type: aType,
|
||||
uri: this._uri,
|
||||
manifest: this._manifest });
|
||||
pageURL: this._pageURL,
|
||||
manifestURL: this._manifestURL });
|
||||
},
|
||||
|
||||
mozHasPendingMessage: function sysMessMgr_hasPendingMessage(aType) {
|
||||
mozHasPendingMessage: function(aType) {
|
||||
debug("asking pending message for [" + aType + "]");
|
||||
|
||||
if (this._isInBrowserElement) {
|
||||
@ -157,11 +166,11 @@ SystemMessageManager.prototype = {
|
||||
|
||||
return cpmm.sendSyncMessage("SystemMessageManager:HasPendingMessages",
|
||||
{ type: aType,
|
||||
uri: this._uri,
|
||||
manifest: this._manifest })[0];
|
||||
pageURL: this._pageURL,
|
||||
manifestURL: this._manifestURL })[0];
|
||||
},
|
||||
|
||||
uninit: function sysMessMgr_uninit() {
|
||||
uninit: function() {
|
||||
this._dispatchers = null;
|
||||
this._pendings = null;
|
||||
|
||||
@ -171,13 +180,13 @@ SystemMessageManager.prototype = {
|
||||
|
||||
if (this._isInBrowserElement) {
|
||||
debug("the app loaded in the browser doesn't need to unregister " +
|
||||
"the manifest for listening to the system messages");
|
||||
"the manifest URL for listening to the system messages");
|
||||
return;
|
||||
}
|
||||
|
||||
cpmm.sendAsyncMessage("SystemMessageManager:Unregister",
|
||||
{ manifest: this._manifest,
|
||||
uri: this._uri,
|
||||
{ manifestURL: this._manifestURL,
|
||||
pageURL: this._pageURL,
|
||||
innerWindowID: this.innerWindowID });
|
||||
},
|
||||
|
||||
@ -191,17 +200,20 @@ SystemMessageManager.prototype = {
|
||||
// This one will be received when the starting child process wants to
|
||||
// retrieve the pending system messages from the parent (i.e. after
|
||||
// sending SystemMessageManager:GetPendingMessages).
|
||||
receiveMessage: function sysMessMgr_receiveMessage(aMessage) {
|
||||
receiveMessage: function(aMessage) {
|
||||
let msg = aMessage.data;
|
||||
debug("receiveMessage " + aMessage.name + " for [" + msg.type + "] " +
|
||||
"with manifest = " + msg.manifest + " and uri = " + msg.uri);
|
||||
"with manifest URL = " + msg.manifestURL +
|
||||
" and page URL = " + msg.pageURL);
|
||||
|
||||
// Multiple windows can share the same target (process), the content
|
||||
// window needs to check if the manifest/page URL is matched. Only
|
||||
// *one* window should handle the system message.
|
||||
if (msg.manifest !== this._manifest || msg.uri !== this._uri) {
|
||||
if (msg.manifestURL !== this._manifestURL ||
|
||||
msg.pageURL !== this._pageURL) {
|
||||
debug("This page shouldn't handle the messages because its " +
|
||||
"manifest = " + this._manifest + " and uri = " + this._uri);
|
||||
"manifest URL = " + this._manifestURL +
|
||||
" and page URL = " + this._pageURL);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -210,8 +222,8 @@ SystemMessageManager.prototype = {
|
||||
// so a re-launched app won't handle it again, which is redundant.
|
||||
cpmm.sendAsyncMessage("SystemMessageManager:Message:Return:OK",
|
||||
{ type: msg.type,
|
||||
manifest: this._manifest,
|
||||
uri: this._uri,
|
||||
manifestURL: this._manifestURL,
|
||||
pageURL: this._pageURL,
|
||||
msgID: msg.msgID });
|
||||
}
|
||||
|
||||
@ -226,17 +238,20 @@ SystemMessageManager.prototype = {
|
||||
this._dispatchMessage(msg.type, dispatcher, aMsg);
|
||||
}, this);
|
||||
} else {
|
||||
// We need to notify the parent that all the queued system messages have
|
||||
// been handled (notice |handledCount: messages.length|), so the parent
|
||||
// can release the CPU wake lock it took on our behalf.
|
||||
// Since no handlers are registered, we need to notify the parent as if
|
||||
// all the queued system messages have been handled (notice |handledCount:
|
||||
// messages.length|), so the parent can release the CPU wake lock it took
|
||||
// on our behalf.
|
||||
cpmm.sendAsyncMessage("SystemMessageManager:HandleMessagesDone",
|
||||
{ type: msg.type,
|
||||
manifest: this._manifest,
|
||||
uri: this._uri,
|
||||
manifestURL: this._manifestURL,
|
||||
pageURL: this._pageURL,
|
||||
handledCount: messages.length });
|
||||
}
|
||||
|
||||
if (!dispatcher || !dispatcher.isHandling) {
|
||||
// We also need to notify the ContentChild to release the CPU wake lock
|
||||
// grabbed by the ContentParent (i.e. NewWakeLockOnBehalfOfProcess()) and
|
||||
// reset the process's priority.
|
||||
//
|
||||
// TODO: Bug 874353 - Remove SystemMessageHandledListener in ContentParent
|
||||
Services.obs.notifyObservers(/* aSubject */ null,
|
||||
"handle-system-messages-done",
|
||||
@ -245,20 +260,21 @@ SystemMessageManager.prototype = {
|
||||
},
|
||||
|
||||
// nsIDOMGlobalPropertyInitializer implementation.
|
||||
init: function sysMessMgr_init(aWindow) {
|
||||
init: function(aWindow) {
|
||||
debug("init");
|
||||
this.initDOMRequestHelper(aWindow, ["SystemMessageManager:Message",
|
||||
"SystemMessageManager:GetPendingMessages:Return"]);
|
||||
this.initDOMRequestHelper(aWindow,
|
||||
["SystemMessageManager:Message",
|
||||
"SystemMessageManager:GetPendingMessages:Return"]);
|
||||
|
||||
let principal = aWindow.document.nodePrincipal;
|
||||
this._isInBrowserElement = principal.isInBrowserElement;
|
||||
this._uri = principal.URI.spec;
|
||||
this._pageURL = principal.URI.spec;
|
||||
|
||||
let appsService = Cc["@mozilla.org/AppsService;1"]
|
||||
.getService(Ci.nsIAppsService);
|
||||
this._manifest = appsService.getManifestURLByLocalId(principal.appId);
|
||||
this._manifestURL = appsService.getManifestURLByLocalId(principal.appId);
|
||||
|
||||
// Two cases are valid to register the manifest for the current process:
|
||||
// Two cases are valid to register the manifest URL for the current process:
|
||||
// 1. This is asked by a child process (parent process must be ready).
|
||||
// 2. Parent process has already constructed the |SystemMessageInternal|.
|
||||
// Otherwise, delay to do it when the |SystemMessageInternal| is ready.
|
||||
@ -271,35 +287,35 @@ SystemMessageManager.prototype = {
|
||||
}
|
||||
}
|
||||
if (readyToRegister) {
|
||||
this._registerManifest();
|
||||
this._registerManifestURL();
|
||||
}
|
||||
|
||||
debug("done");
|
||||
},
|
||||
|
||||
observe: function sysMessMgr_observe(aSubject, aTopic, aData) {
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
if (aTopic === kSystemMessageInternalReady) {
|
||||
this._registerManifest();
|
||||
this._registerManifestURL();
|
||||
}
|
||||
|
||||
// Call the DOMRequestIpcHelper.observe method.
|
||||
this.__proto__.__proto__.observe.call(this, aSubject, aTopic, aData);
|
||||
},
|
||||
|
||||
_registerManifest: function sysMessMgr_registerManifest() {
|
||||
_registerManifestURL: function() {
|
||||
if (this._isInBrowserElement) {
|
||||
debug("the app loaded in the browser doesn't need to register " +
|
||||
"the manifest for listening to the system messages");
|
||||
"the manifest URL for listening to the system messages");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._registerManifestReady) {
|
||||
if (!this._registerManifestURLReady) {
|
||||
cpmm.sendAsyncMessage("SystemMessageManager:Register",
|
||||
{ manifest: this._manifest,
|
||||
uri: this._uri,
|
||||
{ manifestURL: this._manifestURL,
|
||||
pageURL: this._pageURL,
|
||||
innerWindowID: this.innerWindowID });
|
||||
|
||||
this._registerManifestReady = true;
|
||||
this._registerManifestURLReady = true;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -249,18 +249,18 @@ this.SystemMessagePermissionsChecker = {
|
||||
* app's page at run-time based on the current app's permissions.
|
||||
* @param string aSysMsgName
|
||||
* The system messsage name.
|
||||
* @param string aPageURI
|
||||
* The app's page URI.
|
||||
* @param string aPageURL
|
||||
* The app's page URL.
|
||||
* @param string aManifestURL
|
||||
* The app's manifest URL.
|
||||
* @returns bool
|
||||
* Is permitted or not.
|
||||
**/
|
||||
isSystemMessagePermittedToSend:
|
||||
function isSystemMessagePermittedToSend(aSysMsgName, aPageURI, aManifestURL) {
|
||||
function isSystemMessagePermittedToSend(aSysMsgName, aPageURL, aManifestURL) {
|
||||
debug("isSystemMessagePermittedToSend(): " +
|
||||
"aSysMsgName: " + aSysMsgName + ", " +
|
||||
"aPageURI: " + aPageURI + ", " +
|
||||
"aPageURL: " + aPageURL + ", " +
|
||||
"aManifestURL: " + aManifestURL);
|
||||
|
||||
let permNames = this.getSystemMessagePermissions(aSysMsgName);
|
||||
@ -268,7 +268,7 @@ this.SystemMessagePermissionsChecker = {
|
||||
return false;
|
||||
}
|
||||
|
||||
let pageURI = Services.io.newURI(aPageURI, null, null);
|
||||
let pageURI = Services.io.newURI(aPageURL, null, null);
|
||||
for (let permName in permNames) {
|
||||
let permNamesWithAccess = permNames[permName];
|
||||
|
||||
|
@ -419,7 +419,7 @@ nsPluginTag::GetMimeTypes(uint32_t* aCount, char16_t*** aResults)
|
||||
*aCount = count;
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
(*aResults)[i] = ToNewUnicode(mMimeTypes[i]);
|
||||
(*aResults)[i] = ToNewUnicode(NS_ConvertUTF8toUTF16(mMimeTypes[i]));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -436,7 +436,7 @@ nsPluginTag::GetMimeDescriptions(uint32_t* aCount, char16_t*** aResults)
|
||||
*aCount = count;
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
(*aResults)[i] = ToNewUnicode(mMimeDescriptions[i]);
|
||||
(*aResults)[i] = ToNewUnicode(NS_ConvertUTF8toUTF16(mMimeDescriptions[i]));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -453,7 +453,7 @@ nsPluginTag::GetExtensions(uint32_t* aCount, char16_t*** aResults)
|
||||
*aCount = count;
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
(*aResults)[i] = ToNewUnicode(mExtensions[i]);
|
||||
(*aResults)[i] = ToNewUnicode(NS_ConvertUTF8toUTF16(mExtensions[i]));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -39,6 +39,7 @@ support-files =
|
||||
[test_bug863792.html]
|
||||
[test_bug967694.html]
|
||||
[test_bug985859.html]
|
||||
[test_bug986930.html]
|
||||
[test_cocoa_focus.html]
|
||||
skip-if = toolkit != "cocoa"
|
||||
support-files = cocoa_focus.html
|
||||
|
20
dom/plugins/test/mochitest/test_bug986930.html
Normal file
20
dom/plugins/test/mochitest/test_bug986930.html
Normal file
@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<title>Test for Bug 986930</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script class="testbody" type="application/javascript">
|
||||
var testPlugin = getTestPlugin("Test Plug-in");
|
||||
|
||||
var mimeDescriptions = testPlugin.getMimeDescriptions({});
|
||||
|
||||
is(mimeDescriptions[0], "Test \u2122 mimetype",
|
||||
"Plugin should handle non-ascii mime description");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -31,7 +31,7 @@
|
||||
<string>tst</string>
|
||||
</array>
|
||||
<key>WebPluginTypeDescription</key>
|
||||
<string>Test mimetype</string>
|
||||
<string>Test ™ mimetype</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
|
@ -26,7 +26,7 @@ BEGIN
|
||||
VALUE "CompanyName", "mozilla.org"
|
||||
VALUE "FileDescription", L"Plug-in for testing purposes.\x2122 (\x0939\x093f\x0928\x094d\x0926\x0940 \x4e2d\x6587 \x0627\x0644\x0639\x0631\x0628\x064a\x0629)"
|
||||
VALUE "FileExtents", "tst"
|
||||
VALUE "FileOpenName", "Test mimetype"
|
||||
VALUE "FileOpenName", L"Test \x2122 mimetype"
|
||||
VALUE "FileVersion", "1.0"
|
||||
VALUE "InternalName", "nptest"
|
||||
VALUE "MIMEType", "application/x-test"
|
||||
|
@ -3,4 +3,4 @@ const char *sPluginDescription = "Plug-in for testing purposes.\xE2\x84\xA2 " \
|
||||
"(\xe0\xa4\xb9\xe0\xa4\xbf\xe0\xa4\xa8\xe0\xa5\x8d\xe0\xa4\xa6\xe0\xa5\x80 " \
|
||||
"\xe4\xb8\xad\xe6\x96\x87 " \
|
||||
"\xd8\xa7\xd9\x84\xd8\xb9\xd8\xb1\xd8\xa8\xd9\x8a\xd8\xa9)";
|
||||
const char *sMimeDescription = "application/x-test:tst:Test mimetype";
|
||||
const char *sMimeDescription = "application/x-test:tst:Test \xE2\x84\xA2 mimetype";
|
||||
|
@ -304,6 +304,9 @@ partial interface Window {
|
||||
*/
|
||||
[Throws] readonly attribute unsigned long long mozPaintCount;
|
||||
|
||||
[Pure]
|
||||
attribute EventHandler onwheel;
|
||||
|
||||
attribute EventHandler ondevicemotion;
|
||||
attribute EventHandler ondeviceorientation;
|
||||
attribute EventHandler ondeviceproximity;
|
||||
|
@ -111,11 +111,17 @@ var WifiManager = (function() {
|
||||
schedScanRecovery: libcutils.property_get("ro.moz.wifi.sched_scan_recover") === "false" ? false : true,
|
||||
driverDelay: libcutils.property_get("ro.moz.wifi.driverDelay"),
|
||||
p2pSupported: libcutils.property_get("ro.moz.wifi.p2p_supported") === "1",
|
||||
eapSimSupported: libcutils.property_get("ro.moz.wifi.eapsim_supported") === "1",
|
||||
ifname: libcutils.property_get("wifi.interface")
|
||||
};
|
||||
}
|
||||
|
||||
let {sdkVersion, unloadDriverEnabled, schedScanRecovery, driverDelay, p2pSupported, ifname} = getStartupPrefs();
|
||||
let {sdkVersion, unloadDriverEnabled, schedScanRecovery,
|
||||
driverDelay, p2pSupported, eapSimSupported, ifname} = getStartupPrefs();
|
||||
|
||||
let capabilities = {
|
||||
eapSim: eapSimSupported
|
||||
};
|
||||
|
||||
let wifiListener = {
|
||||
onWaitEvent: function(event, iface) {
|
||||
@ -1303,6 +1309,10 @@ var WifiManager = (function() {
|
||||
});
|
||||
};
|
||||
|
||||
manager.getCapabilities = function() {
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
return manager;
|
||||
})();
|
||||
|
||||
@ -1767,7 +1777,7 @@ function WifiWorker() {
|
||||
});
|
||||
|
||||
try {
|
||||
self._allowWpaEap = Services.prefs.getBoolPref("b2g.wifi.allow_unsafe_wpa_eap");
|
||||
self._allowWpaEap = WifiManager.getCapabilities().eapSim;
|
||||
} catch (e) {
|
||||
self._allowWpaEap = false;
|
||||
}
|
||||
|
10
gfx/2d/2D.h
10
gfx/2d/2D.h
@ -336,6 +336,16 @@ public:
|
||||
* DataSourceSurface's data can be accessed directly.
|
||||
*/
|
||||
virtual TemporaryRef<DataSourceSurface> GetDataSurface() = 0;
|
||||
|
||||
void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) {
|
||||
mUserData.Add(key, userData, destroy);
|
||||
}
|
||||
void *GetUserData(UserDataKey *key) {
|
||||
return mUserData.Get(key);
|
||||
}
|
||||
|
||||
protected:
|
||||
UserData mUserData;
|
||||
};
|
||||
|
||||
class DataSourceSurface : public SourceSurface
|
||||
|
@ -5,7 +5,7 @@
|
||||
ifdef MOZ_ANGLE_RENDERER
|
||||
|
||||
libs::
|
||||
ifdef MOZ_HAS_WINSDK_WITH_D3D
|
||||
ifdef MOZ_D3DCOMPILER_DLL_PATH
|
||||
cp -fp "$(MOZ_D3DCOMPILER_DLL_PATH)" "$(DIST)/bin"
|
||||
else
|
||||
ifdef MOZ_D3DCOMPILER_CAB
|
||||
|
@ -5,6 +5,8 @@
|
||||
ifndef GNU_CC
|
||||
# Enable unwind semantics for exception handlers in response to warning C4530.
|
||||
OS_CPPFLAGS += -EHsc
|
||||
else
|
||||
OS_CXXFLAGS := $(filter-out -fno-exceptions,$(OS_CXXFLAGS)) -fexceptions
|
||||
endif
|
||||
|
||||
# End build_angle.gypi transcription.
|
||||
@ -15,19 +17,9 @@ ifndef MOZ_HAS_WINSDK_WITH_D3D
|
||||
CXXFLAGS += -I'$(MOZ_DIRECTX_SDK_PATH)/include'
|
||||
endif
|
||||
|
||||
ifdef GNU_CC
|
||||
|
||||
OS_CXXFLAGS := $(filter-out -fno-exceptions,$(OS_CXXFLAGS)) -fexceptions
|
||||
OS_LIBS += -ld3d9 -ldxguid
|
||||
|
||||
else
|
||||
|
||||
ifdef MOZ_HAS_WINSDK_WITH_D3D
|
||||
EXTRA_DSO_LDOPTS = d3d9.lib dxguid.lib delayimp.lib
|
||||
EXTRA_DSO_LDOPTS = $(call EXPAND_LIBNAME,d3d9 dxguid)
|
||||
else
|
||||
EXTRA_DSO_LDOPTS = '$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)/d3d9.lib' \
|
||||
'$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)/dxguid.lib' \
|
||||
delayimp.lib
|
||||
endif
|
||||
|
||||
EXTRA_DSO_LDOPTS = $(call EXPAND_LIBNAME_PATH,d3d9 dxguid,$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX))
|
||||
endif
|
||||
EXTRA_DSO_LDOPTS += $(call EXPAND_LIBNAME,delayimp)
|
||||
|
@ -47,10 +47,6 @@ public:
|
||||
InfallibleTArray<coord>& texCoords() {
|
||||
return mTexCoords;
|
||||
}
|
||||
|
||||
unsigned int elements() {
|
||||
return mVertexCoords.Length();
|
||||
}
|
||||
private:
|
||||
// Reserve inline storage for one quad (2 triangles, 3 coords).
|
||||
nsAutoTArray<coord, 6> mVertexCoords;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "nsRect.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxUtils.h"
|
||||
#include "GLDrawRectHelper.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
@ -147,25 +148,10 @@ GLBlitTextureImageHelper::BlitTextureImage(TextureImage *aSrc, const nsIntRect&
|
||||
ScopedBindTextureUnit autoTexUnit(mGL, LOCAL_GL_TEXTURE0);
|
||||
ScopedBindTexture autoTex(mGL, aSrc->GetTextureID());
|
||||
|
||||
mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
||||
|
||||
mGL->fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.vertCoords().Elements());
|
||||
mGL->fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.texCoords().Elements());
|
||||
|
||||
mGL->fEnableVertexAttribArray(0);
|
||||
mGL->fEnableVertexAttribArray(1);
|
||||
|
||||
mGL->fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.elements());
|
||||
|
||||
mGL->fDisableVertexAttribArray(0);
|
||||
mGL->fDisableVertexAttribArray(1);
|
||||
|
||||
mGL->DrawRectHelper()->DrawRects(0, 1, rects);
|
||||
} while (aSrc->NextTile());
|
||||
} while (aDst->NextTile());
|
||||
|
||||
mGL->fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, nullptr);
|
||||
mGL->fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, nullptr);
|
||||
|
||||
// unbind the previous texture from the framebuffer
|
||||
SetBlitFramebufferForDestTexture(0);
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "GLBlitHelper.h"
|
||||
#include "GLBlitTextureImageHelper.h"
|
||||
#include "GLReadTexImageHelper.h"
|
||||
#include "GLDrawRectHelper.h"
|
||||
|
||||
#include "gfxCrashReporterUtils.h"
|
||||
#include "gfxUtils.h"
|
||||
@ -483,7 +484,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
||||
|
||||
// Load OpenGL ES 2.0 symbols, or desktop if we aren't using ES 2.
|
||||
if (mInitialized) {
|
||||
if (IsGLES2()) {
|
||||
if (IsGLES()) {
|
||||
SymLoadStruct symbols_ES2[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fGetShaderPrecisionFormat, { "GetShaderPrecisionFormat", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fClearDepthf, { "ClearDepthf", nullptr } },
|
||||
@ -1337,7 +1338,7 @@ GLContext::ChooseGLFormats(const SurfaceCaps& caps) const
|
||||
// If we're on ES2 hardware and we have an explicit request for 16 bits of color or less
|
||||
// OR we don't support full 8-bit color, return a 4444 or 565 format.
|
||||
bool bpp16 = caps.bpp16;
|
||||
if (IsGLES2()) {
|
||||
if (IsGLES()) {
|
||||
if (!IsExtensionSupported(OES_rgb8_rgba8))
|
||||
bpp16 = true;
|
||||
} else {
|
||||
@ -1347,7 +1348,7 @@ GLContext::ChooseGLFormats(const SurfaceCaps& caps) const
|
||||
}
|
||||
|
||||
if (bpp16) {
|
||||
MOZ_ASSERT(IsGLES2());
|
||||
MOZ_ASSERT(IsGLES());
|
||||
if (caps.alpha) {
|
||||
formats.color_texInternalFormat = LOCAL_GL_RGBA;
|
||||
formats.color_texFormat = LOCAL_GL_RGBA;
|
||||
@ -1363,11 +1364,11 @@ GLContext::ChooseGLFormats(const SurfaceCaps& caps) const
|
||||
formats.color_texType = LOCAL_GL_UNSIGNED_BYTE;
|
||||
|
||||
if (caps.alpha) {
|
||||
formats.color_texInternalFormat = IsGLES2() ? LOCAL_GL_RGBA : LOCAL_GL_RGBA8;
|
||||
formats.color_texInternalFormat = IsGLES() ? LOCAL_GL_RGBA : LOCAL_GL_RGBA8;
|
||||
formats.color_texFormat = LOCAL_GL_RGBA;
|
||||
formats.color_rbFormat = LOCAL_GL_RGBA8;
|
||||
} else {
|
||||
formats.color_texInternalFormat = IsGLES2() ? LOCAL_GL_RGB : LOCAL_GL_RGB8;
|
||||
formats.color_texInternalFormat = IsGLES() ? LOCAL_GL_RGB : LOCAL_GL_RGB8;
|
||||
formats.color_texFormat = LOCAL_GL_RGB;
|
||||
formats.color_rbFormat = LOCAL_GL_RGB8;
|
||||
}
|
||||
@ -1386,12 +1387,12 @@ GLContext::ChooseGLFormats(const SurfaceCaps& caps) const
|
||||
|
||||
// Be clear that these are 0 if unavailable.
|
||||
formats.depthStencil = 0;
|
||||
if (!IsGLES2() || IsExtensionSupported(OES_packed_depth_stencil)) {
|
||||
if (!IsGLES() || IsExtensionSupported(OES_packed_depth_stencil)) {
|
||||
formats.depthStencil = LOCAL_GL_DEPTH24_STENCIL8;
|
||||
}
|
||||
|
||||
formats.depth = 0;
|
||||
if (IsGLES2()) {
|
||||
if (IsGLES()) {
|
||||
if (IsExtensionSupported(OES_depth24)) {
|
||||
formats.depth = LOCAL_GL_DEPTH_COMPONENT24;
|
||||
} else {
|
||||
@ -1685,6 +1686,7 @@ GLContext::MarkDestroyed()
|
||||
mBlitHelper = nullptr;
|
||||
mBlitTextureImageHelper = nullptr;
|
||||
mReadTexImageHelper = nullptr;
|
||||
mDrawRectHelper = nullptr;
|
||||
|
||||
mTexGarbageBin->GLContextTeardown();
|
||||
} else {
|
||||
@ -2010,6 +2012,16 @@ GLContext::ReadTexImageHelper()
|
||||
return mReadTexImageHelper;
|
||||
}
|
||||
|
||||
GLDrawRectHelper*
|
||||
GLContext::DrawRectHelper()
|
||||
{
|
||||
if (!mDrawRectHelper) {
|
||||
mDrawRectHelper = new GLDrawRectHelper(this);
|
||||
}
|
||||
|
||||
return mDrawRectHelper;
|
||||
}
|
||||
|
||||
bool
|
||||
DoesStringMatch(const char* aString, const char *aWantedString)
|
||||
{
|
||||
|
@ -71,6 +71,7 @@ namespace mozilla {
|
||||
class GLBlitTextureImageHelper;
|
||||
class GLReadTexImageHelper;
|
||||
class SharedSurface_GL;
|
||||
class GLDrawRectHelper;
|
||||
}
|
||||
|
||||
namespace layers {
|
||||
@ -287,16 +288,6 @@ public:
|
||||
|
||||
virtual bool IsCurrent() = 0;
|
||||
|
||||
/**
|
||||
* If this context is the GLES2 API, returns TRUE.
|
||||
* This means that various GLES2 restrictions might be in effect (modulo
|
||||
* extensions).
|
||||
*/
|
||||
inline bool IsGLES2() const {
|
||||
return IsAtLeast(ContextProfile::OpenGLES, 200);
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
bool mInitialized;
|
||||
@ -1779,7 +1770,7 @@ public:
|
||||
|
||||
private:
|
||||
void raw_fGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
|
||||
MOZ_ASSERT(IsGLES2());
|
||||
MOZ_ASSERT(IsGLES());
|
||||
|
||||
BEFORE_GL_CALL;
|
||||
ASSERT_SYMBOL_PRESENT(fGetShaderPrecisionFormat);
|
||||
@ -1789,7 +1780,7 @@ private:
|
||||
|
||||
public:
|
||||
void fGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
|
||||
if (IsGLES2()) {
|
||||
if (IsGLES()) {
|
||||
raw_fGetShaderPrecisionFormat(shadertype, precisiontype, range, precision);
|
||||
} else {
|
||||
// Fall back to automatic values because almost all desktop hardware supports the OpenGL standard precisions.
|
||||
@ -1877,7 +1868,7 @@ public:
|
||||
|
||||
private:
|
||||
void raw_fDepthRange(GLclampf a, GLclampf b) {
|
||||
MOZ_ASSERT(!IsGLES2());
|
||||
MOZ_ASSERT(!IsGLES());
|
||||
|
||||
BEFORE_GL_CALL;
|
||||
ASSERT_SYMBOL_PRESENT(fDepthRange);
|
||||
@ -1886,7 +1877,7 @@ private:
|
||||
}
|
||||
|
||||
void raw_fDepthRangef(GLclampf a, GLclampf b) {
|
||||
MOZ_ASSERT(IsGLES2());
|
||||
MOZ_ASSERT(IsGLES());
|
||||
|
||||
BEFORE_GL_CALL;
|
||||
ASSERT_SYMBOL_PRESENT(fDepthRangef);
|
||||
@ -1895,7 +1886,7 @@ private:
|
||||
}
|
||||
|
||||
void raw_fClearDepth(GLclampf v) {
|
||||
MOZ_ASSERT(!IsGLES2());
|
||||
MOZ_ASSERT(!IsGLES());
|
||||
|
||||
BEFORE_GL_CALL;
|
||||
ASSERT_SYMBOL_PRESENT(fClearDepth);
|
||||
@ -1904,7 +1895,7 @@ private:
|
||||
}
|
||||
|
||||
void raw_fClearDepthf(GLclampf v) {
|
||||
MOZ_ASSERT(IsGLES2());
|
||||
MOZ_ASSERT(IsGLES());
|
||||
|
||||
BEFORE_GL_CALL;
|
||||
ASSERT_SYMBOL_PRESENT(fClearDepthf);
|
||||
@ -1914,7 +1905,7 @@ private:
|
||||
|
||||
public:
|
||||
void fDepthRange(GLclampf a, GLclampf b) {
|
||||
if (IsGLES2()) {
|
||||
if (IsGLES()) {
|
||||
raw_fDepthRangef(a, b);
|
||||
} else {
|
||||
raw_fDepthRange(a, b);
|
||||
@ -1922,7 +1913,7 @@ public:
|
||||
}
|
||||
|
||||
void fClearDepth(GLclampf v) {
|
||||
if (IsGLES2()) {
|
||||
if (IsGLES()) {
|
||||
raw_fClearDepthf(v);
|
||||
} else {
|
||||
raw_fClearDepth(v);
|
||||
@ -2735,11 +2726,13 @@ protected:
|
||||
ScopedDeletePtr<GLBlitHelper> mBlitHelper;
|
||||
ScopedDeletePtr<GLBlitTextureImageHelper> mBlitTextureImageHelper;
|
||||
ScopedDeletePtr<GLReadTexImageHelper> mReadTexImageHelper;
|
||||
ScopedDeletePtr<GLDrawRectHelper> mDrawRectHelper;
|
||||
|
||||
public:
|
||||
GLBlitHelper* BlitHelper();
|
||||
GLBlitTextureImageHelper* BlitTextureImageHelper();
|
||||
GLReadTexImageHelper* ReadTexImageHelper();
|
||||
GLDrawRectHelper* DrawRectHelper();
|
||||
|
||||
// Assumes shares are created by all sharing with the same global context.
|
||||
bool SharesWith(const GLContext* other) const {
|
||||
|
122
gfx/gl/GLDrawRectHelper.cpp
Normal file
122
gfx/gl/GLDrawRectHelper.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=8 sts=4 et sw=4 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "GLDrawRectHelper.h"
|
||||
#include "GLContext.h"
|
||||
#include "DecomposeIntoNoRepeatTriangles.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
|
||||
static GLfloat quad[] = {
|
||||
/* First quad vertices */
|
||||
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
|
||||
/* Then quad texcoords */
|
||||
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
|
||||
};
|
||||
|
||||
#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
|
||||
|
||||
GLDrawRectHelper::GLDrawRectHelper(GLContext *aGL)
|
||||
: mGL(aGL)
|
||||
{
|
||||
mGL->fGenBuffers(1, &mQuadVBO);
|
||||
mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
|
||||
|
||||
mGL->fBufferData(LOCAL_GL_ARRAY_BUFFER, sizeof(quad), quad, LOCAL_GL_STATIC_DRAW);
|
||||
mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
GLDrawRectHelper::~GLDrawRectHelper()
|
||||
{
|
||||
mGL->fDeleteBuffers(1, &mQuadVBO);
|
||||
}
|
||||
|
||||
void
|
||||
GLDrawRectHelper::DrawRect(GLuint aVertAttribIndex,
|
||||
GLuint aTexCoordAttribIndex)
|
||||
{
|
||||
mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
|
||||
|
||||
mGL->fVertexAttribPointer(aVertAttribIndex,
|
||||
2, LOCAL_GL_FLOAT,
|
||||
LOCAL_GL_FALSE,
|
||||
0, BUFFER_OFFSET(0));
|
||||
mGL->fEnableVertexAttribArray(aVertAttribIndex);
|
||||
|
||||
if (aTexCoordAttribIndex != GLuint(-1)) {
|
||||
mGL->fVertexAttribPointer(aTexCoordAttribIndex,
|
||||
2, LOCAL_GL_FLOAT,
|
||||
LOCAL_GL_FALSE,
|
||||
0, BUFFER_OFFSET(sizeof(quad)/2));
|
||||
mGL->fEnableVertexAttribArray(aTexCoordAttribIndex);
|
||||
}
|
||||
|
||||
mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
if (aTexCoordAttribIndex != GLuint(-1)) {
|
||||
mGL->fDisableVertexAttribArray(aTexCoordAttribIndex);
|
||||
}
|
||||
mGL->fDisableVertexAttribArray(aVertAttribIndex);
|
||||
|
||||
mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
void
|
||||
GLDrawRectHelper::DrawRects(GLuint aVertAttribIndex,
|
||||
GLuint aTexCoordAttribIndex,
|
||||
RectTriangles& aRects)
|
||||
{
|
||||
GLsizei bytes = aRects.vertCoords().Length() * 2 * sizeof(GLfloat);
|
||||
GLsizei total = bytes;
|
||||
if (aTexCoordAttribIndex != GLuint(-1)) {
|
||||
total *= 2;
|
||||
}
|
||||
|
||||
GLuint vbo;
|
||||
mGL->fGenBuffers(1, &vbo);
|
||||
mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, vbo);
|
||||
mGL->fBufferData(LOCAL_GL_ARRAY_BUFFER,
|
||||
total,
|
||||
nullptr,
|
||||
LOCAL_GL_STREAM_DRAW);
|
||||
|
||||
mGL->fBufferSubData(LOCAL_GL_ARRAY_BUFFER,
|
||||
0,
|
||||
bytes,
|
||||
aRects.vertCoords().Elements());
|
||||
mGL->fVertexAttribPointer(aVertAttribIndex,
|
||||
2, LOCAL_GL_FLOAT,
|
||||
LOCAL_GL_FALSE,
|
||||
0, BUFFER_OFFSET(0));
|
||||
mGL->fEnableVertexAttribArray(aVertAttribIndex);
|
||||
|
||||
if (aTexCoordAttribIndex != GLuint(-1)) {
|
||||
mGL->fBufferSubData(LOCAL_GL_ARRAY_BUFFER,
|
||||
bytes,
|
||||
bytes,
|
||||
aRects.texCoords().Elements());
|
||||
mGL->fVertexAttribPointer(aTexCoordAttribIndex,
|
||||
2, LOCAL_GL_FLOAT,
|
||||
LOCAL_GL_FALSE,
|
||||
0, BUFFER_OFFSET(bytes));
|
||||
mGL->fEnableVertexAttribArray(aTexCoordAttribIndex);
|
||||
}
|
||||
|
||||
mGL->fDrawArrays(LOCAL_GL_TRIANGLES, 0, aRects.vertCoords().Length());
|
||||
|
||||
if (aTexCoordAttribIndex != GLuint(-1)) {
|
||||
mGL->fDisableVertexAttribArray(aTexCoordAttribIndex);
|
||||
}
|
||||
mGL->fDisableVertexAttribArray(aVertAttribIndex);
|
||||
|
||||
mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
||||
|
||||
mGL->fDeleteBuffers(1, &vbo);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
41
gfx/gl/GLDrawRectHelper.h
Normal file
41
gfx/gl/GLDrawRectHelper.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=8 sts=4 et sw=4 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GLDRAWRECTHELPER_H_
|
||||
#define GLDRAWRECTHELPER_H_
|
||||
|
||||
#include "GLContextTypes.h"
|
||||
#include "GLConsts.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
|
||||
class GLContext;
|
||||
class RectTriangles;
|
||||
|
||||
/** Helper to draw rectangles to the frame buffer. */
|
||||
class GLDrawRectHelper MOZ_FINAL
|
||||
{
|
||||
public:
|
||||
GLDrawRectHelper(GLContext* aGL);
|
||||
~GLDrawRectHelper();
|
||||
|
||||
void DrawRect(GLuint aVertAttribIndex,
|
||||
GLuint aTexCoordAttribIndex);
|
||||
void DrawRects(GLuint aVertAttribIndex,
|
||||
GLuint aTexCoordAttribIndex,
|
||||
RectTriangles& aRects);
|
||||
|
||||
private:
|
||||
// The GLContext is the sole owner of the GLDrawHelper.
|
||||
GLContext* mGL;
|
||||
GLuint mQuadVBO;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // GLDRAWRECTHELPER_H_
|
@ -168,7 +168,7 @@ GetActualReadFormats(GLContext* gl,
|
||||
}
|
||||
|
||||
bool fallback = true;
|
||||
if (gl->IsGLES2()) {
|
||||
if (gl->IsGLES()) {
|
||||
GLenum auxFormat = 0;
|
||||
GLenum auxType = 0;
|
||||
|
||||
@ -209,6 +209,10 @@ GetActualReadFormats(GLContext* gl,
|
||||
static void SwapRAndBComponents(DataSourceSurface* surf)
|
||||
{
|
||||
uint8_t *row = surf->GetData();
|
||||
if (!row) {
|
||||
MOZ_ASSERT(false, "SwapRAndBComponents: Failed to get data from DataSourceSurface.");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t rowBytes = surf->GetSize().width*4;
|
||||
size_t rowHole = surf->Stride() - rowBytes;
|
||||
@ -764,7 +768,7 @@ GLReadTexImageHelper::ReadTexImage(GLuint aTextureId,
|
||||
mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, rb);
|
||||
|
||||
GLenum rbInternalFormat =
|
||||
mGL->IsGLES2()
|
||||
mGL->IsGLES()
|
||||
? (mGL->IsExtensionSupported(GLContext::OES_rgb8_rgba8) ? LOCAL_GL_RGBA8 : LOCAL_GL_RGBA4)
|
||||
: LOCAL_GL_RGBA;
|
||||
mGL->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, rbInternalFormat, aSize.width, aSize.height);
|
||||
|
@ -225,7 +225,7 @@ TexSubImage2DHelper(GLContext *gl,
|
||||
GLint pixelsize, GLenum format,
|
||||
GLenum type, const GLvoid* pixels)
|
||||
{
|
||||
if (gl->IsGLES2()) {
|
||||
if (gl->IsGLES()) {
|
||||
if (stride == width * pixelsize) {
|
||||
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
|
||||
std::min(GetAddressAlignment((ptrdiff_t)pixels),
|
||||
@ -278,7 +278,7 @@ TexImage2DHelper(GLContext *gl,
|
||||
GLint pixelsize, GLint border, GLenum format,
|
||||
GLenum type, const GLvoid *pixels)
|
||||
{
|
||||
if (gl->IsGLES2()) {
|
||||
if (gl->IsGLES()) {
|
||||
|
||||
NS_ASSERTION(format == (GLenum)internalformat,
|
||||
"format and internalformat not the same for glTexImage2D on GLES2");
|
||||
|
@ -322,7 +322,7 @@ const GLubyte* glGetString_mozilla(GrGLenum name)
|
||||
// on the GL implementation and change them to match what GLContext actually exposes.
|
||||
|
||||
if (name == LOCAL_GL_VERSION) {
|
||||
if (sGLContext.get()->IsGLES2()) {
|
||||
if (sGLContext.get()->IsGLES()) {
|
||||
return reinterpret_cast<const GLubyte*>("OpenGL ES 2.0");
|
||||
} else {
|
||||
return reinterpret_cast<const GLubyte*>("2.0");
|
||||
@ -336,7 +336,7 @@ const GLubyte* glGetString_mozilla(GrGLenum name)
|
||||
if (!extensionsStringBuilt) {
|
||||
extensionsString[0] = '\0';
|
||||
|
||||
if (sGLContext.get()->IsGLES2()) {
|
||||
if (sGLContext.get()->IsGLES()) {
|
||||
// OES is only applicable to GLES2
|
||||
if (sGLContext.get()->IsExtensionSupported(GLContext::OES_packed_depth_stencil)) {
|
||||
strcat(extensionsString, "GL_OES_packed_depth_stencil ");
|
||||
@ -384,7 +384,7 @@ const GLubyte* glGetString_mozilla(GrGLenum name)
|
||||
return reinterpret_cast<const GLubyte*>(extensionsString);
|
||||
|
||||
} else if (name == LOCAL_GL_SHADING_LANGUAGE_VERSION) {
|
||||
if (sGLContext.get()->IsGLES2()) {
|
||||
if (sGLContext.get()->IsGLES()) {
|
||||
return reinterpret_cast<const GLubyte*>("OpenGL ES GLSL ES 1.0");
|
||||
} else {
|
||||
return reinterpret_cast<const GLubyte*>("1.10");
|
||||
@ -770,7 +770,7 @@ static GrGLInterface* CreateGrGLInterfaceFromGLContext(GLContext* context)
|
||||
context->MakeCurrent();
|
||||
|
||||
// We support both desktop GL and GLES2
|
||||
if (context->IsGLES2()) {
|
||||
if (context->IsGLES()) {
|
||||
i->fStandard = kGLES_GrGLStandard;
|
||||
} else {
|
||||
i->fStandard = kGL_GrGLStandard;
|
||||
|
@ -38,6 +38,7 @@ EXPORTS += [
|
||||
'GLContextSymbols.h',
|
||||
'GLContextTypes.h',
|
||||
'GLDefs.h',
|
||||
'GLDrawRectHelper.h',
|
||||
'GLLibraryEGL.h',
|
||||
'GLLibraryLoader.h',
|
||||
'GLReadTexImageHelper.h',
|
||||
@ -123,6 +124,7 @@ UNIFIED_SOURCES += [
|
||||
'GLContextFeatures.cpp',
|
||||
'GLContextTypes.cpp',
|
||||
'GLDebugUtils.cpp',
|
||||
'GLDrawRectHelper.cpp',
|
||||
'GLLibraryEGL.cpp',
|
||||
'GLLibraryLoader.cpp',
|
||||
'GLReadTexImageHelper.cpp',
|
||||
|
@ -14,8 +14,10 @@
|
||||
#include "gfxImageSurface.h"
|
||||
#include "YCbCrUtils.h" // for YCbCr conversions
|
||||
|
||||
#include <OMX_IVCommon.h>
|
||||
#include <ColorConverter.h>
|
||||
#include <cutils/properties.h>
|
||||
#include <OMX_IVCommon.h>
|
||||
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
using namespace android;
|
||||
@ -46,36 +48,28 @@ struct GraphicBufferAutoUnlock {
|
||||
~GraphicBufferAutoUnlock() { mGraphicBuffer->unlock(); }
|
||||
};
|
||||
|
||||
static bool
|
||||
IsInEmulator()
|
||||
{
|
||||
char propQemu[PROPERTY_VALUE_MAX];
|
||||
property_get("ro.kernel.qemu", propQemu, "");
|
||||
return !strncmp(propQemu, "1", 1);
|
||||
}
|
||||
|
||||
GrallocImage::GrallocImage()
|
||||
: PlanarYCbCrImage(nullptr),
|
||||
mBufferAllocated(false),
|
||||
mGraphicBufferLocked(nullptr),
|
||||
mTextureClient(nullptr)
|
||||
: PlanarYCbCrImage(nullptr)
|
||||
{
|
||||
mFormat = ImageFormat::GRALLOC_PLANAR_YCBCR;
|
||||
}
|
||||
|
||||
GrallocImage::~GrallocImage()
|
||||
{
|
||||
// If we have a texture client, the latter takes over the responsibility to
|
||||
// unlock the GraphicBufferLocked.
|
||||
if (mGraphicBufferLocked.get() && !mTextureClient) {
|
||||
// mBufferAllocated is set when gralloc buffer is allocated
|
||||
// in the GrallocImage.
|
||||
// XXX the way of handling gralloc buffer in GrallocImage is inconsistent
|
||||
// between gralloc buffer allocation in GrallocImage and
|
||||
// gralloc buffer allocation outside of GrallocImage
|
||||
if (mBufferAllocated) {
|
||||
ImageBridgeChild *ibc = ImageBridgeChild::GetSingleton();
|
||||
ibc->DeallocSurfaceDescriptorGralloc(mGraphicBufferLocked->GetSurfaceDescriptor());
|
||||
mBufferAllocated = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GrallocImage::SetData(const Data& aData)
|
||||
{
|
||||
MOZ_ASSERT(!mTextureClient, "TextureClient is already set");
|
||||
NS_PRECONDITION(aData.mYSize.width % 2 == 0, "Image should have even width");
|
||||
NS_PRECONDITION(aData.mYSize.height % 2 == 0, "Image should have even height");
|
||||
NS_PRECONDITION(aData.mYStride % 16 == 0, "Image should have stride of multiple of 16 pixels");
|
||||
@ -83,34 +77,29 @@ GrallocImage::SetData(const Data& aData)
|
||||
mData = aData;
|
||||
mSize = aData.mPicSize;
|
||||
|
||||
if (!mGraphicBufferLocked.get()) {
|
||||
|
||||
SurfaceDescriptor desc;
|
||||
ImageBridgeChild *ibc = ImageBridgeChild::GetSingleton();
|
||||
ibc->AllocSurfaceDescriptorGralloc(aData.mYSize,
|
||||
HAL_PIXEL_FORMAT_YV12,
|
||||
GraphicBuffer::USAGE_SW_READ_OFTEN |
|
||||
GraphicBuffer::USAGE_SW_WRITE_OFTEN |
|
||||
GraphicBuffer::USAGE_HW_TEXTURE,
|
||||
&desc);
|
||||
if (desc.type() == SurfaceDescriptor::T__None) {
|
||||
return;
|
||||
}
|
||||
mBufferAllocated = true;
|
||||
mGraphicBufferLocked = new GraphicBufferLocked(desc);
|
||||
}
|
||||
|
||||
sp<GraphicBuffer> graphicBuffer =
|
||||
GrallocBufferActor::GetFrom(
|
||||
mGraphicBufferLocked->GetSurfaceDescriptor().get_SurfaceDescriptorGralloc());
|
||||
if (!graphicBuffer.get()) {
|
||||
if (IsInEmulator()) {
|
||||
// Emulator does not support HAL_PIXEL_FORMAT_YV12.
|
||||
return;
|
||||
}
|
||||
|
||||
if (graphicBuffer->initCheck() != NO_ERROR) {
|
||||
RefPtr<GrallocTextureClientOGL> textureClient =
|
||||
new GrallocTextureClientOGL(ImageBridgeChild::GetSingleton(),
|
||||
gfx::SurfaceFormat::UNKNOWN,
|
||||
gfx::BackendType::NONE);
|
||||
bool result =
|
||||
textureClient->AllocateGralloc(mData.mYSize,
|
||||
HAL_PIXEL_FORMAT_YV12,
|
||||
GraphicBuffer::USAGE_SW_READ_OFTEN |
|
||||
GraphicBuffer::USAGE_SW_WRITE_OFTEN |
|
||||
GraphicBuffer::USAGE_HW_TEXTURE);
|
||||
sp<GraphicBuffer> graphicBuffer = textureClient->GetGraphicBuffer();
|
||||
if (!result || !graphicBuffer.get()) {
|
||||
mTextureClient = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
mTextureClient = textureClient;
|
||||
|
||||
void* vaddr;
|
||||
if (graphicBuffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN,
|
||||
&vaddr) != OK) {
|
||||
@ -159,7 +148,7 @@ GrallocImage::SetData(const Data& aData)
|
||||
|
||||
void GrallocImage::SetData(const GrallocData& aData)
|
||||
{
|
||||
mGraphicBufferLocked = aData.mGraphicBuffer;
|
||||
mTextureClient = static_cast<GrallocTextureClientOGL*>(aData.mGraphicBuffer.get());
|
||||
mSize = aData.mPicSize;
|
||||
}
|
||||
|
||||
@ -207,8 +196,11 @@ ConvertYVU420SPToRGB565(void *aYData, uint32_t aYStride,
|
||||
already_AddRefed<gfxASurface>
|
||||
GrallocImage::DeprecatedGetAsSurface()
|
||||
{
|
||||
if (!mTextureClient) {
|
||||
return nullptr;
|
||||
}
|
||||
android::sp<GraphicBuffer> graphicBuffer =
|
||||
GrallocBufferActor::GetFrom(GetSurfaceDescriptor());
|
||||
mTextureClient->GetGraphicBuffer();
|
||||
|
||||
void *buffer;
|
||||
int32_t rv =
|
||||
@ -297,8 +289,11 @@ GrallocImage::DeprecatedGetAsSurface()
|
||||
TemporaryRef<gfx::SourceSurface>
|
||||
GrallocImage::GetAsSourceSurface()
|
||||
{
|
||||
if (!mTextureClient) {
|
||||
return nullptr;
|
||||
}
|
||||
android::sp<GraphicBuffer> graphicBuffer =
|
||||
GrallocBufferActor::GetFrom(GetSurfaceDescriptor());
|
||||
mTextureClient->GetGraphicBuffer();
|
||||
|
||||
void *buffer;
|
||||
int32_t rv =
|
||||
@ -400,24 +395,33 @@ GrallocImage::GetAsSourceSurface()
|
||||
return surface;
|
||||
}
|
||||
|
||||
void*
|
||||
GrallocImage::GetNativeBuffer()
|
||||
{
|
||||
if (!mTextureClient) {
|
||||
return nullptr;
|
||||
}
|
||||
android::sp<android::GraphicBuffer> graphicBuffer =
|
||||
mTextureClient->GetGraphicBuffer();
|
||||
if (!graphicBuffer.get()) {
|
||||
return nullptr;
|
||||
}
|
||||
return graphicBuffer->getNativeBuffer();
|
||||
}
|
||||
|
||||
SurfaceDescriptor
|
||||
GrallocImage::GetSurfaceDescriptor()
|
||||
{
|
||||
SurfaceDescriptor desc;
|
||||
if (mTextureClient && mTextureClient->ToSurfaceDescriptor(desc)) {
|
||||
return desc;
|
||||
}
|
||||
return SurfaceDescriptor();
|
||||
}
|
||||
|
||||
TextureClient*
|
||||
GrallocImage::GetTextureClient(CompositableClient* aClient)
|
||||
{
|
||||
if (!mTextureClient) {
|
||||
const SurfaceDescriptor& sd = GetSurfaceDescriptor();
|
||||
if (sd.type() != SurfaceDescriptor::TSurfaceDescriptorGralloc) {
|
||||
return nullptr;
|
||||
}
|
||||
const SurfaceDescriptorGralloc& desc = sd.get_SurfaceDescriptorGralloc();
|
||||
TextureFlags flags = desc.external() ? TEXTURE_DEALLOCATE_CLIENT : 0;
|
||||
if (desc.isRBSwapped()) {
|
||||
flags |= TEXTURE_RB_SWAPPED;
|
||||
}
|
||||
GrallocBufferActor* actor = static_cast<GrallocBufferActor*>(desc.bufferChild());
|
||||
mTextureClient = new GrallocTextureClientOGL(actor, mSize, gfx::BackendType::NONE, flags);
|
||||
mTextureClient->SetGraphicBufferLocked(mGraphicBufferLocked);
|
||||
}
|
||||
return mTextureClient;
|
||||
}
|
||||
|
||||
|
@ -22,63 +22,6 @@ namespace layers {
|
||||
|
||||
class GrallocTextureClientOGL;
|
||||
|
||||
/**
|
||||
* The gralloc buffer maintained by android GraphicBuffer can be
|
||||
* shared between the compositor thread and the producer thread. The
|
||||
* mGraphicBuffer is owned by the producer thread, but when it is
|
||||
* wrapped by GraphicBufferLocked and passed to the compositor, the
|
||||
* buffer content is guaranteed to not change until Unlock() is
|
||||
* called. Each producer must maintain their own buffer queue and
|
||||
* implement the GraphicBufferLocked::Unlock() interface.
|
||||
*/
|
||||
class GraphicBufferLocked
|
||||
: public AtomicRefCountedWithFinalize<GraphicBufferLocked>
|
||||
{
|
||||
|
||||
public:
|
||||
GraphicBufferLocked(SurfaceDescriptor aGraphicBuffer)
|
||||
: mSurfaceDescriptor(aGraphicBuffer)
|
||||
{}
|
||||
|
||||
virtual ~GraphicBufferLocked() {}
|
||||
|
||||
SurfaceDescriptor GetSurfaceDescriptor()
|
||||
{
|
||||
return mSurfaceDescriptor;
|
||||
}
|
||||
|
||||
void SetReleaseFenceHandle(const FenceHandle& aReleaseFenceHandle)
|
||||
{
|
||||
mReleaseFenceHandle = aReleaseFenceHandle;
|
||||
}
|
||||
|
||||
const FenceHandle& GetReleaseFenceHandle() const
|
||||
{
|
||||
return mReleaseFenceHandle;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void Unlock() {}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Called once, just before the destructor.
|
||||
*
|
||||
* Here goes the shut-down code that uses virtual methods.
|
||||
* Must only be called by Release().
|
||||
*/
|
||||
void Finalize()
|
||||
{
|
||||
Unlock();
|
||||
}
|
||||
|
||||
friend class AtomicRefCountedWithFinalize<GraphicBufferLocked>;
|
||||
|
||||
protected:
|
||||
SurfaceDescriptor mSurfaceDescriptor;
|
||||
FenceHandle mReleaseFenceHandle;
|
||||
};
|
||||
|
||||
/**
|
||||
* The YUV format supported by Android HAL
|
||||
*
|
||||
@ -107,7 +50,7 @@ class GrallocImage : public PlanarYCbCrImage
|
||||
static uint32_t sColorIdMap[];
|
||||
public:
|
||||
struct GrallocData {
|
||||
nsRefPtr<GraphicBufferLocked> mGraphicBuffer;
|
||||
nsRefPtr<TextureClient> mGraphicBuffer;
|
||||
gfx::IntSize mPicSize;
|
||||
};
|
||||
|
||||
@ -141,23 +84,11 @@ public:
|
||||
virtual already_AddRefed<gfxASurface> DeprecatedGetAsSurface();
|
||||
virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() MOZ_OVERRIDE;
|
||||
|
||||
void* GetNativeBuffer()
|
||||
{
|
||||
if (IsValid()) {
|
||||
return GrallocBufferActor::GetFrom(GetSurfaceDescriptor())->getNativeBuffer();
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
void* GetNativeBuffer();
|
||||
|
||||
virtual bool IsValid() { return GetSurfaceDescriptor().type() != SurfaceDescriptor::T__None; }
|
||||
|
||||
SurfaceDescriptor GetSurfaceDescriptor() {
|
||||
if (mGraphicBufferLocked.get()) {
|
||||
return mGraphicBufferLocked->GetSurfaceDescriptor();
|
||||
}
|
||||
return SurfaceDescriptor();
|
||||
}
|
||||
SurfaceDescriptor GetSurfaceDescriptor();
|
||||
|
||||
virtual ISharedImage* AsSharedImage() MOZ_OVERRIDE { return this; }
|
||||
|
||||
@ -169,8 +100,6 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
bool mBufferAllocated;
|
||||
nsRefPtr<GraphicBufferLocked> mGraphicBufferLocked;
|
||||
RefPtr<GrallocTextureClientOGL> mTextureClient;
|
||||
};
|
||||
|
||||
|
@ -41,10 +41,6 @@ CanvasClient::CreateCanvasClient(CanvasClientType aType,
|
||||
aFlags |= TEXTURE_DEALLOCATE_CLIENT;
|
||||
return new CanvasClientSurfaceStream(aForwarder, aFlags);
|
||||
}
|
||||
if (gfxPlatform::GetPlatform()->UseDeprecatedTextures()) {
|
||||
aFlags |= TEXTURE_DEALLOCATE_CLIENT;
|
||||
return new DeprecatedCanvasClient2D(aForwarder, aFlags);
|
||||
}
|
||||
return new CanvasClient2D(aForwarder, aFlags);
|
||||
}
|
||||
|
||||
@ -65,21 +61,12 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
|
||||
: gfxContentType::COLOR_ALPHA;
|
||||
gfxImageFormat format
|
||||
= gfxPlatform::GetPlatform()->OptimalFormatForContent(contentType);
|
||||
mBuffer = CreateTextureClientForDrawing(gfx::ImageFormatToSurfaceFormat(format),
|
||||
TEXTURE_FLAGS_DEFAULT,
|
||||
gfxPlatform::GetPlatform()->GetPreferredCanvasBackend(),
|
||||
aSize);
|
||||
bool allocSuccess = false;
|
||||
if (mBuffer->AsTextureClientSurface()) {
|
||||
allocSuccess = mBuffer->AsTextureClientSurface()->AllocateForSurface(aSize);
|
||||
} else {
|
||||
MOZ_ASSERT(mBuffer->AsTextureClientDrawTarget());
|
||||
allocSuccess = mBuffer->AsTextureClientDrawTarget()->AllocateForSurface(aSize);
|
||||
}
|
||||
if (!allocSuccess) {
|
||||
mBuffer = nullptr;
|
||||
return;
|
||||
}
|
||||
mBuffer = CreateBufferTextureClient(gfx::ImageFormatToSurfaceFormat(format),
|
||||
TEXTURE_FLAGS_DEFAULT,
|
||||
gfxPlatform::GetPlatform()->GetPreferredCanvasBackend());
|
||||
MOZ_ASSERT(mBuffer->AsTextureClientSurface());
|
||||
mBuffer->AsTextureClientSurface()->AllocateForSurface(aSize);
|
||||
|
||||
bufferCreated = true;
|
||||
}
|
||||
|
||||
@ -90,18 +77,8 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
|
||||
bool updated = false;
|
||||
{
|
||||
// Restrict drawTarget to a scope so that terminates before Unlock.
|
||||
nsRefPtr<gfxASurface> surface;
|
||||
if (mBuffer->AsTextureClientSurface()) {
|
||||
surface = mBuffer->AsTextureClientSurface()->GetAsSurface();
|
||||
} else {
|
||||
RefPtr<gfx::DrawTarget> dt
|
||||
= mBuffer->AsTextureClientDrawTarget()->GetAsDrawTarget();
|
||||
if (dt) {
|
||||
surface = gfxPlatform::GetPlatform()->CreateThebesSurfaceAliasForDrawTarget_hack(dt);
|
||||
}
|
||||
// the DrawTarget will be kept alive until mBuffer->Unlock() so it's
|
||||
// OK to let go of dt before we destroy surface.
|
||||
}
|
||||
nsRefPtr<gfxASurface> surface =
|
||||
mBuffer->AsTextureClientSurface()->GetAsSurface();
|
||||
if (surface) {
|
||||
aLayer->DeprecatedUpdateSurface(surface);
|
||||
updated = true;
|
||||
@ -199,133 +176,5 @@ CanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
|
||||
aLayer->Painted();
|
||||
}
|
||||
|
||||
void
|
||||
DeprecatedCanvasClient2D::Updated()
|
||||
{
|
||||
mForwarder->UpdateTexture(this, 1, mDeprecatedTextureClient->LockSurfaceDescriptor());
|
||||
}
|
||||
|
||||
|
||||
DeprecatedCanvasClient2D::DeprecatedCanvasClient2D(CompositableForwarder* aFwd,
|
||||
TextureFlags aFlags)
|
||||
: CanvasClient(aFwd, aFlags)
|
||||
{
|
||||
mTextureInfo.mCompositableType = BUFFER_IMAGE_SINGLE;
|
||||
}
|
||||
|
||||
void
|
||||
DeprecatedCanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
|
||||
{
|
||||
bool isOpaque = (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE);
|
||||
gfxContentType contentType = isOpaque
|
||||
? gfxContentType::COLOR
|
||||
: gfxContentType::COLOR_ALPHA;
|
||||
|
||||
if (!mDeprecatedTextureClient) {
|
||||
mDeprecatedTextureClient = CreateDeprecatedTextureClient(TEXTURE_CONTENT, contentType);
|
||||
if (!mDeprecatedTextureClient) {
|
||||
mDeprecatedTextureClient = CreateDeprecatedTextureClient(TEXTURE_FALLBACK, contentType);
|
||||
if (!mDeprecatedTextureClient) {
|
||||
NS_WARNING("Could not create texture client");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!mDeprecatedTextureClient->EnsureAllocated(aSize, contentType)) {
|
||||
// We might already be on the fallback texture client if we couldn't create a
|
||||
// better one above. In which case this call to create is wasted. But I don't
|
||||
// think this will happen often enough to be worth complicating the code with
|
||||
// further checks.
|
||||
mDeprecatedTextureClient = CreateDeprecatedTextureClient(TEXTURE_FALLBACK, contentType);
|
||||
MOZ_ASSERT(mDeprecatedTextureClient, "Failed to create texture client");
|
||||
if (!mDeprecatedTextureClient->EnsureAllocated(aSize, contentType)) {
|
||||
NS_WARNING("Could not allocate texture client");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
gfxASurface* surface = mDeprecatedTextureClient->LockSurface();
|
||||
aLayer->DeprecatedUpdateSurface(surface);
|
||||
mDeprecatedTextureClient->Unlock();
|
||||
}
|
||||
|
||||
void
|
||||
DeprecatedCanvasClientSurfaceStream::Updated()
|
||||
{
|
||||
mForwarder->UpdateTextureNoSwap(this, 1, mDeprecatedTextureClient->LockSurfaceDescriptor());
|
||||
}
|
||||
|
||||
|
||||
DeprecatedCanvasClientSurfaceStream::DeprecatedCanvasClientSurfaceStream(CompositableForwarder* aFwd,
|
||||
TextureFlags aFlags)
|
||||
: CanvasClient(aFwd, aFlags)
|
||||
{
|
||||
mTextureInfo.mCompositableType = BUFFER_IMAGE_SINGLE;
|
||||
}
|
||||
|
||||
void
|
||||
DeprecatedCanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
|
||||
{
|
||||
if (!mDeprecatedTextureClient) {
|
||||
mDeprecatedTextureClient = CreateDeprecatedTextureClient(TEXTURE_STREAM_GL,
|
||||
aLayer->GetSurfaceMode() == SurfaceMode::SURFACE_OPAQUE
|
||||
? gfxContentType::COLOR
|
||||
: gfxContentType::COLOR_ALPHA);
|
||||
MOZ_ASSERT(mDeprecatedTextureClient, "Failed to create texture client");
|
||||
}
|
||||
|
||||
NS_ASSERTION(aLayer->mGLContext, "CanvasClientSurfaceStream should only be used with GL canvases");
|
||||
|
||||
// the content type won't be used
|
||||
mDeprecatedTextureClient->EnsureAllocated(aSize, gfxContentType::COLOR);
|
||||
|
||||
GLScreenBuffer* screen = aLayer->mGLContext->Screen();
|
||||
SurfaceStream* stream = nullptr;
|
||||
|
||||
if (aLayer->mStream) {
|
||||
stream = aLayer->mStream;
|
||||
stream->CopySurfaceToProducer(aLayer->mTextureSurface, aLayer->mFactory);
|
||||
stream->SwapProducer(aLayer->mFactory, gfx::IntSize(aSize.width, aSize.height));
|
||||
} else {
|
||||
stream = screen->Stream();
|
||||
}
|
||||
|
||||
bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default);
|
||||
if (isCrossProcess) {
|
||||
// swap staging -> consumer so we can send it to the compositor
|
||||
SharedSurface* surf = stream->SwapConsumer();
|
||||
if (!surf) {
|
||||
printf_stderr("surf is null post-SwapConsumer!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
if (surf->Type() != SharedSurfaceType::Gralloc) {
|
||||
printf_stderr("Unexpected non-Gralloc SharedSurface in IPC path!");
|
||||
return;
|
||||
}
|
||||
|
||||
SharedSurface_Gralloc* grallocSurf = SharedSurface_Gralloc::Cast(surf);
|
||||
//XXX todo
|
||||
//mDeprecatedTextureClient->SetDescriptor(grallocSurf->GetDescriptor());
|
||||
#else
|
||||
printf_stderr("isCrossProcess, but not MOZ_WIDGET_GONK! Someone needs to write some code!");
|
||||
MOZ_ASSERT(false);
|
||||
#endif
|
||||
} else {
|
||||
SurfaceStreamHandle handle = stream->GetShareHandle();
|
||||
mDeprecatedTextureClient->SetDescriptor(SurfaceStreamDescriptor(handle, false));
|
||||
|
||||
// Bug 894405
|
||||
//
|
||||
// Ref this so the SurfaceStream doesn't disappear unexpectedly. The
|
||||
// Compositor will need to unref it when finished.
|
||||
aLayer->mGLContext->AddRef();
|
||||
}
|
||||
|
||||
aLayer->Painted();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -132,56 +132,6 @@ private:
|
||||
RefPtr<TextureClient> mBuffer;
|
||||
};
|
||||
|
||||
class DeprecatedCanvasClient2D : public CanvasClient
|
||||
{
|
||||
public:
|
||||
DeprecatedCanvasClient2D(CompositableForwarder* aLayerForwarder,
|
||||
TextureFlags aFlags);
|
||||
|
||||
TextureInfo GetTextureInfo() const MOZ_OVERRIDE
|
||||
{
|
||||
return mTextureInfo;
|
||||
}
|
||||
|
||||
virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer);
|
||||
virtual void Updated() MOZ_OVERRIDE;
|
||||
|
||||
virtual void SetDescriptorFromReply(TextureIdentifier aTextureId,
|
||||
const SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE
|
||||
{
|
||||
mDeprecatedTextureClient->SetDescriptorFromReply(aDescriptor);
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<DeprecatedTextureClient> mDeprecatedTextureClient;
|
||||
};
|
||||
|
||||
// Used for GL canvases where we don't need to do any readback, i.e., with a
|
||||
// GL backend.
|
||||
class DeprecatedCanvasClientSurfaceStream : public CanvasClient
|
||||
{
|
||||
public:
|
||||
DeprecatedCanvasClientSurfaceStream(CompositableForwarder* aFwd,
|
||||
TextureFlags aFlags);
|
||||
|
||||
TextureInfo GetTextureInfo() const MOZ_OVERRIDE
|
||||
{
|
||||
return mTextureInfo;
|
||||
}
|
||||
|
||||
virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer);
|
||||
virtual void Updated() MOZ_OVERRIDE;
|
||||
|
||||
virtual void SetDescriptorFromReply(TextureIdentifier aTextureId,
|
||||
const SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE
|
||||
{
|
||||
mDeprecatedTextureClient->SetDescriptorFromReply(aDescriptor);
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<DeprecatedTextureClient> mDeprecatedTextureClient;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -216,13 +216,17 @@ ClientTiledThebesLayer::RenderLayer()
|
||||
ToClientLayer(GetMaskLayer())->RenderLayer();
|
||||
}
|
||||
|
||||
bool isFixed = GetIsFixedPosition() || GetParent()->GetIsFixedPosition();
|
||||
|
||||
// Fast path for no progressive updates, no low-precision updates and no
|
||||
// critical display-port set, or no display-port set.
|
||||
// critical display-port set, or no display-port set, or this is a fixed
|
||||
// position layer/contained in a fixed position layer
|
||||
const FrameMetrics& parentMetrics = GetParent()->GetFrameMetrics();
|
||||
if ((!gfxPrefs::UseProgressiveTilePainting() &&
|
||||
!gfxPrefs::UseLowPrecisionBuffer() &&
|
||||
parentMetrics.mCriticalDisplayPort.IsEmpty()) ||
|
||||
parentMetrics.mDisplayPort.IsEmpty()) {
|
||||
parentMetrics.mDisplayPort.IsEmpty() ||
|
||||
isFixed) {
|
||||
mValidRegion = mVisibleRegion;
|
||||
|
||||
NS_ASSERTION(!ClientManager()->IsRepeatTransaction(), "Didn't paint our mask layer");
|
||||
|
@ -38,6 +38,22 @@ using namespace gfx;
|
||||
|
||||
namespace layers {
|
||||
|
||||
static TextureFlags TextureFlagsForRotatedContentBufferFlags(uint32_t aBufferFlags)
|
||||
{
|
||||
TextureFlags result = 0;
|
||||
|
||||
if (aBufferFlags & RotatedContentBuffer::BUFFER_COMPONENT_ALPHA) {
|
||||
result |= TEXTURE_COMPONENT_ALPHA;
|
||||
}
|
||||
|
||||
if (aBufferFlags & RotatedContentBuffer::ALLOW_REPEAT) {
|
||||
result |= TEXTURE_ALLOW_REPEAT;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* static */ TemporaryRef<ContentClient>
|
||||
ContentClient::CreateContentClient(CompositableForwarder* aForwarder)
|
||||
{
|
||||
@ -51,7 +67,12 @@ ContentClient::CreateContentClient(CompositableForwarder* aForwarder)
|
||||
|
||||
bool useDoubleBuffering = false;
|
||||
bool useDeprecatedTextures = true;
|
||||
// XXX We need support for gralloc with non-deprecated textures content before
|
||||
// we can use them with FirefoxOS (bug 946720). We need the same locking for
|
||||
// Windows.
|
||||
#if !defined(XP_WIN)
|
||||
useDeprecatedTextures = gfxPlatform::GetPlatform()->UseDeprecatedTextures();
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
if (backend == LayersBackend::LAYERS_D3D11) {
|
||||
@ -210,7 +231,7 @@ ContentClientRemoteBuffer::BuildTextureClients(SurfaceFormat aFormat,
|
||||
|
||||
mSurfaceFormat = aFormat;
|
||||
mSize = gfx::IntSize(aRect.width, aRect.height);
|
||||
mTextureInfo.mTextureFlags = aFlags & ~TEXTURE_DEALLOCATE_CLIENT;
|
||||
mTextureInfo.mTextureFlags = TextureFlagsForRotatedContentBufferFlags(aFlags);
|
||||
|
||||
if (!CreateAndAllocateTextureClient(mTextureClient, TEXTURE_ON_BLACK) ||
|
||||
!AddTextureClient(mTextureClient)) {
|
||||
@ -396,19 +417,18 @@ DeprecatedContentClientRemoteBuffer::BuildDeprecatedTextureClients(ContentType a
|
||||
|
||||
mContentType = aType;
|
||||
mSize = gfx::IntSize(aRect.width, aRect.height);
|
||||
mTextureInfo.mTextureFlags = aFlags & ~TEXTURE_DEALLOCATE_CLIENT;
|
||||
mTextureInfo.mTextureFlags = TextureFlagsForRotatedContentBufferFlags(aFlags);
|
||||
|
||||
if (!CreateAndAllocateDeprecatedTextureClient(mDeprecatedTextureClient)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (aFlags & BUFFER_COMPONENT_ALPHA) {
|
||||
if (!CreateAndAllocateDeprecatedTextureClient(mDeprecatedTextureClientOnWhite)) {
|
||||
mDeprecatedTextureClient->SetFlags(0);
|
||||
mDeprecatedTextureClient = nullptr;
|
||||
return;
|
||||
}
|
||||
mTextureInfo.mTextureFlags |= TEXTURE_COMPONENT_ALPHA;
|
||||
}
|
||||
|
||||
CreateFrontBufferAndNotify(aRect);
|
||||
|
@ -282,10 +282,6 @@ TextureClient::CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
|
||||
aMoz2DBackend = gfxPlatform::GetPlatform()->GetContentBackend();
|
||||
}
|
||||
|
||||
#if defined(XP_WIN) || defined(MOZ_WIDGET_GONK)
|
||||
int32_t maxTextureSize = aAllocator->GetMaxTextureSize();
|
||||
#endif
|
||||
|
||||
RefPtr<TextureClient> result;
|
||||
|
||||
#ifdef XP_WIN
|
||||
@ -294,10 +290,9 @@ TextureClient::CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
|
||||
(aMoz2DBackend == gfx::BackendType::DIRECT2D ||
|
||||
aMoz2DBackend == gfx::BackendType::DIRECT2D1_1) &&
|
||||
gfxWindowsPlatform::GetPlatform()->GetD2DDevice() &&
|
||||
|
||||
!(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) {
|
||||
if (aSizeHint.width <= maxTextureSize && aSizeHint.height <= maxTextureSize) {
|
||||
result = new TextureClientD3D11(aFormat, aTextureFlags);
|
||||
}
|
||||
result = new TextureClientD3D11(aFormat, aTextureFlags);
|
||||
}
|
||||
if (parentBackend == LayersBackend::LAYERS_D3D9 &&
|
||||
aMoz2DBackend == gfx::BackendType::CAIRO &&
|
||||
@ -342,6 +337,7 @@ TextureClient::CreateTextureClientForDrawing(ISurfaceAllocator* aAllocator,
|
||||
if (!DisableGralloc(aFormat, aSizeHint)) {
|
||||
// Don't allow Gralloc texture clients to exceed the maximum texture size.
|
||||
// BufferTextureClients have code to handle tiling the surface client-side.
|
||||
int32_t maxTextureSize = aAllocator->GetMaxTextureSize();
|
||||
if (aSizeHint.width <= maxTextureSize && aSizeHint.height <= maxTextureSize) {
|
||||
result = new GrallocTextureClientOGL(aAllocator, aFormat, aMoz2DBackend,
|
||||
aTextureFlags);
|
||||
|
@ -132,6 +132,7 @@ ThebesLayerComposite::RenderLayer(const nsIntRect& aClipRect)
|
||||
|
||||
EffectChain effectChain(this);
|
||||
LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain);
|
||||
|
||||
nsIntRegion visibleRegion = GetEffectiveVisibleRegion();
|
||||
|
||||
TiledLayerProperties tiledLayerProps;
|
||||
|
@ -171,10 +171,6 @@ bool
|
||||
TextureClientD3D11::Lock(OpenMode aMode)
|
||||
{
|
||||
MOZ_ASSERT(!mIsLocked, "The Texture is already locked!");
|
||||
if (!mTexture) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LockD3DTexture(mTexture.get());
|
||||
mIsLocked = true;
|
||||
|
||||
@ -215,10 +211,6 @@ TextureClientD3D11::GetAsDrawTarget()
|
||||
return mDrawTarget;
|
||||
}
|
||||
|
||||
if (!mTexture) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mDrawTarget = Factory::CreateDrawTargetForD3D10Texture(mTexture, mFormat);
|
||||
return mDrawTarget;
|
||||
}
|
||||
@ -229,7 +221,7 @@ TextureClientD3D11::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlag
|
||||
mSize = aSize;
|
||||
ID3D10Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
|
||||
|
||||
CD3D10_TEXTURE2D_DESC newDesc(DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
CD3D10_TEXTURE2D_DESC newDesc(SurfaceFormatToDXGIFormat(mFormat),
|
||||
aSize.width, aSize.height, 1, 1,
|
||||
D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE);
|
||||
|
||||
@ -337,10 +329,10 @@ DataTextureSourceD3D11::Update(DataSourceSurface* aSurface,
|
||||
nsIntRegion* aDestRegion,
|
||||
IntPoint* aSrcOffset)
|
||||
{
|
||||
// Right now we only support full surface update. If aDestRegion is provided,
|
||||
// It will be ignered. Incremental update with a source offset is only used
|
||||
// on Mac so it is not clear that we ever will need to support it for D3D.
|
||||
MOZ_ASSERT(!aSrcOffset);
|
||||
// Right now we only support null aDestRegion and aSrcOffset (which means)
|
||||
// full surface update. Incremental update is only used on Mac so it is
|
||||
// not clear that we ever will need to support it for D3D.
|
||||
MOZ_ASSERT(!aDestRegion && !aSrcOffset);
|
||||
MOZ_ASSERT(aSurface);
|
||||
|
||||
if (!mCompositor || !mCompositor->GetDevice()) {
|
||||
|
@ -1061,10 +1061,10 @@ DataTextureSourceD3D9::Update(gfx::DataSourceSurface* aSurface,
|
||||
nsIntRegion* aDestRegion,
|
||||
gfx::IntPoint* aSrcOffset)
|
||||
{
|
||||
// Right now we only support full surface update. If aDestRegion is provided,
|
||||
// It will be ignered. Incremental update with a source offset is only used
|
||||
// on Mac so it is not clear that we ever will need to support it for D3D.
|
||||
MOZ_ASSERT(!aSrcOffset);
|
||||
// Right now we only support null aDestRegion and aSrcOffset (which means
|
||||
// full surface update). Incremental update is only used on Mac so it is
|
||||
// not clear that we ever will need to support it for D3D.
|
||||
MOZ_ASSERT(!aDestRegion && !aSrcOffset);
|
||||
|
||||
if (!mCompositor || !mCompositor->device()) {
|
||||
NS_WARNING("No D3D device to update the texture.");
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "base/message_loop.h" // for MessageLoop
|
||||
#include "base/task.h" // for NewRunnableMethod, etc
|
||||
#include "base/tracked.h" // for FROM_HERE
|
||||
#include "gfxPrefs.h" // for gfxPrefs::UseProgressiveTilePainting
|
||||
#include "gfxPrefs.h" // for gfxPrefs
|
||||
#include "gfxTypes.h" // for gfxFloat
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
#include "mozilla/BasicEvents.h" // for Modifiers, MODIFIER_*
|
||||
@ -133,18 +133,100 @@ namespace layers {
|
||||
|
||||
typedef mozilla::layers::AllowedTouchBehavior AllowedTouchBehavior;
|
||||
|
||||
/**
|
||||
* Specifies whether touch-action property is in force.
|
||||
*/
|
||||
static bool gTouchActionPropertyEnabled = false;
|
||||
|
||||
/**
|
||||
/*
|
||||
* The following prefs are used to control the behaviour of the APZC.
|
||||
* The default values are provided in gfxPrefs.h.
|
||||
*
|
||||
* "apz.allow-checkerboarding"
|
||||
* Pref that allows or disallows checkerboarding
|
||||
*
|
||||
* "apz.asyncscroll.throttle"
|
||||
* The time period in ms that throttles mozbrowserasyncscroll event.
|
||||
*
|
||||
* "apz.asyncscroll.timeout"
|
||||
* The timeout in ms for mAsyncScrollTimeoutTask delay task.
|
||||
*
|
||||
* "apz.axis_lock_mode"
|
||||
* The preferred axis locking style. See AxisLockMode for possible values.
|
||||
*
|
||||
* "apz.content_response_timeout"
|
||||
* Amount of time before we timeout response from content. For example, if
|
||||
* content is being unruly/slow and we don't get a response back within this
|
||||
* time, we will just pretend that content did not preventDefault any touch
|
||||
* events we dispatched to it.
|
||||
*
|
||||
* "apz.cross_slide_enabled"
|
||||
* Pref that enables integration with the Metro "cross-slide" gesture.
|
||||
*
|
||||
* "apz.enlarge_displayport_when_clipped"
|
||||
* Pref that enables enlarging of the displayport along one axis when the
|
||||
* generated displayport's size is beyond that of the scrollable rect on the
|
||||
* opposite axis.
|
||||
*
|
||||
* "apz.fling_friction"
|
||||
* Amount of friction applied during flings.
|
||||
*
|
||||
* "apz.fling_repaint_interval"
|
||||
* Maximum amount of time flinging before sending a viewport change. This will
|
||||
* asynchronously repaint the page.
|
||||
*
|
||||
* "apz.fling_stopped_threshold"
|
||||
* When flinging, if the velocity goes below this number, we just stop the
|
||||
* animation completely. This is to prevent asymptotically approaching 0
|
||||
* velocity and rerendering unnecessarily.
|
||||
*
|
||||
* "apz.max_velocity_inches_per_ms"
|
||||
* Maximum velocity in inches per millisecond. Velocity will be capped at this
|
||||
* value if a faster fling occurs. Negative values indicate unlimited velocity.
|
||||
*
|
||||
* "apz.max_velocity_queue_size"
|
||||
* Maximum size of velocity queue. The queue contains last N velocity records.
|
||||
* On touch end we calculate the average velocity in order to compensate
|
||||
* touch/mouse drivers misbehaviour.
|
||||
*
|
||||
* "apz.min_skate_speed"
|
||||
* Minimum amount of speed along an axis before we switch to "skate" multipliers
|
||||
* rather than using the "stationary" multipliers.
|
||||
*
|
||||
* "apz.num_paint_duration_samples"
|
||||
* Number of samples to store of how long it took to paint after the previous
|
||||
* requests.
|
||||
*
|
||||
* "apz.pan_repaint_interval"
|
||||
* Maximum amount of time while panning before sending a viewport change. This
|
||||
* will asynchronously repaint the page. It is also forced when panning stops.
|
||||
*
|
||||
* "apz.touch_start_tolerance"
|
||||
* Constant describing the tolerance in distance we use, multiplied by the
|
||||
* device DPI, before we start panning the screen. This is to prevent us from
|
||||
* accidentally processing taps as touch moves, and from very short/accidental
|
||||
* touches moving the screen.
|
||||
*
|
||||
* "apz.use_paint_duration"
|
||||
* Whether or not to use the estimated paint duration as a factor when projecting
|
||||
* the displayport in the direction of scrolling. If this value is set to false,
|
||||
* a constant 50ms paint time is used; the projection can be scaled as desired
|
||||
* using the apz.velocity_bias pref below.
|
||||
*
|
||||
* "apz.velocity_bias"
|
||||
* How much to adjust the displayport in the direction of scrolling. This value
|
||||
* is multiplied by the velocity and added to the displayport offset.
|
||||
*
|
||||
* "apz.x_skate_size_multiplier", "apz.y_skate_size_multiplier"
|
||||
* The multiplier we apply to the displayport size if it is skating (current
|
||||
* velocity is above apz.min_skate_speed). We prefer to increase the size of the
|
||||
* Y axis because it is more natural in the case that a user is reading a page
|
||||
* that scrolls up/down. Note that one, both or neither of these may be used
|
||||
* at any instant.
|
||||
* In general we want apz.[xy]_skate_size_multiplier to be smaller than the corresponding
|
||||
* stationary size multiplier because when panning fast we would like to paint
|
||||
* less and get faster, more predictable paint times. When panning slowly we
|
||||
* can afford to paint more even though it's slower.
|
||||
*
|
||||
* "apz.x_stationary_size_multiplier", "apz.y_stationary_size_multiplier"
|
||||
* The multiplier we apply to the displayport size if it is not skating (see
|
||||
* documentation for the skate size multipliers above).
|
||||
*/
|
||||
static float gTouchStartTolerance = 1.0f/4.5f;
|
||||
|
||||
/**
|
||||
* Default touch behavior (is used when not touch behavior is set).
|
||||
@ -177,43 +259,6 @@ static const double AXIS_BREAKOUT_ANGLE = M_PI / 8.0; // 22.5 degrees
|
||||
*/
|
||||
static const double ALLOWED_DIRECT_PAN_ANGLE = M_PI / 3.0; // 60 degrees
|
||||
|
||||
/**
|
||||
* The preferred axis locking style. See AxisLockMode for possible values.
|
||||
*/
|
||||
static int32_t gAxisLockMode = 0;
|
||||
|
||||
/**
|
||||
* Maximum amount of time while panning before sending a viewport change. This
|
||||
* will asynchronously repaint the page. It is also forced when panning stops.
|
||||
*/
|
||||
static int32_t gPanRepaintInterval = 250;
|
||||
|
||||
/**
|
||||
* Maximum amount of time flinging before sending a viewport change. This will
|
||||
* asynchronously repaint the page.
|
||||
*/
|
||||
static int32_t gFlingRepaintInterval = 75;
|
||||
|
||||
/**
|
||||
* Minimum amount of speed along an axis before we switch to "skate" multipliers
|
||||
* rather than using the "stationary" multipliers.
|
||||
*/
|
||||
static float gMinSkateSpeed = 1.0f;
|
||||
|
||||
/**
|
||||
* Whether or not to use the estimated paint duration as a factor when projecting
|
||||
* the displayport in the direction of scrolling. If this value is set to false,
|
||||
* a constant 50ms paint time is used; the projection can be scaled as desired
|
||||
* using the gVelocityBias pref below.
|
||||
*/
|
||||
static bool gUsePaintDuration = true;
|
||||
|
||||
/**
|
||||
* How much to adjust the displayport in the direction of scrolling. This value
|
||||
* is multiplied by the velocity and added to the displayport offset.
|
||||
*/
|
||||
static float gVelocityBias = 1.0f;
|
||||
|
||||
/**
|
||||
* Duration of a zoom to animation.
|
||||
*/
|
||||
@ -234,71 +279,6 @@ static const CSSToScreenScale MAX_ZOOM(8.0f);
|
||||
*/
|
||||
static const CSSToScreenScale MIN_ZOOM(0.125f);
|
||||
|
||||
/**
|
||||
* Amount of time before we timeout response from content. For example, if
|
||||
* content is being unruly/slow and we don't get a response back within this
|
||||
* time, we will just pretend that content did not preventDefault any touch
|
||||
* events we dispatched to it.
|
||||
*/
|
||||
static int gContentResponseTimeout = 300;
|
||||
|
||||
/**
|
||||
* Number of samples to store of how long it took to paint after the previous
|
||||
* requests.
|
||||
*/
|
||||
static int gNumPaintDurationSamples = 3;
|
||||
|
||||
/**
|
||||
* The multiplier we apply to the displayport size if it is skating (current
|
||||
* velocity is above gMinSkateSpeed). We prefer to increase the size of the
|
||||
* Y axis because it is more natural in the case that a user is reading a page
|
||||
* that scrolls up/down. Note that one, both or neither of these may be used
|
||||
* at any instant.
|
||||
* In general we want g[XY]SkateSizeMultiplier to be smaller than the corresponding
|
||||
* stationary size multiplier because when panning fast we would like to paint
|
||||
* less and get faster, more predictable paint times. When panning slowly we
|
||||
* can afford to paint more even though it's slower.
|
||||
*/
|
||||
static float gXSkateSizeMultiplier = 1.5f;
|
||||
static float gYSkateSizeMultiplier = 2.5f;
|
||||
|
||||
/**
|
||||
* The multiplier we apply to the displayport size if it is not skating (see
|
||||
* documentation for gXSkateSizeMultiplier).
|
||||
*/
|
||||
static float gXStationarySizeMultiplier = 3.0f;
|
||||
static float gYStationarySizeMultiplier = 3.5f;
|
||||
|
||||
/**
|
||||
* The time period in ms that throttles mozbrowserasyncscroll event.
|
||||
* Default is 100ms if there is no "apz.asyncscroll.throttle" in preference.
|
||||
*/
|
||||
|
||||
static int gAsyncScrollThrottleTime = 100;
|
||||
|
||||
/**
|
||||
* The timeout in ms for mAsyncScrollTimeoutTask delay task.
|
||||
* Default is 300ms if there is no "apz.asyncscroll.timeout" in preference.
|
||||
*/
|
||||
static int gAsyncScrollTimeout = 300;
|
||||
|
||||
/**
|
||||
* Pref that enables integration with the Metro "cross-slide" gesture.
|
||||
*/
|
||||
static bool gCrossSlideEnabled = false;
|
||||
|
||||
/**
|
||||
* Pref that allows or disallows checkerboarding
|
||||
*/
|
||||
static bool gAllowCheckerboarding = true;
|
||||
|
||||
/**
|
||||
* Pref that enables enlarging of the displayport along one axis when the
|
||||
* generated displayport's size is beyond that of the scrollable rect on the
|
||||
* opposite axis.
|
||||
*/
|
||||
static bool gEnlargeDisplayPortWhenClipped = false;
|
||||
|
||||
/**
|
||||
* Is aAngle within the given threshold of the horizontal axis?
|
||||
* @param aAngle an angle in radians in the range [0, pi]
|
||||
@ -350,7 +330,7 @@ GetFrameTime() {
|
||||
class FlingAnimation: public AsyncPanZoomAnimation {
|
||||
public:
|
||||
FlingAnimation(AsyncPanZoomController& aApzc)
|
||||
: AsyncPanZoomAnimation(TimeDuration::FromMilliseconds(gFlingRepaintInterval))
|
||||
: AsyncPanZoomAnimation(TimeDuration::FromMilliseconds(gfxPrefs::APZFlingRepaintInterval()))
|
||||
, mApzc(aApzc)
|
||||
{}
|
||||
/**
|
||||
@ -411,27 +391,6 @@ AsyncPanZoomController::InitializeGlobalState()
|
||||
return;
|
||||
sInitialized = true;
|
||||
|
||||
Preferences::AddBoolVarCache(&gTouchActionPropertyEnabled, "layout.css.touch_action.enabled", gTouchActionPropertyEnabled);
|
||||
Preferences::AddIntVarCache(&gPanRepaintInterval, "apz.pan_repaint_interval", gPanRepaintInterval);
|
||||
Preferences::AddIntVarCache(&gFlingRepaintInterval, "apz.fling_repaint_interval", gFlingRepaintInterval);
|
||||
Preferences::AddFloatVarCache(&gMinSkateSpeed, "apz.min_skate_speed", gMinSkateSpeed);
|
||||
Preferences::AddBoolVarCache(&gUsePaintDuration, "apz.use_paint_duration", gUsePaintDuration);
|
||||
Preferences::AddFloatVarCache(&gVelocityBias, "apz.velocity_bias", gVelocityBias);
|
||||
Preferences::AddIntVarCache(&gContentResponseTimeout, "apz.content_response_timeout", gContentResponseTimeout);
|
||||
Preferences::AddIntVarCache(&gNumPaintDurationSamples, "apz.num_paint_duration_samples", gNumPaintDurationSamples);
|
||||
Preferences::AddFloatVarCache(&gTouchStartTolerance, "apz.touch_start_tolerance", gTouchStartTolerance);
|
||||
Preferences::AddFloatVarCache(&gXSkateSizeMultiplier, "apz.x_skate_size_multiplier", gXSkateSizeMultiplier);
|
||||
Preferences::AddFloatVarCache(&gYSkateSizeMultiplier, "apz.y_skate_size_multiplier", gYSkateSizeMultiplier);
|
||||
Preferences::AddFloatVarCache(&gXStationarySizeMultiplier, "apz.x_stationary_size_multiplier", gXStationarySizeMultiplier);
|
||||
Preferences::AddFloatVarCache(&gYStationarySizeMultiplier, "apz.y_stationary_size_multiplier", gYStationarySizeMultiplier);
|
||||
Preferences::AddIntVarCache(&gAsyncScrollThrottleTime, "apz.asyncscroll.throttle", gAsyncScrollThrottleTime);
|
||||
Preferences::AddIntVarCache(&gAsyncScrollTimeout, "apz.asyncscroll.timeout", gAsyncScrollTimeout);
|
||||
Preferences::AddBoolVarCache(&gCrossSlideEnabled, "apz.cross_slide.enabled", gCrossSlideEnabled);
|
||||
Preferences::AddIntVarCache(&gAxisLockMode, "apz.axis_lock_mode", gAxisLockMode);
|
||||
Preferences::AddBoolVarCache(&gAllowCheckerboarding, "apz.allow-checkerboarding", gAllowCheckerboarding);
|
||||
Preferences::AddBoolVarCache(&gEnlargeDisplayPortWhenClipped, "apz.enlarge_displayport_when_clipped",
|
||||
gEnlargeDisplayPortWhenClipped);
|
||||
|
||||
gComputedTimingFunction = new ComputedTimingFunction();
|
||||
gComputedTimingFunction->Init(
|
||||
nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE));
|
||||
@ -448,7 +407,7 @@ AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId,
|
||||
mGeckoContentController(aGeckoContentController),
|
||||
mRefPtrMonitor("RefPtrMonitor"),
|
||||
mMonitor("AsyncPanZoomController"),
|
||||
mTouchActionPropertyEnabled(gTouchActionPropertyEnabled),
|
||||
mTouchActionPropertyEnabled(gfxPrefs::TouchActionEnabled()),
|
||||
mContentResponseTimeoutTask(nullptr),
|
||||
mX(MOZ_THIS_IN_INITIALIZER_LIST()),
|
||||
mY(MOZ_THIS_IN_INITIALIZER_LIST()),
|
||||
@ -529,12 +488,12 @@ AsyncPanZoomController::IsDestroyed()
|
||||
/* static */float
|
||||
AsyncPanZoomController::GetTouchStartTolerance()
|
||||
{
|
||||
return (gTouchStartTolerance * APZCTreeManager::GetDPI());
|
||||
return (gfxPrefs::APZTouchStartTolerance() * APZCTreeManager::GetDPI());
|
||||
}
|
||||
|
||||
/* static */AsyncPanZoomController::AxisLockMode AsyncPanZoomController::GetAxisLockMode()
|
||||
{
|
||||
return static_cast<AxisLockMode>(gAxisLockMode);
|
||||
return static_cast<AxisLockMode>(gfxPrefs::APZAxisLockMode());
|
||||
}
|
||||
|
||||
nsEventStatus AsyncPanZoomController::ReceiveInputEvent(const InputData& aEvent) {
|
||||
@ -1088,7 +1047,7 @@ void AsyncPanZoomController::HandlePanningWithTouchAction(double aAngle, TouchBe
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::HandlePanning(double aAngle) {
|
||||
if (!gCrossSlideEnabled && (!mX.Scrollable() || !mY.Scrollable())) {
|
||||
if (!gfxPrefs::APZCrossSlideEnabled() && (!mX.Scrollable() || !mY.Scrollable())) {
|
||||
SetState(PANNING);
|
||||
} else if (IsCloseToHorizontal(aAngle, AXIS_LOCK_ANGLE)) {
|
||||
mY.SetAxisLocked(true);
|
||||
@ -1187,7 +1146,7 @@ void AsyncPanZoomController::AttemptScroll(const ScreenPoint& aStartPoint,
|
||||
ScheduleComposite();
|
||||
|
||||
TimeDuration timePaintDelta = mPaintThrottler.TimeSinceLastRequest(GetFrameTime());
|
||||
if (timePaintDelta.ToMilliseconds() > gPanRepaintInterval) {
|
||||
if (timePaintDelta.ToMilliseconds() > gfxPrefs::APZPanRepaintInterval()) {
|
||||
RequestContentRepaint();
|
||||
}
|
||||
UpdateSharedCompositorFrameMetrics();
|
||||
@ -1386,12 +1345,12 @@ static CSSSize
|
||||
CalculateDisplayPortSize(const CSSSize& aCompositionSize,
|
||||
const CSSPoint& aVelocity)
|
||||
{
|
||||
float xMultiplier = fabsf(aVelocity.x) < gMinSkateSpeed
|
||||
? gXStationarySizeMultiplier
|
||||
: gXSkateSizeMultiplier;
|
||||
float yMultiplier = fabsf(aVelocity.y) < gMinSkateSpeed
|
||||
? gYStationarySizeMultiplier
|
||||
: gYSkateSizeMultiplier;
|
||||
float xMultiplier = fabsf(aVelocity.x) < gfxPrefs::APZMinSkateSpeed()
|
||||
? gfxPrefs::APZXStationarySizeMultiplier()
|
||||
: gfxPrefs::APZXSkateSizeMultiplier();
|
||||
float yMultiplier = fabsf(aVelocity.y) < gfxPrefs::APZMinSkateSpeed()
|
||||
? gfxPrefs::APZYStationarySizeMultiplier()
|
||||
: gfxPrefs::APZYSkateSizeMultiplier();
|
||||
return CSSSize(aCompositionSize.width * xMultiplier,
|
||||
aCompositionSize.height * yMultiplier);
|
||||
}
|
||||
@ -1439,15 +1398,15 @@ const LayerMargin AsyncPanZoomController::CalculatePendingDisplayPort(
|
||||
// Calculate the displayport size based on how fast we're moving along each axis.
|
||||
CSSSize displayPortSize = CalculateDisplayPortSize(compositionSize, velocity);
|
||||
|
||||
if (gEnlargeDisplayPortWhenClipped) {
|
||||
if (gfxPrefs::APZEnlargeDisplayPortWhenClipped()) {
|
||||
RedistributeDisplayPortExcess(displayPortSize, scrollableRect);
|
||||
}
|
||||
|
||||
// Offset the displayport, depending on how fast we're moving and the
|
||||
// estimated time it takes to paint, to try to minimise checkerboarding.
|
||||
float estimatedPaintDurationMillis = (float)(aEstimatedPaintDuration * 1000.0);
|
||||
float paintFactor = (gUsePaintDuration ? estimatedPaintDurationMillis : 50.0f);
|
||||
CSSRect displayPort = CSSRect(scrollOffset + (velocity * paintFactor * gVelocityBias),
|
||||
float paintFactor = (gfxPrefs::APZUsePaintDuration() ? estimatedPaintDurationMillis : 50.0f);
|
||||
CSSRect displayPort = CSSRect(scrollOffset + (velocity * paintFactor * gfxPrefs::APZVelocityBias()),
|
||||
displayPortSize);
|
||||
|
||||
// Re-center the displayport based on its expansion over the composition size.
|
||||
@ -1646,7 +1605,7 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
|
||||
// with the last event.
|
||||
// Otherwise, start a timer to fire the event sAsyncScrollTimeout ms from now.
|
||||
TimeDuration delta = aSampleTime - mLastAsyncScrollTime;
|
||||
if (delta.ToMilliseconds() > gAsyncScrollThrottleTime &&
|
||||
if (delta.ToMilliseconds() > gfxPrefs::APZAsyncScrollThrottleTime() &&
|
||||
mCurrentAsyncScrollOffset != mLastAsyncScrollOffset) {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
mLastAsyncScrollTime = aSampleTime;
|
||||
@ -1658,7 +1617,7 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
|
||||
NewRunnableMethod(this, &AsyncPanZoomController::FireAsyncScrollOnTimeout);
|
||||
MessageLoop::current()->PostDelayedTask(FROM_HERE,
|
||||
mAsyncScrollTimeoutTask,
|
||||
gAsyncScrollTimeout);
|
||||
gfxPrefs::APZAsyncScrollTimeout());
|
||||
}
|
||||
|
||||
return requestAnimationFrame;
|
||||
@ -1677,7 +1636,7 @@ ViewTransform AsyncPanZoomController::GetCurrentAsyncTransform() {
|
||||
|
||||
// If checkerboarding has been disallowed, clamp the scroll position to stay
|
||||
// within rendered content.
|
||||
if (!gAllowCheckerboarding &&
|
||||
if (!gfxPrefs::APZAllowCheckerboarding() &&
|
||||
!mLastContentPaintMetrics.mDisplayPort.IsEmpty()) {
|
||||
CSSSize compositedSize = mLastContentPaintMetrics.CalculateCompositedSizeInCssPixels();
|
||||
CSSPoint maxScrollOffset = lastPaintScrollOffset +
|
||||
@ -1756,7 +1715,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
|
||||
// Initialize our internal state to something sane when the content
|
||||
// that was just painted is something we knew nothing about previously
|
||||
mPaintThrottler.ClearHistory();
|
||||
mPaintThrottler.SetMaxDurations(gNumPaintDurationSamples);
|
||||
mPaintThrottler.SetMaxDurations(gfxPrefs::APZNumPaintDurationSamples());
|
||||
|
||||
mX.CancelTouch();
|
||||
mY.CancelTouch();
|
||||
@ -2045,7 +2004,7 @@ void AsyncPanZoomController::SetContentResponseTimer() {
|
||||
mContentResponseTimeoutTask =
|
||||
NewRunnableMethod(this, &AsyncPanZoomController::TimeoutContentResponse);
|
||||
|
||||
PostDelayedTask(mContentResponseTimeoutTask, gContentResponseTimeout);
|
||||
PostDelayedTask(mContentResponseTimeoutTask, gfxPrefs::APZContentResponseTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,58 +22,6 @@
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
/**
|
||||
* These are the preferences that control the behavior of APZ
|
||||
*/
|
||||
|
||||
/**
|
||||
* "apz.max_event_acceleration"
|
||||
*
|
||||
* Maximum acceleration that can happen between two frames. Velocity is
|
||||
* throttled if it's above this. This may happen if a time delta is very low,
|
||||
* or we get a touch point very far away from the previous position for some
|
||||
* reason.
|
||||
*
|
||||
* The default value is 999.0f, set in gfxPrefs.h
|
||||
*/
|
||||
|
||||
/**
|
||||
* "apz.fling_friction"
|
||||
*
|
||||
* Amount of friction applied during flings.
|
||||
*
|
||||
* The default value is 0.002f, set in gfxPrefs.h
|
||||
*/
|
||||
|
||||
/**
|
||||
* "apz.fling_stopped_threshold"
|
||||
*
|
||||
* When flinging, if the velocity goes below this number, we just stop the
|
||||
* animation completely. This is to prevent asymptotically approaching 0
|
||||
* velocity and rerendering unnecessarily.
|
||||
*
|
||||
* The default value is 0.01f, set in gfxPrefs.h.
|
||||
*/
|
||||
|
||||
/**
|
||||
* "apz.max_velocity_queue_size"
|
||||
*
|
||||
* Maximum size of velocity queue. The queue contains last N velocity records.
|
||||
* On touch end we calculate the average velocity in order to compensate
|
||||
* touch/mouse drivers misbehaviour.
|
||||
*
|
||||
* The default value is 5, set in gfxPrefs.h
|
||||
*/
|
||||
|
||||
/**
|
||||
* "apz.max_velocity_inches_per_ms"
|
||||
*
|
||||
* Maximum velocity in inches per millisecond. Velocity will be capped at this
|
||||
* value if a faster fling occurs. Negative values indicate unlimited velocity.
|
||||
*
|
||||
* The default value is -1.0f, set in gfxPrefs.h
|
||||
*/
|
||||
|
||||
Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController)
|
||||
: mPos(0),
|
||||
mVelocity(0.0f),
|
||||
|
@ -228,42 +228,34 @@ struct GrallocParam {
|
||||
IntSize size;
|
||||
uint32_t format;
|
||||
uint32_t usage;
|
||||
SurfaceDescriptor* buffer;
|
||||
MaybeMagicGrallocBufferHandle* handle;
|
||||
PGrallocBufferChild** child;
|
||||
|
||||
GrallocParam(const IntSize& aSize,
|
||||
const uint32_t& aFormat,
|
||||
const uint32_t& aUsage,
|
||||
SurfaceDescriptor* aBuffer)
|
||||
MaybeMagicGrallocBufferHandle* aHandle,
|
||||
PGrallocBufferChild** aChild)
|
||||
: size(aSize)
|
||||
, format(aFormat)
|
||||
, usage(aUsage)
|
||||
, buffer(aBuffer)
|
||||
, handle(aHandle)
|
||||
, child(aChild)
|
||||
{}
|
||||
};
|
||||
|
||||
// dispatched function
|
||||
static void AllocSurfaceDescriptorGrallocSync(const GrallocParam& aParam,
|
||||
Monitor* aBarrier,
|
||||
bool* aDone)
|
||||
static void AllocGrallocBufferSync(const GrallocParam& aParam,
|
||||
Monitor* aBarrier,
|
||||
bool* aDone)
|
||||
{
|
||||
MonitorAutoLock autoMon(*aBarrier);
|
||||
|
||||
sImageBridgeChildSingleton->AllocSurfaceDescriptorGrallocNow(aParam.size,
|
||||
aParam.format,
|
||||
aParam.usage,
|
||||
aParam.buffer);
|
||||
*aDone = true;
|
||||
aBarrier->NotifyAll();
|
||||
}
|
||||
|
||||
// dispatched function
|
||||
static void DeallocSurfaceDescriptorGrallocSync(const SurfaceDescriptor& aBuffer,
|
||||
Monitor* aBarrier,
|
||||
bool* aDone)
|
||||
{
|
||||
MonitorAutoLock autoMon(*aBarrier);
|
||||
|
||||
sImageBridgeChildSingleton->DeallocSurfaceDescriptorGrallocNow(aBuffer);
|
||||
sImageBridgeChildSingleton->AllocGrallocBufferNow(aParam.size,
|
||||
aParam.format,
|
||||
aParam.usage,
|
||||
aParam.handle,
|
||||
aParam.child);
|
||||
*aDone = true;
|
||||
aBarrier->NotifyAll();
|
||||
}
|
||||
@ -712,92 +704,6 @@ ImageBridgeChild::DeallocPGrallocBufferChild(PGrallocBufferChild* actor)
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
ImageBridgeChild::AllocSurfaceDescriptorGralloc(const IntSize& aSize,
|
||||
const uint32_t& aFormat,
|
||||
const uint32_t& aUsage,
|
||||
SurfaceDescriptor* aBuffer)
|
||||
{
|
||||
if (InImageBridgeChildThread()) {
|
||||
return ImageBridgeChild::AllocSurfaceDescriptorGrallocNow(aSize, aFormat, aUsage, aBuffer);
|
||||
}
|
||||
|
||||
Monitor barrier("AllocSurfaceDescriptorGralloc Lock");
|
||||
MonitorAutoLock autoMon(barrier);
|
||||
bool done = false;
|
||||
|
||||
GetMessageLoop()->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableFunction(&AllocSurfaceDescriptorGrallocSync,
|
||||
GrallocParam(aSize, aFormat, aUsage, aBuffer), &barrier, &done));
|
||||
|
||||
while (!done) {
|
||||
barrier.Wait();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ImageBridgeChild::AllocSurfaceDescriptorGrallocNow(const IntSize& aSize,
|
||||
const uint32_t& aFormat,
|
||||
const uint32_t& aUsage,
|
||||
SurfaceDescriptor* aBuffer)
|
||||
{
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
MaybeMagicGrallocBufferHandle handle;
|
||||
PGrallocBufferChild* gc = SendPGrallocBufferConstructor(aSize, aFormat, aUsage, &handle);
|
||||
if (handle.Tnull_t == handle.type()) {
|
||||
PGrallocBufferChild::Send__delete__(gc);
|
||||
return false;
|
||||
}
|
||||
|
||||
GrallocBufferActor* gba = static_cast<GrallocBufferActor*>(gc);
|
||||
gba->InitFromHandle(handle.get_MagicGrallocBufferHandle());
|
||||
|
||||
*aBuffer = SurfaceDescriptorGralloc(nullptr, gc, aSize, /* external */ false, /* swapRB */ false);
|
||||
return true;
|
||||
#else
|
||||
NS_RUNTIMEABORT("No gralloc buffers for you");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
ImageBridgeChild::DeallocSurfaceDescriptorGralloc(const SurfaceDescriptor& aBuffer)
|
||||
{
|
||||
if (InImageBridgeChildThread()) {
|
||||
return ImageBridgeChild::DeallocSurfaceDescriptorGrallocNow(aBuffer);
|
||||
}
|
||||
|
||||
Monitor barrier("DeallocSurfaceDescriptor Lock");
|
||||
MonitorAutoLock autoMon(barrier);
|
||||
bool done = false;
|
||||
|
||||
GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&DeallocSurfaceDescriptorGrallocSync,
|
||||
aBuffer, &barrier, &done));
|
||||
|
||||
while (!done) {
|
||||
barrier.Wait();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ImageBridgeChild::DeallocSurfaceDescriptorGrallocNow(const SurfaceDescriptor& aBuffer)
|
||||
{
|
||||
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
|
||||
PGrallocBufferChild* gbp =
|
||||
aBuffer.get_SurfaceDescriptorGralloc().bufferChild();
|
||||
PGrallocBufferChild::Send__delete__(gbp);
|
||||
|
||||
return true;
|
||||
#else
|
||||
NS_RUNTIMEABORT("Um, how did we get here?");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
ImageBridgeChild::AllocUnsafeShmem(size_t aSize,
|
||||
ipc::SharedMemory::SharedMemoryType aType,
|
||||
@ -924,15 +830,44 @@ ImageBridgeChild::AllocGrallocBuffer(const IntSize& aSize,
|
||||
uint32_t aFormat,
|
||||
uint32_t aUsage,
|
||||
MaybeMagicGrallocBufferHandle* aHandle)
|
||||
{
|
||||
if (InImageBridgeChildThread()) {
|
||||
PGrallocBufferChild* child = nullptr;
|
||||
ImageBridgeChild::AllocGrallocBufferNow(aSize, aFormat, aUsage, aHandle, &child);
|
||||
return child;
|
||||
}
|
||||
|
||||
Monitor barrier("AllocGrallocBuffer Lock");
|
||||
MonitorAutoLock autoMon(barrier);
|
||||
bool done = false;
|
||||
PGrallocBufferChild* child = nullptr;
|
||||
|
||||
GetMessageLoop()->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableFunction(&AllocGrallocBufferSync,
|
||||
GrallocParam(aSize, aFormat, aUsage, aHandle, &child), &barrier, &done));
|
||||
|
||||
while (!done) {
|
||||
barrier.Wait();
|
||||
}
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
void
|
||||
ImageBridgeChild::AllocGrallocBufferNow(const gfx::IntSize& aSize,
|
||||
uint32_t aFormat, uint32_t aUsage,
|
||||
MaybeMagicGrallocBufferHandle* aHandle,
|
||||
PGrallocBufferChild** aChild)
|
||||
{
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
return SendPGrallocBufferConstructor(aSize,
|
||||
aFormat,
|
||||
aUsage,
|
||||
aHandle);
|
||||
*aChild = SendPGrallocBufferConstructor(aSize,
|
||||
aFormat,
|
||||
aUsage,
|
||||
aHandle);
|
||||
#else
|
||||
NS_RUNTIMEABORT("not implemented");
|
||||
return nullptr;
|
||||
aChild = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -200,44 +200,6 @@ public:
|
||||
virtual bool
|
||||
DeallocPTextureChild(PTextureChild* actor) MOZ_OVERRIDE;
|
||||
|
||||
/**
|
||||
* Allocate a gralloc SurfaceDescriptor remotely.
|
||||
*/
|
||||
bool
|
||||
AllocSurfaceDescriptorGralloc(const gfx::IntSize& aSize,
|
||||
const uint32_t& aFormat,
|
||||
const uint32_t& aUsage,
|
||||
SurfaceDescriptor* aBuffer);
|
||||
|
||||
/**
|
||||
* Part of the allocation of gralloc SurfaceDescriptor that is
|
||||
* executed on the ImageBridgeChild thread after invoking
|
||||
* AllocSurfaceDescriptorGralloc.
|
||||
*
|
||||
* Must be called from the ImageBridgeChild thread.
|
||||
*/
|
||||
bool
|
||||
AllocSurfaceDescriptorGrallocNow(const gfx::IntSize& aSize,
|
||||
const uint32_t& aFormat,
|
||||
const uint32_t& aUsage,
|
||||
SurfaceDescriptor* aBuffer);
|
||||
|
||||
/**
|
||||
* Deallocate a remotely allocated gralloc buffer.
|
||||
*/
|
||||
bool
|
||||
DeallocSurfaceDescriptorGralloc(const SurfaceDescriptor& aBuffer);
|
||||
|
||||
/**
|
||||
* Part of the deallocation of gralloc SurfaceDescriptor that is
|
||||
* executed on the ImageBridgeChild thread after invoking
|
||||
* DeallocSurfaceDescriptorGralloc.
|
||||
*
|
||||
* Must be called from the ImageBridgeChild thread.
|
||||
*/
|
||||
bool
|
||||
DeallocSurfaceDescriptorGrallocNow(const SurfaceDescriptor& aBuffer);
|
||||
|
||||
TemporaryRef<ImageClient> CreateImageClient(CompositableType aType);
|
||||
TemporaryRef<ImageClient> CreateImageClientNow(CompositableType aType);
|
||||
|
||||
@ -383,6 +345,10 @@ public:
|
||||
|
||||
virtual bool IsSameProcess() const MOZ_OVERRIDE;
|
||||
|
||||
void AllocGrallocBufferNow(const gfx::IntSize& aSize,
|
||||
uint32_t aFormat, uint32_t aUsage,
|
||||
MaybeMagicGrallocBufferHandle* aHandle,
|
||||
PGrallocBufferChild** aChild);
|
||||
protected:
|
||||
ImageBridgeChild();
|
||||
bool DispatchAllocShmemInternal(size_t aSize,
|
||||
|
@ -449,10 +449,6 @@ void
|
||||
ShadowLayerForwarder::RemoveTextureFromCompositable(CompositableClient* aCompositable,
|
||||
TextureClient* aTexture)
|
||||
{
|
||||
MOZ_ASSERT(aCompositable);
|
||||
MOZ_ASSERT(aCompositable->GetIPDLActor());
|
||||
MOZ_ASSERT(aTexture);
|
||||
MOZ_ASSERT(aTexture->GetIPDLActor());
|
||||
mTxn->AddEdit(OpRemoveTexture(nullptr, aCompositable->GetIPDLActor(),
|
||||
nullptr, aTexture->GetIPDLActor()));
|
||||
if (aTexture->GetFlags() & TEXTURE_DEALLOCATE_CLIENT) {
|
||||
|
@ -98,7 +98,7 @@ DrawQuads(GLContext *aGLContext,
|
||||
aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
|
||||
bool texCoords = (texCoordAttribIndex != GLuint(-1));
|
||||
|
||||
GLsizei bytes = aRects.elements() * 2 * sizeof(GLfloat);
|
||||
GLsizei bytes = aRects.vertCoords().Length() * 2 * sizeof(GLfloat);
|
||||
|
||||
GLsizei total = bytes;
|
||||
if (texCoords) {
|
||||
@ -136,7 +136,7 @@ DrawQuads(GLContext *aGLContext,
|
||||
aGLContext->fDisableVertexAttribArray(texCoordAttribIndex);
|
||||
}
|
||||
|
||||
aGLContext->fDrawArrays(aMode, 0, aRects.elements());
|
||||
aGLContext->fDrawArrays(aMode, 0, aRects.vertCoords().Length());
|
||||
|
||||
aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
@ -282,7 +282,7 @@ CompositorOGL::Initialize()
|
||||
LOCAL_GL_NONE
|
||||
};
|
||||
|
||||
if (!mGLContext->IsGLES2()) {
|
||||
if (!mGLContext->IsGLES()) {
|
||||
// No TEXTURE_RECTANGLE_ARB available on ES2
|
||||
textureTargets[1] = LOCAL_GL_TEXTURE_RECTANGLE_ARB;
|
||||
}
|
||||
@ -372,8 +372,6 @@ CompositorOGL::Initialize()
|
||||
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
|
||||
/* Then quad texcoords */
|
||||
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
|
||||
/* Then flipped quad texcoords */
|
||||
0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
|
||||
};
|
||||
mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, sizeof(vertices), vertices, LOCAL_GL_STATIC_DRAW);
|
||||
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
||||
@ -479,7 +477,7 @@ CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
|
||||
Matrix4x4 transform;
|
||||
ToMatrix4x4(aTextureTransform * textureTransform, transform);
|
||||
aProg->SetTextureTransform(transform);
|
||||
BindAndDrawQuad(aProg, false);
|
||||
BindAndDrawQuad(aProg);
|
||||
} else {
|
||||
Matrix4x4 transform;
|
||||
ToMatrix4x4(aTextureTransform, transform);
|
||||
@ -736,7 +734,7 @@ CompositorOGL::CreateFBOWithTexture(const IntRect& aRect, bool aCopyFromSource,
|
||||
GetFrameBufferInternalFormat(gl(), aSourceFrameBuffer, mWidget);
|
||||
|
||||
bool isFormatCompatibleWithRGBA
|
||||
= gl()->IsGLES2() ? (format == LOCAL_GL_RGBA)
|
||||
= gl()->IsGLES() ? (format == LOCAL_GL_RGBA)
|
||||
: true;
|
||||
|
||||
if (isFormatCompatibleWithRGBA) {
|
||||
@ -988,7 +986,7 @@ CompositorOGL::DrawQuadInternal(const Rect& aRect,
|
||||
BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE0, maskQuadTransform);
|
||||
}
|
||||
|
||||
BindAndDrawQuad(program, false, aDrawMode);
|
||||
BindAndDrawQuad(program, aDrawMode);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1072,7 +1070,12 @@ CompositorOGL::DrawQuadInternal(const Rect& aRect,
|
||||
|
||||
surface->BindTexture(LOCAL_GL_TEXTURE0, mFBOTextureTarget);
|
||||
|
||||
program->SetTextureTransform(Matrix4x4());
|
||||
// Drawing is always flipped, but when copying between surfaces we want to avoid
|
||||
// this, so apply a flip here to cancel the other one out.
|
||||
Matrix transform;
|
||||
transform.Translate(0.0, 1.0);
|
||||
transform.Scale(1.0f, -1.0f);
|
||||
program->SetTextureTransform(Matrix4x4::From2D(transform));
|
||||
program->SetTextureUnit(0);
|
||||
|
||||
if (maskType != MaskNone) {
|
||||
@ -1089,7 +1092,7 @@ CompositorOGL::DrawQuadInternal(const Rect& aRect,
|
||||
// Drawing is always flipped, but when copying between surfaces we want to avoid
|
||||
// this. Pass true for the flip parameter to introduce a second flip
|
||||
// that cancels the other one out.
|
||||
BindAndDrawQuad(program, true);
|
||||
BindAndDrawQuad(program);
|
||||
}
|
||||
break;
|
||||
case EFFECT_COMPONENT_ALPHA: {
|
||||
@ -1190,19 +1193,19 @@ CompositorOGL::EndFrame()
|
||||
// Unbind all textures
|
||||
mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
|
||||
if (!mGLContext->IsGLES2()) {
|
||||
if (!mGLContext->IsGLES()) {
|
||||
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
}
|
||||
|
||||
mGLContext->fActiveTexture(LOCAL_GL_TEXTURE1);
|
||||
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
|
||||
if (!mGLContext->IsGLES2()) {
|
||||
if (!mGLContext->IsGLES()) {
|
||||
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
}
|
||||
|
||||
mGLContext->fActiveTexture(LOCAL_GL_TEXTURE2);
|
||||
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
|
||||
if (!mGLContext->IsGLES2()) {
|
||||
if (!mGLContext->IsGLES()) {
|
||||
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
}
|
||||
}
|
||||
@ -1317,7 +1320,7 @@ CompositorOGL::CopyToTarget(DrawTarget *aTarget, const gfx::Matrix& aTransform)
|
||||
|
||||
mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
|
||||
|
||||
if (!mGLContext->IsGLES2()) {
|
||||
if (!mGLContext->IsGLES()) {
|
||||
// GLES2 promises that binding to any custom FBO will attach
|
||||
// to GL_COLOR_ATTACHMENT0 attachment point.
|
||||
mGLContext->fReadBuffer(LOCAL_GL_BACK);
|
||||
@ -1429,28 +1432,16 @@ CompositorOGL::QuadVBOTexCoordsAttrib(GLuint aAttribIndex) {
|
||||
(GLvoid*) QuadVBOTexCoordOffset());
|
||||
}
|
||||
|
||||
void
|
||||
CompositorOGL::QuadVBOFlippedTexCoordsAttrib(GLuint aAttribIndex) {
|
||||
mGLContext->fVertexAttribPointer(aAttribIndex, 2,
|
||||
LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
|
||||
(GLvoid*) QuadVBOFlippedTexCoordOffset());
|
||||
}
|
||||
|
||||
void
|
||||
CompositorOGL::BindAndDrawQuad(GLuint aVertAttribIndex,
|
||||
GLuint aTexCoordAttribIndex,
|
||||
bool aFlipped,
|
||||
GLuint aDrawMode)
|
||||
{
|
||||
BindQuadVBO();
|
||||
QuadVBOVerticesAttrib(aVertAttribIndex);
|
||||
|
||||
if (aTexCoordAttribIndex != GLuint(-1)) {
|
||||
if (aFlipped)
|
||||
QuadVBOFlippedTexCoordsAttrib(aTexCoordAttribIndex);
|
||||
else
|
||||
QuadVBOTexCoordsAttrib(aTexCoordAttribIndex);
|
||||
|
||||
QuadVBOTexCoordsAttrib(aTexCoordAttribIndex);
|
||||
mGLContext->fEnableVertexAttribArray(aTexCoordAttribIndex);
|
||||
}
|
||||
|
||||
@ -1464,13 +1455,12 @@ CompositorOGL::BindAndDrawQuad(GLuint aVertAttribIndex,
|
||||
|
||||
void
|
||||
CompositorOGL::BindAndDrawQuad(ShaderProgramOGL *aProg,
|
||||
bool aFlipped,
|
||||
GLuint aDrawMode)
|
||||
{
|
||||
NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
|
||||
BindAndDrawQuad(aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib),
|
||||
aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib),
|
||||
aFlipped, aDrawMode);
|
||||
aDrawMode);
|
||||
}
|
||||
|
||||
GLuint
|
||||
|
@ -311,9 +311,10 @@ private:
|
||||
CompositingRenderTargetOGL* mWindowRenderTarget;
|
||||
#endif
|
||||
|
||||
/** VBO that has some basics in it for a textured quad,
|
||||
* including vertex coords and texcoords for both
|
||||
* flipped and unflipped textures */
|
||||
/**
|
||||
* VBO that has some basics in it for a textured quad, including vertex
|
||||
* coords and texcoords.
|
||||
*/
|
||||
GLuint mQuadVBO;
|
||||
|
||||
/**
|
||||
@ -366,18 +367,14 @@ private:
|
||||
|
||||
GLintptr QuadVBOVertexOffset() { return 0; }
|
||||
GLintptr QuadVBOTexCoordOffset() { return sizeof(float)*4*2; }
|
||||
GLintptr QuadVBOFlippedTexCoordOffset() { return sizeof(float)*8*2; }
|
||||
|
||||
void BindQuadVBO();
|
||||
void QuadVBOVerticesAttrib(GLuint aAttribIndex);
|
||||
void QuadVBOTexCoordsAttrib(GLuint aAttribIndex);
|
||||
void QuadVBOFlippedTexCoordsAttrib(GLuint aAttribIndex);
|
||||
void BindAndDrawQuad(GLuint aVertAttribIndex,
|
||||
GLuint aTexCoordAttribIndex,
|
||||
bool aFlipped = false,
|
||||
GLuint aDrawMode = LOCAL_GL_TRIANGLE_STRIP);
|
||||
void BindAndDrawQuad(ShaderProgramOGL *aProg,
|
||||
bool aFlipped = false,
|
||||
GLuint aDrawMode = LOCAL_GL_TRIANGLE_STRIP);
|
||||
void BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
|
||||
const gfx3DMatrix& aTextureTransform,
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxASurface.h"
|
||||
#include "gfxImageSurface.h" // for gfxImageSurface
|
||||
#include "GrallocImages.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
@ -21,29 +20,6 @@ namespace layers {
|
||||
using namespace mozilla::gfx;
|
||||
using namespace android;
|
||||
|
||||
class GraphicBufferLockedTextureClientData : public TextureClientData {
|
||||
public:
|
||||
GraphicBufferLockedTextureClientData(GraphicBufferLocked* aBufferLocked)
|
||||
: mBufferLocked(aBufferLocked)
|
||||
{
|
||||
MOZ_COUNT_CTOR(GrallocTextureClientData);
|
||||
}
|
||||
|
||||
~GraphicBufferLockedTextureClientData()
|
||||
{
|
||||
MOZ_COUNT_DTOR(GrallocTextureClientData);
|
||||
MOZ_ASSERT(!mBufferLocked, "Forgot to unlock the GraphicBufferLocked?");
|
||||
}
|
||||
|
||||
virtual void DeallocateSharedData(ISurfaceAllocator*) MOZ_OVERRIDE
|
||||
{
|
||||
mBufferLocked = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<GraphicBufferLocked> mBufferLocked;
|
||||
};
|
||||
|
||||
class GrallocTextureClientData : public TextureClientData {
|
||||
public:
|
||||
GrallocTextureClientData(GrallocBufferActor* aActor)
|
||||
@ -55,7 +31,7 @@ public:
|
||||
~GrallocTextureClientData()
|
||||
{
|
||||
MOZ_COUNT_DTOR(GrallocTextureClientData);
|
||||
MOZ_ASSERT(!mGrallocActor, "Forgot to unlock the GraphicBufferLocked?");
|
||||
MOZ_ASSERT(!mGrallocActor);
|
||||
}
|
||||
|
||||
virtual void DeallocateSharedData(ISurfaceAllocator* allocator) MOZ_OVERRIDE
|
||||
@ -76,18 +52,10 @@ private:
|
||||
TextureClientData*
|
||||
GrallocTextureClientOGL::DropTextureData()
|
||||
{
|
||||
if (mBufferLocked) {
|
||||
TextureClientData* result = new GraphicBufferLockedTextureClientData(mBufferLocked);
|
||||
mBufferLocked = nullptr;
|
||||
mGrallocActor = nullptr;
|
||||
mGraphicBuffer = nullptr;
|
||||
return result;
|
||||
} else {
|
||||
TextureClientData* result = new GrallocTextureClientData(mGrallocActor);
|
||||
mGrallocActor = nullptr;
|
||||
mGraphicBuffer = nullptr;
|
||||
return result;
|
||||
}
|
||||
TextureClientData* result = new GrallocTextureClientData(mGrallocActor);
|
||||
mGrallocActor = nullptr;
|
||||
mGraphicBuffer = nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
GrallocTextureClientOGL::GrallocTextureClientOGL(GrallocBufferActor* aActor,
|
||||
@ -96,6 +64,7 @@ GrallocTextureClientOGL::GrallocTextureClientOGL(GrallocBufferActor* aActor,
|
||||
TextureFlags aFlags)
|
||||
: BufferTextureClient(nullptr, gfx::SurfaceFormat::UNKNOWN, aMoz2dBackend, aFlags)
|
||||
, mMappedBuffer(nullptr)
|
||||
, mMediaBuffer(nullptr)
|
||||
{
|
||||
InitWith(aActor, aSize);
|
||||
MOZ_COUNT_CTOR(GrallocTextureClientOGL);
|
||||
@ -107,6 +76,7 @@ GrallocTextureClientOGL::GrallocTextureClientOGL(ISurfaceAllocator* aAllocator,
|
||||
TextureFlags aFlags)
|
||||
: BufferTextureClient(aAllocator, aFormat, aMoz2dBackend, aFlags)
|
||||
, mMappedBuffer(nullptr)
|
||||
, mMediaBuffer(nullptr)
|
||||
{
|
||||
MOZ_COUNT_CTOR(GrallocTextureClientOGL);
|
||||
}
|
||||
@ -117,16 +87,14 @@ GrallocTextureClientOGL::~GrallocTextureClientOGL()
|
||||
if (ShouldDeallocateInDestructor()) {
|
||||
// If the buffer has never been shared we must deallocate it or it would
|
||||
// leak.
|
||||
if (!mBufferLocked) {
|
||||
// We just need to wrap the actor in a SurfaceDescriptor because that's what
|
||||
// ISurfaceAllocator uses as input, we don't care about the other parameters.
|
||||
SurfaceDescriptor sd = SurfaceDescriptorGralloc(nullptr, mGrallocActor,
|
||||
IntSize(0, 0),
|
||||
false, false);
|
||||
// We just need to wrap the actor in a SurfaceDescriptor because that's what
|
||||
// ISurfaceAllocator uses as input, we don't care about the other parameters.
|
||||
SurfaceDescriptor sd = SurfaceDescriptorGralloc(nullptr, mGrallocActor,
|
||||
IntSize(0, 0),
|
||||
false, false);
|
||||
|
||||
ISurfaceAllocator* allocator = GetAllocator();
|
||||
allocator->DestroySharedSurface(&sd);
|
||||
}
|
||||
ISurfaceAllocator* allocator = GetAllocator();
|
||||
allocator->DestroySharedSurface(&sd);
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,12 +109,6 @@ GrallocTextureClientOGL::InitWith(GrallocBufferActor* aActor, gfx::IntSize aSize
|
||||
mSize = aSize;
|
||||
}
|
||||
|
||||
void
|
||||
GrallocTextureClientOGL::SetGraphicBufferLocked(GraphicBufferLocked* aBufferLocked)
|
||||
{
|
||||
mBufferLocked = aBufferLocked;
|
||||
}
|
||||
|
||||
bool
|
||||
GrallocTextureClientOGL::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
|
||||
{
|
||||
@ -180,11 +142,7 @@ GrallocTextureClientOGL::UpdateSurface(gfxASurface* aSurface)
|
||||
void
|
||||
GrallocTextureClientOGL::SetReleaseFenceHandle(FenceHandle aReleaseFenceHandle)
|
||||
{
|
||||
if (mBufferLocked) {
|
||||
mBufferLocked->SetReleaseFenceHandle(aReleaseFenceHandle);
|
||||
} else {
|
||||
mReleaseFenceHandle = aReleaseFenceHandle;
|
||||
}
|
||||
mReleaseFenceHandle = aReleaseFenceHandle;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -13,11 +13,14 @@
|
||||
#include "mozilla/layers/ShadowLayerUtilsGralloc.h"
|
||||
#include <ui/GraphicBuffer.h>
|
||||
|
||||
|
||||
namespace android {
|
||||
class MediaBuffer;
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class GraphicBufferLocked;
|
||||
|
||||
/**
|
||||
* A TextureClient implementation based on android::GraphicBuffer (also referred to
|
||||
* as "gralloc").
|
||||
@ -102,7 +105,20 @@ public:
|
||||
|
||||
virtual size_t GetBufferSize() const MOZ_OVERRIDE;
|
||||
|
||||
void SetGraphicBufferLocked(GraphicBufferLocked* aBufferLocked);
|
||||
/**
|
||||
* Hold android::MediaBuffer.
|
||||
* MediaBuffer needs to be add refed to keep MediaBuffer alive
|
||||
* during TextureClient is in use.
|
||||
*/
|
||||
void SetMediaBuffer(android::MediaBuffer* aMediaBuffer)
|
||||
{
|
||||
mMediaBuffer = aMediaBuffer;
|
||||
}
|
||||
|
||||
android::MediaBuffer* GetMediaBuffer()
|
||||
{
|
||||
return mMediaBuffer;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
@ -110,8 +126,6 @@ protected:
|
||||
*/
|
||||
GrallocBufferActor* mGrallocActor;
|
||||
|
||||
RefPtr<GraphicBufferLocked> mBufferLocked;
|
||||
|
||||
android::sp<android::GraphicBuffer> mGraphicBuffer;
|
||||
|
||||
/**
|
||||
@ -128,6 +142,8 @@ protected:
|
||||
* Extra size member is necessary. See Bug 850566.
|
||||
*/
|
||||
gfx::IntSize mSize;
|
||||
|
||||
android::MediaBuffer* mMediaBuffer;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
@ -74,6 +74,14 @@ public:
|
||||
NS_ERROR("This shouldn't be called because we never enable hyphens");
|
||||
return 0;
|
||||
}
|
||||
virtual already_AddRefed<gfxContext> GetContext() {
|
||||
NS_ERROR("This shouldn't be called because we never enable hyphens");
|
||||
return nullptr;
|
||||
}
|
||||
virtual uint32_t GetAppUnitsPerDevUnit() {
|
||||
NS_ERROR("This shouldn't be called because we never enable hyphens");
|
||||
return 60;
|
||||
}
|
||||
virtual void GetSpacing(uint32_t aStart, uint32_t aLength,
|
||||
Spacing* aSpacing) {
|
||||
NS_ERROR("This shouldn't be called because we never enable spacing");
|
||||
|
@ -335,14 +335,14 @@ ApzcTap(AsyncPanZoomController* apzc, int aX, int aY, int& aTime, int aTapLength
|
||||
return ApzcUp(apzc, aX, aY, aTime);
|
||||
}
|
||||
|
||||
TEST(AsyncPanZoomController, Constructor) {
|
||||
TEST_F(AsyncPanZoomControllerTester, Constructor) {
|
||||
// RefCounted class can't live in the stack
|
||||
nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
|
||||
nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
|
||||
apzc->SetFrameMetrics(TestFrameMetrics());
|
||||
}
|
||||
|
||||
TEST(AsyncPanZoomController, Pinch) {
|
||||
TEST_F(AsyncPanZoomControllerTester, Pinch) {
|
||||
nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
|
||||
nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
|
||||
|
||||
@ -385,7 +385,7 @@ TEST(AsyncPanZoomController, Pinch) {
|
||||
apzc->Destroy();
|
||||
}
|
||||
|
||||
TEST(AsyncPanZoomController, PinchWithTouchActionNone) {
|
||||
TEST_F(AsyncPanZoomControllerTester, PinchWithTouchActionNone) {
|
||||
nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
|
||||
nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
|
||||
|
||||
@ -419,7 +419,7 @@ TEST(AsyncPanZoomController, PinchWithTouchActionNone) {
|
||||
EXPECT_EQ(fm.GetScrollOffset().y, 300);
|
||||
}
|
||||
|
||||
TEST(AsyncPanZoomController, Overzoom) {
|
||||
TEST_F(AsyncPanZoomControllerTester, Overzoom) {
|
||||
nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
|
||||
nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
|
||||
|
||||
@ -446,7 +446,7 @@ TEST(AsyncPanZoomController, Overzoom) {
|
||||
EXPECT_LT(abs(fm.GetScrollOffset().y), 1e-5);
|
||||
}
|
||||
|
||||
TEST(AsyncPanZoomController, SimpleTransform) {
|
||||
TEST_F(AsyncPanZoomControllerTester, SimpleTransform) {
|
||||
TimeStamp testStartTime = TimeStamp::Now();
|
||||
// RefCounted class can't live in the stack
|
||||
nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
|
||||
@ -462,7 +462,7 @@ TEST(AsyncPanZoomController, SimpleTransform) {
|
||||
}
|
||||
|
||||
|
||||
TEST(AsyncPanZoomController, ComplexTransform) {
|
||||
TEST_F(AsyncPanZoomControllerTester, ComplexTransform) {
|
||||
TimeStamp testStartTime = TimeStamp::Now();
|
||||
AsyncPanZoomController::SetFrameTime(testStartTime);
|
||||
|
||||
@ -962,7 +962,7 @@ GetTargetAPZC(APZCTreeManager* manager, const ScreenPoint& aPoint,
|
||||
}
|
||||
|
||||
// A simple hit testing test that doesn't involve any transforms on layers.
|
||||
TEST(APZCTreeManager, HitTesting1) {
|
||||
TEST_F(APZCTreeManagerTester, HitTesting1) {
|
||||
nsTArray<nsRefPtr<Layer> > layers;
|
||||
nsRefPtr<LayerManager> lm;
|
||||
nsRefPtr<Layer> root = CreateTestLayerTree1(lm, layers);
|
||||
|
1039
gfx/thebes/CJKCompatSVS.cpp
Normal file
1039
gfx/thebes/CJKCompatSVS.cpp
Normal file
File diff suppressed because it is too large
Load Diff
77
gfx/thebes/gencjkcisvs.py
Normal file
77
gfx/thebes/gencjkcisvs.py
Normal file
@ -0,0 +1,77 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import os.path
|
||||
import re
|
||||
import sys
|
||||
|
||||
f = open(sys.argv[1] if len(sys.argv) > 1 else 'StandardizedVariants.txt')
|
||||
|
||||
line = f.readline()
|
||||
m = re.compile('^# (StandardizedVariants(-\d+(\.\d+)*)?\.txt)').search(line)
|
||||
fileversion = m.group(1)
|
||||
vsdict = {}
|
||||
r = re.compile('^([0-9A-F]{4,6}) (FE0[0-9A-F]); CJK COMPATIBILITY IDEOGRAPH-([0-9A-F]{4,6});')
|
||||
while True:
|
||||
line = f.readline()
|
||||
if not line:
|
||||
break
|
||||
if not 'CJK COMPATIBILITY IDEOGRAPH-' in line:
|
||||
continue
|
||||
|
||||
m = r.search(line)
|
||||
unified = int(m.group(1), 16)
|
||||
vs = int(m.group(2), 16)
|
||||
compat = int(m.group(3), 16)
|
||||
|
||||
if not vs in vsdict:
|
||||
vsdict[vs] = {}
|
||||
vsdict[vs][unified] = compat
|
||||
|
||||
f.close
|
||||
|
||||
offsets = []
|
||||
length = 10 + 11 * len(vsdict)
|
||||
for (k, mappings) in sorted(vsdict.items()):
|
||||
offsets.append(length)
|
||||
length += 4 + 5 * len(mappings)
|
||||
|
||||
f = open(sys.argv[2] if len(sys.argv) > 2 else 'CJKCompatSVS.cpp', 'wb')
|
||||
f.write("""// Generated by %s. Do not edit.
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define U16(v) (((v) >> 8) & 0xFF), ((v) & 0xFF)
|
||||
#define U24(v) (((v) >> 16) & 0xFF), (((v) >> 8) & 0xFF), ((v) & 0xFF)
|
||||
#define U32(v) (((v) >> 24) & 0xFF), (((v) >> 16) & 0xFF), (((v) >> 8) & 0xFF), ((v) & 0xFF)
|
||||
#define GLYPH(v) U16(v >= 0x2F800 ? (v) - (0x2F800 - 0xFB00) : (v))
|
||||
|
||||
// Fallback mappings for CJK Compatibility Ideographs Standardized Variants
|
||||
// taken from %s.
|
||||
// Using OpenType format 14 cmap subtable structure to reuse the lookup code
|
||||
// for fonts. The glyphID field is used to store the corresponding codepoints
|
||||
// CJK Compatibility Ideographs. To fit codepoints into the 16-bit glyphID
|
||||
// field, CJK Compatibility Ideographs Supplement (U+2F800..U+2FA1F) will be
|
||||
// mapped to 0xFB00..0xFD1F.
|
||||
extern const uint8_t sCJKCompatSVSTable[] = {
|
||||
""" % (os.path.basename(sys.argv[0]), fileversion))
|
||||
f.write(' U16(14), // format\n')
|
||||
f.write(' U32(%d), // length\n' % length)
|
||||
f.write(' U32(%d), // numVarSelectorRecords\n' % len(vsdict))
|
||||
for i, k in enumerate(sorted(vsdict.keys())):
|
||||
f.write(' U24(0x%04X), U32(0), U32(%d), // varSelectorRecord[%d]\n' % (k, offsets[i], i))
|
||||
for (k, mappings) in sorted(vsdict.items()):
|
||||
f.write(' // 0x%04X\n' % k)
|
||||
f.write(' U32(%d), // numUVSMappings\n' % len(mappings))
|
||||
for (unified, compat) in sorted(mappings.items()):
|
||||
f.write(' U24(0x%04X), GLYPH(0x%04X),\n' % (unified, compat))
|
||||
f.write("""};
|
||||
|
||||
#undef U16
|
||||
#undef U24
|
||||
#undef U32
|
||||
#undef GLYPH
|
||||
|
||||
static_assert(sizeof sCJKCompatSVSTable == %d, "Table generator has a bug.");
|
||||
""" % length)
|
@ -8,6 +8,7 @@
|
||||
#include "harfbuzz/hb.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "gfxFontConstants.h"
|
||||
#include "gfxFontUtils.h"
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
@ -155,6 +156,10 @@ gfxFT2FontBase::GetGlyph(uint32_t unicode, uint32_t variation_selector)
|
||||
gfxFT2LockedFace(this).GetUVSGlyph(unicode, variation_selector);
|
||||
if (id)
|
||||
return id;
|
||||
id = gfxFontUtils::GetUVSFallback(unicode, variation_selector);
|
||||
if (id) {
|
||||
unicode = id;
|
||||
}
|
||||
}
|
||||
|
||||
return GetGlyph(unicode);
|
||||
|
@ -4878,13 +4878,17 @@ gfxFontGroup::MakeHyphenTextRun(gfxContext *aCtx, uint32_t aAppUnitsPerDevUnit)
|
||||
}
|
||||
|
||||
gfxFloat
|
||||
gfxFontGroup::GetHyphenWidth(gfxContext *aCtx, uint32_t aAppUnitsPerDevUnit)
|
||||
gfxFontGroup::GetHyphenWidth(gfxTextRun::PropertyProvider *aProvider)
|
||||
{
|
||||
if (mHyphenWidth < 0) {
|
||||
nsAutoPtr<gfxTextRun> hyphRun(MakeHyphenTextRun(aCtx,
|
||||
aAppUnitsPerDevUnit));
|
||||
mHyphenWidth = hyphRun.get() ?
|
||||
hyphRun->GetAdvanceWidth(0, hyphRun->GetLength(), nullptr) : 0;
|
||||
nsRefPtr<gfxContext> ctx(aProvider->GetContext());
|
||||
if (ctx) {
|
||||
nsAutoPtr<gfxTextRun>
|
||||
hyphRun(MakeHyphenTextRun(ctx,
|
||||
aProvider->GetAppUnitsPerDevUnit()));
|
||||
mHyphenWidth = hyphRun.get() ?
|
||||
hyphRun->GetAdvanceWidth(0, hyphRun->GetLength(), nullptr) : 0;
|
||||
}
|
||||
}
|
||||
return mHyphenWidth;
|
||||
}
|
||||
|
@ -2834,6 +2834,14 @@ public:
|
||||
*/
|
||||
virtual void GetSpacing(uint32_t aStart, uint32_t aLength,
|
||||
Spacing *aSpacing) = 0;
|
||||
|
||||
// Returns a gfxContext that can be used to measure the hyphen glyph.
|
||||
// Only called if the hyphen width is requested.
|
||||
virtual already_AddRefed<gfxContext> GetContext() = 0;
|
||||
|
||||
// Return the appUnitsPerDevUnit value to be used when measuring.
|
||||
// Only called if the hyphen width is requested.
|
||||
virtual uint32_t GetAppUnitsPerDevUnit() = 0;
|
||||
};
|
||||
|
||||
class ClusterIterator {
|
||||
@ -3433,7 +3441,7 @@ public:
|
||||
* needed to initialize the cached hyphen width; otherwise they are
|
||||
* ignored.
|
||||
*/
|
||||
gfxFloat GetHyphenWidth(gfxContext *aCtx, uint32_t aAppUnitsPerDevUnit);
|
||||
gfxFloat GetHyphenWidth(gfxTextRun::PropertyProvider* aProvider);
|
||||
|
||||
/**
|
||||
* Make a text run representing a single hyphen character.
|
||||
|
@ -692,9 +692,27 @@ gfxFontUtils::MapCharToGlyph(const uint8_t *aCmapBuf, uint32_t aBufLength,
|
||||
uint32_t varGID =
|
||||
gfxFontUtils::MapUVSToGlyphFormat14(aCmapBuf + uvsOffset,
|
||||
aUnicode, aVarSelector);
|
||||
if (!varGID) {
|
||||
aUnicode = gfxFontUtils::GetUVSFallback(aUnicode, aVarSelector);
|
||||
if (aUnicode) {
|
||||
switch (format) {
|
||||
case 4:
|
||||
if (aUnicode < UNICODE_BMP_LIMIT) {
|
||||
varGID = MapCharToGlyphFormat4(aCmapBuf + offset,
|
||||
char16_t(aUnicode));
|
||||
}
|
||||
break;
|
||||
case 12:
|
||||
varGID = MapCharToGlyphFormat12(aCmapBuf + offset,
|
||||
aUnicode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (varGID) {
|
||||
gid = varGID;
|
||||
}
|
||||
|
||||
// else the variation sequence was not supported, use default mapping
|
||||
// of the character code alone
|
||||
}
|
||||
|
@ -639,6 +639,8 @@ enum gfxUserFontType {
|
||||
GFX_USERFONT_WOFF = 3
|
||||
};
|
||||
|
||||
extern const uint8_t sCJKCompatSVSTable[];
|
||||
|
||||
class gfxFontUtils {
|
||||
|
||||
public:
|
||||
@ -784,6 +786,15 @@ public:
|
||||
static uint16_t
|
||||
MapUVSToGlyphFormat14(const uint8_t *aBuf, uint32_t aCh, uint32_t aVS);
|
||||
|
||||
// sCJKCompatSVSTable is a 'cmap' format 14 subtable that maps
|
||||
// <char + var-selector> pairs to the corresponding Unicode
|
||||
// compatibility ideograph codepoints.
|
||||
static MOZ_ALWAYS_INLINE uint32_t
|
||||
GetUVSFallback(uint32_t aCh, uint32_t aVS) {
|
||||
aCh = MapUVSToGlyphFormat14(sCJKCompatSVSTable, aCh, aVS);
|
||||
return aCh >= 0xFB00 ? aCh + (0x2F800 - 0xFB00) : aCh;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
MapCharToGlyph(const uint8_t *aCmapBuf, uint32_t aBufLength,
|
||||
uint32_t aUnicode, uint32_t aVarSelector = 0);
|
||||
|
@ -95,6 +95,24 @@ gfxHarfBuzzShaper::GetGlyph(hb_codepoint_t unicode,
|
||||
unicode,
|
||||
variation_selector);
|
||||
}
|
||||
if (!gid) {
|
||||
uint32_t compat =
|
||||
gfxFontUtils::GetUVSFallback(unicode, variation_selector);
|
||||
if (compat) {
|
||||
switch (mCmapFormat) {
|
||||
case 4:
|
||||
if (compat < UNICODE_BMP_LIMIT) {
|
||||
gid = gfxFontUtils::MapCharToGlyphFormat4(data + mSubtableOffset,
|
||||
compat);
|
||||
}
|
||||
break;
|
||||
case 12:
|
||||
gid = gfxFontUtils::MapCharToGlyphFormat12(data + mSubtableOffset,
|
||||
compat);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the variation sequence was not supported, return zero here;
|
||||
// harfbuzz will call us again for the base character alone
|
||||
return gid;
|
||||
|
@ -273,7 +273,7 @@ gfxPlatform::gfxPlatform()
|
||||
#ifdef XP_WIN
|
||||
// XXX - When 957560 is fixed, the pref can go away entirely
|
||||
mLayersUseDeprecated =
|
||||
Preferences::GetBool("layers.use-deprecated-textures", false)
|
||||
Preferences::GetBool("layers.use-deprecated-textures", true)
|
||||
&& !gfxPrefs::LayersPreferOpenGL();
|
||||
#else
|
||||
mLayersUseDeprecated = false;
|
||||
@ -632,6 +632,18 @@ void SourceBufferDestroy(void *srcSurfUD)
|
||||
delete static_cast<SourceSurfaceUserData*>(srcSurfUD);
|
||||
}
|
||||
|
||||
UserDataKey kThebesSurface;
|
||||
|
||||
struct DependentSourceSurfaceUserData
|
||||
{
|
||||
nsRefPtr<gfxASurface> mSurface;
|
||||
};
|
||||
|
||||
void SourceSurfaceDestroyed(void *aData)
|
||||
{
|
||||
delete static_cast<DependentSourceSurfaceUserData*>(aData);
|
||||
}
|
||||
|
||||
#if MOZ_TREE_CAIRO
|
||||
void SourceSnapshotDetached(cairo_surface_t *nullSurf)
|
||||
{
|
||||
@ -654,6 +666,34 @@ gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface *aSurface)
|
||||
aSurface->SetData(&kSourceSurface, nullptr, nullptr);
|
||||
}
|
||||
|
||||
static TemporaryRef<DataSourceSurface>
|
||||
CopySurface(gfxASurface* aSurface)
|
||||
{
|
||||
const nsIntSize size = aSurface->GetSize();
|
||||
gfxImageFormat format = gfxPlatform::GetPlatform()->OptimalFormatForContent(aSurface->GetContentType());
|
||||
RefPtr<DataSourceSurface> data =
|
||||
Factory::CreateDataSourceSurface(ToIntSize(size),
|
||||
ImageFormatToSurfaceFormat(format));
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DataSourceSurface::MappedSurface map;
|
||||
DebugOnly<bool> result = data->Map(DataSourceSurface::WRITE, &map);
|
||||
MOZ_ASSERT(result, "Should always succeed mapping raw data surfaces!");
|
||||
|
||||
nsRefPtr<gfxImageSurface> image = new gfxImageSurface(map.mData, size, map.mStride, format);
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(image);
|
||||
|
||||
ctx->SetSource(aSurface);
|
||||
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
ctx->Paint();
|
||||
|
||||
data->Unmap();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
RefPtr<SourceSurface>
|
||||
gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurface)
|
||||
{
|
||||
@ -722,18 +762,24 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
|
||||
}
|
||||
}
|
||||
|
||||
bool dependsOnData = false;
|
||||
if (!srcBuffer) {
|
||||
nsRefPtr<gfxImageSurface> imgSurface = aSurface->GetAsImageSurface();
|
||||
|
||||
bool isWin32ImageSurf = imgSurface &&
|
||||
aSurface->GetType() == gfxSurfaceType::Win32;
|
||||
|
||||
RefPtr<DataSourceSurface> copy;
|
||||
if (!imgSurface) {
|
||||
imgSurface = new gfxImageSurface(aSurface->GetSize(), OptimalFormatForContent(aSurface->GetContentType()));
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(imgSurface);
|
||||
ctx->SetSource(aSurface);
|
||||
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
ctx->Paint();
|
||||
copy = CopySurface(aSurface);
|
||||
|
||||
if (!copy) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DataSourceSurface::MappedSurface map;
|
||||
DebugOnly<bool> result = copy->Map(DataSourceSurface::WRITE, &map);
|
||||
MOZ_ASSERT(result, "Should always succeed mapping raw data surfaces!");
|
||||
|
||||
imgSurface = new gfxImageSurface(map.mData, aSurface->GetSize(), map.mStride,
|
||||
SurfaceFormatToImageFormat(copy->GetFormat()));
|
||||
}
|
||||
|
||||
gfxImageFormat cairoFormat = imgSurface->Format();
|
||||
@ -760,38 +806,56 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
|
||||
imgSurface->Stride(),
|
||||
format);
|
||||
|
||||
if (!srcBuffer) {
|
||||
// We need to check if our gfxASurface will keep the underlying data
|
||||
// alive. This is true if gfxASurface actually -is- an ImageSurface or
|
||||
// if it is a gfxWindowsSurface which supports GetAsImageSurface.
|
||||
if (imgSurface != aSurface && !isWin32ImageSurf) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
srcBuffer = Factory::CreateWrappingDataSourceSurface(imgSurface->Data(),
|
||||
imgSurface->Stride(),
|
||||
size, format);
|
||||
|
||||
if (copy) {
|
||||
copy->Unmap();
|
||||
}
|
||||
|
||||
if (!srcBuffer) {
|
||||
// If we had to make a copy, then just return that. Otherwise aSurface
|
||||
// must have supported GetAsImageSurface, so we can just wrap that data.
|
||||
if (copy) {
|
||||
srcBuffer = copy;
|
||||
} else {
|
||||
srcBuffer = Factory::CreateWrappingDataSourceSurface(imgSurface->Data(),
|
||||
imgSurface->Stride(),
|
||||
size, format);
|
||||
dependsOnData = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!srcBuffer) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!dependsOnData) {
|
||||
#if MOZ_TREE_CAIRO
|
||||
cairo_surface_t *nullSurf =
|
||||
cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
|
||||
cairo_surface_set_user_data(nullSurf,
|
||||
&kSourceSurface,
|
||||
imgSurface,
|
||||
nullptr);
|
||||
cairo_surface_attach_snapshot(imgSurface->CairoSurface(), nullSurf, SourceSnapshotDetached);
|
||||
cairo_surface_destroy(nullSurf);
|
||||
cairo_surface_t *nullSurf =
|
||||
cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
|
||||
cairo_surface_set_user_data(nullSurf,
|
||||
&kSourceSurface,
|
||||
imgSurface,
|
||||
nullptr);
|
||||
cairo_surface_attach_snapshot(imgSurface->CairoSurface(), nullSurf, SourceSnapshotDetached);
|
||||
cairo_surface_destroy(nullSurf);
|
||||
#else
|
||||
cairo_surface_set_mime_data(imgSurface->CairoSurface(), "mozilla/magic", (const unsigned char*) "data", 4, SourceSnapshotDetached, imgSurface.get());
|
||||
cairo_surface_set_mime_data(imgSurface->CairoSurface(), "mozilla/magic", (const unsigned char*) "data", 4, SourceSnapshotDetached, imgSurface.get());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
SourceSurfaceUserData *srcSurfUD = new SourceSurfaceUserData;
|
||||
srcSurfUD->mBackendType = aTarget->GetType();
|
||||
srcSurfUD->mSrcSurface = srcBuffer;
|
||||
aSurface->SetData(&kSourceSurface, srcSurfUD, SourceBufferDestroy);
|
||||
if (dependsOnData) {
|
||||
// If we wrapped the underlying data of aSurface, then we need to add user data
|
||||
// to make sure aSurface stays alive until we are done with the data.
|
||||
DependentSourceSurfaceUserData *srcSurfUD = new DependentSourceSurfaceUserData;
|
||||
srcSurfUD->mSurface = aSurface;
|
||||
srcBuffer->AddUserData(&kThebesSurface, srcSurfUD, SourceSurfaceDestroyed);
|
||||
} else {
|
||||
// Otherwise add user data to aSurface so we can cache lookups in the future.
|
||||
SourceSurfaceUserData *srcSurfUD = new SourceSurfaceUserData;
|
||||
srcSurfUD->mBackendType = aTarget->GetType();
|
||||
srcSurfUD->mSrcSurface = srcBuffer;
|
||||
aSurface->SetData(&kSourceSurface, srcSurfUD, SourceBufferDestroy);
|
||||
}
|
||||
|
||||
return srcBuffer;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user