--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
#
# Modifying this file will now automatically clobber the buildbot machines \o/
#
# Are you updating CLOBBER because you think it's needed for your WebIDL
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
-Bug 1069071: IPDL changes require CLOBBER
+Bug 1069071: IPDL changes require CLOBBER (second time around)
--- a/accessible/base/ARIAMap.cpp
+++ b/accessible/base/ARIAMap.cpp
@@ -734,17 +734,17 @@ static const AttrCharacteristics gWAIUni
{&nsGkAtoms::aria_valuetext, ATTR_BYPASSOBJ }
};
namespace {
struct RoleComparator
{
const nsDependentSubstring& mRole;
- RoleComparator(const nsDependentSubstring& aRole) : mRole(aRole) {}
+ explicit RoleComparator(const nsDependentSubstring& aRole) : mRole(aRole) {}
int operator()(const nsRoleMapEntry& aEntry) const {
return Compare(mRole, aEntry.ARIARoleString());
}
};
}
nsRoleMapEntry*
--- a/accessible/generic/Accessible-inl.h
+++ b/accessible/generic/Accessible-inl.h
@@ -62,12 +62,20 @@ Accessible::HasNumericValue() const
inline void
Accessible::ScrollTo(uint32_t aHow) const
{
if (mContent)
nsCoreUtils::ScrollTo(mDoc->PresShell(), mContent, aHow);
}
+inline bool
+Accessible::UpdateChildren()
+{
+ AutoTreeMutation mut(this);
+ InvalidateChildren();
+ return EnsureChildren();
+}
+
} // namespace a11y
} // namespace mozilla
#endif
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -1931,30 +1931,34 @@ Accessible::BindToParent(Accessible* aPa
NS_ERROR("Binding to the same parent!");
return;
}
}
mParent = aParent;
mIndexInParent = aIndexInParent;
- mParent->InvalidateChildrenGroupInfo();
+#ifdef DEBUG
+ AssertInMutatingSubtree();
+#endif
// Note: this is currently only used for richlistitems and their children.
if (mParent->HasNameDependentParent() || mParent->IsXULListItem())
mContextFlags |= eHasNameDependentParent;
else
mContextFlags &= ~eHasNameDependentParent;
}
// Accessible protected
void
Accessible::UnbindFromParent()
{
- mParent->InvalidateChildrenGroupInfo();
+#ifdef DEBUG
+ AssertInMutatingSubtree();
+#endif
mParent = nullptr;
mIndexInParent = -1;
mIndexOfEmbeddedChild = -1;
mGroupInfo = nullptr;
mContextFlags &= ~eHasNameDependentParent;
}
////////////////////////////////////////////////////////////////////////////////
@@ -2653,16 +2657,31 @@ Accessible::StaticAsserts() const
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!");
}
+void
+Accessible::AssertInMutatingSubtree() const
+{
+ if (IsDoc() || IsApplication())
+ return;
+
+ const Accessible *acc = this;
+ while (!acc->IsDoc() && !(acc->mStateFlags & eSubtreeMutating)) {
+ acc = acc->Parent();
+ if (!acc)
+ return;
+ }
+
+ MOZ_ASSERT(acc->mStateFlags & eSubtreeMutating);
+}
////////////////////////////////////////////////////////////////////////////////
// KeyBinding class
// static
uint32_t
KeyBinding::AccelModifier()
{
--- a/accessible/generic/Accessible.h
+++ b/accessible/generic/Accessible.h
@@ -368,21 +368,17 @@ public:
* Set the ARIA role map entry for a new accessible.
*/
void SetRoleMapEntry(nsRoleMapEntry* aRoleMapEntry)
{ mRoleMapEntry = aRoleMapEntry; }
/**
* Update the children cache.
*/
- inline bool UpdateChildren()
- {
- InvalidateChildren();
- return EnsureChildren();
- }
+ bool UpdateChildren();
/**
* Cache children if necessary. Return true if the accessible is defunct.
*/
bool EnsureChildren();
/**
* Set the child count to -1 (unknown) and null out cached child pointers.
@@ -943,17 +939,18 @@ protected:
*/
enum StateFlags {
eIsDefunct = 1 << 0, // accessible is defunct
eIsNotInDocument = 1 << 1, // accessible is not in document
eSharedNode = 1 << 2, // accessible shares DOM node from another accessible
eNotNodeMapEntry = 1 << 3, // accessible shouldn't be in document node map
eHasNumericValue = 1 << 4, // accessible has a numeric value
eGroupInfoDirty = 1 << 5, // accessible needs to update group info
- eIgnoreDOMUIEvent = 1 << 6, // don't process DOM UI events for a11y events
+ eSubtreeMutating = 1 << 6, // subtree is being mutated
+ eIgnoreDOMUIEvent = 1 << 7, // don't process DOM UI events for a11y events
eLastStateFlag = eIgnoreDOMUIEvent
};
/**
* Flags used for contextual information about the accessible.
*/
enum ContextFlags {
@@ -1059,34 +1056,36 @@ protected:
nsCOMPtr<nsIContent> mContent;
DocAccessible* mDoc;
nsRefPtr<Accessible> mParent;
nsTArray<nsRefPtr<Accessible> > mChildren;
int32_t mIndexInParent;
static const uint8_t kChildrenFlagsBits = 2;
- static const uint8_t kStateFlagsBits = 7;
+ static const uint8_t kStateFlagsBits = 8;
static const uint8_t kContextFlagsBits = 1;
static const uint8_t kTypeBits = 6;
static const uint8_t kGenericTypesBits = 13;
/**
* 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;
void StaticAsserts() const;
+ void AssertInMutatingSubtree() const;
friend class DocAccessible;
friend class xpcAccessible;
+ friend class AutoTreeMutation;
nsAutoPtr<mozilla::a11y::EmbeddedObjCollector> mEmbeddedObjCollector;
int32_t mIndexOfEmbeddedChild;
friend class EmbeddedObjCollector;
nsAutoPtr<AccGroupInfo> mGroupInfo;
friend class AccGroupInfo;
@@ -1160,12 +1159,41 @@ public:
private:
void ToPlatformFormat(nsAString& aValue) const;
void ToAtkFormat(nsAString& aValue) const;
uint32_t mKey;
uint32_t mModifierMask;
};
+/**
+ * This class makes sure required tasks are done before and after tree
+ * mutations. Currently this only includes group info invalidation. You must
+ * have an object of this class on the stack when calling methods that mutate
+ * the accessible tree.
+ */
+class AutoTreeMutation
+{
+public:
+ AutoTreeMutation(Accessible* aRoot, bool aInvalidationRequired = true) :
+ mInvalidationRequired(aInvalidationRequired), mRoot(aRoot)
+ {
+ MOZ_ASSERT(!(mRoot->mStateFlags & Accessible::eSubtreeMutating));
+ mRoot->mStateFlags |= Accessible::eSubtreeMutating;
+ }
+ ~AutoTreeMutation()
+ {
+ if (mInvalidationRequired)
+ mRoot->InvalidateChildrenGroupInfo();
+
+ MOZ_ASSERT(mRoot->mStateFlags & Accessible::eSubtreeMutating);
+ mRoot->mStateFlags &= ~Accessible::eSubtreeMutating;
+ }
+
+ bool mInvalidationRequired;
+private:
+ Accessible* mRoot;
+};
+
} // namespace a11y
} // namespace mozilla
#endif
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -478,17 +478,23 @@ DocAccessible::Shutdown()
mVirtualCursor = nullptr;
}
mPresShell->SetDocAccessible(nullptr);
mPresShell = nullptr; // Avoid reentrancy
mDependentIDsHash.Clear();
mNodeToAccessibleMap.Clear();
- ClearCache(mAccessibleCache);
+
+ {
+ // We're about to get rid of all of our children so there won't be anything
+ // to invalidate.
+ AutoTreeMutation mut(this, false);
+ ClearCache(mAccessibleCache);
+ }
HyperTextAccessibleWrap::Shutdown();
GetAccService()->NotifyOfDocumentShutdown(kungFuDeathGripDoc);
}
nsIFrame*
DocAccessible::GetFrame() const
@@ -1313,18 +1319,20 @@ DocAccessible::ProcessInvalidationList()
Accessible* container = GetContainerAccessible(content);
if (container) {
container->UpdateChildren();
accessible = GetAccessible(content);
}
}
// Make sure the subtree is created.
- if (accessible)
+ if (accessible) {
+ AutoTreeMutation mut(accessible);
CacheChildrenInSubtree(accessible);
+ }
}
mInvalidationList.Clear();
}
Accessible*
DocAccessible::GetAccessibleEvenIfNotInMap(nsINode* aNode) const
{
@@ -1420,17 +1428,19 @@ DocAccessible::DoInitialUpdate()
// miss the notification (since content tree change notifications are ignored
// prior to initial update). Make sure the content element is valid.
nsIContent* contentElm = nsCoreUtils::GetRoleContent(mDocumentNode);
if (mContent != contentElm) {
mContent = contentElm;
SetRoleMapEntry(aria::GetRoleMap(mContent));
}
- // Build initial tree.
+ // Build initial tree. Since its the initial tree there's no group info to
+ // invalidate.
+ AutoTreeMutation mut(this, false);
CacheChildrenInSubtree(this);
// Fire reorder event after the document tree is constructed. Note, since
// this reorder event is processed by parent document then events targeted to
// this document may be fired prior to this reorder event. If this is
// a problem then consider to keep event processing per tab document.
if (!IsRoot()) {
nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(Parent());
@@ -1654,16 +1664,19 @@ DocAccessible::ProcessContentInserted(Ac
// there is no HTML body element.
}
// XXX: Invalidate parent-child relations for container accessible and its
// children because there's no good way to find insertion point of new child
// accessibles into accessible tree. We need to invalidate children even
// there's no inserted accessibles in the end because accessible children
// are created while parent recaches child accessibles.
+ // XXX Group invalidation here may be redundant with invalidation in
+ // UpdateTree.
+ AutoTreeMutation mut(aContainer);
aContainer->InvalidateChildren();
CacheChildrenInSubtree(aContainer);
}
UpdateTree(aContainer, aInsertedContent->ElementAt(idx), true);
}
}
@@ -1686,16 +1699,17 @@ DocAccessible::UpdateTree(Accessible* aC
else
logging::MsgEntry("child accessible: null");
logging::MsgEnd();
}
#endif
nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(aContainer);
+ AutoTreeMutation mut(aContainer);
if (child) {
updateFlags |= UpdateTreeInternal(child, aIsInsert, reorderEvent);
} else {
if (aIsInsert) {
TreeWalker walker(aContainer, aChildNode, TreeWalker::eWalkCache);
while ((child = walker.NextChild()))
--- a/accessible/html/HTMLImageMapAccessible.cpp
+++ b/accessible/html/HTMLImageMapAccessible.cpp
@@ -80,33 +80,34 @@ HTMLImageMapAccessible::UpdateChildAreas
{
nsImageFrame* imageFrame = do_QueryFrame(mContent->GetPrimaryFrame());
// If image map is not initialized yet then we trigger one time more later.
nsImageMap* imageMapObj = imageFrame->GetExistingImageMap();
if (!imageMapObj)
return;
- bool doReorderEvent = false;
+ bool treeChanged = false;
+ AutoTreeMutation mut(this);
nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(this);
// Remove areas that are not a valid part of the image map anymore.
for (int32_t childIdx = mChildren.Length() - 1; childIdx >= 0; childIdx--) {
Accessible* area = mChildren.ElementAt(childIdx);
if (area->GetContent()->GetPrimaryFrame())
continue;
if (aDoFireEvents) {
nsRefPtr<AccHideEvent> event = new AccHideEvent(area, area->GetContent());
mDoc->FireDelayedEvent(event);
reorderEvent->AddSubMutationEvent(event);
- doReorderEvent = true;
}
RemoveChild(area);
+ treeChanged = true;
}
// Insert new areas into the tree.
uint32_t areaElmCount = imageMapObj->AreaCount();
for (uint32_t idx = 0; idx < areaElmCount; idx++) {
nsIContent* areaContent = imageMapObj->GetAreaAt(idx);
Accessible* area = mChildren.SafeElementAt(idx);
@@ -118,24 +119,28 @@ HTMLImageMapAccessible::UpdateChildAreas
mDoc->UnbindFromDocument(area);
break;
}
if (aDoFireEvents) {
nsRefPtr<AccShowEvent> event = new AccShowEvent(area, areaContent);
mDoc->FireDelayedEvent(event);
reorderEvent->AddSubMutationEvent(event);
- doReorderEvent = true;
}
+
+ treeChanged = true;
}
}
// Fire reorder event if needed.
- if (doReorderEvent)
+ if (treeChanged && aDoFireEvents)
mDoc->FireDelayedEvent(reorderEvent);
+
+ if (!treeChanged)
+ mut.mInvalidationRequired = false;
}
Accessible*
HTMLImageMapAccessible::GetChildAccessibleFor(const nsINode* aNode) const
{
uint32_t length = mChildren.Length();
for (uint32_t i = 0; i < length; i++) {
Accessible* area = mChildren[i];
--- a/accessible/jsat/OutputGenerator.jsm
+++ b/accessible/jsat/OutputGenerator.jsm
@@ -380,16 +380,24 @@ let OutputGenerator = {
}, {
string: this._getOutputName('tblRowInfo'),
count: table.rowCount
});
this._addName(output, aAccessible, aFlags);
this._addLandmark(output, aAccessible);
return output;
}
+ },
+
+ gridcell: function gridcell(aAccessible, aRoleStr, aState, aFlags) {
+ let output = [];
+ this._addState(output, aState);
+ this._addName(output, aAccessible, aFlags);
+ this._addLandmark(output, aAccessible);
+ return output;
}
}
};
/**
* Generates speech utterances from objects, actions and state changes.
* An utterance is an array of speech data.
*
--- a/accessible/tests/mochitest/jsat/test_output.html
+++ b/accessible/tests/mochitest/jsat/test_output.html
@@ -435,16 +435,22 @@ https://bugzilla.mozilla.org/show_bug.cg
oldAccOrElmOrID: "grid",
expectedUtterance: [["3"], ["3"]],
expectedBraille: [["3"], ["3"]]
}, {
accOrElmOrID: "gridcell2",
oldAccOrElmOrID: "grid",
expectedUtterance: [["4", "7"], ["4", "7"]],
expectedBraille: [["4", "7"], ["4", "7"]]
+ }, {
+ accOrElmOrID: "gridcell3",
+ oldAccOrElmOrID: "grid",
+ expectedUtterance: [[{"string": "stateSelected"}, "5"],
+ ["5", {"string": "stateSelected"}]],
+ expectedBraille: [["5"], ["5"]],
}];
// Test all possible utterance order preference values.
tests.forEach(function run(test) {
var utteranceOrderValues = [0, 1];
utteranceOrderValues.forEach(
function testUtteranceOrder(utteranceOrder) {
SpecialPowers.setIntPref(PREF_UTTERANCE_ORDER, utteranceOrder);
@@ -576,15 +582,15 @@ https://bugzilla.mozilla.org/show_bug.cg
</ol>
<ol role="row">
<li id="rowheader" role="rowheader" aria-label="Week 1">1</li>
<li id="gridcell1" role="gridcell"><span>3</span><div></div></li>
<li id="gridcell2" role="gridcell"><span>4</span><div>7</div></li>
</ol>
<ol role="row">
<li role="rowheader">2</li>
- <li role="gridcell">5</li>
+ <li id="gridcell3" aria-selected="true" role="gridcell">5</li>
<li role="gridcell">6</li>
</ol>
</section>
</div>
</body>
</html>
--- a/b2g/installer/Makefile.in
+++ b/b2g/installer/Makefile.in
@@ -52,18 +52,20 @@ endif
endif
include $(topsrcdir)/toolkit/mozapps/installer/packager.mk
# Note that JS_BINARY can be defined in packager.mk, so this test must come after
# including that file. MOZ_PACKAGER_MINIFY_JS is used in packager.mk, but since
# recipe evaluation is deferred, we can set it here after the inclusion.
ifneq (,$(JS_BINARY))
+ifndef MOZ_DEBUG
MOZ_PACKAGER_MINIFY_JS=1
endif
+endif
ifeq (bundle, $(MOZ_FS_LAYOUT))
BINPATH = $(_BINPATH)
DEFINES += -DAPPNAME=$(_APPNAME)
else
# Every other platform just winds up in dist/bin
BINPATH = bin
endif
--- a/browser/base/content/test/general/mochitest.ini
+++ b/browser/base/content/test/general/mochitest.ini
@@ -18,17 +18,16 @@ support-files =
offlineChild.cacheManifest^headers^
offlineChild.html
offlineChild2.cacheManifest
offlineChild2.cacheManifest^headers^
offlineChild2.html
offlineEvent.cacheManifest
offlineEvent.cacheManifest^headers^
offlineEvent.html
- privateBrowsingMode.js
subtst_contextmenu.html
video.ogg
[test_bug364677.html]
[test_bug395533.html]
[test_contextmenu.html]
skip-if = toolkit == "gtk2" || toolkit == "gtk3" # disabled on Linux due to bug 513558
[test_contextmenu_input.html]
deleted file mode 100644
--- a/browser/base/content/test/general/privateBrowsingMode.js
+++ /dev/null
@@ -1,3 +0,0 @@
-// This file is only present in per-window private browsing buikds.
-var perWindowPrivateBrowsing = true;
-
--- a/browser/base/content/test/general/test_contextmenu.html
+++ b/browser/base/content/test/general/test_contextmenu.html
@@ -10,18 +10,16 @@
<body>
Browser context menu tests.
<p id="display"></p>
<div id="content">
</div>
<pre id="test">
-<script> var perWindowPrivateBrowsing = false; </script>
-<script type="text/javascript" src="privateBrowsingMode.js"></script>
<script type="text/javascript" src="contextmenu_common.js"></script>
<script class="testbody" type="text/javascript">
SpecialPowers.Cu.import("resource://gre/modules/InlineSpellChecker.jsm", window);
const Ci = SpecialPowers.Ci;
function executeCopyCommand(command, expectedValue)
@@ -106,36 +104,25 @@ function runTest(testNum) {
].concat(inspectItems);
checkContextMenu(plainTextItems);
closeContextMenu();
openContextMenuFor(link); // Invoke context menu for next test.
},
function () {
// Context menu for text link
- if (perWindowPrivateBrowsing) {
- checkContextMenu(["context-openlinkintab", true,
- "context-openlink", true,
- "context-openlinkprivate", true,
- "---", null,
- "context-bookmarklink", true,
- "context-savelink", true,
- "context-copylink", true,
- "context-searchselect", true
- ].concat(inspectItems));
- } else {
- checkContextMenu(["context-openlinkintab", true,
- "context-openlink", true,
- "---", null,
- "context-bookmarklink", true,
- "context-savelink", true,
- "context-copylink", true,
- "context-searchselect", true
- ].concat(inspectItems));
- }
+ checkContextMenu(["context-openlinkintab", true,
+ "context-openlink", true,
+ "context-openlinkprivate", true,
+ "---", null,
+ "context-bookmarklink", true,
+ "context-savelink", true,
+ "context-copylink", true,
+ "context-searchselect", true
+ ].concat(inspectItems));
closeContextMenu();
openContextMenuFor(mailto); // Invoke context menu for next test.
},
function () {
// Context menu for text mailto-link
checkContextMenu(["context-copyemail", true,
"context-searchselect", true
@@ -582,90 +569,56 @@ function runTest(testNum) {
selectText(selecttextlink); // Select text prior to opening context menu.
openContextMenuFor(selecttextlink); // Invoke context menu for next test.
},
function () {
// Context menu for selected text which matches valid URL pattern
if (SpecialPowers.Services.appinfo.OS == "Darwin") {
// This test is only enabled on Mac due to bug 736399.
- if (perWindowPrivateBrowsing) {
- checkContextMenu(["context-openlinkincurrent", true,
- "context-openlinkintab", true,
- "context-openlink", true,
- "context-openlinkprivate", true,
- "---", null,
- "context-bookmarklink", true,
- "context-savelink", true,
- "context-copy", true,
- "context-selectall", true,
- "---", null,
- "context-searchselect", true,
- "context-viewpartialsource-selection", true
- ].concat(inspectItems));
- } else {
- checkContextMenu(["context-openlinkincurrent", true,
- "context-openlinkintab", true,
- "context-openlink", true,
- "---", null,
- "context-bookmarklink", true,
- "context-savelink", true,
- "context-copy", true,
- "context-selectall", true,
- "---", null,
- "context-searchselect", true,
- "context-viewpartialsource-selection", true
- ].concat(inspectItems));
- }
+ checkContextMenu(["context-openlinkincurrent", true,
+ "context-openlinkintab", true,
+ "context-openlink", true,
+ "context-openlinkprivate", true,
+ "---", null,
+ "context-bookmarklink", true,
+ "context-savelink", true,
+ "context-copy", true,
+ "context-selectall", true,
+ "---", null,
+ "context-searchselect", true,
+ "context-viewpartialsource-selection", true
+ ].concat(inspectItems));
}
closeContextMenu();
// clear the selection because following tests don't expect any selection
subwindow.getSelection().removeAllRanges();
openContextMenuFor(imagelink)
},
function () {
// Context menu for image link
- if (perWindowPrivateBrowsing) {
- checkContextMenu(["context-openlinkintab", true,
- "context-openlink", true,
- "context-openlinkprivate", true,
- "---", null,
- "context-bookmarklink", true,
- "context-savelink", true,
- "context-copylink", true,
- "---", null,
- "context-viewimage", true,
- "context-copyimage-contents", true,
- "context-copyimage", true,
- "---", null,
- "context-saveimage", true,
- "context-sendimage", true,
- "context-setDesktopBackground", true,
- "context-viewimageinfo", true
- ].concat(inspectItems));
- } else {
- checkContextMenu(["context-openlinkintab", true,
- "context-openlink", true,
- "---", null,
- "context-bookmarklink", true,
- "context-savelink", true,
- "context-copylink", true,
- "---", null,
- "context-viewimage", true,
- "context-copyimage-contents", true,
- "context-copyimage", true,
- "---", null,
- "context-saveimage", true,
- "context-sendimage", true,
- "context-setDesktopBackground", true,
- "context-viewimageinfo", true
- ].concat(inspectItems));
- }
+ checkContextMenu(["context-openlinkintab", true,
+ "context-openlink", true,
+ "context-openlinkprivate", true,
+ "---", null,
+ "context-bookmarklink", true,
+ "context-savelink", true,
+ "context-copylink", true,
+ "---", null,
+ "context-viewimage", true,
+ "context-copyimage-contents", true,
+ "context-copyimage", true,
+ "---", null,
+ "context-saveimage", true,
+ "context-sendimage", true,
+ "context-setDesktopBackground", true,
+ "context-viewimageinfo", true
+ ].concat(inspectItems));
closeContextMenu();
selectInputText(select_inputtext); // Select text prior to opening context menu.
openContextMenuFor(select_inputtext); // Invoke context menu for next test.
},
function () {
// Context menu for selected text in input
checkContextMenu(["context-undo", false,
--- a/browser/components/dirprovider/tests/unit/xpcshell.ini
+++ b/browser/components/dirprovider/tests/unit/xpcshell.ini
@@ -1,7 +1,8 @@
[DEFAULT]
head = head_dirprovider.js
tail =
firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_bookmark_pref.js]
[test_keys.js]
--- a/browser/components/downloads/test/unit/xpcshell.ini
+++ b/browser/components/downloads/test/unit/xpcshell.ini
@@ -1,6 +1,7 @@
[DEFAULT]
head = head.js
tail =
firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_DownloadsCommon.js]
--- a/browser/components/feeds/test/unit/xpcshell.ini
+++ b/browser/components/feeds/test/unit/xpcshell.ini
@@ -1,7 +1,8 @@
[DEFAULT]
head = head_feeds.js
tail =
firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_355473.js]
[test_758990.js]
--- a/browser/components/loop/test/xpcshell/xpcshell.ini
+++ b/browser/components/loop/test/xpcshell/xpcshell.ini
@@ -1,12 +1,13 @@
[DEFAULT]
head = head.js
tail =
firefox-appdir = browser
+skip-if = toolkit == 'gonk'
[test_loopapi_hawk_request.js]
[test_looppush_initialize.js]
[test_loopservice_directcall.js]
[test_loopservice_dnd.js]
[test_loopservice_expiry.js]
[test_loopservice_hawk_errors.js]
[test_loopservice_loop_prefs.js]
--- a/browser/components/migration/tests/unit/xpcshell.ini
+++ b/browser/components/migration/tests/unit/xpcshell.ini
@@ -1,7 +1,8 @@
[DEFAULT]
head = head_migration.js
tail =
firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_IE_bookmarks.js]
skip-if = os != "win"
--- a/browser/components/places/tests/unit/xpcshell.ini
+++ b/browser/components/places/tests/unit/xpcshell.ini
@@ -1,12 +1,13 @@
[DEFAULT]
head = head_bookmarks.js
tail =
firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
support-files =
bookmarks.glue.html
bookmarks.glue.json
corruptDB.sqlite
distribution.ini
[test_421483.js]
[test_browserGlue_bookmarkshtml.js]
--- a/browser/components/sessionstore/test/unit/xpcshell.ini
+++ b/browser/components/sessionstore/test/unit/xpcshell.ini
@@ -1,12 +1,13 @@
[DEFAULT]
head = head.js
tail =
firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
support-files =
data/sessionCheckpoints_all.json
data/sessionstore_invalid.js
data/sessionstore_valid.js
[test_backup_once.js]
[test_startup_nosession_async.js]
[test_startup_session_async.js]
--- a/browser/components/shell/test/unit/xpcshell.ini
+++ b/browser/components/shell/test/unit/xpcshell.ini
@@ -1,6 +1,7 @@
[DEFAULT]
head =
tail =
firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_421977.js]
--- a/browser/components/translation/test/unit/xpcshell.ini
+++ b/browser/components/translation/test/unit/xpcshell.ini
@@ -1,7 +1,8 @@
[DEFAULT]
head =
tail =
firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_cld2.js]
[test_healthreport.js]
--- a/browser/devtools/shared/test/unit/xpcshell.ini
+++ b/browser/devtools/shared/test/unit/xpcshell.ini
@@ -1,8 +1,9 @@
[DEFAULT]
head =
tail =
firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_bezierCanvas.js]
[test_cubicBezier.js]
[test_undoStack.js]
--- a/browser/devtools/styleinspector/test/unit/xpcshell.ini
+++ b/browser/devtools/styleinspector/test/unit/xpcshell.ini
@@ -1,7 +1,8 @@
[DEFAULT]
head =
tail =
firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_parseDeclarations.js]
[test_parseSingleValue.js]
--- a/browser/experiments/test/xpcshell/xpcshell.ini
+++ b/browser/experiments/test/xpcshell/xpcshell.ini
@@ -1,12 +1,13 @@
[DEFAULT]
head = head.js
tail =
firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
support-files =
experiments_1.manifest
experiment-1.xpi
experiment-1a.xpi
experiment-2.xpi
experiment-racybranch.xpi
generated-files =
experiment-1.xpi
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -439,16 +439,19 @@
@BINPATH@/components/nsUpdateService.js
@BINPATH@/components/nsUpdateServiceStub.js
#endif
@BINPATH@/components/nsUpdateTimerManager.manifest
@BINPATH@/components/nsUpdateTimerManager.js
@BINPATH@/components/addoncompat.manifest
@BINPATH@/components/multiprocessShims.js
@BINPATH@/components/pluginGlue.manifest
+@BINPATH@/components/ProcessSingleton.manifest
+@BINPATH@/components/MainProcessSingleton.js
+@BINPATH@/components/ContentProcessSingleton.js
@BINPATH@/browser/components/nsSessionStore.manifest
@BINPATH@/browser/components/nsSessionStartup.js
@BINPATH@/browser/components/nsSessionStore.js
@BINPATH@/components/nsURLFormatter.manifest
@BINPATH@/components/nsURLFormatter.js
@BINPATH@/browser/components/@DLL_PREFIX@browsercomps@DLL_SUFFIX@
@BINPATH@/components/txEXSLTRegExFunctions.manifest
@BINPATH@/components/txEXSLTRegExFunctions.js
--- a/browser/locales/Makefile.in
+++ b/browser/locales/Makefile.in
@@ -69,17 +69,20 @@ STUB_HOOK = $(NSINSTALL) -D '$(_ABS_DIST
endif
ifeq ($(MOZ_WIDGET_TOOLKIT) $(DIST_SUBDIR),windows metro)
SEARCHPLUGINS_NAMES = $(shell cat $(call MERGE_FILE,/searchplugins/metrolist.txt))
else
SEARCHPLUGINS_NAMES = $(shell cat $(call MERGE_FILE,/searchplugins/list.txt))
endif
SEARCHPLUGINS_PATH := $(FINAL_TARGET)/searchplugins
-SEARCHPLUGINS := $(addsuffix .xml,$(SEARCHPLUGINS_NAMES))
+# metro build call a searchplugins target for search engine plugins
+.PHONY: searchplugins
+SEARCHPLUGINS_TARGET := libs searchplugins
+SEARCHPLUGINS := $(foreach plugin,$(addsuffix .xml,$(SEARCHPLUGINS_NAMES)),$(or $(wildcard $(call MERGE_FILE,searchplugins/$(plugin))),$(info Missing searchplugin: $(plugin))))
PP_TARGETS += SEARCHPLUGINS
# Required for l10n.mk - defines a list of app sub dirs that should
# be included in langpack xpis.
ifdef MOZ_METRO
# metro build, include both app folders
DIST_SUBDIRS = browser metro
else
@@ -114,20 +117,16 @@ NO_JA_JP_MAC_AB_CD := $(if $(filter ja-J
libs:: $(FINAL_TARGET)/defaults/profile/bookmarks.html ;
libs:: $(addprefix generic/profile/,$(PROFILE_FILES))
$(SYSINSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)/defaults/profile
libs:: $(call MERGE_FILES,$(addprefix profile/chrome/,$(PROFILE_CHROME)))
$(SYSINSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)/defaults/profile/chrome
-# metro build calls back here for search engine plugins
-searchplugins: $(addprefix $(FINAL_TARGET)/searchplugins/,$(SEARCHPLUGINS))
-.PHONY: searchplugins
-
libs-%:
$(NSINSTALL) -D $(DIST)/install
@$(MAKE) -C ../../toolkit/locales libs-$*
@$(MAKE) -C ../../services/sync/locales AB_CD=$* XPI_NAME=locale-$*
ifdef MOZ_WEBAPP_RUNTIME
@$(MAKE) -C ../../webapprt/locales AB_CD=$* XPI_NAME=locale-$*
endif
@$(MAKE) -C ../../extensions/spellcheck/locales AB_CD=$* XPI_NAME=locale-$*
--- a/browser/modules/test/unit/social/xpcshell.ini
+++ b/browser/modules/test/unit/social/xpcshell.ini
@@ -1,8 +1,9 @@
[DEFAULT]
head = head.js
tail =
firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
support-files = blocklist.xml
[test_social.js]
[test_socialDisabledStartup.js]
--- a/browser/modules/test/xpcshell/xpcshell.ini
+++ b/browser/modules/test/xpcshell/xpcshell.ini
@@ -1,6 +1,7 @@
[DEFAULT]
head =
tail =
firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_DirectoryLinksProvider.js]
--- a/build/autoconf/compiler-opts.m4
+++ b/build/autoconf/compiler-opts.m4
@@ -321,16 +321,44 @@ if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -
rm -rf conftest*])
if test "$GC_SECTIONS_BREAKS_DEBUG_RANGES" = no; then
DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections"
fi
else
DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections"
fi
fi
+
+# bionic in Android < 4.1 doesn't support PIE
+# On OSX, the linker defaults to building PIE programs when targetting OSX 10.7+,
+# but not when targetting OSX < 10.7. OSX < 10.7 doesn't support running PIE
+# programs, so as long as support for OSX 10.6 is kept, we can't build PIE.
+# Even after dropping 10.6 support, MOZ_PIE would not be useful since it's the
+# default (and clang says the -pie option is not used).
+# On other Unix systems, some file managers (Nautilus) can't start PIE programs
+MOZ_PIE=
+
+MOZ_ARG_ENABLE_BOOL(pie,
+[ --enable-pie Enable Position Independent Executables],
+ MOZ_PIE=1,
+ MOZ_PIE= )
+
+if test "$GNU_CC" -a -n "$MOZ_PIE"; then
+ AC_MSG_CHECKING([for PIE support])
+ _SAVE_LDFLAGS=$LDFLAGS
+ LDFLAGS="$LDFLAGS -pie"
+ AC_TRY_LINK(,,AC_MSG_RESULT([yes])
+ [MOZ_PROGRAM_LDFLAGS="$MOZ_PROGRAM_LDFLAGS -pie"],
+ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([--enable-pie requires PIE support from the linker.]))
+ LDFLAGS=$_SAVE_LDFLAGS
+fi
+
+AC_SUBST(MOZ_PROGRAM_LDFLAGS)
+
])
dnl GCC and clang will fail if given an unknown warning option like -Wfoobar.
dnl But later versions won't fail if given an unknown negated warning option
dnl like -Wno-foobar. So when we are check for support of negated warning
dnl options, we actually test the positive form, but add the negated form to
dnl the flags variable.
--- a/chrome/test/unit/xpcshell.ini
+++ b/chrome/test/unit/xpcshell.ini
@@ -1,11 +1,12 @@
[DEFAULT]
head = head_crtestutils.js
tail =
+skip-if = toolkit == 'gonk'
support-files = data/**
[test_abi.js]
[test_bug292789.js]
[test_bug380398.js]
[test_bug397073.js]
[test_bug399707.js]
[test_bug401153.js]
--- a/chrome/test/unit_ipc/xpcshell.ini
+++ b/chrome/test/unit_ipc/xpcshell.ini
@@ -1,5 +1,6 @@
[DEFAULT]
head =
tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_resolve_uris_ipc.js]
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -636,16 +636,18 @@ ifdef GNU_CC
# Force rebuilding libraries and programs in both passes because each
# pass uses different object files.
$(PROGRAM) $(SHARED_LIBRARY) $(LIBRARY): FORCE
endif
endif
endif # NO_PROFILE_GUIDED_OPTIMIZE
+MOZ_PROGRAM_LDFLAGS += $(MOZ_GLUE_PROGRAM_LDFLAGS)
+
##############################################
checkout:
$(MAKE) -C $(topsrcdir) -f client.mk checkout
clean clobber realclean clobber_all::
-$(RM) $(ALL_TRASH)
-$(RM) -r $(ALL_TRASH_DIRS)
@@ -668,17 +670,17 @@ alltags:
#
# PROGRAM = Foo
# creates OBJS, links with LIBS to create Foo
#
$(PROGRAM): $(PROGOBJS) $(STATIC_LIBS_DEPS) $(EXTRA_DEPS) $(EXE_DEF_FILE) $(RESFILE) $(GLOBAL_DEPS)
$(REPORT_BUILD)
@$(RM) $@.manifest
ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
- $(EXPAND_LD) -NOLOGO -OUT:$@ -PDB:$(LINK_PDBFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(PROGOBJS) $(RESFILE) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS)
+ $(EXPAND_LD) -NOLOGO -OUT:$@ -PDB:$(LINK_PDBFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_PROGRAM_LDFLAGS) $(PROGOBJS) $(RESFILE) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS)
ifdef MSMANIFEST_TOOL
@if test -f $@.manifest; then \
if test -f '$(srcdir)/$@.manifest'; then \
echo 'Embedding manifest from $(srcdir)/$@.manifest and $@.manifest'; \
mt.exe -NOLOGO -MANIFEST '$(win_srcdir)/$@.manifest' $@.manifest -OUTPUTRESOURCE:$@\;1; \
else \
echo 'Embedding manifest from $@.manifest'; \
mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \
@@ -689,17 +691,17 @@ ifdef MSMANIFEST_TOOL
fi
endif # MSVC with manifest tool
ifdef MOZ_PROFILE_GENERATE
# touch it a few seconds into the future to work around FAT's
# 2-second granularity
touch -t `date +%Y%m%d%H%M.%S -d 'now+5seconds'` pgo.relink
endif
else # !WINNT || GNU_CC
- $(EXPAND_CCC) -o $@ $(CXXFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(EXE_DEF_FILE) $(STLPORT_LIBS)
+ $(EXPAND_CCC) -o $@ $(CXXFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(EXE_DEF_FILE) $(STLPORT_LIBS)
$(call CHECK_BINARY,$@)
endif # WINNT && !GNU_CC
ifdef ENABLE_STRIP
$(STRIP) $(STRIP_FLAGS) $@
endif
ifdef MOZ_POST_PROGRAM_COMMAND
$(MOZ_POST_PROGRAM_COMMAND) $@
@@ -737,25 +739,25 @@ endif
# Foo.o (from either Foo.c or Foo.cpp).
#
# SIMPLE_PROGRAMS = Foo Bar
# creates Foo.o Bar.o, links with LIBS to create Foo, Bar.
#
$(SIMPLE_PROGRAMS): %$(BIN_SUFFIX): %.$(OBJ_SUFFIX) $(STATIC_LIBS_DEPS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
$(REPORT_BUILD)
ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
- $(EXPAND_LD) -nologo -out:$@ -pdb:$(LINK_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS)
+ $(EXPAND_LD) -nologo -out:$@ -pdb:$(LINK_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_PROGRAM_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS)
ifdef MSMANIFEST_TOOL
@if test -f $@.manifest; then \
mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \
rm -f $@.manifest; \
fi
endif # MSVC with manifest tool
else
- $(EXPAND_CCC) $(CXXFLAGS) -o $@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(STLPORT_LIBS)
+ $(EXPAND_CCC) $(CXXFLAGS) -o $@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(STLPORT_LIBS)
$(call CHECK_BINARY,$@)
endif # WINNT && !GNU_CC
ifdef ENABLE_STRIP
$(STRIP) $(STRIP_FLAGS) $@
endif
ifdef MOZ_POST_PROGRAM_COMMAND
$(MOZ_POST_PROGRAM_COMMAND) $@
--- a/configure.in
+++ b/configure.in
@@ -1407,32 +1407,64 @@ if test "$GNU_CC"; then
else
DSO_LDOPTS="$DSO_LDOPTS -Wl,--warn-unresolved-symbols"
fi
;;
esac
fi
fi
- # Turn on GNU-specific warnings:
+ # Turn on gcc/clang warnings:
+ # https://gcc.gnu.org/onlinedocs/gcc-4.4.0/gcc/Warning-Options.html
+ #
# -Wall - turn on a lot of warnings
- # -Wpointer-arith - good to have
+ # -Wchar-subscripts - catches array index using signed char
+ # -Wcomment - catches nested comments
# -Wdeclaration-after-statement - MSVC doesn't like these
- # -Werror=return-type - catches missing returns, zero false positives
- # -Werror=int-to-pointer-cast - catches cast to pointer from integer of different size
- # -Wtype-limits - catches overflow bugs, few false positives
# -Wempty-body - catches bugs, e.g. "if (c); foo();", few false positives
+ # -Wendif-labels - catches `#else FOO` and `#endif FOO` not in comment
+ # -Wenum-compare - catches comparison of different enum types
+ # -Wignored-qualifiers - catches returns types with qualifiers like const
+ # -Wimplicit-int - catches C variable declaration without a type
+ # -Wint-to-pointer-cast - catches cast to pointer from integer of different size
+ # -Wmultichar - catches multicharacter integer constants like 'THIS'
+ # -Wnonnull - catches NULL used with functions arguments marked as non-null
+ # -Wpointer-arith - catches pointer arithmetic using NULL or sizeof(void)
+ # -Wpointer-sign - catches mixing pointers to signed and unsigned types
+ # -Wpointer-to-int-cast - catches casts from pointer to different sized int
+ # -Wreturn-type - catches missing returns, zero false positives
+ # -Wsequence-point - catches undefined order behavior like `a = a++`
# -Wsign-compare - catches comparison of signed and unsigned types
+ # -Wtrigraphs - catches unlikely use of trigraphs
+ # -Wtype-limits - catches overflow bugs, few false positives
+ # -Wunknown-pragmas - catches unexpected #pragma directives
#
- _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wall -Wpointer-arith -Wdeclaration-after-statement"
- MOZ_C_SUPPORTS_WARNING(-W, error=return-type, ac_c_has_werror_return_type)
- MOZ_C_SUPPORTS_WARNING(-W, error=int-to-pointer-cast, ac_c_has_werror_int_to_pointer_cast)
- MOZ_C_SUPPORTS_WARNING(-W, type-limits, ac_c_has_wtype_limits)
- MOZ_C_SUPPORTS_WARNING(-W, empty-body, ac_c_has_wempty_body)
- MOZ_C_SUPPORTS_WARNING(-W, sign-compare, ac_c_has_sign_compare)
+ _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wall"
+ _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wdeclaration-after-statement"
+ _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wempty-body"
+ _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wpointer-to-int-cast"
+ _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wsign-compare"
+ _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wtype-limits"
+
+ # Treat some warnings as errors:
+ _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=char-subscripts"
+ _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=comment"
+ _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=endif-labels"
+ _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=enum-compare"
+ _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=ignored-qualifiers"
+ _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=implicit-int"
+ _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=int-to-pointer-cast"
+ _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=multichar"
+ _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=nonnull"
+ _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=pointer-arith"
+ _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=pointer-sign"
+ _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=return-type"
+ _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=sequence-point"
+ _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=trigraphs"
+ _WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=unknown-pragmas"
# Turn off the following warnings that -Wall turns on:
# -Wno-unused - lots of violations in third-party code
#
_WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wno-unused"
if test -z "$INTEL_CC" -a -z "$CLANG_CC"; then
# Don't use -Wcast-align with ICC or clang
@@ -1473,40 +1505,61 @@ else
DSO_PIC_CFLAGS='-KPIC'
_DEFINES_CFLAGS='$(ACDEFINES) -D_MOZILLA_CONFIG_H_ -DMOZILLA_CLIENT'
fi
if test "$GNU_CXX"; then
# FIXME: Let us build with strict aliasing. bug 414641.
CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-strict-aliasing"
- # Turn on GNU-specific warnings:
+ # Turn on gcc/clang warnings:
+ # https://gcc.gnu.org/onlinedocs/gcc-4.4.0/gcc/Warning-Options.html
+ #
# -Wall - turn on a lot of warnings
- # -Wpointer-arith - good to have
- # -Woverloaded-virtual - ???
- # -Werror=return-type - catches missing returns, zero false positives
- # -Werror=int-to-pointer-cast - catches cast to pointer from integer of different size
- # -Werror=type-limits - catches overflow bugs, few false positives
# -Wempty-body - catches bugs, e.g. "if (c); foo();", few false positives
+ # -Wendif-labels - catches `#else FOO` and `#endif FOO` not in comment
+ # -Wint-to-pointer-cast - catches cast to pointer from integer of different size
+ # -Wmissing-braces - catches aggregate initializers missing nested braces
+ # -Woverloaded-virtual - function declaration hides virtual function from base class
+ # -Wparentheses - catches `if (a=b)` and operator precedence bugs
+ # -Wpointer-arith - catches pointer arithmetic using NULL or sizeof(void)
+ # -Wreturn-type - catches missing returns, zero false positives
+ # -Wsequence-point - catches undefined order behavior like `a = a++`
# -Wsign-compare - catches comparison of signed and unsigned types
+ # -Wtrigraphs - catches unlikely use of trigraphs
+ # -Wtype-limits - catches overflow bugs, few false positives
+ # -Wunused-label - catches unused goto labels
+ # -Wwrite-strings - catches non-const char* pointers to string literals
#
- _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall -Wpointer-arith -Woverloaded-virtual"
- MOZ_CXX_SUPPORTS_WARNING(-W, error=return-type, ac_cxx_has_werror_return_type)
- MOZ_CXX_SUPPORTS_WARNING(-W, error=int-to-pointer-cast, ac_cxx_has_werror_int_to_pointer_cast)
- MOZ_CXX_SUPPORTS_WARNING(-W, error=type-limits, ac_cxx_has_werror_type_limits)
- MOZ_CXX_SUPPORTS_WARNING(-W, empty-body, ac_cxx_has_wempty_body)
- MOZ_CXX_SUPPORTS_WARNING(-W, sign-compare, ac_cxx_has_sign_compare)
+ _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall"
+ _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wempty-body"
+ _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Woverloaded-virtual"
+ _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wpointer-arith"
+ _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wsign-compare"
+ _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wwrite-strings"
+
+ # Treat some warnings as errors:
+ _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=endif-labels"
+ _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=int-to-pointer-cast"
+ _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=missing-braces"
+ _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=parentheses"
+ _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=return-type"
+ _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=sequence-point"
+ _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=unused-label"
+ _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=trigraphs"
+ _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=type-limits"
# Turn off the following warnings that -Wall turns on:
# -Wno-invalid-offsetof - we use offsetof on non-POD types frequently
# -Wno-inline-new-delete - we inline 'new' and 'delete' in mozalloc
# for performance reasons, and because GCC and clang accept it (though
# clang warns about it).
#
- MOZ_CXX_SUPPORTS_WARNING(-Wno-, invalid-offsetof, ac_cxx_has_wno_invalid_offsetof)
+ _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-invalid-offsetof"
+
MOZ_CXX_SUPPORTS_WARNING(-Wno-, inline-new-delete, ac_cxx_has_wno_inline_new_delete)
if test -z "$INTEL_CXX" -a -z "$CLANG_CXX"; then
# Don't use -Wcast-align with ICC or clang
case "$CPU_ARCH" in
# And don't use it on hppa, ia64, sparc, arm, since it's noisy there
hppa | ia64 | sparc | arm)
;;
--- a/content/base/src/ImportManager.h
+++ b/content/base/src/ImportManager.h
@@ -65,17 +65,17 @@ class ImportLoader MOZ_FINAL : public ns
, public nsIDOMEventListener
{
// A helper inner class to decouple the logic of updating the import graph
// after a new import link has been found by one of the parsers.
class Updater {
public:
- Updater(ImportLoader* aLoader) : mLoader(aLoader)
+ explicit Updater(ImportLoader* aLoader) : mLoader(aLoader)
{}
// After a new link is added that refers to this import, we
// have to update the spanning tree, since given this new link the
// priority of this import might be higher in the scripts
// execution order than before. It updates mMainReferrer, mImportParent,
// the corresponding pending ScriptRunners, etc.
// It also handles updating additional dependant loaders via the
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -550,17 +550,17 @@ nsIdentifierMapEntry::FireChangeCallback
mChangeCallbacks->EnumerateEntries(FireChangeEnumerator, &args);
}
namespace {
struct PositionComparator
{
Element* const mElement;
- PositionComparator(Element* const aElement) : mElement(aElement) {}
+ explicit PositionComparator(Element* const aElement) : mElement(aElement) {}
int operator()(void* aElement) const {
Element* curElement = static_cast<Element*>(aElement);
if (mElement == curElement) {
return 0;
}
if (nsContentUtils::PositionIsBefore(mElement, curElement)) {
return -1;
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -1730,17 +1730,17 @@ public:
InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
if (aCpows && !cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
return false;
}
if (aIsSync) {
return cc->SendSyncMessage(PromiseFlatString(aMessage), data, cpows,
IPC::Principal(aPrincipal), aJSONRetVal);
}
- return cc->CallRpcMessage(PromiseFlatString(aMessage), data, cpows,
+ return cc->SendRpcMessage(PromiseFlatString(aMessage), data, cpows,
IPC::Principal(aPrincipal), aJSONRetVal);
}
virtual bool DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const mozilla::dom::StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal) MOZ_OVERRIDE
--- a/content/base/src/nsPlainTextSerializer.cpp
+++ b/content/base/src/nsPlainTextSerializer.cpp
@@ -1868,17 +1868,17 @@ struct interval
{
uint16_t first;
uint16_t last;
};
struct CombiningComparator
{
const char16_t mUcs;
- CombiningComparator(char16_t ucs) : mUcs(ucs) {}
+ explicit CombiningComparator(char16_t aUcs) : mUcs(aUcs) {}
int operator()(const interval& combining) const {
if (mUcs > combining.last)
return 1;
if (mUcs < combining.first)
return -1;
MOZ_ASSERT(combining.first <= mUcs);
MOZ_ASSERT(mUcs <= combining.last);
--- a/content/base/test/unit/xpcshell.ini
+++ b/content/base/test/unit/xpcshell.ini
@@ -1,11 +1,12 @@
[DEFAULT]
head = head_utilities.js
tail =
+skip-if = toolkit == 'gonk'
support-files =
1_original.xml
1_result.xml
2_original.xml
2_result_1.xml
2_result_2.xml
2_result_3.xml
2_result_4.xml
--- a/content/base/test/unit_ipc/xpcshell.ini
+++ b/content/base/test/unit_ipc/xpcshell.ini
@@ -1,6 +1,7 @@
[DEFAULT]
head =
tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_bug553888_wrap.js]
[test_xhr_document_ipc.js]
--- a/content/html/content/src/HTMLFormElement.cpp
+++ b/content/html/content/src/HTMLFormElement.cpp
@@ -2239,33 +2239,33 @@ HTMLFormElement::Clear()
mPastNameLookupTable.Clear();
}
namespace {
struct PositionComparator
{
nsIContent* const mElement;
- PositionComparator(nsIContent* const element) : mElement(element) {}
+ explicit PositionComparator(nsIContent* const aElement) : mElement(aElement) {}
int operator()(nsIContent* aElement) const {
if (mElement == aElement) {
return 0;
}
if (nsContentUtils::PositionIsBefore(mElement, aElement)) {
return -1;
}
return 1;
}
};
struct NodeListAdaptor
{
nsINodeList* const mList;
- NodeListAdaptor(nsINodeList* aList) : mList(aList) {}
+ explicit NodeListAdaptor(nsINodeList* aList) : mList(aList) {}
nsIContent* operator[](size_t aIdx) const {
return mList->Item(aIdx);
}
};
} // namespace
nsresult
--- a/content/media/MediaDecoderStateMachine.cpp
+++ b/content/media/MediaDecoderStateMachine.cpp
@@ -2473,18 +2473,18 @@ nsresult MediaDecoderStateMachine::RunSt
return NS_OK;
}
StopAudioThread();
// When we're decoding to a stream, the stream's main-thread finish signal
// will take care of calling MediaDecoder::PlaybackEnded.
if (mDecoder->GetState() == MediaDecoder::PLAY_STATE_PLAYING &&
!mDecoder->GetDecodedStream()) {
- int64_t videoTime = HasVideo() ? mVideoFrameEndTime : 0;
- int64_t clockTime = std::max(mEndTime, videoTime);
+ int64_t clockTime = std::max(mAudioEndTime, mVideoFrameEndTime);
+ clockTime = std::max(int64_t(0), std::max(clockTime, mEndTime));
UpdatePlaybackPosition(clockTime);
{
// Wait for the state change is completed in the main thread,
// otherwise we might see |mDecoder->GetState() == MediaDecoder::PLAY_STATE_PLAYING|
// in next loop and send |MediaDecoder::PlaybackEnded| again to trigger 'ended'
// event twice in the media element.
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
@@ -3138,17 +3138,23 @@ void MediaDecoderStateMachine::OnAudioSi
AssertCurrentThreadInMonitor();
// AudioSink not used with captured streams, so ignore errors in this case.
if (mAudioCaptured) {
return;
}
mAudioCompleted = true;
- // Notify media decoder/element about this error.
+ // Make the best effort to continue playback when there is video.
+ if (HasVideo()) {
+ return;
+ }
+
+ // Otherwise notify media decoder/element about this error for it makes
+ // no sense to play an audio-only file without sound output.
RefPtr<nsIRunnable> task(
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::OnDecodeError));
nsresult rv = mDecodeTaskQueue->Dispatch(task);
if (NS_FAILED(rv)) {
DECODER_WARN("Failed to dispatch OnDecodeError");
}
}
--- a/content/media/webaudio/AudioBuffer.cpp
+++ b/content/media/webaudio/AudioBuffer.cpp
@@ -221,17 +221,17 @@ StealJSArrayDataIntoThreadSharedFloatArr
for (uint32_t i = 0; i < aJSArrays.Length(); ++i) {
JS::Rooted<JSObject*> arrayBufferView(aJSContext, aJSArrays[i]);
JS::Rooted<JSObject*> arrayBuffer(aJSContext,
JS_GetArrayBufferViewBuffer(aJSContext, arrayBufferView));
uint8_t* stolenData = arrayBuffer
? (uint8_t*) JS_StealArrayBufferContents(aJSContext, arrayBuffer)
: nullptr;
if (stolenData) {
- result->SetData(i, stolenData, reinterpret_cast<float*>(stolenData));
+ result->SetData(i, stolenData, js_free, reinterpret_cast<float*>(stolenData));
} else {
return nullptr;
}
}
return result.forget();
}
ThreadSharedFloatArrayBufferList*
--- a/content/media/webaudio/AudioNodeEngine.h
+++ b/content/media/webaudio/AudioNodeEngine.h
@@ -33,50 +33,61 @@ public:
* Construct with null data.
*/
explicit ThreadSharedFloatArrayBufferList(uint32_t aCount)
{
mContents.SetLength(aCount);
}
struct Storage {
- Storage()
- {
- mDataToFree = nullptr;
- mSampleData = nullptr;
+ Storage() :
+ mDataToFree(nullptr),
+ mFree(nullptr),
+ mSampleData(nullptr)
+ {}
+ ~Storage() {
+ if (mFree) {
+ mFree(mDataToFree);
+ } else { MOZ_ASSERT(!mDataToFree); }
}
- ~Storage() { free(mDataToFree); }
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
{
// NB: mSampleData might not be owned, if it is it just points to
// mDataToFree.
return aMallocSizeOf(mDataToFree);
}
void* mDataToFree;
+ void (*mFree)(void*);
const float* mSampleData;
};
/**
* This can be called on any thread.
*/
uint32_t GetChannels() const { return mContents.Length(); }
/**
* This can be called on any thread.
*/
const float* GetData(uint32_t aIndex) const { return mContents[aIndex].mSampleData; }
/**
* Call this only during initialization, before the object is handed to
* any other thread.
*/
- void SetData(uint32_t aIndex, void* aDataToFree, const float* aData)
+ void SetData(uint32_t aIndex, void* aDataToFree, void (*aFreeFunc)(void*), const float* aData)
{
Storage* s = &mContents[aIndex];
- free(s->mDataToFree);
+ if (s->mFree) {
+ s->mFree(s->mDataToFree);
+ } else {
+ MOZ_ASSERT(!s->mDataToFree);
+ }
+
s->mDataToFree = aDataToFree;
+ s->mFree = aFreeFunc;
s->mSampleData = aData;
}
/**
* Put this object into an error state where there are no channels.
*/
void Clear() { mContents.Clear(); }
--- a/content/media/webaudio/ConvolverNode.cpp
+++ b/content/media/webaudio/ConvolverNode.cpp
@@ -253,17 +253,17 @@ ConvolverNode::SetBuffer(JSContext* aCx,
// has enough data to compute FFTs from.
length = WEBAUDIO_BLOCK_SIZE;
nsRefPtr<ThreadSharedFloatArrayBufferList> paddedBuffer =
new ThreadSharedFloatArrayBufferList(data->GetChannels());
float* channelData = (float*) malloc(sizeof(float) * length * data->GetChannels());
for (uint32_t i = 0; i < data->GetChannels(); ++i) {
PodCopy(channelData + length * i, data->GetData(i), mBuffer->Length());
PodZero(channelData + length * i + mBuffer->Length(), WEBAUDIO_BLOCK_SIZE - mBuffer->Length());
- paddedBuffer->SetData(i, (i == 0) ? channelData : nullptr, channelData);
+ paddedBuffer->SetData(i, (i == 0) ? channelData : nullptr, free, channelData);
}
data = paddedBuffer;
}
SendInt32ParameterToStream(ConvolverNodeEngine::BUFFER_LENGTH, length);
SendDoubleParameterToStream(ConvolverNodeEngine::SAMPLE_RATE,
mBuffer->SampleRate());
ns->SetBuffer(data.forget());
} else {
--- a/content/media/webaudio/PeriodicWave.cpp
+++ b/content/media/webaudio/PeriodicWave.cpp
@@ -33,19 +33,19 @@ PeriodicWave::PeriodicWave(AudioContext*
// Copy coefficient data. The two arrays share an allocation.
mCoefficients = new ThreadSharedFloatArrayBufferList(2);
float* buffer = static_cast<float*>(malloc(aLength*sizeof(float)*2));
if (buffer == nullptr) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
PodCopy(buffer, aRealData, aLength);
- mCoefficients->SetData(0, buffer, buffer);
+ mCoefficients->SetData(0, buffer, free, buffer);
PodCopy(buffer+aLength, aImagData, aLength);
- mCoefficients->SetData(1, nullptr, buffer+aLength);
+ mCoefficients->SetData(1, nullptr, free, buffer+aLength);
}
size_t
PeriodicWave::SizeOfExcludingThisIfNotShared(MallocSizeOf aMallocSizeOf) const
{
// Not owned:
// - mContext
size_t amount = 0;
--- a/content/media/webspeech/synth/ipc/PSpeechSynthesis.ipdl
+++ b/content/media/webspeech/synth/ipc/PSpeechSynthesis.ipdl
@@ -12,17 +12,17 @@ namespace dom {
struct RemoteVoice {
nsString voiceURI;
nsString name;
nsString lang;
bool localService;
};
-intr protocol PSpeechSynthesis
+sync protocol PSpeechSynthesis
{
manager PContent;
manages PSpeechSynthesisRequest;
child:
VoiceAdded(RemoteVoice aVoice);
--- a/content/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl
+++ b/content/media/webspeech/synth/ipc/PSpeechSynthesisRequest.ipdl
@@ -4,17 +4,17 @@
* 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 protocol PSpeechSynthesis;
namespace mozilla {
namespace dom {
-intr protocol PSpeechSynthesisRequest
+async protocol PSpeechSynthesisRequest
{
manager PSpeechSynthesis;
parent:
Pause();
Resume();
--- a/content/test/unit/xpcshell.ini
+++ b/content/test/unit/xpcshell.ini
@@ -1,11 +1,12 @@
[DEFAULT]
head = head_content.js
tail =
+skip-if = toolkit == 'gonk'
support-files =
empty_document.xml
isequalnode_data.xml
nodelist_data_1.xml
nodelist_data_2.xul
test_delete_range.xml
[test_isequalnode.js]
--- a/docshell/test/unit/xpcshell.ini
+++ b/docshell/test/unit/xpcshell.ini
@@ -1,11 +1,12 @@
[DEFAULT]
head = head_docshell.js
tail =
+skip-if = toolkit == 'gonk'
[test_bug414201_jfif.js]
[test_bug442584.js]
[test_nsDefaultURIFixup.js]
[test_nsDefaultURIFixup_search.js]
skip-if = os == 'android'
[test_nsDefaultURIFixup_info.js]
skip-if = os == 'android'
--- a/docshell/test/unit_ipc/xpcshell.ini
+++ b/docshell/test/unit_ipc/xpcshell.ini
@@ -1,7 +1,8 @@
[DEFAULT]
head =
tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_pb_notification_ipc.js]
# Bug 751575: Perma-fails with: command timed out: 1200 seconds without output
skip-if = true
--- a/dom/activities/tests/unit/xpcshell.ini
+++ b/dom/activities/tests/unit/xpcshell.ini
@@ -1,5 +1,6 @@
[DEFAULT]
head =
tail =
+skip-if = toolkit == 'gonk'
[test_activityFilters.js]
--- a/dom/base/URLSearchParams.cpp
+++ b/dom/base/URLSearchParams.cpp
@@ -1,16 +1,17 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "URLSearchParams.h"
#include "mozilla/dom/URLSearchParamsBinding.h"
#include "mozilla/dom/EncodingUtils.h"
+#include "nsDOMString.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(URLSearchParams, mObservers)
NS_IMPL_CYCLE_COLLECTING_ADDREF(URLSearchParams)
NS_IMPL_CYCLE_COLLECTING_RELEASE(URLSearchParams)
@@ -225,17 +226,17 @@ void
URLSearchParams::RemoveObservers()
{
mObservers.Clear();
}
void
URLSearchParams::Get(const nsAString& aName, nsString& aRetval)
{
- aRetval.Truncate();
+ SetDOMStringToNull(aRetval);
for (uint32_t i = 0, len = mSearchParams.Length(); i < len; ++i) {
if (mSearchParams[i].mKey.Equals(aName)) {
aRetval.Assign(mSearchParams[i].mValue);
break;
}
}
}
--- a/dom/base/test/test_urlSearchParams.html
+++ b/dom/base/test/test_urlSearchParams.html
@@ -1,17 +1,17 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=887836
-->
<head>
<meta charset="utf-8">
- <title>Test for Bug 887836</title>
+ <title>Test for URLSearchParams</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=887836">Mozilla Bug 887836</a>
<p id="display"></p>
<div id="content" style="display: none">
<iframe name="x" id="x"></iframe>
@@ -25,17 +25,17 @@ https://bugzilla.mozilla.org/show_bug.cg
/** Test for Bug 887836 **/
ok("URLSearchParams" in window, "window.URLSearchParams exists");
function testSimpleURLSearchParams() {
var u = new URLSearchParams();
ok(u, "URLSearchParams created");
is(u.has('foo'), false, 'URLSearchParams.has(foo)');
- is(u.get('foo'), '', 'URLSearchParams.get(foo)');
+ is(u.get('foo'), null, 'URLSearchParams.get(foo)');
is(u.getAll('foo').length, 0, 'URLSearchParams.getAll(foo)');
u.append('foo', 'bar');
is(u.has('foo'), true, 'URLSearchParams.has(foo)');
is(u.get('foo'), 'bar', 'URLSearchParams.get(foo)');
is(u.getAll('foo').length, 1, 'URLSearchParams.getAll(foo)');
u.set('foo', 'bar2');
@@ -270,27 +270,41 @@ https://bugzilla.mozilla.org/show_bug.cg
a.delete('a');
is(a.getAll('a').length, 0, "Correct length of getAll()");
is(a.toString(), "b=3&c=4&c=5", "Order is correct");
runTest();
}
+ function testGetNULL() {
+
+ var u = new URLSearchParams();
+ is(typeof u.get(''), "object", "typeof URL.searchParams.get('')");
+ is(u.get(''), null, "URL.searchParams.get('') should be null");
+
+ var url = new URL('http://www.example.net?a=b');
+ is(url.searchParams.get('b'), null, "URL.searchParams.get('b') should be null");
+ is(url.searchParams.get('a'), 'b', "URL.searchParams.get('a')");
+
+ runTest();
+ }
+
var tests = [
testSimpleURLSearchParams,
testCopyURLSearchParams,
testParserURLSearchParams,
testURL,
function() { testElement(document.getElementById('anchor')) },
function() { testElement(document.getElementById('area')) },
testEncoding,
testMultiURL,
testOrdering,
- testDelete
+ testDelete,
+ testGetNULL
];
function runTest() {
if (!tests.length) {
SimpleTest.finish();
return;
}
--- a/dom/canvas/WebGL2ContextTextures.cpp
+++ b/dom/canvas/WebGL2ContextTextures.cpp
@@ -148,26 +148,19 @@ WebGL2Context::TexStorage2D(GLenum targe
WebGLTexture* tex = activeBoundTextureForTarget(target);
tex->SetImmutable();
const size_t facesCount = (target == LOCAL_GL_TEXTURE_2D) ? 1 : 6;
GLsizei w = width;
GLsizei h = height;
for (size_t l = 0; l < size_t(levels); l++) {
for (size_t f = 0; f < facesCount; f++) {
- TexImageTarget imageTarget = TexImageTargetForTargetAndFace(target, f);
- // FIXME: SetImageInfo wants a type, to go with the internalformat that it stores.
- // 'type' is deprecated by sized internalformats, which are how TexStorage works.
- // We must fix WebGLTexture::ImageInfo to store an "effective internalformat",
- // which in the present case is just the sized internalformat, and drop 'types'
- // altogether. For now, we just pass LOCAL_GL_UNSIGNED_BYTE, which works For
- // the most commonly used formats.
- const GLenum type = LOCAL_GL_UNSIGNED_BYTE;
- tex->SetImageInfo(imageTarget, l, w, h,
- internalformat, type,
+ tex->SetImageInfo(TexImageTargetForTargetAndFace(target, f),
+ l, w, h,
+ internalformat,
WebGLImageDataStatus::UninitializedImageData);
}
w = std::max(1, w/2);
h = std::max(1, h/2);
}
gl->fTexStorage2D(target, levels, internalformat, width, height);
}
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -1755,16 +1755,23 @@ WebGLContext::DidRefresh()
gl->FlushIfHeavyGLCallsSinceLastFlush();
}
}
bool WebGLContext::TexImageFromVideoElement(const TexImageTarget texImageTarget, GLint level,
GLenum internalformat, GLenum format, GLenum type,
mozilla::dom::Element& elt)
{
+ if (type == LOCAL_GL_HALF_FLOAT_OES) {
+ type = LOCAL_GL_HALF_FLOAT;
+ }
+
+ if (!ValidateTexImageFormatAndType(format, type, WebGLTexImageFunc::TexImage))
+ return false;
+
HTMLVideoElement* video = HTMLVideoElement::FromContentOrNull(&elt);
if (!video) {
return false;
}
uint16_t readyState;
if (NS_SUCCEEDED(video->GetReadyState(&readyState)) &&
readyState < nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA)
@@ -1802,18 +1809,21 @@ bool WebGLContext::TexImageFromVideoElem
bool dimensionsMatch = info.Width() == srcImage->GetSize().width &&
info.Height() == srcImage->GetSize().height;
if (!dimensionsMatch) {
// we need to allocation
gl->fTexImage2D(texImageTarget.get(), level, internalformat, srcImage->GetSize().width, srcImage->GetSize().height, 0, format, type, nullptr);
}
bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage.get(), srcImage->GetSize(), tex->GLName(), texImageTarget.get(), mPixelStoreFlipY);
if (ok) {
- tex->SetImageInfo(texImageTarget, level, srcImage->GetSize().width, srcImage->GetSize().height, internalformat, type,
- WebGLImageDataStatus::InitializedImageData);
+ TexInternalFormat effectiveinternalformat =
+ EffectiveInternalFormatFromInternalFormatAndType(internalformat, type);
+ MOZ_ASSERT(effectiveinternalformat != LOCAL_GL_NONE);
+ tex->SetImageInfo(texImageTarget, level, srcImage->GetSize().width, srcImage->GetSize().height,
+ effectiveinternalformat, WebGLImageDataStatus::InitializedImageData);
tex->Bind(TexImageTargetToTexTarget(texImageTarget));
}
srcImage = nullptr;
container->UnlockCurrentImage();
return ok;
}
////////////////////////////////////////////////////////////////////////////////
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -89,17 +89,17 @@ class Element;
struct WebGLContextAttributes;
template<typename> struct Nullable;
}
namespace gfx {
class SourceSurface;
}
-WebGLTexelFormat GetWebGLTexelFormat(TexInternalFormat format, TexType type);
+WebGLTexelFormat GetWebGLTexelFormat(TexInternalFormat format);
void AssertUintParamCorrect(gl::GLContext* gl, GLenum pname, GLuint shadow);
struct WebGLContextOptions {
// these are defaults
WebGLContextOptions();
bool operator==(const WebGLContextOptions& other) const {
@@ -485,19 +485,16 @@ public:
auto dims = 2;
if (!ValidateTexImageTarget(dims, rawTexImgTarget, WebGLTexImageFunc::TexImage))
return ErrorInvalidEnumInfo("texSubImage2D: target", rawTexImgTarget);
const TexImageTarget texImageTarget(rawTexImgTarget);
- if (!ValidateTexImageFormatAndType(format, type, WebGLTexImageFunc::TexImage))
- return;
-
if (level < 0)
return ErrorInvalidValue("texImage2D: level is negative");
const int32_t maxLevel = MaxTextureLevelForTexImageTarget(texImageTarget);
if (level > maxLevel)
return ErrorInvalidValue("texImage2D: level %d is too large, max is %d", level, maxLevel);
WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
@@ -555,32 +552,29 @@ public:
if (IsContextLost())
return;
if (!ValidateTexImageTarget(2, rawTexImageTarget, WebGLTexImageFunc::TexSubImage))
return ErrorInvalidEnumInfo("texSubImage2D: target", rawTexImageTarget);
const TexImageTarget texImageTarget(rawTexImageTarget);
- if (!ValidateTexImageFormatAndType(format, type, WebGLTexImageFunc::TexImage))
- return;
-
if (level < 0)
return ErrorInvalidValue("texSubImage2D: level is negative");
const int32_t maxLevel = MaxTextureLevelForTexImageTarget(texImageTarget);
if (level > maxLevel)
return ErrorInvalidValue("texSubImage2D: level %d is too large, max is %d", level, maxLevel);
WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
if (!tex) {
return ErrorInvalidOperation("texSubImage2D: no texture bound on active texture unit");
}
const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(texImageTarget, level);
- const TexInternalFormat internalformat = imageInfo.InternalFormat();
+ const TexInternalFormat internalformat = imageInfo.EffectiveInternalFormat();
// Trying to handle the video by GPU directly first
if (TexImageFromVideoElement(texImageTarget, level,
internalformat.get(), format, type, elt))
{
return;
}
@@ -1140,18 +1134,16 @@ protected:
GLsizei width, GLsizei height,
GLsizei levelWidth, GLsizei levelHeight,
WebGLTexImageFunc func);
bool ValidateCompTexImageDataSize(GLint level,
GLenum internalformat,
GLsizei width, GLsizei height,
uint32_t byteLength, WebGLTexImageFunc func);
- static uint32_t GetBitsPerTexel(TexInternalFormat format, TexType type);
-
void Invalidate();
void DestroyResourcesAndContext();
void MakeContextCurrent() const;
// helpers
void TexImage2D_base(TexImageTarget target,
GLint level,
@@ -1198,17 +1190,17 @@ protected:
}
nsresult SurfaceFromElementResultToImageSurface(nsLayoutUtils::SurfaceFromElementResult& res,
RefPtr<gfx::DataSourceSurface>& imageOut,
WebGLTexelFormat *format);
void CopyTexSubImage2D_base(TexImageTarget texImageTarget,
GLint level,
- GLenum internalformat,
+ TexInternalFormat internalformat,
GLint xoffset,
GLint yoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
bool sub);
@@ -1358,17 +1350,17 @@ protected:
WebGLContext& mWebGL;
const bool mNeedsChange;
static bool NeedsChange(WebGLContext& webgl) {
return webgl.mNeedsFakeNoAlpha &&
webgl.mColorWriteMask[3] != false;
}
- ScopedMaskWorkaround(WebGLContext& webgl);
+ explicit ScopedMaskWorkaround(WebGLContext& aWebgl);
~ScopedMaskWorkaround();
};
void LoseOldestWebGLContextIfLimitExceeded();
void UpdateLastUseIndex();
template <typename WebGLObjectType>
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -671,17 +671,17 @@ WebGLContext::BindFakeBlackTexturesHelpe
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());
+ FormatHasAlpha(boundTexturesArray[i]->ImageInfoBase().EffectiveInternalFormat());
UniquePtr<FakeBlackTexture>&
blackTexturePtr = alpha
? transparentTextureScopedPtr
: opaqueTextureScopedPtr;
if (!blackTexturePtr) {
GLenum format = alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
blackTexturePtr = MakeUnique<FakeBlackTexture>(gl, target, format);
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -349,17 +349,17 @@ WebGLContext::CheckFramebufferStatus(GLe
return LOCAL_GL_FRAMEBUFFER_COMPLETE;
return mBoundFramebuffer->CheckFramebufferStatus().get();
}
void
WebGLContext::CopyTexSubImage2D_base(TexImageTarget texImageTarget,
GLint level,
- GLenum internalformat,
+ TexInternalFormat internalformat,
GLint xoffset,
GLint yoffset,
GLint x,
GLint y,
GLsizei width,
GLsizei height,
bool sub)
{
@@ -367,27 +367,27 @@ WebGLContext::CopyTexSubImage2D_base(Tex
GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
const char* info = sub ? "copyTexSubImage2D" : "copyTexImage2D";
WebGLTexImageFunc func = sub ? WebGLTexImageFunc::CopyTexSubImage : WebGLTexImageFunc::CopyTexImage;
// TODO: This changes with color_buffer_float. Reassess when the
// patch lands.
- if (!ValidateTexImage(2, texImageTarget, level, internalformat,
+ if (!ValidateTexImage(2, texImageTarget, level, internalformat.get(),
xoffset, yoffset, 0,
width, height, 0,
0,
LOCAL_GL_NONE, LOCAL_GL_NONE,
func))
{
return;
}
- if (!ValidateCopyTexImage(internalformat, func))
+ if (!ValidateCopyTexImage(internalformat.get(), func))
return;
if (!mBoundFramebuffer)
ClearBackbufferIfNeeded();
MakeContextCurrent();
WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
@@ -396,60 +396,60 @@ WebGLContext::CopyTexSubImage2D_base(Tex
return ErrorInvalidOperation("%s: no texture is bound to this target");
if (tex->IsImmutable()) {
if (!sub) {
return ErrorInvalidOperation("copyTexImage2D: disallowed because the texture bound to this target has already been made immutable by texStorage2D");
}
}
+ TexType framebuffertype = LOCAL_GL_NONE;
+ if (mBoundFramebuffer) {
+ TexInternalFormat framebuffereffectiveformat = mBoundFramebuffer->ColorAttachment(0).EffectiveInternalFormat();
+ framebuffertype = TypeFromInternalFormat(framebuffereffectiveformat);
+ } else {
+ // FIXME - here we're assuming that the default framebuffer is backed by UNSIGNED_BYTE
+ // that might not always be true, say if we had a 16bpp default framebuffer.
+ framebuffertype = LOCAL_GL_UNSIGNED_BYTE;
+ }
+
+ TexInternalFormat effectiveinternalformat =
+ EffectiveInternalFormatFromUnsizedInternalFormatAndType(internalformat, framebuffertype);
+
+ // this should never fail, validation happened earlier.
+ MOZ_ASSERT(effectiveinternalformat != LOCAL_GL_NONE);
+
+ // check if the memory size of this texture may change with this call
+ bool sizeMayChange = !sub;
+ if (!sub && tex->HasImageInfoAt(texImageTarget, level)) {
+ const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
+ sizeMayChange = width != imageInfo.Width() ||
+ height != imageInfo.Height() ||
+ effectiveinternalformat != imageInfo.EffectiveInternalFormat();
+ }
+
+ if (sizeMayChange)
+ GetAndFlushUnderlyingGLErrors();
+
if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, framebufferWidth, framebufferHeight)) {
if (sub)
gl->fCopyTexSubImage2D(texImageTarget.get(), level, xoffset, yoffset, x, y, width, height);
else
- gl->fCopyTexImage2D(texImageTarget.get(), level, internalformat, x, y, width, height, 0);
+ gl->fCopyTexImage2D(texImageTarget.get(), level, internalformat.get(), x, y, width, height, 0);
} else {
// the rect doesn't fit in the framebuffer
- /*** first, we initialize the texture as black ***/
-
- // first, compute the size of the buffer we should allocate to initialize the texture as black
-
- if (!ValidateTexInputData(LOCAL_GL_UNSIGNED_BYTE, -1, func))
- return;
-
- uint32_t texelSize = GetBitsPerTexel(internalformat, LOCAL_GL_UNSIGNED_BYTE) / 8;
-
- CheckedUint32 checked_neededByteLength =
- GetImageSize(height, width, texelSize, mPixelStoreUnpackAlignment);
-
- if (!checked_neededByteLength.isValid())
- return ErrorInvalidOperation("%s: integer overflow computing the needed buffer size", info);
-
- uint32_t bytesNeeded = checked_neededByteLength.value();
-
- // now that the size is known, create the buffer
-
- // We need some zero pages, because GL doesn't guarantee the
- // contents of a texture allocated with nullptr data.
- // Hopefully calloc will just mmap zero pages here.
- void* tempZeroData = calloc(1, bytesNeeded);
- if (!tempZeroData)
- return ErrorOutOfMemory("%s: could not allocate %d bytes (for zero fill)", info, bytesNeeded);
-
- // now initialize the texture as black
-
- if (sub)
- gl->fTexSubImage2D(texImageTarget.get(), level, 0, 0, width, height,
- internalformat, LOCAL_GL_UNSIGNED_BYTE, tempZeroData);
- else
- gl->fTexImage2D(texImageTarget.get(), level, internalformat, width, height,
- 0, internalformat, LOCAL_GL_UNSIGNED_BYTE, tempZeroData);
- free(tempZeroData);
+ // first, we initialize the texture as black
+ if (!sub) {
+ tex->SetImageInfo(texImageTarget, level, width, height,
+ effectiveinternalformat,
+ WebGLImageDataStatus::UninitializedImageData);
+ tex->DoDeferredImageInitialization(texImageTarget, level);
+ }
// if we are completely outside of the framebuffer, we can exit now with our black texture
if ( x >= framebufferWidth
|| x+width <= 0
|| y >= framebufferHeight
|| y+height <= 0)
{
// we are completely outside of range, can exit now with buffer filled with zeros
@@ -463,16 +463,30 @@ WebGLContext::CopyTexSubImage2D_base(Tex
GLint actual_y = clamped(y, 0, framebufferHeight);
GLint actual_y_plus_height = clamped(y + height, 0, framebufferHeight);
GLsizei actual_height = actual_y_plus_height - actual_y;
GLint actual_yoffset = yoffset + actual_y - y;
gl->fCopyTexSubImage2D(texImageTarget.get(), level, actual_xoffset, actual_yoffset, actual_x, actual_y, actual_width, actual_height);
}
+
+ if (sizeMayChange) {
+ GLenum error = GetAndFlushUnderlyingGLErrors();
+ if (error) {
+ GenerateWarning("copyTexImage2D generated error %s", ErrorName(error));
+ return;
+ }
+ }
+
+ if (!sub) {
+ tex->SetImageInfo(texImageTarget, level, width, height,
+ effectiveinternalformat,
+ WebGLImageDataStatus::InitializedImageData);
+ }
}
void
WebGLContext::CopyTexImage2D(GLenum rawTexImgTarget,
GLint level,
GLenum internalformat,
GLint x,
GLint y,
@@ -499,47 +513,17 @@ WebGLContext::CopyTexImage2D(GLenum rawT
}
if (!ValidateCopyTexImage(internalformat, func))
return;
if (!mBoundFramebuffer)
ClearBackbufferIfNeeded();
- const TexImageTarget texImageTarget(rawTexImgTarget);
-
- // check if the memory size of this texture may change with this call
- bool sizeMayChange = true;
- WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
- if (tex->HasImageInfoAt(texImageTarget, level)) {
- const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
-
- sizeMayChange = width != imageInfo.Width() ||
- height != imageInfo.Height() ||
- internalformat != imageInfo.InternalFormat();
- }
-
- if (sizeMayChange)
- GetAndFlushUnderlyingGLErrors();
-
- CopyTexSubImage2D_base(texImageTarget, level, internalformat, 0, 0, x, y, width, height, false);
-
- if (sizeMayChange) {
- GLenum error = GetAndFlushUnderlyingGLErrors();
- if (error) {
- GenerateWarning("copyTexImage2D generated error %s", ErrorName(error));
- return;
- }
- }
-
- tex->SetImageInfo(texImageTarget, level, width, height,
- internalformat,
- LOCAL_GL_UNSIGNED_BYTE, /* dummy, artifact of us storing
- the wrong data in ImageInfo */
- WebGLImageDataStatus::InitializedImageData);
+ CopyTexSubImage2D_base(rawTexImgTarget, level, internalformat, 0, 0, x, y, width, height, false);
}
void
WebGLContext::CopyTexSubImage2D(GLenum rawTexImgTarget,
GLint level,
GLint xoffset,
GLint yoffset,
GLint x,
@@ -597,17 +581,21 @@ WebGLContext::CopyTexSubImage2D(GLenum r
if (!mBoundFramebuffer)
ClearBackbufferIfNeeded();
if (imageInfo.HasUninitializedImageData()) {
tex->DoDeferredImageInitialization(texImageTarget, level);
}
- return CopyTexSubImage2D_base(texImageTarget, level, imageInfo.InternalFormat().get(), xoffset, yoffset, x, y, width, height, true);
+ TexInternalFormat internalformat;
+ TexType type;
+ UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(imageInfo.EffectiveInternalFormat(),
+ &internalformat, &type);
+ return CopyTexSubImage2D_base(texImageTarget, level, internalformat, xoffset, yoffset, x, y, width, height, true);
}
already_AddRefed<WebGLProgram>
WebGLContext::CreateProgram()
{
if (IsContextLost())
return nullptr;
@@ -917,17 +905,17 @@ WebGLContext::GenerateMipmap(GLenum rawT
if (!tex->HasImageInfoAt(imageTarget, 0))
{
return ErrorInvalidOperation("generateMipmap: Level zero of texture is not defined.");
}
if (!tex->IsFirstImagePowerOfTwo())
return ErrorInvalidOperation("generateMipmap: Level zero of texture does not have power-of-two width and height.");
- TexInternalFormat internalformat = tex->ImageInfoAt(imageTarget, 0).InternalFormat();
+ TexInternalFormat internalformat = tex->ImageInfoAt(imageTarget, 0).EffectiveInternalFormat();
if (IsTextureFormatCompressed(internalformat))
return ErrorInvalidOperation("generateMipmap: Texture data at level zero is compressed.");
if (IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture) &&
(IsGLDepthFormat(internalformat) || IsGLDepthStencilFormat(internalformat)))
{
return ErrorInvalidOperation("generateMipmap: "
"A texture that has a base internal format of "
@@ -1178,22 +1166,27 @@ WebGLContext::GetFramebufferAttachmentPa
}
ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: pname", pname);
return JS::NullValue();
} else if (fba.Texture()) {
switch (pname) {
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT:
if (IsExtensionEnabled(WebGLExtensionID::EXT_sRGB)) {
- const TexInternalFormat internalformat =
- fba.Texture()->ImageInfoBase().InternalFormat();
- return (internalformat == LOCAL_GL_SRGB ||
- internalformat == LOCAL_GL_SRGB_ALPHA) ?
- JS::NumberValue(uint32_t(LOCAL_GL_SRGB)) :
- JS::NumberValue(uint32_t(LOCAL_GL_LINEAR));
+ const TexInternalFormat effectiveinternalformat =
+ fba.Texture()->ImageInfoBase().EffectiveInternalFormat();
+ TexInternalFormat unsizedinternalformat = LOCAL_GL_NONE;
+ TexType type = LOCAL_GL_NONE;
+ UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(
+ effectiveinternalformat, &unsizedinternalformat, &type);
+ MOZ_ASSERT(unsizedinternalformat != LOCAL_GL_NONE);
+ const bool srgb = unsizedinternalformat == LOCAL_GL_SRGB ||
+ unsizedinternalformat == LOCAL_GL_SRGB_ALPHA;
+ return srgb ? JS::NumberValue(uint32_t(LOCAL_GL_SRGB))
+ : JS::NumberValue(uint32_t(LOCAL_GL_LINEAR));
}
break;
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
return JS::NumberValue(uint32_t(LOCAL_GL_TEXTURE));
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
return WebGLObjectAsJSValue(cx, fba.Texture(), rv);
@@ -1219,28 +1212,29 @@ WebGLContext::GetFramebufferAttachmentPa
ErrorInvalidOperation("getFramebufferAttachmentParameter: cannot component"
" type of depth-stencil attachments.");
return JS::NullValue();
}
if (!fba.IsComplete())
return JS::NumberValue(uint32_t(LOCAL_GL_NONE));
- uint32_t ret = LOCAL_GL_NONE;
- TexType type = fba.Texture()->ImageInfoAt(fba.ImageTarget(),
- fba.MipLevel()).Type();
+ TexInternalFormat effectiveinternalformat =
+ fba.Texture()->ImageInfoAt(fba.ImageTarget(), fba.MipLevel()).EffectiveInternalFormat();
+ TexType type = TypeFromInternalFormat(effectiveinternalformat);
+ GLenum ret = LOCAL_GL_NONE;
switch (type.get()) {
case LOCAL_GL_UNSIGNED_BYTE:
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
ret = LOCAL_GL_UNSIGNED_NORMALIZED;
break;
case LOCAL_GL_FLOAT:
- case LOCAL_GL_HALF_FLOAT_OES:
+ case LOCAL_GL_HALF_FLOAT:
ret = LOCAL_GL_FLOAT;
break;
case LOCAL_GL_UNSIGNED_SHORT:
case LOCAL_GL_UNSIGNED_INT:
ret = LOCAL_GL_UNSIGNED_INT;
break;
default:
MOZ_ASSERT(false, "Unhandled RB component type.");
@@ -3348,17 +3342,17 @@ WebGLContext::CompressedTexImage2D(GLenu
return ErrorInvalidOperation(
"compressedTexImage2D: disallowed because the texture bound to "
"this target has already been made immutable by texStorage2D");
}
MakeContextCurrent();
gl->fCompressedTexImage2D(texImageTarget.get(), level, internalformat, width, height, border, byteLength, view.Data());
- tex->SetImageInfo(texImageTarget, level, width, height, internalformat, LOCAL_GL_UNSIGNED_BYTE,
+ tex->SetImageInfo(texImageTarget, level, width, height, internalformat,
WebGLImageDataStatus::InitializedImageData);
}
void
WebGLContext::CompressedTexSubImage2D(GLenum rawTexImgTarget, GLint level, GLint xoffset,
GLint yoffset, GLsizei width, GLsizei height,
GLenum internalformat,
const ArrayBufferView& view)
@@ -3382,17 +3376,17 @@ WebGLContext::CompressedTexSubImage2D(GL
}
const TexImageTarget texImageTarget(rawTexImgTarget);
WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
MOZ_ASSERT(tex);
WebGLTexture::ImageInfo& levelInfo = tex->ImageInfoAt(texImageTarget, level);
- if (internalformat != levelInfo.InternalFormat()) {
+ if (internalformat != levelInfo.EffectiveInternalFormat()) {
return ErrorInvalidOperation("compressedTexImage2D: internalformat does not match the existing image");
}
view.ComputeLengthAndData();
uint32_t byteLength = view.Length();
if (!ValidateCompTexImageDataSize(level, internalformat, width, height, byteLength, func))
return;
@@ -3594,41 +3588,47 @@ WebGLContext::GetShaderTranslatedSource(
if (!ValidateObject("getShaderTranslatedSource: shader", shader))
return;
retval.Assign(shader->TranslatedSource());
}
GLenum WebGLContext::CheckedTexImage2D(TexImageTarget texImageTarget,
GLint level,
- TexInternalFormat internalFormat,
+ TexInternalFormat internalformat,
GLsizei width,
GLsizei height,
GLint border,
TexFormat format,
TexType type,
const GLvoid *data)
{
WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
MOZ_ASSERT(tex != nullptr, "no texture bound");
+ TexInternalFormat effectiveInternalFormat =
+ EffectiveInternalFormatFromInternalFormatAndType(internalformat, type);
bool sizeMayChange = true;
if (tex->HasImageInfoAt(texImageTarget, level)) {
const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
sizeMayChange = width != imageInfo.Width() ||
height != imageInfo.Height() ||
- internalFormat != imageInfo.InternalFormat();
+ effectiveInternalFormat != imageInfo.EffectiveInternalFormat();
}
// Convert to format and type required by OpenGL 'driver'.
- GLenum driverType = DriverTypeFromType(gl, type);
+ GLenum driverType = LOCAL_GL_NONE;
GLenum driverInternalFormat = LOCAL_GL_NONE;
GLenum driverFormat = LOCAL_GL_NONE;
- DriverFormatsFromFormatAndType(gl, internalFormat, type, &driverInternalFormat, &driverFormat);
+ DriverFormatsFromEffectiveInternalFormat(gl,
+ effectiveInternalFormat,
+ &driverInternalFormat,
+ &driverFormat,
+ &driverType);
if (sizeMayChange) {
GetAndFlushUnderlyingGLErrors();
}
gl->fTexImage2D(texImageTarget.get(), level, driverInternalFormat, width, height, border, driverFormat, driverType, data);
GLenum error = LOCAL_GL_NO_ERROR;
@@ -3647,16 +3647,20 @@ WebGLContext::TexImage2D_base(TexImageTa
GLenum format,
GLenum type,
void* data, uint32_t byteLength,
int jsArrayType, // a TypedArray format enum, or -1 if not relevant
WebGLTexelFormat srcFormat, bool srcPremultiplied)
{
const WebGLTexImageFunc func = WebGLTexImageFunc::TexImage;
+ if (type == LOCAL_GL_HALF_FLOAT_OES) {
+ type = LOCAL_GL_HALF_FLOAT;
+ }
+
if (!ValidateTexImage(2, texImageTarget, level, internalformat,
0, 0, 0,
width, height, 0,
border, format, type, func))
{
return;
}
@@ -3669,17 +3673,24 @@ WebGLContext::TexImage2D_base(TexImageTa
"with format of DEPTH_COMPONENT or DEPTH_STENCIL, "
"data must be nullptr, "
"level must be zero");
}
if (!ValidateTexInputData(type, jsArrayType, func))
return;
- WebGLTexelFormat dstFormat = GetWebGLTexelFormat(internalformat, type);
+ TexInternalFormat effectiveinternalformat =
+ EffectiveInternalFormatFromInternalFormatAndType(internalformat, type);
+
+ if (effectiveinternalformat == LOCAL_GL_NONE) {
+ return ErrorInvalidOperation("texImage2D: bad combination of internalformat and type");
+ }
+
+ WebGLTexelFormat dstFormat = GetWebGLTexelFormat(effectiveinternalformat);
WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat;
uint32_t srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(actualSrcFormat);
CheckedUint32 checked_neededByteLength =
GetImageSize(height, width, srcTexelSize, mPixelStoreUnpackAlignment);
CheckedUint32 checked_plainRowSize = CheckedUint32(width) * srcTexelSize;
@@ -3707,18 +3718,20 @@ WebGLContext::TexImage2D_base(TexImageTa
}
MakeContextCurrent();
nsAutoArrayPtr<uint8_t> convertedData;
void* pixels = nullptr;
WebGLImageDataStatus imageInfoStatusIfSuccess = WebGLImageDataStatus::UninitializedImageData;
if (byteLength) {
+ size_t bitspertexel = GetBitsPerTexel(effectiveinternalformat);
+ MOZ_ASSERT((bitspertexel % 8) == 0); // should not have compressed formats here.
+ size_t dstTexelSize = bitspertexel / 8;
size_t srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
- uint32_t dstTexelSize = GetBitsPerTexel(internalformat, type) / 8;
size_t dstPlainRowSize = dstTexelSize * width;
size_t unpackAlignment = mPixelStoreUnpackAlignment;
size_t dstStride = ((dstPlainRowSize + unpackAlignment-1) / unpackAlignment) * unpackAlignment;
if (actualSrcFormat == dstFormat &&
srcPremultiplied == mPixelStorePremultiplyAlpha &&
srcStride == dstStride &&
!mPixelStoreFlipY)
@@ -3747,17 +3760,18 @@ WebGLContext::TexImage2D_base(TexImageTa
return;
}
// in all of the code paths above, we should have either initialized data,
// or allocated data and left it uninitialized, but in any case we shouldn't
// have NoImageData at this point.
MOZ_ASSERT(imageInfoStatusIfSuccess != WebGLImageDataStatus::NoImageData);
- tex->SetImageInfo(texImageTarget, level, width, height, internalformat, type, imageInfoStatusIfSuccess);
+ tex->SetImageInfo(texImageTarget, level, width, height,
+ effectiveinternalformat, imageInfoStatusIfSuccess);
}
void
WebGLContext::TexImage2D(GLenum rawTarget, GLint level,
GLenum internalformat, GLsizei width,
GLsizei height, GLint border, GLenum format,
GLenum type, const Nullable<ArrayBufferView> &pixels, ErrorResult& rv)
{
@@ -3825,39 +3839,53 @@ WebGLContext::TexSubImage2D_base(TexImag
GLsizei width, GLsizei height, GLsizei srcStrideOrZero,
GLenum format, GLenum type,
void* data, uint32_t byteLength,
int jsArrayType,
WebGLTexelFormat srcFormat, bool srcPremultiplied)
{
const WebGLTexImageFunc func = WebGLTexImageFunc::TexSubImage;
+ if (type == LOCAL_GL_HALF_FLOAT_OES) {
+ type = LOCAL_GL_HALF_FLOAT;
+ }
+
WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
if (!tex) {
return ErrorInvalidOperation("texSubImage2D: no texture bound on active texture unit");
}
+
+ if (!tex->HasImageInfoAt(texImageTarget, level)) {
+ return ErrorInvalidOperation("texSubImage2D: no previously defined texture image");
+ }
+
const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
- const TexInternalFormat internalformat = imageInfo.InternalFormat();
-
- if (!ValidateTexImage(2, texImageTarget, level, internalformat.get(),
+ const TexInternalFormat existingEffectiveInternalFormat = imageInfo.EffectiveInternalFormat();
+ TexInternalFormat existingUnsizedInternalFormat = LOCAL_GL_NONE;
+ TexType existingType = LOCAL_GL_NONE;
+ UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(existingEffectiveInternalFormat,
+ &existingUnsizedInternalFormat,
+ &existingType);
+
+ if (!ValidateTexImage(2, texImageTarget, level, existingUnsizedInternalFormat.get(),
xoffset, yoffset, 0,
width, height, 0,
0, format, type, func))
{
return;
}
if (!ValidateTexInputData(type, jsArrayType, func))
return;
- if (imageInfo.Type() != type) {
- return ErrorInvalidOperation("texSubImage2D: type parameter does not match the existing image");
+ if (type != existingType) {
+ return ErrorInvalidOperation("texSubImage2D: type differs from that of the existing image");
}
- WebGLTexelFormat dstFormat = GetWebGLTexelFormat(internalformat, type);
+ WebGLTexelFormat dstFormat = GetWebGLTexelFormat(existingEffectiveInternalFormat);
WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat;
uint32_t srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(actualSrcFormat);
if (width == 0 || height == 0)
return; // ES 2.0 says it has no effect, we better return right now
CheckedUint32 checked_neededByteLength =
@@ -3877,17 +3905,17 @@ WebGLContext::TexSubImage2D_base(TexImag
return ErrorInvalidOperation("texSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, byteLength);
if (imageInfo.HasUninitializedImageData())
tex->DoDeferredImageInitialization(texImageTarget, level);
MakeContextCurrent();
size_t srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
- uint32_t dstTexelSize = GetBitsPerTexel(internalformat, type) / 8;
+ uint32_t dstTexelSize = GetBitsPerTexel(existingEffectiveInternalFormat) / 8;
size_t dstPlainRowSize = dstTexelSize * width;
// There are checks above to ensure that this won't overflow.
size_t dstStride = RoundedToNextMultipleOf(dstPlainRowSize, mPixelStoreUnpackAlignment).value();
void* pixels = data;
nsAutoArrayPtr<uint8_t> convertedData;
// no conversion, no flipping, so we avoid copying anything and just pass the source pointer
@@ -3901,20 +3929,24 @@ WebGLContext::TexSubImage2D_base(TexImag
convertedData = new uint8_t[convertedDataSize];
ConvertImage(width, height, srcStride, dstStride,
static_cast<const uint8_t*>(data), convertedData,
actualSrcFormat, srcPremultiplied,
dstFormat, mPixelStorePremultiplyAlpha, dstTexelSize);
pixels = reinterpret_cast<void*>(convertedData.get());
}
- GLenum driverType = DriverTypeFromType(gl, type);
+ GLenum driverType = LOCAL_GL_NONE;
GLenum driverInternalFormat = LOCAL_GL_NONE;
GLenum driverFormat = LOCAL_GL_NONE;
- DriverFormatsFromFormatAndType(gl, internalformat, type, &driverInternalFormat, &driverFormat);
+ DriverFormatsFromEffectiveInternalFormat(gl,
+ existingEffectiveInternalFormat,
+ &driverInternalFormat,
+ &driverFormat,
+ &driverType);
gl->fTexSubImage2D(texImageTarget.get(), level, xoffset, yoffset, width, height, driverFormat, driverType, pixels);
}
void
WebGLContext::TexSubImage2D(GLenum rawTarget, GLint level,
GLint xoffset, GLint yoffset,
GLsizei width, GLsizei height,
@@ -4061,129 +4093,47 @@ BaseTypeAndSizeFromUniformType(GLenum uT
default:
return false;
}
return true;
}
-WebGLTexelFormat mozilla::GetWebGLTexelFormat(TexInternalFormat internalformat, TexType type)
+WebGLTexelFormat
+mozilla::GetWebGLTexelFormat(TexInternalFormat effectiveinternalformat)
{
- //
- // WEBGL_depth_texture
- if (internalformat == LOCAL_GL_DEPTH_COMPONENT) {
- switch (type.get()) {
- case LOCAL_GL_UNSIGNED_SHORT:
- return WebGLTexelFormat::D16;
- case LOCAL_GL_UNSIGNED_INT:
- return WebGLTexelFormat::D32;
- }
-
- MOZ_CRASH("Invalid WebGL texture format/type?");
- }
-
- if (internalformat == LOCAL_GL_DEPTH_STENCIL) {
- switch (type.get()) {
- case LOCAL_GL_UNSIGNED_INT_24_8_EXT:
- return WebGLTexelFormat::D24S8;
- }
-
- MOZ_CRASH("Invalid WebGL texture format/type?");
- }
-
- if (internalformat == LOCAL_GL_DEPTH_COMPONENT16) {
- return WebGLTexelFormat::D16;
- }
-
- if (internalformat == LOCAL_GL_DEPTH_COMPONENT32) {
- return WebGLTexelFormat::D32;
- }
-
- if (internalformat == LOCAL_GL_DEPTH24_STENCIL8) {
- return WebGLTexelFormat::D24S8;
- }
-
- if (type == LOCAL_GL_UNSIGNED_BYTE) {
- switch (internalformat.get()) {
- case LOCAL_GL_RGBA:
- case LOCAL_GL_SRGB_ALPHA_EXT:
- return WebGLTexelFormat::RGBA8;
- case LOCAL_GL_RGB:
- case LOCAL_GL_SRGB_EXT:
- return WebGLTexelFormat::RGB8;
- case LOCAL_GL_ALPHA:
- return WebGLTexelFormat::A8;
- case LOCAL_GL_LUMINANCE:
- return WebGLTexelFormat::R8;
- case LOCAL_GL_LUMINANCE_ALPHA:
- return WebGLTexelFormat::RA8;
- }
-
- MOZ_CRASH("Invalid WebGL texture format/type?");
- }
-
- if (type == LOCAL_GL_FLOAT) {
- // OES_texture_float
- switch (internalformat.get()) {
- case LOCAL_GL_RGBA:
- case LOCAL_GL_RGBA32F:
- return WebGLTexelFormat::RGBA32F;
- case LOCAL_GL_RGB:
- case LOCAL_GL_RGB32F:
- return WebGLTexelFormat::RGB32F;
- case LOCAL_GL_ALPHA:
- case LOCAL_GL_ALPHA32F_ARB:
- return WebGLTexelFormat::A32F;
- case LOCAL_GL_LUMINANCE:
- case LOCAL_GL_LUMINANCE32F_ARB:
- return WebGLTexelFormat::R32F;
- case LOCAL_GL_LUMINANCE_ALPHA:
- case LOCAL_GL_LUMINANCE_ALPHA32F_ARB:
- return WebGLTexelFormat::RA32F;
- }
-
- MOZ_CRASH("Invalid WebGL texture format/type?");
- } else if (type == LOCAL_GL_HALF_FLOAT_OES) {
- // OES_texture_half_float
- switch (internalformat.get()) {
- case LOCAL_GL_RGBA:
- case LOCAL_GL_RGBA16F:
- return WebGLTexelFormat::RGBA16F;
- case LOCAL_GL_RGB:
- case LOCAL_GL_RGB16F:
- return WebGLTexelFormat::RGB16F;
- case LOCAL_GL_ALPHA:
- case LOCAL_GL_ALPHA16F_ARB:
- return WebGLTexelFormat::A16F;
- case LOCAL_GL_LUMINANCE:
- case LOCAL_GL_LUMINANCE16F_ARB:
- return WebGLTexelFormat::R16F;
- case LOCAL_GL_LUMINANCE_ALPHA:
- case LOCAL_GL_LUMINANCE_ALPHA16F_ARB:
- return WebGLTexelFormat::RA16F;
- default:
- MOZ_ASSERT(false, "Coding mistake?! Should never reach this point.");
- return WebGLTexelFormat::BadFormat;
- }
- }
-
- switch (type.get()) {
- case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
- return WebGLTexelFormat::RGBA4444;
- case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
- return WebGLTexelFormat::RGBA5551;
- case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
- return WebGLTexelFormat::RGB565;
+ switch (effectiveinternalformat.get()) {
+ case LOCAL_GL_DEPTH_COMPONENT16: return WebGLTexelFormat::D16;
+ case LOCAL_GL_DEPTH_COMPONENT24: return WebGLTexelFormat::D32;
+ case LOCAL_GL_DEPTH24_STENCIL8: return WebGLTexelFormat::D24S8;
+ case LOCAL_GL_RGBA8: return WebGLTexelFormat::RGBA8;
+ case LOCAL_GL_SRGB8_ALPHA8: return WebGLTexelFormat::RGBA8;
+ case LOCAL_GL_RGB8: return WebGLTexelFormat::RGB8;
+ case LOCAL_GL_SRGB8: return WebGLTexelFormat::RGB8;
+ case LOCAL_GL_ALPHA8: return WebGLTexelFormat::A8;
+ case LOCAL_GL_LUMINANCE8: return WebGLTexelFormat::R8;
+ case LOCAL_GL_LUMINANCE8_ALPHA8: return WebGLTexelFormat::RA8;
+ case LOCAL_GL_RGBA32F: return WebGLTexelFormat::RGBA32F;
+ case LOCAL_GL_RGB32F: return WebGLTexelFormat::RGB32F;
+ case LOCAL_GL_ALPHA32F_EXT: return WebGLTexelFormat::A32F;
+ case LOCAL_GL_LUMINANCE32F_EXT: return WebGLTexelFormat::R32F;
+ case LOCAL_GL_LUMINANCE_ALPHA32F_EXT: return WebGLTexelFormat::RA32F;
+ case LOCAL_GL_RGBA16F: return WebGLTexelFormat::RGBA16F;
+ case LOCAL_GL_RGB16F: return WebGLTexelFormat::RGB16F;
+ case LOCAL_GL_ALPHA16F_EXT: return WebGLTexelFormat::A16F;
+ case LOCAL_GL_LUMINANCE16F_EXT: return WebGLTexelFormat::R16F;
+ case LOCAL_GL_LUMINANCE_ALPHA16F_EXT: return WebGLTexelFormat::RA16F;
+ case LOCAL_GL_RGBA4: return WebGLTexelFormat::RGBA4444;
+ case LOCAL_GL_RGB5_A1: return WebGLTexelFormat::RGBA5551;
+ case LOCAL_GL_RGB565: return WebGLTexelFormat::RGB565;
default:
- MOZ_ASSERT(false, "Coding mistake?! Should never reach this point.");
+ MOZ_CRASH("Unhandled format");
return WebGLTexelFormat::BadFormat;
}
-
- MOZ_CRASH("Invalid WebGL texture format/type?");
}
void
WebGLContext::BlendColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) {
if (IsContextLost())
return;
MakeContextCurrent();
gl->fBlendColor(r, g, b, a);
--- a/dom/canvas/WebGLContextUtils.cpp
+++ b/dom/canvas/WebGLContextUtils.cpp
@@ -26,39 +26,38 @@
#include "mozilla/dom/ScriptSettings.h"
namespace mozilla {
using namespace gl;
bool
-IsGLDepthFormat(TexInternalFormat webGLFormat)
+IsGLDepthFormat(TexInternalFormat internalformat)
{
- return (webGLFormat == LOCAL_GL_DEPTH_COMPONENT ||
- webGLFormat == LOCAL_GL_DEPTH_COMPONENT16 ||
- webGLFormat == LOCAL_GL_DEPTH_COMPONENT32);
+ TexInternalFormat unsizedformat = UnsizedInternalFormatFromInternalFormat(internalformat);
+ return unsizedformat == LOCAL_GL_DEPTH_COMPONENT;
}
bool
-IsGLDepthStencilFormat(TexInternalFormat webGLFormat)
+IsGLDepthStencilFormat(TexInternalFormat internalformat)
{
- return (webGLFormat == LOCAL_GL_DEPTH_STENCIL ||
- webGLFormat == LOCAL_GL_DEPTH24_STENCIL8);
+ TexInternalFormat unsizedformat = UnsizedInternalFormatFromInternalFormat(internalformat);
+ return unsizedformat == LOCAL_GL_DEPTH_STENCIL;
}
bool
-FormatHasAlpha(TexInternalFormat webGLFormat)
+FormatHasAlpha(TexInternalFormat internalformat)
{
- return webGLFormat == LOCAL_GL_RGBA ||
- webGLFormat == LOCAL_GL_LUMINANCE_ALPHA ||
- webGLFormat == LOCAL_GL_ALPHA ||
- webGLFormat == LOCAL_GL_RGBA4 ||
- webGLFormat == LOCAL_GL_RGB5_A1 ||
- webGLFormat == LOCAL_GL_SRGB_ALPHA;
+ TexInternalFormat unsizedformat = UnsizedInternalFormatFromInternalFormat(internalformat);
+ return unsizedformat == LOCAL_GL_RGBA ||
+ unsizedformat == LOCAL_GL_LUMINANCE_ALPHA ||
+ unsizedformat == LOCAL_GL_ALPHA ||
+ unsizedformat == LOCAL_GL_SRGB_ALPHA ||
+ unsizedformat == LOCAL_GL_RGBA_INTEGER;
}
TexTarget
TexImageTargetToTexTarget(TexImageTarget texImageTarget)
{
switch (texImageTarget.get()) {
case LOCAL_GL_TEXTURE_2D:
return LOCAL_GL_TEXTURE_2D;
@@ -71,21 +70,22 @@ TexImageTargetToTexTarget(TexImageTarget
return LOCAL_GL_TEXTURE_CUBE_MAP;
default:
MOZ_ASSERT(false, "Bad texture conversion");
// Should be caught by the constructor for TexTarget
return LOCAL_GL_NONE;
}
}
-GLComponents::GLComponents(TexInternalFormat format)
+GLComponents::GLComponents(TexInternalFormat internalformat)
{
+ TexInternalFormat unsizedformat = UnsizedInternalFormatFromInternalFormat(internalformat);
mComponents = 0;
- switch (format.get()) {
+ switch (unsizedformat.get()) {
case LOCAL_GL_RGBA:
case LOCAL_GL_RGBA4:
case LOCAL_GL_RGBA8:
case LOCAL_GL_RGB5_A1:
// Luminance + Alpha can be converted
// to and from RGBA
case LOCAL_GL_LUMINANCE_ALPHA:
mComponents |= Components::Alpha;
@@ -112,162 +112,287 @@ GLComponents::GLComponents(TexInternalFo
}
bool
GLComponents::IsSubsetOf(const GLComponents& other) const
{
return (mComponents | other.mComponents) == other.mComponents;
}
+TexType
+TypeFromInternalFormat(TexInternalFormat internalformat)
+{
+#define HANDLE_WEBGL_INTERNAL_FORMAT(table_effectiveinternalformat, table_internalformat, table_type) \
+ if (internalformat == table_effectiveinternalformat) { \
+ return table_type; \
+ }
+
+#include "WebGLInternalFormatsTable.h"
+
+ // if we're here, then internalformat is not an effective internalformat i.e. is an unsized internalformat.
+ return LOCAL_GL_NONE; // no size, no type
+}
+
+TexInternalFormat
+UnsizedInternalFormatFromInternalFormat(TexInternalFormat internalformat)
+{
+#define HANDLE_WEBGL_INTERNAL_FORMAT(table_effectiveinternalformat, table_internalformat, table_type) \
+ if (internalformat == table_effectiveinternalformat) { \
+ return table_internalformat; \
+ }
+
+#include "WebGLInternalFormatsTable.h"
+
+ // if we're here, then internalformat is not an effective internalformat i.e. is an unsized internalformat.
+ // so we can just return it.
+ return internalformat;
+}
+
+/*
+ * Note that the following two functions are inverse of each other:
+ * EffectiveInternalFormatFromInternalFormatAndType and
+ * InternalFormatAndTypeFromEffectiveInternalFormat both implement OpenGL ES 3.0.3 Table 3.2
+ * but in opposite directions.
+ */
+TexInternalFormat
+EffectiveInternalFormatFromUnsizedInternalFormatAndType(TexInternalFormat internalformat,
+ TexType type)
+{
+ MOZ_ASSERT(TypeFromInternalFormat(internalformat) == LOCAL_GL_NONE);
+
+#define HANDLE_WEBGL_INTERNAL_FORMAT(table_effectiveinternalformat, table_internalformat, table_type) \
+ if (internalformat == table_internalformat && type == table_type) { \
+ return table_effectiveinternalformat; \
+ }
+
+#include "WebGLInternalFormatsTable.h"
+
+ // If we're here, that means that type was incompatible with the given internalformat.
+ return LOCAL_GL_NONE;
+}
+
+void
+UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(TexInternalFormat effectiveinternalformat,
+ TexInternalFormat* out_internalformat,
+ TexType* out_type)
+{
+ MOZ_ASSERT(TypeFromInternalFormat(effectiveinternalformat) != LOCAL_GL_NONE);
+
+ MOZ_ASSERT(out_internalformat);
+ MOZ_ASSERT(out_type);
+
+ GLenum internalformat = LOCAL_GL_NONE;
+ GLenum type = LOCAL_GL_NONE;
+
+ switch (effectiveinternalformat.get()) {
+
+#define HANDLE_WEBGL_INTERNAL_FORMAT(table_effectiveinternalformat, table_internalformat, table_type) \
+ case table_effectiveinternalformat: \
+ internalformat = table_internalformat; \
+ type = table_type; \
+ break;
+
+#include "WebGLInternalFormatsTable.h"
+
+ default:
+ MOZ_CRASH(); // impossible to get here
+ }
+
+ *out_internalformat = internalformat;
+ *out_type = type;
+}
+
+TexInternalFormat
+EffectiveInternalFormatFromInternalFormatAndType(TexInternalFormat internalformat,
+ TexType type)
+{
+ TexType typeOfInternalFormat = TypeFromInternalFormat(internalformat);
+ if (typeOfInternalFormat == LOCAL_GL_NONE) {
+ return EffectiveInternalFormatFromUnsizedInternalFormatAndType(internalformat, type);
+ } else if (typeOfInternalFormat == type) {
+ return internalformat;
+ } else {
+ return LOCAL_GL_NONE;
+ }
+}
+
/**
- * Convert WebGL/ES format and type into GL internal
- * format valid for underlying driver.
+ * Convert effective internalformat into GL function parameters
+ * valid for underlying driver.
*/
void
-DriverFormatsFromFormatAndType(GLContext* gl, TexInternalFormat webGLInternalFormat, TexType webGLType,
- GLenum* out_driverInternalFormat, GLenum* out_driverFormat)
+DriverFormatsFromEffectiveInternalFormat(gl::GLContext* gl,
+ TexInternalFormat effectiveinternalformat,
+ GLenum* out_driverInternalFormat,
+ GLenum* out_driverFormat,
+ GLenum* out_driverType)
{
MOZ_ASSERT(out_driverInternalFormat);
MOZ_ASSERT(out_driverFormat);
+ MOZ_ASSERT(out_driverType);
- // ES2 requires that format == internalformat; floating-point is
- // indicated purely by the type that's loaded. For desktop GL, we
- // have to specify a floating point internal format.
- if (gl->IsGLES()) {
- *out_driverFormat = *out_driverInternalFormat = webGLInternalFormat.get();
- return;
+ TexInternalFormat unsizedinternalformat = LOCAL_GL_NONE;
+ TexType type = LOCAL_GL_NONE;
+
+ UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(effectiveinternalformat,
+ &unsizedinternalformat, &type);
+
+ // driverType: almost always the generic type that we just got, except on ES
+ // we must replace HALF_FLOAT by HALF_FLOAT_OES
+ GLenum driverType = type.get();
+ if (gl->IsGLES() && type == LOCAL_GL_HALF_FLOAT) {
+ driverType = LOCAL_GL_HALF_FLOAT_OES;
}
- GLenum internalFormat = LOCAL_GL_NONE;
- GLenum format = LOCAL_GL_NONE;
-
- if (webGLInternalFormat == LOCAL_GL_DEPTH_COMPONENT) {
- format = LOCAL_GL_DEPTH_COMPONENT;
- if (webGLType == LOCAL_GL_UNSIGNED_SHORT)
- internalFormat = LOCAL_GL_DEPTH_COMPONENT16;
- else if (webGLType == LOCAL_GL_UNSIGNED_INT)
- internalFormat = LOCAL_GL_DEPTH_COMPONENT32;
- } else if (webGLInternalFormat == LOCAL_GL_DEPTH_STENCIL) {
- format = LOCAL_GL_DEPTH_STENCIL;
- if (webGLType == LOCAL_GL_UNSIGNED_INT_24_8_EXT)
- internalFormat = LOCAL_GL_DEPTH24_STENCIL8;
- } else {
- switch (webGLType.get()) {
- case LOCAL_GL_UNSIGNED_BYTE:
- case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
- case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
- case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
- format = internalFormat = webGLInternalFormat.get();
- break;
-
- case LOCAL_GL_FLOAT:
- switch (webGLInternalFormat.get()) {
- case LOCAL_GL_RGBA:
- format = LOCAL_GL_RGBA;
- internalFormat = LOCAL_GL_RGBA32F;
- break;
-
- case LOCAL_GL_RGB:
- format = LOCAL_GL_RGB;
- internalFormat = LOCAL_GL_RGB32F;
- break;
-
- case LOCAL_GL_ALPHA:
- format = LOCAL_GL_ALPHA;
- internalFormat = LOCAL_GL_ALPHA32F_ARB;
- break;
+ // driverFormat: always just the unsized internalformat that we just got
+ GLenum driverFormat = unsizedinternalformat.get();
- case LOCAL_GL_LUMINANCE:
- format = LOCAL_GL_LUMINANCE;
- internalFormat = LOCAL_GL_LUMINANCE32F_ARB;
- break;
-
- case LOCAL_GL_LUMINANCE_ALPHA:
- format = LOCAL_GL_LUMINANCE_ALPHA;
- internalFormat = LOCAL_GL_LUMINANCE_ALPHA32F_ARB;
- break;
- }
- break;
-
- case LOCAL_GL_HALF_FLOAT_OES:
- switch (webGLInternalFormat.get()) {
- case LOCAL_GL_RGBA:
- format = LOCAL_GL_RGBA;
- internalFormat = LOCAL_GL_RGBA16F;
- break;
-
- case LOCAL_GL_RGB:
- format = LOCAL_GL_RGB;
- internalFormat = LOCAL_GL_RGB16F;
- break;
-
- case LOCAL_GL_ALPHA:
- format = LOCAL_GL_ALPHA;
- internalFormat = LOCAL_GL_ALPHA16F_ARB;
- break;
-
- case LOCAL_GL_LUMINANCE:
- format = LOCAL_GL_LUMINANCE;
- internalFormat = LOCAL_GL_LUMINANCE16F_ARB;
- break;
-
- case LOCAL_GL_LUMINANCE_ALPHA:
- format = LOCAL_GL_LUMINANCE_ALPHA;
- internalFormat = LOCAL_GL_LUMINANCE_ALPHA16F_ARB;
- break;
- }
- break;
-
- default:
- break;
+ // driverInternalFormat: almost always the same as driverFormat, but on desktop GL,
+ // in some cases we must pass a different value. On ES, they are equal by definition
+ // as it is an error to pass internalformat!=format.
+ GLenum driverInternalFormat = driverFormat;
+ if (!gl->IsGLES()) {
+ // Cases where desktop OpenGL requires a tweak to 'format'
+ if (driverFormat == LOCAL_GL_SRGB) {
+ driverFormat = LOCAL_GL_RGB;
+ } else if (driverFormat == LOCAL_GL_SRGB_ALPHA) {
+ driverFormat = LOCAL_GL_RGBA;
}
- // Handle ES2 and GL differences when supporting sRGB internal formats. GL ES
- // requires that format == internalformat, but GL will fail in this case.
- // GL requires:
- // format -> internalformat
- // GL_RGB GL_SRGB_EXT
- // GL_RGBA GL_SRGB_ALPHA_EXT
- switch (webGLInternalFormat.get()) {
- case LOCAL_GL_SRGB:
- format = LOCAL_GL_RGB;
- internalFormat = LOCAL_GL_SRGB;
- break;
- case LOCAL_GL_SRGB_ALPHA:
- format = LOCAL_GL_RGBA;
- internalFormat = LOCAL_GL_SRGB_ALPHA;
- break;
+ // Cases where desktop OpenGL requires a sized internalformat,
+ // as opposed to the unsized internalformat that had the same
+ // GLenum value as 'format', in order to get the precise
+ // semantics that we want. For example, for floating-point formats,
+ // we seem to need a sized internalformat to get non-clamped floating
+ // point texture sampling. Can't find the spec reference for that,
+ // but that's at least the case on my NVIDIA driver version 331.
+ if (unsizedinternalformat == LOCAL_GL_DEPTH_COMPONENT ||
+ unsizedinternalformat == LOCAL_GL_DEPTH_STENCIL ||
+ type == LOCAL_GL_FLOAT ||
+ type == LOCAL_GL_HALF_FLOAT)
+ {
+ driverInternalFormat = effectiveinternalformat.get();
}
}
- MOZ_ASSERT(webGLInternalFormat != LOCAL_GL_NONE && internalFormat != LOCAL_GL_NONE,
- "Coding mistake -- bad format/type passed?");
-
- *out_driverInternalFormat = internalFormat;
- *out_driverFormat = format;
+ *out_driverInternalFormat = driverInternalFormat;
+ *out_driverFormat = driverFormat;
+ *out_driverType = driverType;
}
-GLenum
-DriverTypeFromType(GLContext* gl, TexType webGLType)
+/**
+ * Return the bits per texel for format & type combination.
+ * Assumes that format & type are a valid combination as checked with
+ * ValidateTexImageFormatAndType().
+ */
+size_t
+GetBitsPerTexel(TexInternalFormat effectiveinternalformat)
{
- GLenum type = webGLType.get();
+ switch (effectiveinternalformat.get()) {
+ case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
+ case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
+ return 2;
+
+ case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ case LOCAL_GL_ATC_RGB:
+ case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
+ case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
+ case LOCAL_GL_ETC1_RGB8_OES:
+ return 4;
- if (gl->IsGLES())
- return type;
+ case LOCAL_GL_ALPHA8:
+ case LOCAL_GL_LUMINANCE8:
+ case LOCAL_GL_R8:
+ case LOCAL_GL_R8I:
+ case LOCAL_GL_R8UI:
+ case LOCAL_GL_R8_SNORM:
+ case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+ case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+ case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
+ case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
+ return 8;
+
+ case LOCAL_GL_LUMINANCE8_ALPHA8:
+ case LOCAL_GL_RGBA4:
+ case LOCAL_GL_RGB5_A1:
+ case LOCAL_GL_DEPTH_COMPONENT16:
+ case LOCAL_GL_RG8:
+ case LOCAL_GL_R16I:
+ case LOCAL_GL_R16UI:
+ case LOCAL_GL_RGB565:
+ case LOCAL_GL_R16F:
+ case LOCAL_GL_RG8I:
+ case LOCAL_GL_RG8UI:
+ case LOCAL_GL_RG8_SNORM:
+ case LOCAL_GL_ALPHA16F_EXT:
+ case LOCAL_GL_LUMINANCE16F_EXT:
+ return 16;
- // convert type for half float if not on GLES2
- if (type == LOCAL_GL_HALF_FLOAT_OES) {
- if (gl->IsSupported(gl::GLFeature::texture_half_float)) {
- return LOCAL_GL_HALF_FLOAT;
- } else {
- MOZ_ASSERT(gl->IsExtensionSupported(gl::GLContext::OES_texture_half_float));
- }
+ case LOCAL_GL_RGB8:
+ case LOCAL_GL_DEPTH_COMPONENT24:
+ case LOCAL_GL_SRGB8:
+ case LOCAL_GL_RGB8UI:
+ case LOCAL_GL_RGB8I:
+ case LOCAL_GL_RGB8_SNORM:
+ return 24;
+
+ case LOCAL_GL_RGBA8:
+ case LOCAL_GL_RGB10_A2:
+ case LOCAL_GL_R32F:
+ case LOCAL_GL_RG16F:
+ case LOCAL_GL_R32I:
+ case LOCAL_GL_R32UI:
+ case LOCAL_GL_RG16I:
+ case LOCAL_GL_RG16UI:
+ case LOCAL_GL_DEPTH24_STENCIL8:
+ case LOCAL_GL_R11F_G11F_B10F:
+ case LOCAL_GL_RGB9_E5:
+ case LOCAL_GL_SRGB8_ALPHA8:
+ case LOCAL_GL_DEPTH_COMPONENT32F:
+ case LOCAL_GL_RGBA8UI:
+ case LOCAL_GL_RGBA8I:
+ case LOCAL_GL_RGBA8_SNORM:
+ case LOCAL_GL_RGB10_A2UI:
+ case LOCAL_GL_LUMINANCE_ALPHA16F_EXT:
+ case LOCAL_GL_ALPHA32F_EXT:
+ case LOCAL_GL_LUMINANCE32F_EXT:
+ return 32;
+
+ case LOCAL_GL_DEPTH32F_STENCIL8:
+ return 40;
+
+ case LOCAL_GL_RGB16F:
+ case LOCAL_GL_RGB16UI:
+ case LOCAL_GL_RGB16I:
+ return 48;
+
+ case LOCAL_GL_RG32F:
+ case LOCAL_GL_RG32I:
+ case LOCAL_GL_RG32UI:
+ case LOCAL_GL_RGBA16F:
+ case LOCAL_GL_RGBA16UI:
+ case LOCAL_GL_RGBA16I:
+ case LOCAL_GL_LUMINANCE_ALPHA32F_EXT:
+ return 64;
+
+ case LOCAL_GL_RGB32F:
+ case LOCAL_GL_RGB32UI:
+ case LOCAL_GL_RGB32I:
+ return 96;
+
+ case LOCAL_GL_RGBA32F:
+ case LOCAL_GL_RGBA32UI:
+ case LOCAL_GL_RGBA32I:
+ return 128;
+
+ default:
+ MOZ_ASSERT(false, "Unhandled format");
+ return 0;
}
-
- return type;
}
void
WebGLContext::GenerateWarning(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
--- a/dom/canvas/WebGLContextUtils.h
+++ b/dom/canvas/WebGLContextUtils.h
@@ -11,19 +11,38 @@
#include "mozilla/Assertions.h"
#include "mozilla/dom/BindingUtils.h"
namespace mozilla {
bool IsGLDepthFormat(TexInternalFormat webGLFormat);
bool IsGLDepthStencilFormat(TexInternalFormat webGLFormat);
bool FormatHasAlpha(TexInternalFormat webGLFormat);
-void DriverFormatsFromFormatAndType(gl::GLContext* gl, TexInternalFormat webGLFormat, TexType webGLType,
- GLenum* out_driverInternalFormat, GLenum* out_driverFormat);
-GLenum DriverTypeFromType(gl::GLContext* gl, TexType webGLType);
+void
+DriverFormatsFromEffectiveInternalFormat(gl::GLContext* gl,
+ TexInternalFormat internalformat,
+ GLenum* out_driverInternalFormat,
+ GLenum* out_driverFormat,
+ GLenum* out_driverType);
+TexInternalFormat
+EffectiveInternalFormatFromInternalFormatAndType(TexInternalFormat internalformat,
+ TexType type);
+TexInternalFormat
+EffectiveInternalFormatFromUnsizedInternalFormatAndType(TexInternalFormat internalformat,
+ TexType type);
+void
+UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(TexInternalFormat effectiveinternalformat,
+ TexInternalFormat* out_internalformat,
+ TexType* out_type);
+TexType
+TypeFromInternalFormat(TexInternalFormat internalformat);
+TexInternalFormat
+UnsizedInternalFormatFromInternalFormat(TexInternalFormat internalformat);
+size_t
+GetBitsPerTexel(TexInternalFormat effectiveinternalformat);
// For use with the different texture calls, i.e.
// TexImage2D, CopyTex[Sub]Image2D, ...
// that take a "target" parameter. This parameter is not always the same as
// the texture binding location, like GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP.
// For example, cube maps would pass GL_TEXTURE_CUBE_MAP_[POS|NEG]_[X|Y|Z]
// instead of just GL_TEXTURE_CUBE_MAP.
//
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -668,17 +668,17 @@ WebGLContext::ValidateTexImageType(GLenu
bool validType = IsExtensionEnabled(WebGLExtensionID::OES_texture_float);
if (!validType)
ErrorInvalidEnum("%s: invalid type %s: need OES_texture_float enabled",
InfoFrom(func), WebGLContext::EnumName(type));
return validType;
}
/* OES_texture_half_float add types */
- if (type == LOCAL_GL_HALF_FLOAT_OES) {
+ if (type == LOCAL_GL_HALF_FLOAT) {
bool validType = IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float);
if (!validType)
ErrorInvalidEnum("%s: invalid type %s: need OES_texture_half_float enabled",
InfoFrom(func), WebGLContext::EnumName(type));
return validType;
}
/* WEBGL_depth_texture added types */
@@ -1021,105 +1021,16 @@ WebGLContext::ValidateTexSubImageSize(GL
ErrorInvalidValue("%s: subtexture rectangle out-of-bounds", InfoFrom(func));
return false;
}
return true;
}
/**
- * Return the bits per texel for format & type combination.
- * Assumes that format & type are a valid combination as checked with
- * ValidateTexImageFormatAndType().
- */
-uint32_t
-WebGLContext::GetBitsPerTexel(TexInternalFormat format, TexType type)
-{
- /* Known fixed-sized types */
- if (type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
- type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 ||
- type == LOCAL_GL_UNSIGNED_SHORT_5_6_5)
- {
- return 16;
- }
-
- if (type == LOCAL_GL_UNSIGNED_INT_24_8)
- return 32;
-
- int bitsPerComponent = 0;
- switch (type.get()) {
- case LOCAL_GL_UNSIGNED_BYTE:
- bitsPerComponent = 8;
- break;
-
- case LOCAL_GL_HALF_FLOAT:
- case LOCAL_GL_HALF_FLOAT_OES:
- case LOCAL_GL_UNSIGNED_SHORT:
- bitsPerComponent = 16;
- break;
-
- case LOCAL_GL_FLOAT:
- case LOCAL_GL_UNSIGNED_INT:
- bitsPerComponent = 32;
- break;
-
- default:
- MOZ_ASSERT(false, "Unhandled type.");
- break;
- }
-
- switch (format.get()) {
- // Uncompressed formats
- case LOCAL_GL_ALPHA:
- case LOCAL_GL_LUMINANCE:
- case LOCAL_GL_DEPTH_COMPONENT:
- case LOCAL_GL_DEPTH_STENCIL:
- return 1 * bitsPerComponent;
-
- case LOCAL_GL_LUMINANCE_ALPHA:
- return 2 * bitsPerComponent;
-
- case LOCAL_GL_RGB:
- case LOCAL_GL_RGB32F:
- case LOCAL_GL_SRGB_EXT:
- return 3 * bitsPerComponent;
-
- case LOCAL_GL_RGBA:
- case LOCAL_GL_RGBA32F:
- case LOCAL_GL_SRGB_ALPHA_EXT:
- return 4 * bitsPerComponent;
-
- // Compressed formats
- case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
- case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
- return 2;
-
- case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
- case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
- case LOCAL_GL_ATC_RGB:
- case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
- case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
- case LOCAL_GL_ETC1_RGB8_OES:
- return 4;
-
- case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
- case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
- case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
- case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
- return 8;
-
- default:
- break;
- }
-
- MOZ_ASSERT(false, "Unhandled format+type combo.");
- return 0;
-}
-
-/**
* Perform validation of format/type combinations for TexImage variants.
* Returns true if the format/type is a valid combination, false otherwise.
*/
bool
WebGLContext::ValidateTexImageFormatAndType(GLenum format,
GLenum type, WebGLTexImageFunc func)
{
if (IsCompressedFunc(func) || IsCopyFunc(func))
@@ -1136,36 +1047,33 @@ WebGLContext::ValidateTexImageFormatAndT
bool validCombo = false;
switch (format) {
case LOCAL_GL_ALPHA:
case LOCAL_GL_LUMINANCE:
case LOCAL_GL_LUMINANCE_ALPHA:
validCombo = (type == LOCAL_GL_UNSIGNED_BYTE ||
type == LOCAL_GL_HALF_FLOAT ||
- type == LOCAL_GL_HALF_FLOAT_OES ||
type == LOCAL_GL_FLOAT);
break;
case LOCAL_GL_RGB:
case LOCAL_GL_SRGB:
validCombo = (type == LOCAL_GL_UNSIGNED_BYTE ||
type == LOCAL_GL_UNSIGNED_SHORT_5_6_5 ||
type == LOCAL_GL_HALF_FLOAT ||
- type == LOCAL_GL_HALF_FLOAT_OES ||
type == LOCAL_GL_FLOAT);
break;
case LOCAL_GL_RGBA:
case LOCAL_GL_SRGB_ALPHA:
validCombo = (type == LOCAL_GL_UNSIGNED_BYTE ||
type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 ||
type == LOCAL_GL_HALF_FLOAT ||
- type == LOCAL_GL_HALF_FLOAT_OES ||
type == LOCAL_GL_FLOAT);
break;
case LOCAL_GL_DEPTH_COMPONENT:
validCombo = (type == LOCAL_GL_UNSIGNED_SHORT ||
type == LOCAL_GL_UNSIGNED_INT);
break;
@@ -1286,17 +1194,16 @@ WebGLContext::ValidateTexInputData(GLenu
// First, we check for packed types
switch (type) {
case LOCAL_GL_UNSIGNED_BYTE:
validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Uint8);
break;
case LOCAL_GL_HALF_FLOAT:
- case LOCAL_GL_HALF_FLOAT_OES:
case LOCAL_GL_UNSIGNED_SHORT:
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Uint16);
break;
case LOCAL_GL_UNSIGNED_INT:
@@ -1444,16 +1351,17 @@ WebGLContext::ValidateTexImage(GLuint di
if (IsSubFunc(func)) {
if (!tex->HasImageInfoAt(texImageTarget, level)) {
ErrorInvalidOperation("%s: no texture image previously defined for target %s at level %d",
info, WebGLContext::EnumName(texImageTarget.get()), level);
return false;
}
const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
+
if (!ValidateTexSubImageSize(xoffset, yoffset, zoffset,
width, height, depth,
imageInfo.Width(), imageInfo.Height(), 0,
func))
{
return false;
}
}
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -74,73 +74,66 @@ WebGLFramebuffer::Attachment::IsDefined(
}
bool
WebGLFramebuffer::Attachment::HasAlpha() const
{
MOZ_ASSERT(HasImage());
if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel))
- return FormatHasAlpha(Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).InternalFormat());
+ return FormatHasAlpha(Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).EffectiveInternalFormat());
else if (Renderbuffer())
return FormatHasAlpha(Renderbuffer()->InternalFormat());
else return false;
}
GLenum
WebGLFramebuffer::GetFormatForAttachment(const WebGLFramebuffer::Attachment& attachment) const
{
MOZ_ASSERT(attachment.IsDefined());
MOZ_ASSERT(attachment.Texture() || attachment.Renderbuffer());
if (attachment.Texture()) {
const WebGLTexture& tex = *attachment.Texture();
MOZ_ASSERT(tex.HasImageInfoAt(attachment.ImageTarget(), 0));
const WebGLTexture::ImageInfo& imgInfo = tex.ImageInfoAt(attachment.ImageTarget(), 0);
- return imgInfo.InternalFormat().get();
+ return imgInfo.EffectiveInternalFormat().get();
}
if (attachment.Renderbuffer())
return attachment.Renderbuffer()->InternalFormat();
return LOCAL_GL_NONE;
}
-bool
-WebGLFramebuffer::Attachment::IsReadableFloat() const
+TexInternalFormat
+WebGLFramebuffer::Attachment::EffectiveInternalFormat() const
{
const WebGLTexture* tex = Texture();
if (tex && tex->HasImageInfoAt(mTexImageTarget, mTexImageLevel)) {
- GLenum type = tex->ImageInfoAt(mTexImageTarget, mTexImageLevel).Type().get();
- switch (type) {
- case LOCAL_GL_FLOAT:
- case LOCAL_GL_HALF_FLOAT_OES:
- return true;
- }
- return false;
+ return tex->ImageInfoAt(mTexImageTarget, mTexImageLevel).EffectiveInternalFormat();
}
const WebGLRenderbuffer* rb = Renderbuffer();
if (rb) {
- GLenum format = rb->InternalFormat();
- switch (format) {
- case LOCAL_GL_RGB16F:
- case LOCAL_GL_RGBA16F:
- case LOCAL_GL_RGB32F:
- case LOCAL_GL_RGBA32F:
- return true;
- }
- return false;
+ return rb->InternalFormat();
}
- // If we arrive here Attachment isn't correct setup because it has
- // no texture nor render buffer pointer.
- MOZ_ASSERT(false, "Should not get here.");
- return false;
+ return LOCAL_GL_NONE;
+}
+
+bool
+WebGLFramebuffer::Attachment::IsReadableFloat() const
+{
+ TexInternalFormat internalformat = EffectiveInternalFormat();
+ MOZ_ASSERT(internalformat != LOCAL_GL_NONE);
+ TexType type = TypeFromInternalFormat(internalformat);
+ return type == LOCAL_GL_FLOAT ||
+ type == LOCAL_GL_HALF_FLOAT;
}
void
WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level)
{
mTexturePtr = tex;
mRenderbufferPtr = nullptr;
mTexImageTarget = target;
@@ -225,65 +218,45 @@ WebGLFramebuffer::Attachment::RectangleO
MOZ_CRASH("Should not get here.");
}
/* The following IsValidFBOTextureXXX functions check the internal
format that is used by GL or GL ES texture formats. This
corresponds to the state that is stored in
WebGLTexture::ImageInfo::InternalFormat()*/
static inline bool
-IsValidFBOTextureColorFormat(GLenum internalFormat)
+IsValidFBOTextureColorFormat(TexInternalFormat internalformat)
{
/* These formats are internal formats for each texture -- the actual
* low level format, which we might have to do conversions for when
* running against desktop GL (e.g. GL_RGBA + GL_FLOAT -> GL_RGBA32F).
*
* This function just handles all of them whether desktop GL or ES.
*/
- return (
- /* linear 8-bit formats */
- internalFormat == LOCAL_GL_ALPHA ||
- internalFormat == LOCAL_GL_LUMINANCE ||
- internalFormat == LOCAL_GL_LUMINANCE_ALPHA ||
- internalFormat == LOCAL_GL_RGB ||
- internalFormat == LOCAL_GL_RGBA ||
- /* sRGB 8-bit formats */
- internalFormat == LOCAL_GL_SRGB_EXT ||
- internalFormat == LOCAL_GL_SRGB_ALPHA_EXT ||
- /* linear float32 formats */
- internalFormat == LOCAL_GL_ALPHA32F_ARB ||
- internalFormat == LOCAL_GL_LUMINANCE32F_ARB ||
- internalFormat == LOCAL_GL_LUMINANCE_ALPHA32F_ARB ||
- internalFormat == LOCAL_GL_RGB32F_ARB ||
- internalFormat == LOCAL_GL_RGBA32F_ARB ||
- /* texture_half_float formats */
- internalFormat == LOCAL_GL_ALPHA16F_ARB ||
- internalFormat == LOCAL_GL_LUMINANCE16F_ARB ||
- internalFormat == LOCAL_GL_LUMINANCE_ALPHA16F_ARB ||
- internalFormat == LOCAL_GL_RGB16F_ARB ||
- internalFormat == LOCAL_GL_RGBA16F_ARB
- );
+ TexInternalFormat unsizedformat = UnsizedInternalFormatFromInternalFormat(internalformat);
+ return unsizedformat == LOCAL_GL_ALPHA ||
+ unsizedformat == LOCAL_GL_LUMINANCE ||
+ unsizedformat == LOCAL_GL_LUMINANCE_ALPHA ||
+ unsizedformat == LOCAL_GL_RGB ||
+ unsizedformat == LOCAL_GL_RGBA ||
+ unsizedformat == LOCAL_GL_SRGB ||
+ unsizedformat == LOCAL_GL_SRGB_ALPHA;
}
static inline bool
-IsValidFBOTextureDepthFormat(GLenum internalFormat)
+IsValidFBOTextureDepthFormat(GLenum internalformat)
{
- return (
- internalFormat == LOCAL_GL_DEPTH_COMPONENT ||
- internalFormat == LOCAL_GL_DEPTH_COMPONENT16 ||
- internalFormat == LOCAL_GL_DEPTH_COMPONENT32);
+ return IsGLDepthFormat(internalformat);
}
static inline bool
-IsValidFBOTextureDepthStencilFormat(GLenum internalFormat)
+IsValidFBOTextureDepthStencilFormat(GLenum internalformat)
{
- return (
- internalFormat == LOCAL_GL_DEPTH_STENCIL ||
- internalFormat == LOCAL_GL_DEPTH24_STENCIL8);
+ return IsGLDepthStencilFormat(internalformat);
}
/* The following IsValidFBORenderbufferXXX functions check the internal
format that is stored by WebGLRenderbuffer::InternalFormat(). Valid
values can be found in WebGLContext::RenderbufferStorage. */
static inline bool
IsValidFBORenderbufferColorFormat(GLenum internalFormat)
{
@@ -325,17 +298,17 @@ WebGLFramebuffer::Attachment::IsComplete
{
return false;
}
if (Texture()) {
MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel));
const WebGLTexture::ImageInfo& imageInfo =
Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel);
- GLenum internalformat = imageInfo.InternalFormat().get();
+ GLenum internalformat = imageInfo.EffectiveInternalFormat().get();
if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT)
return IsValidFBOTextureDepthFormat(internalformat);
if (mAttachmentPoint == LOCAL_GL_STENCIL_ATTACHMENT)
return false; // Textures can't have the correct format for stencil buffers
if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
--- a/dom/canvas/WebGLFramebuffer.h
+++ b/dom/canvas/WebGLFramebuffer.h
@@ -48,16 +48,18 @@ public:
explicit Attachment(FBAttachment aAttachmentPoint = LOCAL_GL_COLOR_ATTACHMENT0);
~Attachment();
bool IsDefined() const;
bool IsDeleteRequested() const;
+ TexInternalFormat EffectiveInternalFormat() const;
+
bool HasAlpha() const;
bool IsReadableFloat() const;
void SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level);
void SetRenderbuffer(WebGLRenderbuffer* rb);
const WebGLTexture* Texture() const {
return mTexturePtr;
new file mode 100644
--- /dev/null
+++ b/dom/canvas/WebGLInternalFormatsTable.h
@@ -0,0 +1,82 @@
+// intentionally no include guard here.
+
+#ifndef HANDLE_WEBGL_INTERNAL_FORMAT
+#error This header is meant to be included by other files defining HANDLE_WEBGL_INTERNAL_FORMAT.
+#endif
+
+#define WEBGL_INTERNAL_FORMAT(effectiveinternalformat, unsizedinternalformat, type) \
+ HANDLE_WEBGL_INTERNAL_FORMAT(LOCAL_GL_##effectiveinternalformat, \
+ LOCAL_GL_##unsizedinternalformat, \
+ LOCAL_GL_##type)
+
+// OpenGL ES 3.0.3, Table 3.2
+//
+// Maps effective internal formats to (unsized internal format, type) pairs.
+//
+// Effective int. fmt. Unsized int. fmt. Type
+WEBGL_INTERNAL_FORMAT(ALPHA8, ALPHA, UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(LUMINANCE8, LUMINANCE, UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(LUMINANCE8_ALPHA8, LUMINANCE_ALPHA, UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(RGB8, RGB, UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(RGBA4, RGBA, UNSIGNED_SHORT_4_4_4_4)
+WEBGL_INTERNAL_FORMAT(RGB5_A1, RGBA, UNSIGNED_SHORT_5_5_5_1)
+WEBGL_INTERNAL_FORMAT(RGBA8, RGBA, UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(RGB10_A2, RGB, UNSIGNED_INT_2_10_10_10_REV)
+WEBGL_INTERNAL_FORMAT(DEPTH_COMPONENT16, DEPTH_COMPONENT, UNSIGNED_SHORT)
+WEBGL_INTERNAL_FORMAT(DEPTH_COMPONENT24, DEPTH_COMPONENT, UNSIGNED_INT)
+WEBGL_INTERNAL_FORMAT(R8, RED, UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(RG8, RG, UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(R16F, RED, HALF_FLOAT)
+WEBGL_INTERNAL_FORMAT(R32F, RED, FLOAT)
+WEBGL_INTERNAL_FORMAT(RG16F, RG, HALF_FLOAT)
+WEBGL_INTERNAL_FORMAT(RG32F, RG, UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(R8I, RED_INTEGER, BYTE)
+WEBGL_INTERNAL_FORMAT(R8UI, RED_INTEGER, UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(R16I, RED_INTEGER, BYTE)
+WEBGL_INTERNAL_FORMAT(R16UI, RED_INTEGER, UNSIGNED_SHORT)
+WEBGL_INTERNAL_FORMAT(R32I, RED_INTEGER, INT)
+WEBGL_INTERNAL_FORMAT(R32UI, RED_INTEGER, UNSIGNED_INT)
+WEBGL_INTERNAL_FORMAT(RG8I, RG_INTEGER, BYTE)
+WEBGL_INTERNAL_FORMAT(RG8UI, RG_INTEGER, UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(RG16I, RG_INTEGER, SHORT)
+WEBGL_INTERNAL_FORMAT(RG16UI, RG_INTEGER, UNSIGNED_SHORT)
+WEBGL_INTERNAL_FORMAT(RG32I, RG_INTEGER, INT)
+WEBGL_INTERNAL_FORMAT(RG32UI, RG_INTEGER, UNSIGNED_INT)
+WEBGL_INTERNAL_FORMAT(RGBA32F, RGBA, FLOAT)
+WEBGL_INTERNAL_FORMAT(RGB32F, RGB, FLOAT)
+WEBGL_INTERNAL_FORMAT(ALPHA32F_EXT, ALPHA, FLOAT)
+WEBGL_INTERNAL_FORMAT(LUMINANCE32F_EXT, LUMINANCE, FLOAT)
+WEBGL_INTERNAL_FORMAT(LUMINANCE_ALPHA32F_EXT, LUMINANCE_ALPHA, FLOAT)
+WEBGL_INTERNAL_FORMAT(RGBA16F, RGBA, HALF_FLOAT)
+WEBGL_INTERNAL_FORMAT(RGB16F, RGB, HALF_FLOAT)
+WEBGL_INTERNAL_FORMAT(ALPHA16F_EXT, ALPHA, HALF_FLOAT)
+WEBGL_INTERNAL_FORMAT(LUMINANCE16F_EXT, LUMINANCE, HALF_FLOAT)
+WEBGL_INTERNAL_FORMAT(LUMINANCE_ALPHA16F_EXT, LUMINANCE_ALPHA, HALF_FLOAT)
+WEBGL_INTERNAL_FORMAT(DEPTH24_STENCIL8, DEPTH_STENCIL, UNSIGNED_INT_24_8)
+WEBGL_INTERNAL_FORMAT(R11F_G11F_B10F, RGB, UNSIGNED_INT_10F_11F_11F_REV)
+WEBGL_INTERNAL_FORMAT(RGB9_E5, RGB, UNSIGNED_INT_5_9_9_9_REV)
+WEBGL_INTERNAL_FORMAT(SRGB8, SRGB, UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(SRGB8_ALPHA8, SRGB_ALPHA, UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(DEPTH_COMPONENT32F, DEPTH_COMPONENT, FLOAT)
+WEBGL_INTERNAL_FORMAT(DEPTH32F_STENCIL8, DEPTH_STENCIL, FLOAT_32_UNSIGNED_INT_24_8_REV)
+WEBGL_INTERNAL_FORMAT(RGB565, RGB, UNSIGNED_SHORT_5_6_5)
+WEBGL_INTERNAL_FORMAT(RGBA32UI, RGBA_INTEGER, UNSIGNED_INT)
+WEBGL_INTERNAL_FORMAT(RGB32UI, RGB_INTEGER, UNSIGNED_INT)
+WEBGL_INTERNAL_FORMAT(RGBA16UI, RGBA_INTEGER, UNSIGNED_SHORT)
+WEBGL_INTERNAL_FORMAT(RGB16UI, RGB_INTEGER, UNSIGNED_SHORT)
+WEBGL_INTERNAL_FORMAT(RGBA8UI, RGBA_INTEGER, UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(RGB8UI, RGB_INTEGER, UNSIGNED_BYTE)
+WEBGL_INTERNAL_FORMAT(RGBA32I, RGBA_INTEGER, INT)
+WEBGL_INTERNAL_FORMAT(RGB32I, RGB_INTEGER, INT)
+WEBGL_INTERNAL_FORMAT(RGBA16I, RGBA_INTEGER, SHORT)
+WEBGL_INTERNAL_FORMAT(RGB16I, RGB_INTEGER, SHORT)
+WEBGL_INTERNAL_FORMAT(RGBA8I, RGBA_INTEGER, BYTE)
+WEBGL_INTERNAL_FORMAT(RGB8I, RGB_INTEGER, BYTE)
+WEBGL_INTERNAL_FORMAT(R8_SNORM, RED, BYTE)
+WEBGL_INTERNAL_FORMAT(RG8_SNORM, RG, BYTE)
+WEBGL_INTERNAL_FORMAT(RGB8_SNORM, RGB, BYTE)
+WEBGL_INTERNAL_FORMAT(RGBA8_SNORM, RGBA, BYTE)
+WEBGL_INTERNAL_FORMAT(RGB10_A2UI, RGBA_INTEGER, UNSIGNED_INT_2_10_10_10_REV)
+
+#undef WEBGL_INTERNAL_FORMAT
+#undef HANDLE_WEBGL_INTERNAL_FORMAT
--- a/dom/canvas/WebGLStrongTypes.h
+++ b/dom/canvas/WebGLStrongTypes.h
@@ -294,16 +294,19 @@ STRONG_GLENUM_END(TexFormat)
STRONG_GLENUM_BEGIN(TexInternalFormat)
STRONG_GLENUM_VALUE(NONE),
STRONG_GLENUM_VALUE(DEPTH_COMPONENT),
STRONG_GLENUM_VALUE(ALPHA),
STRONG_GLENUM_VALUE(RGB),
STRONG_GLENUM_VALUE(RGBA),
STRONG_GLENUM_VALUE(LUMINANCE),
STRONG_GLENUM_VALUE(LUMINANCE_ALPHA),
+ STRONG_GLENUM_VALUE(ALPHA8),
+ STRONG_GLENUM_VALUE(LUMINANCE8),
+ STRONG_GLENUM_VALUE(LUMINANCE8_ALPHA8),
STRONG_GLENUM_VALUE(RGB8),
STRONG_GLENUM_VALUE(RGBA4),
STRONG_GLENUM_VALUE(RGB5_A1),
STRONG_GLENUM_VALUE(RGBA8),
STRONG_GLENUM_VALUE(RGB10_A2),
STRONG_GLENUM_VALUE(DEPTH_COMPONENT16),
STRONG_GLENUM_VALUE(DEPTH_COMPONENT24),
STRONG_GLENUM_VALUE(R8),
@@ -327,18 +330,24 @@ STRONG_GLENUM_BEGIN(TexInternalFormat)
STRONG_GLENUM_VALUE(COMPRESSED_RGB_S3TC_DXT1_EXT),
STRONG_GLENUM_VALUE(COMPRESSED_RGBA_S3TC_DXT1_EXT),
STRONG_GLENUM_VALUE(COMPRESSED_RGBA_S3TC_DXT3_EXT),
STRONG_GLENUM_VALUE(COMPRESSED_RGBA_S3TC_DXT5_EXT),
STRONG_GLENUM_VALUE(DEPTH_STENCIL),
STRONG_GLENUM_VALUE(ATC_RGBA_INTERPOLATED_ALPHA),
STRONG_GLENUM_VALUE(RGBA32F),
STRONG_GLENUM_VALUE(RGB32F),
+ STRONG_GLENUM_VALUE(ALPHA32F_EXT),
+ STRONG_GLENUM_VALUE(LUMINANCE32F_EXT),
+ STRONG_GLENUM_VALUE(LUMINANCE_ALPHA32F_EXT),
STRONG_GLENUM_VALUE(RGBA16F),
STRONG_GLENUM_VALUE(RGB16F),
+ STRONG_GLENUM_VALUE(ALPHA16F_EXT),
+ STRONG_GLENUM_VALUE(LUMINANCE16F_EXT),
+ STRONG_GLENUM_VALUE(LUMINANCE_ALPHA16F_EXT),
STRONG_GLENUM_VALUE(DEPTH24_STENCIL8),
STRONG_GLENUM_VALUE(COMPRESSED_RGB_PVRTC_4BPPV1),
STRONG_GLENUM_VALUE(COMPRESSED_RGB_PVRTC_2BPPV1),
STRONG_GLENUM_VALUE(COMPRESSED_RGBA_PVRTC_4BPPV1),
STRONG_GLENUM_VALUE(COMPRESSED_RGBA_PVRTC_2BPPV1),
STRONG_GLENUM_VALUE(R11F_G11F_B10F),
STRONG_GLENUM_VALUE(RGB9_E5),
STRONG_GLENUM_VALUE(SRGB),
--- a/dom/canvas/WebGLTexture.cpp
+++ b/dom/canvas/WebGLTexture.cpp
@@ -47,17 +47,17 @@ WebGLTexture::Delete() {
mContext->gl->fDeleteTextures(1, &mGLName);
LinkedListElement<WebGLTexture>::removeFrom(mContext->mTextures);
}
int64_t
WebGLTexture::ImageInfo::MemoryUsage() const {
if (mImageDataStatus == WebGLImageDataStatus::NoImageData)
return 0;
- int64_t bitsPerTexel = WebGLContext::GetBitsPerTexel(mInternalFormat, mType);
+ int64_t bitsPerTexel = GetBitsPerTexel(mEffectiveInternalFormat);
return int64_t(mWidth) * int64_t(mHeight) * bitsPerTexel/8;
}
int64_t
WebGLTexture::MemoryUsage() const {
if (IsDeleted())
return 0;
int64_t result = 0;
@@ -133,26 +133,25 @@ WebGLTexture::Bind(TexTarget aTexTarget)
if (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP && !mContext->gl->IsGLES())
mContext->gl->fTexParameteri(aTexTarget.get(), LOCAL_GL_TEXTURE_WRAP_R, LOCAL_GL_CLAMP_TO_EDGE);
}
}
void
WebGLTexture::SetImageInfo(TexImageTarget aTexImageTarget, GLint aLevel,
GLsizei aWidth, GLsizei aHeight,
- TexInternalFormat aInternalFormat, TexType aType,
- WebGLImageDataStatus aStatus)
+ TexInternalFormat aEffectiveInternalFormat, WebGLImageDataStatus aStatus)
{
MOZ_ASSERT(TexImageTargetToTexTarget(aTexImageTarget) == mTarget);
if (TexImageTargetToTexTarget(aTexImageTarget) != mTarget)
return;
EnsureMaxLevelWithCustomImagesAtLeast(aLevel);
- ImageInfoAt(aTexImageTarget, aLevel) = ImageInfo(aWidth, aHeight, aInternalFormat, aType, aStatus);
+ ImageInfoAt(aTexImageTarget, aLevel) = ImageInfo(aWidth, aHeight, aEffectiveInternalFormat, aStatus);
if (aLevel > 0)
SetCustomMipmap();
// Invalidate framebuffer status cache
NotifyFBsStatusChanged();
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
@@ -324,17 +323,19 @@ WebGLTexture::ResolvedFakeBlackStatus()
mContext->GenerateWarning("%s is a cube map texture, with a minification filter not requiring a mipmap, "
"with some level 0 image having width or height not a power of two, and with a wrap mode "
"different from CLAMP_TO_EDGE.", msg_rendering_as_black);
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
}
}
}
- if (ImageInfoBase().mType == LOCAL_GL_FLOAT &&
+ TexType type = TypeFromInternalFormat(ImageInfoBase().mEffectiveInternalFormat);
+
+ if (type == LOCAL_GL_FLOAT &&
!Context()->IsExtensionEnabled(WebGLExtensionID::OES_texture_float_linear))
{
if (mMinFilter == LOCAL_GL_LINEAR ||
mMinFilter == LOCAL_GL_LINEAR_MIPMAP_LINEAR ||
mMinFilter == LOCAL_GL_LINEAR_MIPMAP_NEAREST ||
mMinFilter == LOCAL_GL_NEAREST_MIPMAP_LINEAR)
{
mContext->GenerateWarning("%s is a texture with a linear minification filter, "
@@ -344,17 +345,17 @@ WebGLTexture::ResolvedFakeBlackStatus()
}
else if (mMagFilter == LOCAL_GL_LINEAR)
{
mContext->GenerateWarning("%s is a texture with a linear magnification filter, "
"which is not compatible with gl.FLOAT by default. "
"Try enabling the OES_texture_float_linear extension if supported.", msg_rendering_as_black);
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
}
- } else if (ImageInfoBase().mType == LOCAL_GL_HALF_FLOAT_OES &&
+ } else if (type == LOCAL_GL_HALF_FLOAT &&
!Context()->IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float_linear))
{
if (mMinFilter == LOCAL_GL_LINEAR ||
mMinFilter == LOCAL_GL_LINEAR_MIPMAP_LINEAR ||
mMinFilter == LOCAL_GL_LINEAR_MIPMAP_NEAREST ||
mMinFilter == LOCAL_GL_NEAREST_MIPMAP_LINEAR)
{
mContext->GenerateWarning("%s is a texture with a linear minification filter, "
@@ -529,47 +530,49 @@ void
WebGLTexture::DoDeferredImageInitialization(TexImageTarget imageTarget, GLint level)
{
const ImageInfo& imageInfo = ImageInfoAt(imageTarget, level);
MOZ_ASSERT(imageInfo.mImageDataStatus == WebGLImageDataStatus::UninitializedImageData);
mContext->MakeContextCurrent();
// Try to clear with glCLear.
- TexInternalFormat internalformat = imageInfo.mInternalFormat;
- TexType type = imageInfo.mType;
- WebGLTexelFormat texelformat = GetWebGLTexelFormat(internalformat, type);
bool cleared = ClearWithTempFB(mContext, GLName(),
imageTarget, level,
- internalformat, imageInfo.mHeight, imageInfo.mWidth);
+ imageInfo.mEffectiveInternalFormat,
+ imageInfo.mHeight, imageInfo.mWidth);
if (cleared) {
SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData);
return;
}
// That didn't work. Try uploading zeros then.
gl::ScopedBindTexture autoBindTex(mContext->gl, GLName(), mTarget.get());
- uint32_t texelsize = WebGLTexelConversions::TexelBytesForFormat(texelformat);
+ size_t bitspertexel = GetBitsPerTexel(imageInfo.mEffectiveInternalFormat);
+ MOZ_ASSERT((bitspertexel % 8) == 0); // that would only happen for compressed images, which
+ // cannot use deferred initialization.
+ size_t bytespertexel = bitspertexel / 8;
CheckedUint32 checked_byteLength
= WebGLContext::GetImageSize(
imageInfo.mHeight,
imageInfo.mWidth,
- texelsize,
+ bytespertexel,
mContext->mPixelStoreUnpackAlignment);
MOZ_ASSERT(checked_byteLength.isValid()); // should have been checked earlier
ScopedFreePtr<void> zeros;
zeros = calloc(1, checked_byteLength.value());
gl::GLContext* gl = mContext->gl;
- GLenum driverType = DriverTypeFromType(gl, type);
GLenum driverInternalFormat = LOCAL_GL_NONE;
GLenum driverFormat = LOCAL_GL_NONE;
- DriverFormatsFromFormatAndType(gl, internalformat, type, &driverInternalFormat, &driverFormat);
+ GLenum driverType = LOCAL_GL_NONE;
+ DriverFormatsFromEffectiveInternalFormat(gl, imageInfo.mEffectiveInternalFormat,
+ &driverInternalFormat, &driverFormat, &driverType);
mContext->GetAndFlushUnderlyingGLErrors();
gl->fTexImage2D(imageTarget.get(), level, driverInternalFormat,
imageInfo.mWidth, imageInfo.mHeight,
0, driverFormat, driverType,
zeros);
GLenum error = mContext->GetAndFlushUnderlyingGLErrors();
if (error) {
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -62,41 +62,37 @@ protected:
public:
class ImageInfo
: public WebGLRectangleObject
{
public:
ImageInfo()
- : mInternalFormat(LOCAL_GL_NONE)
- , mType(LOCAL_GL_NONE)
+ : mEffectiveInternalFormat(LOCAL_GL_NONE)
, mImageDataStatus(WebGLImageDataStatus::NoImageData)
{}
ImageInfo(GLsizei width,
GLsizei height,
- TexInternalFormat internalFormat,
- TexType type,
+ TexInternalFormat effectiveInternalFormat,
WebGLImageDataStatus status)
: WebGLRectangleObject(width, height)
- , mInternalFormat(internalFormat)
- , mType(type)
+ , mEffectiveInternalFormat(effectiveInternalFormat)
, mImageDataStatus(status)
{
// shouldn't use this constructor to construct a null ImageInfo
MOZ_ASSERT(status != WebGLImageDataStatus::NoImageData);
}
bool operator==(const ImageInfo& a) const {
return mImageDataStatus == a.mImageDataStatus &&
mWidth == a.mWidth &&
mHeight == a.mHeight &&
- mInternalFormat == a.mInternalFormat &&
- mType == a.mType;
+ mEffectiveInternalFormat == a.mEffectiveInternalFormat;
}
bool operator!=(const ImageInfo& a) const {
return !(*this == a);
}
bool IsSquare() const {
return mWidth == mHeight;
}
bool IsPositive() const {
@@ -105,31 +101,27 @@ public:
bool IsPowerOfTwo() const {
return is_pot_assuming_nonnegative(mWidth) &&
is_pot_assuming_nonnegative(mHeight); // negative sizes should never happen (caught in texImage2D...)
}
bool HasUninitializedImageData() const {
return mImageDataStatus == WebGLImageDataStatus::UninitializedImageData;
}
int64_t MemoryUsage() const;
- /*! This is the format passed from JS to WebGL.
- * It can be converted to a value to be passed to driver with
- * DriverFormatsFromFormatAndType().
- */
- TexInternalFormat InternalFormat() const { return mInternalFormat; }
- /*! This is the type passed from JS to WebGL.
- * It can be converted to a value to be passed to driver with
- * DriverTypeFromType().
- */
- TexType Type() const { return mType; }
+ TexInternalFormat EffectiveInternalFormat() const { return mEffectiveInternalFormat; }
protected:
- TexInternalFormat mInternalFormat; //!< This is the WebGL/GLES internal format.
- TexType mType; //!< This is the WebGL/GLES type
+ /*
+ * This is the "effective internal format" of the texture,
+ * an official OpenGL spec concept, see
+ * OpenGL ES 3.0.3 spec, section 3.8.3, page 126 and below.
+ */
+ TexInternalFormat mEffectiveInternalFormat;
+
WebGLImageDataStatus mImageDataStatus;
friend class WebGLTexture;
};
private:
static size_t FaceForTarget(TexImageTarget texImageTarget) {
if (texImageTarget == LOCAL_GL_TEXTURE_2D)
@@ -225,18 +217,17 @@ protected:
bool DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImageTarget) const;
public:
void Bind(TexTarget aTexTarget);
void SetImageInfo(TexImageTarget aTarget, GLint aLevel,
GLsizei aWidth, GLsizei aHeight,
- TexInternalFormat aInternalFormat, TexType aType,
- WebGLImageDataStatus aStatus);
+ TexInternalFormat aFormat, WebGLImageDataStatus aStatus);
void SetMinFilter(TexMinFilter aMinFilter) {
mMinFilter = aMinFilter;
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
}
void SetMagFilter(TexMagFilter aMagFilter) {
mMagFilter = aMagFilter;
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
--- a/dom/cellbroadcast/CellBroadcast.cpp
+++ b/dom/cellbroadcast/CellBroadcast.cpp
@@ -27,17 +27,17 @@ class CellBroadcast::Listener MOZ_FINAL
{
private:
CellBroadcast* mCellBroadcast;
public:
NS_DECL_ISUPPORTS
NS_FORWARD_SAFE_NSICELLBROADCASTLISTENER(mCellBroadcast)
- Listener(CellBroadcast* aCellBroadcast)
+ explicit Listener(CellBroadcast* aCellBroadcast)
: mCellBroadcast(aCellBroadcast)
{
MOZ_ASSERT(mCellBroadcast);
}
void Disconnect()
{
MOZ_ASSERT(mCellBroadcast);
--- a/dom/encoding/test/unit/xpcshell.ini
+++ b/dom/encoding/test/unit/xpcshell.ini
@@ -1,11 +1,12 @@
[DEFAULT]
head = head.js
tail =
+skip-if = toolkit == 'gonk'
[test_misc.js]
[test_utf.js]
[test_big5.js]
[test_euc-jp.js]
[test_euc-kr.js]
[test_gbk.js]
--- a/dom/fetch/Response.h
+++ b/dom/fetch/Response.h
@@ -22,17 +22,17 @@ class Promise;
class Response MOZ_FINAL : public nsISupports
, public nsWrapperCache
{
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Response)
public:
- Response(nsISupports* aOwner);
+ explicit Response(nsISupports* aOwner);
JSObject*
WrapObject(JSContext* aCx)
{
return ResponseBinding::Wrap(aCx, this);
}
ResponseType
--- a/dom/indexedDB/test/mochitest.ini
+++ b/dom/indexedDB/test/mochitest.ini
@@ -110,16 +110,18 @@ skip-if = (buildapp == 'b2g' && toolkit
[test_bfcache.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_blob_archive.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_blob_simple.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_blob_worker_crash.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
+[test_blob_worker_xhr_post.html]
+skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_blocked_order.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_bug937006.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_clear.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_complex_keyPaths.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/test_blob_worker_xhr_post.html
@@ -0,0 +1,113 @@
+<!--
+ Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+ <title>Indexed Database Property Test</title>
+
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <script type="text/javascript;version=1.7">
+ function testSteps()
+ {
+ const BLOB_DATA = ["fun ", "times ", "all ", "around!"];
+ const BLOB_TYPE = "text/plain";
+ const BLOB_SIZE = BLOB_DATA.join("").length;
+
+ info("Setting up");
+
+ let request = indexedDB.open(window.location.pathname, 1);
+ request.onerror = errorHandler;
+ request.onupgradeneeded = grabEventAndContinueHandler;
+ request.onsuccess = unexpectedSuccessHandler;
+ let event = yield undefined;
+
+ let db = event.target.result;
+ db.onerror = errorHandler;
+
+ ok(db, "Created database");
+
+ info("Creating objectStore");
+
+ let objectStore = db.createObjectStore("foo", { autoIncrement: true });
+
+ request.onupgradeneeded = unexpectedSuccessHandler;
+ request.onsuccess = grabEventAndContinueHandler;
+ event = yield undefined;
+
+ ok(true, "Opened database");
+
+ let blob = new Blob(BLOB_DATA, { type: BLOB_TYPE });
+
+ info("Adding blob to database");
+
+ objectStore = db.transaction("foo", "readwrite").objectStore("foo");
+ objectStore.add(blob).onsuccess = grabEventAndContinueHandler;
+ event = yield undefined;
+
+ let blobKey = event.target.result;
+ ok(blobKey, "Got a key for the blob");
+
+ info("Getting blob from the database");
+
+ objectStore = db.transaction("foo").objectStore("foo");
+ objectStore.get(blobKey).onsuccess = grabEventAndContinueHandler;
+ event = yield undefined;
+
+ blob = event.target.result;
+
+ ok(blob instanceof Blob, "Got a blob");
+ is(blob.size, BLOB_SIZE, "Correct size");
+ is(blob.type, BLOB_TYPE, "Correct type");
+
+ let slice = blob.slice(0, BLOB_DATA[0].length, BLOB_TYPE);
+
+ ok(slice instanceof Blob, "Slice returned a blob");
+ is(slice.size, BLOB_DATA[0].length, "Correct size for slice");
+ is(slice.type, BLOB_TYPE, "Correct type for slice");
+
+ info("Sending slice to a worker");
+
+ function workerScript() {
+ onmessage = function(event) {
+ var blob = event.data;
+ var xhr = new XMLHttpRequest();
+ // We just want to make sure the error case doesn't fire; it's fine for
+ // us to just want a 404.
+ xhr.open('POST', 'http://mochi.test:8888/does-not-exist', true);
+ xhr.onload = function() {
+ postMessage({ status: xhr.status });
+ };
+ xhr.onerror = function() {
+ postMessage({ status: 'error' });
+ }
+ xhr.send(blob);
+ }
+ }
+
+ let workerScriptUrl =
+ URL.createObjectURL(new Blob(["(", workerScript.toSource(), ")()"]));
+
+ let xhrWorker = new Worker(workerScriptUrl);
+ xhrWorker.postMessage(slice);
+ xhrWorker.onmessage = grabEventAndContinueHandler;
+ event = yield undefined;
+
+ is(event.data.status, 404, "XHR generated the expected 404");
+ xhrWorker.terminate();
+
+ URL.revokeObjectURL(workerScriptUrl);
+
+ finishTest();
+ yield undefined;
+ }
+ </script>
+ <script type="text/javascript;version=1.7" src="helpers.js"></script>
+
+</head>
+
+<body onload="runTest();"></body>
+
+</html>
--- a/dom/indexedDB/test/unit/xpcshell-child-process.ini
+++ b/dom/indexedDB/test/unit/xpcshell-child-process.ini
@@ -1,16 +1,17 @@
# 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/.
[DEFAULT]
dupe-manifest =
head = xpcshell-head-child-process.js
tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
support-files =
GlobalObjectsChild.js
GlobalObjectsComponent.js
GlobalObjectsComponent.manifest
GlobalObjectsModule.jsm
GlobalObjectsSandbox.js
xpcshell-head-parent-process.js
xpcshell-shared.ini
--- a/dom/indexedDB/test/unit/xpcshell-parent-process.ini
+++ b/dom/indexedDB/test/unit/xpcshell-parent-process.ini
@@ -1,16 +1,17 @@
# 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/.
[DEFAULT]
dupe-manifest =
head = xpcshell-head-parent-process.js
tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
support-files =
GlobalObjectsChild.js
GlobalObjectsComponent.js
GlobalObjectsComponent.manifest
GlobalObjectsModule.jsm
GlobalObjectsSandbox.js
xpcshell-shared.ini
--- a/dom/indexedDB/test/unit/xpcshell-shared.ini
+++ b/dom/indexedDB/test/unit/xpcshell-shared.ini
@@ -1,11 +1,13 @@
# 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/.
+[DEFAULT]
+skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_add_put.js]
[test_add_twice_failure.js]
[test_advance.js]
[test_autoIncrement.js]
[test_autoIncrement_indexes.js]
[test_blocked_order.js]
[test_clear.js]
--- a/dom/ipc/Blob.cpp
+++ b/dom/ipc/Blob.cpp
@@ -324,17 +324,17 @@ class RemoteInputStream MOZ_FINAL
nsCOMPtr<nsIInputStream> mStream;
nsRefPtr<DOMFileImpl> mBlobImpl;
nsCOMPtr<nsIEventTarget> mEventTarget;
nsISeekableStream* mWeakSeekableStream;
public:
NS_DECL_THREADSAFE_ISUPPORTS
- RemoteInputStream(DOMFileImpl* aBlobImpl)
+ explicit RemoteInputStream(DOMFileImpl* aBlobImpl)
: mMonitor("RemoteInputStream.mMonitor")
, mBlobImpl(aBlobImpl)
, mWeakSeekableStream(nullptr)
{
MOZ_ASSERT(IsOnOwningThread());
MOZ_ASSERT(aBlobImpl);
if (!NS_IsMainThread()) {
@@ -354,27 +354,29 @@ public:
{
MOZ_ASSERT(IsOnOwningThread());
}
void
Serialize(InputStreamParams& aParams,
FileDescriptorArray& /* aFileDescriptors */)
{
+ MOZ_RELEASE_ASSERT(mBlobImpl);
+
nsCOMPtr<nsIRemoteBlob> remote = do_QueryInterface(mBlobImpl);
MOZ_ASSERT(remote);
- MOZ_ASSERT(remote->GetBlobChild());
-
- aParams = RemoteInputStreamParams(
- nullptr /* sourceParent */,
- remote->GetBlobChild() /* sourceChild */);
+
+ BlobChild* actor = remote->GetBlobChild();
+ MOZ_ASSERT(actor);
+
+ aParams = RemoteInputStreamParams(actor->ParentID());
}
bool
- Deserialize(const InputStreamParams& aParams,
+ Deserialize(const InputStreamParams& /* aParams */,
const FileDescriptorArray& /* aFileDescriptors */)
{
// See InputStreamUtils.cpp to see how deserialization of a
// RemoteInputStream is special-cased.
MOZ_CRASH("RemoteInputStream should never be deserialized");
}
void
@@ -414,25 +416,58 @@ public:
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHOD
Available(uint64_t* aAvailable) MOZ_OVERRIDE
{
- // See large comment in FileInputStreamWrapper::Available.
- if (IsOnOwningThread()) {
+ if (!IsOnOwningThread()) {
+ nsresult rv = BlockAndWaitForStream();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = mStream->Available(aAvailable);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+#ifdef DEBUG
+ if (NS_IsMainThread()) {
+ NS_WARNING("Someone is trying to do main-thread I/O...");
+ }
+#endif
+
+ nsresult rv;
+
+ // See if we already have our real stream.
+ nsCOMPtr<nsIInputStream> inputStream;
+ {
+ MonitorAutoLock lock(mMonitor);
+
+ inputStream = mStream;
+ }
+
+ // If we do then just call through.
+ if (inputStream) {
+ rv = inputStream->Available(aAvailable);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_OK;
+ }
+
+ // If the stream is already closed then we can't do anything.
+ if (!mBlobImpl) {
return NS_BASE_STREAM_CLOSED;
}
- nsresult rv = BlockAndWaitForStream();
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = mStream->Available(aAvailable);
+ // Otherwise fake it...
+ NS_WARNING("Available() called before real stream has been delivered, "
+ "guessing the amount of data available!");
+
+ rv = mBlobImpl->GetSize(aAvailable);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHOD
Read(char* aBuffer, uint32_t aCount, uint32_t* aResult) MOZ_OVERRIDE
{
@@ -685,43 +720,57 @@ public:
DebugOnly<bool> isMutable;
MOZ_ASSERT(NS_SUCCEEDED(aBlobImpl->GetMutable(&isMutable)));
MOZ_ASSERT(!isMutable);
return GetOrCreateInternal(aID,
aProcessID,
aBlobImpl,
/* aMayCreate */ true,
- /* aMayGet */ false);
+ /* aMayGet */ false,
+ /* aIgnoreProcessID */ false);
}
static already_AddRefed<IDTableEntry>
Get(const nsID& aID, intptr_t aProcessID)
{
return GetOrCreateInternal(aID,
aProcessID,
nullptr,
/* aMayCreate */ false,
- /* aMayGet */ true);
+ /* aMayGet */ true,
+ /* aIgnoreProcessID */ false);
+ }
+
+ static already_AddRefed<IDTableEntry>
+ Get(const nsID& aID)
+ {
+ return GetOrCreateInternal(aID,
+ 0,
+ nullptr,
+ /* aMayCreate */ false,
+ /* aMayGet */ true,
+ /* aIgnoreProcessID */ true);
}
static already_AddRefed<IDTableEntry>
GetOrCreate(const nsID& aID, intptr_t aProcessID, DOMFileImpl* aBlobImpl)
{
MOZ_ASSERT(aBlobImpl);
DebugOnly<bool> isMutable;
MOZ_ASSERT(NS_SUCCEEDED(aBlobImpl->GetMutable(&isMutable)));
MOZ_ASSERT(!isMutable);
return GetOrCreateInternal(aID,
aProcessID,
aBlobImpl,
/* aMayCreate */ true,
- /* aMayGet */ true);
+ /* aMayGet */ true,
+ /* aIgnoreProcessID */ false);
}
const nsID&
ID() const
{
return mID;
}
@@ -743,17 +792,18 @@ private:
IDTableEntry(const nsID& aID, intptr_t aProcessID, DOMFileImpl* aBlobImpl);
~IDTableEntry();
static already_AddRefed<IDTableEntry>
GetOrCreateInternal(const nsID& aID,
intptr_t aProcessID,
DOMFileImpl* aBlobImpl,
bool aMayCreate,
- bool aMayGet);
+ bool aMayGet,
+ bool aIgnoreProcessID);
};
// Each instance of this class will be dispatched to the network stream thread
// pool to run the first time where it will open the file input stream. It will
// then dispatch itself back to the owning thread to send the child process its
// response (assuming that the child has not crashed). The runnable will then
// dispatch itself to the thread pool again in order to close the file input
// stream.
@@ -2913,16 +2963,36 @@ BlobParent::Create(PBackgroundParent* aM
{
AssertCorrectThreadForManager(aManager);
MOZ_ASSERT(aManager);
return CreateFromParams(aManager, aParams);
}
// static
+already_AddRefed<DOMFileImpl>
+BlobParent::GetBlobImplForID(const nsID& aID)
+{
+ if (NS_WARN_IF(gProcessType != GeckoProcessType_Default)) {
+ ASSERT_UNLESS_FUZZING();
+ return nullptr;
+ }
+
+ nsRefPtr<IDTableEntry> idTableEntry = IDTableEntry::Get(aID);
+ if (NS_WARN_IF(!idTableEntry)) {
+ return nullptr;
+ }
+
+ nsRefPtr<DOMFileImpl> blobImpl = idTableEntry->BlobImpl();
+ MOZ_ASSERT(blobImpl);
+
+ return blobImpl.forget();
+}
+
+// static
template <class ParentManagerType>
BlobParent*
BlobParent::GetOrCreateFromImpl(ParentManagerType* aManager,
DOMFileImpl* aBlobImpl)
{
AssertCorrectThreadForManager(aManager);
MOZ_ASSERT(aManager);
MOZ_ASSERT(aBlobImpl);
@@ -3545,17 +3615,18 @@ IDTableEntry::~IDTableEntry()
// static
already_AddRefed<BlobParent::IDTableEntry>
BlobParent::
IDTableEntry::GetOrCreateInternal(const nsID& aID,
intptr_t aProcessID,
DOMFileImpl* aBlobImpl,
bool aMayCreate,
- bool aMayGet)
+ bool aMayGet,
+ bool aIgnoreProcessID)
{
MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
MOZ_ASSERT(sIDTableMutex);
sIDTableMutex->AssertNotCurrentThreadOwns();
nsRefPtr<IDTableEntry> entry;
{
@@ -3573,17 +3644,17 @@ IDTableEntry::GetOrCreateInternal(const
if (entry) {
MOZ_ASSERT_IF(aBlobImpl, entry->BlobImpl() == aBlobImpl);
if (NS_WARN_IF(!aMayGet)) {
return nullptr;
}
- if (NS_WARN_IF(entry->mProcessID != aProcessID)) {
+ if (!aIgnoreProcessID && NS_WARN_IF(entry->mProcessID != aProcessID)) {
return nullptr;
}
} else {
if (NS_WARN_IF(!aMayCreate)) {
return nullptr;
}
MOZ_ASSERT(aBlobImpl);
--- a/dom/ipc/BlobParent.h
+++ b/dom/ipc/BlobParent.h
@@ -102,16 +102,19 @@ public:
const ParentBlobConstructorParams& aParams);
static void
Destroy(PBlobParent* aActor)
{
delete static_cast<BlobParent*>(aActor);
}
+ static already_AddRefed<DOMFileImpl>
+ GetBlobImplForID(const nsID& aID);
+
bool
HasManager() const
{
return mBackgroundManager || mContentManager;
}
PBackgroundParent*
GetBackgroundManager() const
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -3512,24 +3512,24 @@ ContentParent::RecvSyncMessage(const nsS
const IPC::Principal& aPrincipal,
InfallibleTArray<nsString>* aRetvals)
{
return nsIContentParent::RecvSyncMessage(aMsg, aData, aCpows, aPrincipal,
aRetvals);
}
bool
-ContentParent::AnswerRpcMessage(const nsString& aMsg,
- const ClonedMessageData& aData,
- const InfallibleTArray<CpowEntry>& aCpows,
- const IPC::Principal& aPrincipal,
- InfallibleTArray<nsString>* aRetvals)
+ContentParent::RecvRpcMessage(const nsString& aMsg,
+ const ClonedMessageData& aData,
+ const InfallibleTArray<CpowEntry>& aCpows,
+ const IPC::Principal& aPrincipal,
+ InfallibleTArray<nsString>* aRetvals)
{
- return nsIContentParent::AnswerRpcMessage(aMsg, aData, aCpows, aPrincipal,
- aRetvals);
+ return nsIContentParent::RecvRpcMessage(aMsg, aData, aCpows, aPrincipal,
+ aRetvals);
}
bool
ContentParent::RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows,
const IPC::Principal& aPrincipal)
{
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -558,21 +558,21 @@ private:
virtual bool RecvLoadURIExternal(const URIParams& uri) MOZ_OVERRIDE;
virtual bool RecvSyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows,
const IPC::Principal& aPrincipal,
InfallibleTArray<nsString>* aRetvals) MOZ_OVERRIDE;
- virtual bool AnswerRpcMessage(const nsString& aMsg,
- const ClonedMessageData& aData,
- const InfallibleTArray<CpowEntry>& aCpows,
- const IPC::Principal& aPrincipal,
- InfallibleTArray<nsString>* aRetvals) MOZ_OVERRIDE;
+ virtual bool RecvRpcMessage(const nsString& aMsg,
+ const ClonedMessageData& aData,
+ const InfallibleTArray<CpowEntry>& aCpows,
+ const IPC::Principal& aPrincipal,
+ InfallibleTArray<nsString>* aRetvals) MOZ_OVERRIDE;
virtual bool RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows,
const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
virtual bool RecvFilePathUpdateNotify(const nsString& aType,
const nsString& aStorageName,
const nsString& aFilePath,
--- a/dom/ipc/DOMTypes.ipdlh
+++ b/dom/ipc/DOMTypes.ipdlh
@@ -2,19 +2,16 @@
/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
/* 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 protocol PBlob;
include InputStreamParams;
-using struct nsID
- from "nsID.h";
-
using struct mozilla::void_t
from "ipc/IPCMessageUtils.h";
using struct mozilla::SerializedStructuredCloneBuffer
from "ipc/IPCMessageUtils.h";
namespace mozilla {
namespace dom {
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -64,17 +64,17 @@ struct NativeKeyBinding
};
union MaybeNativeKeyBinding
{
NativeKeyBinding;
void_t;
};
-intr protocol PBrowser
+prio(normal upto high) intr protocol PBrowser
{
manager PContent or PContentBridge;
manages PColorPicker;
manages PDocumentRenderer;
manages PContentPermissionRequest;
manages PFilePicker;
manages PIndexedDBPermissionRequest;
@@ -103,18 +103,18 @@ parent:
nsString aFeatures,
nsString aBaseURI)
returns (bool windowIsNew, PBrowser window);
sync SyncMessage(nsString aMessage, ClonedMessageData aData,
CpowEntry[] aCpows, Principal aPrincipal)
returns (nsString[] retval);
- rpc RpcMessage(nsString aMessage, ClonedMessageData aData,
- CpowEntry[] aCpows, Principal aPrincipal)
+ prio(high) sync RpcMessage(nsString aMessage, ClonedMessageData aData,
+ CpowEntry[] aCpows, Principal aPrincipal)
returns (nsString[] retval);
/**
* The IME sequence number (seqno) parameter is used to make sure
* that a notification is discarded if it arrives at the chrome process
* too late. If the notification is late and we accept it, we will have
* an out-of-date view of the content process, which means events that we
* dispatch based on this out-of-date view will be wrong also.
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -314,17 +314,17 @@ struct VolumeInfo {
bool isUnmounting;
};
union MaybeFileDesc {
FileDescriptor;
void_t;
};
-intr protocol PContent
+prio(normal upto high) intr protocol PContent
{
parent opens PCompositor;
parent opens PSharedBufferManager;
parent opens PImageBridge;
child opens PBackground;
manages PAsmJSCacheEntry;
manages PBlob;
@@ -532,17 +532,17 @@ parent:
returns (bool isSecureURI);
PHal();
PMobileConnection(uint32_t clientId);
PNecko();
- rpc PScreenManager()
+ prio(high) sync PScreenManager()
returns (uint32_t numberOfScreens,
float systemDefaultScale,
bool success);
PCellBroadcast();
PSms();
@@ -572,18 +572,18 @@ parent:
sync ReadPrefsArray() returns (PrefSetting[] prefs);
sync ReadFontList() returns (FontListEntry[] retValue);
sync SyncMessage(nsString aMessage, ClonedMessageData aData,
CpowEntry[] aCpows, Principal aPrincipal)
returns (nsString[] retval);
- rpc RpcMessage(nsString aMessage, ClonedMessageData aData,
- CpowEntry[] aCpows, Principal aPrincipal)
+ prio(high) sync RpcMessage(nsString aMessage, ClonedMessageData aData,
+ CpowEntry[] aCpows, Principal aPrincipal)
returns (nsString[] retval);
ShowAlertNotification(nsString imageUrl,
nsString title,
nsString text,
bool textClickable,
nsString cookie,
nsString name,
--- a/dom/ipc/PContentBridge.ipdl
+++ b/dom/ipc/PContentBridge.ipdl
@@ -21,17 +21,17 @@ namespace dom {
/*
* PContentBridge allows us to represent a parent/child relationship between two
* child processes. When a child process wants to open its own child, it asks
* the root process to create a new process and then bridge them. The first
* child will allocate the PContentBridgeParent, and the newly opened child will
* allocate the PContentBridgeChild. This protocol allows these processes to
* share PBrowsers and send messages to each other.
*/
-intr protocol PContentBridge
+prio(normal upto high) intr protocol PContentBridge
{
bridges PContent, PContent;
manages PBlob;
manages PBrowser;
manages PJavaScript;
parent:
--- a/dom/ipc/PCrashReporter.ipdl
+++ b/dom/ipc/PCrashReporter.ipdl
@@ -14,17 +14,17 @@ namespace dom {
struct Mapping {
nsCString library_name;
nsCString file_id;
uintptr_t start_address;
size_t mapping_length;
size_t file_offset;
};
-intr protocol PCrashReporter {
+async protocol PCrashReporter {
manager PContent or PPluginModule or PGMP;
parent:
AnnotateCrashReport(nsCString key, nsCString data);
AppendAppNotes(nsCString data);
__delete__();
};
}
--- a/dom/ipc/PScreenManager.ipdl
+++ b/dom/ipc/PScreenManager.ipdl
@@ -17,42 +17,42 @@ struct ScreenDetails {
nsIntRect rectDisplayPix;
nsIntRect availRect;
nsIntRect availRectDisplayPix;
int32_t pixelDepth;
int32_t colorDepth;
double contentsScaleFactor;
};
-rpc protocol PScreenManager
+prio(normal upto high) sync protocol PScreenManager
{
manager PContent;
parent:
- rpc Refresh()
+ prio(high) sync Refresh()
returns (uint32_t numberOfScreens,
float systemDefaultScale,
bool success);
- rpc ScreenRefresh(uint32_t aId)
+ prio(high) sync ScreenRefresh(uint32_t aId)
returns (ScreenDetails screen,
bool success);
- rpc GetPrimaryScreen()
+ prio(high) sync GetPrimaryScreen()
returns (ScreenDetails screen,
bool success);
- rpc ScreenForRect(int32_t aLeft,
+ prio(high) sync ScreenForRect(int32_t aLeft,
int32_t aTop,
int32_t aWidth,
int32_t aHeight)
returns (ScreenDetails screen,
bool success);
- rpc ScreenForBrowser(PBrowser aBrowser)
+ prio(high) sync ScreenForBrowser(PBrowser aBrowser)
returns (ScreenDetails screen,
bool success);
child:
__delete__();
};
} // namespace dom
--- a/dom/ipc/ScreenManagerParent.cpp
+++ b/dom/ipc/ScreenManagerParent.cpp
@@ -19,23 +19,23 @@ ScreenManagerParent::ScreenManagerParent
float* aSystemDefaultScale,
bool* aSuccess)
{
mScreenMgr = do_GetService(sScreenManagerContractID);
if (!mScreenMgr) {
MOZ_CRASH("Couldn't get nsIScreenManager from ScreenManagerParent.");
}
- unused << AnswerRefresh(aNumberOfScreens, aSystemDefaultScale, aSuccess);
+ unused << RecvRefresh(aNumberOfScreens, aSystemDefaultScale, aSuccess);
}
bool
-ScreenManagerParent::AnswerRefresh(uint32_t* aNumberOfScreens,
- float* aSystemDefaultScale,
- bool* aSuccess)
+ScreenManagerParent::RecvRefresh(uint32_t* aNumberOfScreens,
+ float* aSystemDefaultScale,
+ bool* aSuccess)
{
*aSuccess = false;
nsresult rv = mScreenMgr->GetNumberOfScreens(aNumberOfScreens);
if (NS_FAILED(rv)) {
return true;
}
@@ -44,19 +44,19 @@ ScreenManagerParent::AnswerRefresh(uint3
return true;
}
*aSuccess = true;
return true;
}
bool
-ScreenManagerParent::AnswerScreenRefresh(const uint32_t& aId,
- ScreenDetails* aRetVal,
- bool* aSuccess)
+ScreenManagerParent::RecvScreenRefresh(const uint32_t& aId,
+ ScreenDetails* aRetVal,
+ bool* aSuccess)
{
*aSuccess = false;
nsCOMPtr<nsIScreen> screen;
nsresult rv = mScreenMgr->ScreenForId(aId, getter_AddRefs(screen));
if (NS_FAILED(rv)) {
return true;
}
@@ -65,18 +65,18 @@ ScreenManagerParent::AnswerScreenRefresh
unused << ExtractScreenDetails(screen, details);
*aRetVal = details;
*aSuccess = true;
return true;
}
bool
-ScreenManagerParent::AnswerGetPrimaryScreen(ScreenDetails* aRetVal,
- bool* aSuccess)
+ScreenManagerParent::RecvGetPrimaryScreen(ScreenDetails* aRetVal,
+ bool* aSuccess)
{
*aSuccess = false;
nsCOMPtr<nsIScreen> screen;
nsresult rv = mScreenMgr->GetPrimaryScreen(getter_AddRefs(screen));
NS_ENSURE_SUCCESS(rv, true);
@@ -86,22 +86,22 @@ ScreenManagerParent::AnswerGetPrimaryScr
}
*aRetVal = details;
*aSuccess = true;
return true;
}
bool
-ScreenManagerParent::AnswerScreenForRect(const int32_t& aLeft,
- const int32_t& aTop,
- const int32_t& aWidth,
- const int32_t& aHeight,
- ScreenDetails* aRetVal,
- bool* aSuccess)
+ScreenManagerParent::RecvScreenForRect(const int32_t& aLeft,
+ const int32_t& aTop,
+ const int32_t& aWidth,
+ const int32_t& aHeight,
+ ScreenDetails* aRetVal,
+ bool* aSuccess)
{
*aSuccess = false;
nsCOMPtr<nsIScreen> screen;
nsresult rv = mScreenMgr->ScreenForRect(aLeft, aTop, aWidth, aHeight, getter_AddRefs(screen));
NS_ENSURE_SUCCESS(rv, true);
@@ -111,19 +111,19 @@ ScreenManagerParent::AnswerScreenForRect
}
*aRetVal = details;
*aSuccess = true;
return true;
}
bool
-ScreenManagerParent::AnswerScreenForBrowser(PBrowserParent* aBrowser,
- ScreenDetails* aRetVal,
- bool* aSuccess)
+ScreenManagerParent::RecvScreenForBrowser(PBrowserParent* aBrowser,
+ ScreenDetails* aRetVal,
+ bool* aSuccess)
{
*aSuccess = false;
// Find the mWidget associated with the tabparent, and then return
// the nsIScreen it's on.
TabParent* tabParent = static_cast<TabParent*>(aBrowser);
nsCOMPtr<nsIWidget> widget = tabParent->GetWidget();
if (!widget) {
--- a/dom/ipc/ScreenManagerParent.h
+++ b/dom/ipc/ScreenManagerParent.h
@@ -16,39 +16,39 @@ namespace dom {
class ScreenManagerParent : public PScreenManagerParent
{
public:
ScreenManagerParent(uint32_t* aNumberOfScreens,
float* aSystemDefaultScale,
bool* aSuccess);
~ScreenManagerParent() {};
- virtual bool AnswerRefresh(uint32_t* aNumberOfScreens,
- float* aSystemDefaultScale,
- bool* aSuccess) MOZ_OVERRIDE;
+ virtual bool RecvRefresh(uint32_t* aNumberOfScreens,
+ float* aSystemDefaultScale,
+ bool* aSuccess) MOZ_OVERRIDE;
- virtual bool AnswerScreenRefresh(const uint32_t& aId,
- ScreenDetails* aRetVal,
- bool* aSuccess) MOZ_OVERRIDE;
+ virtual bool RecvScreenRefresh(const uint32_t& aId,
+ ScreenDetails* aRetVal,
+ bool* aSuccess) MOZ_OVERRIDE;
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
- virtual bool AnswerGetPrimaryScreen(ScreenDetails* aRetVal,
- bool* aSuccess) MOZ_OVERRIDE;
+ virtual bool RecvGetPrimaryScreen(ScreenDetails* aRetVal,
+ bool* aSuccess) MOZ_OVERRIDE;
- virtual bool AnswerScreenForRect(const int32_t& aLeft,
- const int32_t& aTop,
- const int32_t& aWidth,
- const int32_t& aHeight,
- ScreenDetails* aRetVal,
- bool* aSuccess) MOZ_OVERRIDE;
+ virtual bool RecvScreenForRect(const int32_t& aLeft,
+ const int32_t& aTop,
+ const int32_t& aWidth,
+ const int32_t& aHeight,
+ ScreenDetails* aRetVal,
+ bool* aSuccess) MOZ_OVERRIDE;
- virtual bool AnswerScreenForBrowser(PBrowserParent* aBrowser,
- ScreenDetails* aRetVal,
- bool* aSuccess);
+ virtual bool RecvScreenForBrowser(PBrowserParent* aBrowser,
+ ScreenDetails* aRetVal,
+ bool* aSuccess);
private:
bool ExtractScreenDetails(nsIScreen* aScreen, ScreenDetails &aDetails);
nsCOMPtr<nsIScreenManager> mScreenMgr;
};
} // namespace dom
} // namespace mozilla
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2917,17 +2917,17 @@ TabChild::DoSendBlockingMessage(JSContex
if (aCpows && !Manager()->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
return false;
}
if (aIsSync) {
return SendSyncMessage(PromiseFlatString(aMessage), data, cpows,
Principal(aPrincipal), aJSONRetVal);
}
- return CallRpcMessage(PromiseFlatString(aMessage), data, cpows,
+ return SendRpcMessage(PromiseFlatString(aMessage), data, cpows,
Principal(aPrincipal), aJSONRetVal);
}
bool
TabChild::DoSendAsyncMessage(JSContext* aCx,
const nsAString& aMessage,
const StructuredCloneData& aData,
JS::Handle<JSObject *> aCpows,
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1123,21 +1123,21 @@ TabParent::RecvSyncMessage(const nsStrin
}
StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
CpowIdHolder cpows(Manager(), aCpows);
return ReceiveMessage(aMessage, true, &cloneData, &cpows, aPrincipal, aJSONRetVal);
}
bool
-TabParent::AnswerRpcMessage(const nsString& aMessage,
- const ClonedMessageData& aData,
- const InfallibleTArray<CpowEntry>& aCpows,
- const IPC::Principal& aPrincipal,
- InfallibleTArray<nsString>* aJSONRetVal)
+TabParent::RecvRpcMessage(const nsString& aMessage,
+ const ClonedMessageData& aData,
+ const InfallibleTArray<CpowEntry>& aCpows,
+ const IPC::Principal& aPrincipal,
+ InfallibleTArray<nsString>* aJSONRetVal)
{
// FIXME Permission check for TabParent in Content process
nsIPrincipal* principal = aPrincipal;
if (Manager()->IsContentParent()) {
ContentParent* parent = Manager()->AsContentParent();
if (!ContentParent::IgnoreIPCPrincipal() &&
parent && principal && !AssertAppPrincipal(parent, principal)) {
return false;
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -142,21 +142,21 @@ public:
const nsString& aBaseURI,
bool* aWindowIsNew,
PBrowserParent** aRetVal) MOZ_OVERRIDE;
virtual bool RecvSyncMessage(const nsString& aMessage,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows,
const IPC::Principal& aPrincipal,
InfallibleTArray<nsString>* aJSONRetVal) MOZ_OVERRIDE;
- virtual bool AnswerRpcMessage(const nsString& aMessage,
- const ClonedMessageData& aData,
- const InfallibleTArray<CpowEntry>& aCpows,
- const IPC::Principal& aPrincipal,
- InfallibleTArray<nsString>* aJSONRetVal) MOZ_OVERRIDE;
+ virtual bool RecvRpcMessage(const nsString& aMessage,
+ const ClonedMessageData& aData,
+ const InfallibleTArray<CpowEntry>& aCpows,
+ const IPC::Principal& aPrincipal,
+ InfallibleTArray<nsString>* aJSONRetVal) MOZ_OVERRIDE;
virtual bool RecvAsyncMessage(const nsString& aMessage,
const ClonedMessageData& aData,
const InfallibleTArray<CpowEntry>& aCpows,
const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
virtual bool RecvNotifyIMEFocus(const bool& aFocus,
nsIMEUpdatePreference* aPreference,
uint32_t* aSeqno) MOZ_OVERRIDE;
virtual bool RecvNotifyIMETextChange(const uint32_t& aStart,
--- a/dom/ipc/nsIContentParent.cpp
+++ b/dom/ipc/nsIContentParent.cpp
@@ -188,21 +188,21 @@ nsIContentParent::RecvSyncMessage(const
CpowIdHolder cpows(this, aCpows);
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
aMsg, true, &cloneData, &cpows, aPrincipal, aRetvals);
}
return true;
}
bool
-nsIContentParent::AnswerRpcMessage(const nsString& aMsg,
- const ClonedMessageData& aData,
- const InfallibleTArray<CpowEntry>& aCpows,
- const IPC::Principal& aPrincipal,
- InfallibleTArray<nsString>* aRetvals)
+nsIContentParent::RecvRpcMessage(const nsString& aMsg,
+ const ClonedMessageData& aData,
+ const InfallibleTArray<CpowEntry>& aCpows,
+ const IPC::Principal& aPrincipal,
+ InfallibleTArray<nsString>* aRetvals)
{
// FIXME Permission check in Content process
nsIPrincipal* principal = aPrincipal;
if (IsContentParent()) {
ContentParent* parent = AsContentParent();
if (!ContentParent::IgnoreIPCPrincipal() &&
parent && principal && !AssertAppPrincipal(parent, principal)) {
return false;
--- a/dom/ipc/nsIContentParent.h
+++ b/dom/ipc/nsIContentParent.h
@@ -86,21 +86,21 @@ protected: // IPDL methods
virtual bool DeallocPBlobParent(PBlobParent* aActor);
virtual bool RecvSyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
const InfallibleTArray<jsipc::CpowEntry>& aCpows,
const IPC::Principal& aPrincipal,
InfallibleTArray<nsString>* aRetvals);
- virtual bool AnswerRpcMessage(const nsString& aMsg,
- const ClonedMessageData& aData,
- const InfallibleTArray<jsipc::CpowEntry>& aCpows,
- const IPC::Principal& aPrincipal,
- InfallibleTArray<nsString>* aRetvals);
+ virtual bool RecvRpcMessage(const nsString& aMsg,
+ const ClonedMessageData& aData,
+ const InfallibleTArray<jsipc::CpowEntry>& aCpows,
+ const IPC::Principal& aPrincipal,
+ InfallibleTArray<nsString>* aRetvals);
virtual bool RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
const InfallibleTArray<jsipc::CpowEntry>& aCpows,
const IPC::Principal& aPrincipal);
protected: // members
nsRefPtr<nsFrameMessageManager> mMessageManager;
};
--- a/dom/json/test/unit/xpcshell.ini
+++ b/dom/json/test/unit/xpcshell.ini
@@ -1,11 +1,12 @@
[DEFAULT]
head =
tail =
+skip-if = toolkit == 'gonk'
support-files =
decodeFromStream-01.json
decodeFromStream-small.json
[test_decodeFromStream.js]
[test_decode_long_input.js]
[test_encode.js]
--- a/dom/network/tests/unit/xpcshell.ini
+++ b/dom/network/tests/unit/xpcshell.ini
@@ -1,9 +1,10 @@
[DEFAULT]
head =
tail =
+skip-if = toolkit == 'gonk'
[test_tcpsocket.js]
[test_multisend.js]
[test_tcpserversocket.js]
run-sequentially = Uses hardcoded port, bug 903830.
skip-if = os == 'mac' # bug 953208 - frequent timeouts on OSX
--- a/dom/network/tests/unit_ipc/xpcshell.ini
+++ b/dom/network/tests/unit_ipc/xpcshell.ini
@@ -1,7 +1,8 @@
[DEFAULT]
head =
tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_tcpsocket_ipc.js]
[test_tcpserversocket_ipc.js]
run-sequentially = Uses hardcoded port, bug 903830.
--- a/dom/notification/test/unit/xpcshell.ini
+++ b/dom/notification/test/unit/xpcshell.ini
@@ -1,6 +1,7 @@
[DEFAULT]
head = common_test_notificationdb.js
tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_notificationdb.js]
[test_notificationdb_bug1024090.js]
--- a/dom/payment/tests/unit/xpcshell.ini
+++ b/dom/payment/tests/unit/xpcshell.ini
@@ -1,5 +1,6 @@
[DEFAULT]
head = header_helper.js
tail =
+skip-if = toolkit == 'gonk'
[test_paymanager_get_payment_request.js]
--- a/dom/permission/tests/unit/xpcshell.ini
+++ b/dom/permission/tests/unit/xpcshell.ini
@@ -1,5 +1,6 @@
[DEFAULT]
head =
tail =
+skip-if = toolkit == 'gonk'
[test_bug808734.js]
--- a/dom/plugins/test/unit/xpcshell.ini
+++ b/dom/plugins/test/unit/xpcshell.ini
@@ -1,10 +1,10 @@
[DEFAULT]
-skip-if = buildapp == 'mulet'
+skip-if = buildapp == 'mulet' || toolkit == 'android' || toolkit == 'gonk'
head = head_plugins.js
tail =
[test_bug455213.js]
# Bug 676953: test fails consistently on Android
fail-if = os == "android"
[test_bug471245.js]
# Bug 676953: test fails consistently on Android
--- a/dom/system/gonk/AudioManager.cpp
+++ b/dom/system/gonk/AudioManager.cpp
@@ -73,16 +73,17 @@ static int sMaxStreamVolumeTbl[AUDIO_STR
15, // BT SCO
15, // enforced audible
15, // DTMF
15, // TTS
15, // FM
};
// A bitwise variable for recording what kind of headset is attached.
static int sHeadsetState;
+static bool sBluetoothA2dpEnabled;
static const int kBtSampleRate = 8000;
static bool sSwitchDone = true;
static bool sA2dpSwitchDone = true;
namespace mozilla {
namespace dom {
namespace gonk {
class RecoverTask : public nsRunnable
@@ -285,17 +286,23 @@ AudioManager::HandleBluetoothStatusChang
} else {
AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
audioState, aAddress.get());
String8 cmd("bluetooth_enabled=true");
AudioSystem::setParameters(0, cmd);
cmd.setTo("A2dpSuspended=false");
AudioSystem::setParameters(0, cmd);
sA2dpSwitchDone = true;
+#if ANDROID_VERSION >= 17
+ if (AudioSystem::getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) == AUDIO_POLICY_FORCE_NO_BT_A2DP) {
+ SetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, AUDIO_POLICY_FORCE_NONE);
+ }
+#endif
}
+ sBluetoothA2dpEnabled = audioState == AUDIO_POLICY_DEVICE_STATE_AVAILABLE;
} else if (!strcmp(aTopic, BLUETOOTH_HFP_STATUS_CHANGED_ID)) {
AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
audioState, aAddress.get());
AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,
audioState, aAddress.get());
}
#endif
}
@@ -391,33 +398,47 @@ NotifyHeadphonesStatus(SwitchState aStat
obs->NotifyObservers(nullptr, HEADPHONES_STATUS_CHANGED, HEADPHONES_STATUS_UNKNOWN);
}
}
}
class HeadphoneSwitchObserver : public SwitchObserver
{
public:
+ HeadphoneSwitchObserver(AudioManager* aAudioManager)
+ : mAudioManager(aAudioManager) { }
void Notify(const SwitchEvent& aEvent) {
NotifyHeadphonesStatus(aEvent.status());
// When user pulled out the headset, a delay of routing here can avoid the leakage of audio from speaker.
if (aEvent.status() == SWITCH_STATE_OFF && sSwitchDone) {
MessageLoop::current()->PostDelayedTask(
FROM_HERE, NewRunnableFunction(&ProcessDelayedAudioRoute, SWITCH_STATE_OFF), 1000);
sSwitchDone = false;
} else if (aEvent.status() != SWITCH_STATE_OFF) {
InternalSetAudioRoutes(aEvent.status());
sSwitchDone = true;
}
+ // Handle the coexistence of a2dp / headset device, latest one wins.
+#if ANDROID_VERSION >= 17
+ int32_t forceUse = 0;
+ mAudioManager->GetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, &forceUse);
+ if (aEvent.status() != SWITCH_STATE_OFF && sBluetoothA2dpEnabled) {
+ mAudioManager->SetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, AUDIO_POLICY_FORCE_NO_BT_A2DP);
+ } else if (forceUse == AUDIO_POLICY_FORCE_NO_BT_A2DP) {
+ mAudioManager->SetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, AUDIO_POLICY_FORCE_NONE);
+ }
+#endif
}
+private:
+ AudioManager* mAudioManager;
};
AudioManager::AudioManager()
: mPhoneState(PHONE_STATE_CURRENT)
- , mObserver(new HeadphoneSwitchObserver())
+ , mObserver(new HeadphoneSwitchObserver(this))
#ifdef MOZ_B2G_RIL
, mMuteCallToRIL(false)
#endif
{
RegisterSwitchObserver(SWITCH_HEADPHONES, mObserver);
InternalSetAudioRoutes(GetCurrentSwitchState(SWITCH_HEADPHONES));
NotifyHeadphonesStatus(GetCurrentSwitchState(SWITCH_HEADPHONES));
--- a/dom/system/gonk/android_audio/AudioSystem.h
+++ b/dom/system/gonk/android_audio/AudioSystem.h
@@ -37,22 +37,19 @@ typedef enum {
AUDIO_POLICY_FORCE_NONE,
AUDIO_POLICY_FORCE_SPEAKER,
AUDIO_POLICY_FORCE_HEADPHONES,
AUDIO_POLICY_FORCE_BT_SCO,
AUDIO_POLICY_FORCE_BT_A2DP,
AUDIO_POLICY_FORCE_WIRED_ACCESSORY,
AUDIO_POLICY_FORCE_BT_CAR_DOCK,
AUDIO_POLICY_FORCE_BT_DESK_DOCK,
-
-#ifdef VANILLA_ANDROID
AUDIO_POLICY_FORCE_ANALOG_DOCK,
AUDIO_POLICY_FORCE_DIGITAL_DOCK,
-#endif
-
+ AUDIO_POLICY_FORCE_NO_BT_A2DP,
AUDIO_POLICY_FORCE_CFG_CNT,
AUDIO_POLICY_FORCE_CFG_MAX = AUDIO_POLICY_FORCE_CFG_CNT - 1,
AUDIO_POLICY_FORCE_DEFAULT = AUDIO_POLICY_FORCE_NONE,
} audio_policy_forced_cfg_t;
/* usages used for audio_policy->set_force_use() */
typedef enum {
@@ -719,16 +716,19 @@ public:
FORCE_NONE,
FORCE_SPEAKER,
FORCE_HEADPHONES,
FORCE_BT_SCO,
FORCE_BT_A2DP,
FORCE_WIRED_ACCESSORY,
FORCE_BT_CAR_DOCK,
FORCE_BT_DESK_DOCK,
+ FORCE_ANALOG_DOCK,
+ FORCE_DIGITAL_DOCK,
+ FORCE_NO_BT_A2DP,
NUM_FORCE_CONFIG,
FORCE_DEFAULT = FORCE_NONE
};
// usages used for setForceUse()
enum force_use {
FOR_COMMUNICATION,
FOR_MEDIA,
--- a/dom/system/gonk/nsIAudioManager.idl
+++ b/dom/system/gonk/nsIAudioManager.idl
@@ -11,17 +11,17 @@ interface nsIAudioManager : nsISupports
* Microphone muted?
*/
attribute boolean microphoneMuted;
/**
* Are we playing audio from the FM radio?
*/
attribute boolean fmRadioAudioEnabled;
-
+
/**
* Set the phone's audio mode.
*/
const long PHONE_STATE_INVALID = -2;
const long PHONE_STATE_CURRENT = -1;
const long PHONE_STATE_NORMAL = 0;
const long PHONE_STATE_RINGTONE = 1;
const long PHONE_STATE_IN_CALL = 2;
@@ -36,17 +36,19 @@ interface nsIAudioManager : nsISupports
const long FORCE_NONE = 0; // the default
const long FORCE_SPEAKER = 1;
const long FORCE_HEADPHONES = 2;
const long FORCE_BT_SCO = 3;
const long FORCE_BT_A2DP = 4;
const long FORCE_WIRED_ACCESSORY = 5;
const long FORCE_BT_CAR_DOCK = 6;
const long FORCE_BT_DESK_DOCK = 7;
-
+ const long FORCE_ANALOG_DOCK = 8;
+ const long FORCE_DIGITAL_DOCK = 9;
+ const long FORCE_NO_BT_A2DP = 10;
const long USE_COMMUNICATION = 0;
const long USE_MEDIA = 1;
const long USE_RECORD = 2;
const long USE_DOCK = 3;
void setForceForUse(in long usage, in long force);
long getForceForUse(in long usage);
--- a/dom/tests/unit/xpcshell.ini
+++ b/dom/tests/unit/xpcshell.ini
@@ -1,11 +1,12 @@
[DEFAULT]
head =
tail =
+skip-if = toolkit == 'gonk'
[test_bug319968.js]
[test_bug465752.js]
[test_geolocation_provider.js]
# Bug 684962: test hangs consistently on Android
skip-if = os == "android"
[test_geolocation_timeout.js]
# Bug 919946: test hangs consistently on Android
--- a/dom/voicemail/Voicemail.cpp
+++ b/dom/voicemail/Voicemail.cpp
@@ -28,17 +28,17 @@ using mozilla::ErrorResult;
class Voicemail::Listener MOZ_FINAL : public nsIVoicemailListener
{
Voicemail* mVoicemail;
public:
NS_DECL_ISUPPORTS
NS_FORWARD_SAFE_NSIVOICEMAILLISTENER(mVoicemail)
- Listener(Voicemail* aVoicemail)
+ explicit Listener(Voicemail* aVoicemail)
: mVoicemail(aVoicemail)
{
MOZ_ASSERT(mVoicemail);
}
void Disconnect()
{
MOZ_ASSERT(mVoicemail);
--- a/dom/voicemail/ipc/VoicemailIPCService.cpp
+++ b/dom/voicemail/ipc/VoicemailIPCService.cpp
@@ -18,17 +18,17 @@ namespace voicemail {
class VoicemailIPCProvider MOZ_FINAL : public nsIVoicemailProvider
{
friend class VoicemailIPCService;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIVOICEMAILPROVIDER
- VoicemailIPCProvider(uint32_t aServiceId);
+ explicit VoicemailIPCProvider(uint32_t aServiceId);
private:
// MOZ_FINAL suppresses -Werror,-Wdelete-non-virtual-dtor
~VoicemailIPCProvider() {}
private:
uint32_t mServiceId;
nsString mNumber;
--- a/dom/workers/test/urlSearchParams_worker.js
+++ b/dom/workers/test/urlSearchParams_worker.js
@@ -17,17 +17,17 @@ onmessage = function() {
} catch(e) {
}
ok(status, "URLSearchParams in workers \\o/");
function testSimpleURLSearchParams() {
var u = new URLSearchParams();
ok(u, "URLSearchParams created");
is(u.has('foo'), false, 'URLSearchParams.has(foo)');
- is(u.get('foo'), '', 'URLSearchParams.get(foo)');
+ is(u.get('foo'), null, 'URLSearchParams.get(foo)');
is(u.getAll('foo').length, 0, 'URLSearchParams.getAll(foo)');
u.append('foo', 'bar');
is(u.has('foo'), true, 'URLSearchParams.has(foo)');
is(u.get('foo'), 'bar', 'URLSearchParams.get(foo)');
is(u.getAll('foo').length, 1, 'URLSearchParams.getAll(foo)');
u.set('foo', 'bar2');
--- a/dom/workers/test/xpcshell/xpcshell.ini
+++ b/dom/workers/test/xpcshell/xpcshell.ini
@@ -1,8 +1,9 @@
[DEFAULT]
head =
tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
support-files =
data/worker.js
data/chrome.manifest
[test_workers.js]
--- a/embedding/tests/unit/xpcshell.ini
+++ b/embedding/tests/unit/xpcshell.ini
@@ -1,6 +1,7 @@
[DEFAULT]
head =
tail =
+skip-if = toolkit == 'gonk'
[test_wwauthpromptfactory.js]
[test_wwpromptfactory.js]
--- a/extensions/cookie/test/unit/xpcshell.ini
+++ b/extensions/cookie/test/unit/xpcshell.ini
@@ -1,11 +1,12 @@
[DEFAULT]
head = head_cookies.js
tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
support-files =
cookieprompt.js
cookieprompt.manifest
[test_bug526789.js]
[test_bug650522.js]
[test_bug667087.js]
[test_cookies_async_failure.js]
--- a/extensions/cookie/test/unit_ipc/xpcshell.ini
+++ b/extensions/cookie/test/unit_ipc/xpcshell.ini
@@ -1,6 +1,7 @@
[DEFAULT]
head =
tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_child.js]
[test_parent.js]
--- a/extensions/spellcheck/hunspell/tests/unit/xpcshell.ini
+++ b/extensions/spellcheck/hunspell/tests/unit/xpcshell.ini
@@ -1,6 +1,7 @@
[DEFAULT]
head =
tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
support-files = data/**
[test_hunspell.js]
--- a/gfx/2d/FilterNodeSoftware.cpp
+++ b/gfx/2d/FilterNodeSoftware.cpp
@@ -1151,51 +1151,41 @@ FilterNodeTransformSoftware::SourceRectF
}
TemporaryRef<DataSourceSurface>
FilterNodeTransformSoftware::Render(const IntRect& aRect)
{
IntRect srcRect = SourceRectForOutputRect(aRect);
RefPtr<DataSourceSurface> input =
- GetInputDataSourceSurface(IN_TRANSFORM_IN, srcRect);
+ GetInputDataSourceSurface(IN_TRANSFORM_IN, srcRect, NEED_COLOR_CHANNELS);
if (!input) {
return nullptr;
}
Matrix transform = Matrix::Translation(srcRect.x, srcRect.y) * mMatrix *
Matrix::Translation(-aRect.x, -aRect.y);
if (transform.IsIdentity() && srcRect.Size() == aRect.Size()) {
return input.forget();
}
- RefPtr<DataSourceSurface> surf =
- Factory::CreateDataSourceSurface(aRect.Size(), input->GetFormat());
-
- DataSourceSurface::MappedSurface mapping;
- surf->Map(DataSourceSurface::MapType::WRITE, &mapping);
-
RefPtr<DrawTarget> dt =
- Factory::CreateDrawTargetForData(BackendType::CAIRO,
- mapping.mData,
- surf->GetSize(),
- mapping.mStride,
- surf->GetFormat());
+ Factory::CreateDrawTarget(BackendType::CAIRO, aRect.Size(), input->GetFormat());
if (!dt) {
return nullptr;
}
Rect r(0, 0, srcRect.width, srcRect.height);
dt->SetTransform(transform);
dt->DrawSurface(input, r, r, DrawSurfaceOptions(mFilter));
- dt->Flush();
- surf->Unmap();
- return surf.forget();
+ RefPtr<SourceSurface> result = dt->Snapshot();
+ RefPtr<DataSourceSurface> resultData = result->GetDataSurface();
+ return resultData.forget();
}
void
FilterNodeTransformSoftware::RequestFromInputsForRect(const IntRect &aRect)
{
RequestInputRect(IN_TRANSFORM_IN, SourceRectForOutputRect(aRect));
}
--- a/gfx/2d/Matrix.h
+++ b/gfx/2d/Matrix.h
@@ -78,18 +78,18 @@ public:
/**
* Apply a translation to this matrix.
*
* The "Pre" in this method's name means that the translation is applied
* -before- this matrix's existing transformation. That is, any vector that
* is multiplied by the resulting matrix will first be translated, then be
* transformed by the original transform.
*
- * Thus calling this method will result in this matrix having the same value
- * as the result of:
+ * Calling this method will result in this matrix having the same value as
+ * the result of:
*
* Matrix::Translation(x, y) * this
*
* (Note that in performance critical code multiplying by the result of a
* Translation()/Scaling() call is not recommended since that results in a
* full matrix multiply involving 12 floating-point multiplications. Calling
* this method would be preferred since it only involves four floating-point
* multiplications.)
@@ -132,32 +132,32 @@ public:
}
static Matrix Scaling(Float aScaleX, Float aScaleY)
{
return Matrix(aScaleX, 0.0f, 0.0f, aScaleY, 0.0f, 0.0f);
}
/**
- * Similar to PreTranslate, but applies a scale to this matrix.
+ * Similar to PreTranslate, but applies a scale instead of a translation.
*/
Matrix &PreScale(Float aX, Float aY)
{
_11 *= aX;
_12 *= aX;
_21 *= aY;
_22 *= aY;
return *this;
}
GFX2D_API static Matrix Rotation(Float aAngle);
/**
- * Similar to PreTranslate, but applies a rotation to this matrix.
+ * Similar to PreTranslate, but applies a rotation instead of a translation.
*/
Matrix &PreRotate(Float aAngle)
{
return *this = Matrix::Rotation(aAngle) * *this;
}
bool Invert()
{
@@ -360,16 +360,26 @@ class Matrix4x4
public:
Matrix4x4()
: _11(1.0f), _12(0.0f), _13(0.0f), _14(0.0f)
, _21(0.0f), _22(1.0f), _23(0.0f), _24(0.0f)
, _31(0.0f), _32(0.0f), _33(1.0f), _34(0.0f)
, _41(0.0f), _42(0.0f), _43(0.0f), _44(1.0f)
{}
+ Matrix4x4(Float a11, Float a12, Float a13, Float a14,
+ Float a21, Float a22, Float a23, Float a24,
+ Float a31, Float a32, Float a33, Float a34,
+ Float a41, Float a42, Float a43, Float a44)
+ : _11(a11), _12(a12), _13(a13), _14(a14)
+ , _21(a21), _22(a22), _23(a23), _24(a24)
+ , _31(a31), _32(a32), _33(a33), _34(a34)
+ , _41(a41), _42(a42), _43(a43), _44(a44)
+ {}
+
Float _11, _12, _13, _14;
Float _21, _22, _23, _24;
Float _31, _32, _33, _34;
Float _41, _42, _43, _44;
Point4D& operator[](int aIndex)
{
MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index");
@@ -453,16 +463,18 @@ public:
// Solving for z when z' = 0 gives us:
float z = -(aPoint.x * _13 + aPoint.y * _23 + _43) / _33;
// Compute the transformed point
return *this * Point4D(aPoint.x, aPoint.y, z, 1);
}
+ Rect ProjectRectBounds(const Rect& aRect) const;
+
static Matrix4x4 From2D(const Matrix &aMatrix) {
Matrix4x4 matrix;
matrix._11 = aMatrix._11;
matrix._12 = aMatrix._12;
matrix._21 = aMatrix._21;
matrix._22 = aMatrix._22;
matrix._41 = aMatrix._31;
matrix._42 = aMatrix._32;
@@ -513,59 +525,127 @@ public:
temp = *this * temp;
temp /= temp.w;
return Point(temp.x, temp.y);
}
GFX2D_API Rect TransformBounds(const Rect& rect) const;
- // Apply a scale to this matrix. This scale will be applied -before- the
- // existing transformation of the matrix.
+
+ static Matrix4x4 Translation(Float aX, Float aY, Float aZ)
+ {
+ return Matrix4x4(1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ aX, aY, aZ, 1.0f);
+ }
+
+ /**
+ * Apply a translation to this matrix.
+ *
+ * The "Pre" in this method's name means that the translation is applied
+ * -before- this matrix's existing transformation. That is, any vector that
+ * is multiplied by the resulting matrix will first be translated, then be
+ * transformed by the original transform.
+ *
+ * Calling this method will result in this matrix having the same value as
+ * the result of:
+ *
+ * Matrix4x4::Translation(x, y) * this
+ *
+ * (Note that in performance critical code multiplying by the result of a
+ * Translation()/Scaling() call is not recommended since that results in a
+ * full matrix multiply involving 64 floating-point multiplications. Calling
+ * this method would be preferred since it only involves 12 floating-point
+ * multiplications.)
+ */
+ Matrix4x4 &Translate(Float aX, Float aY, Float aZ)
+ {
+ _41 += aX * _11 + aY * _21 + aZ * _31;
+ _42 += aX * _12 + aY * _22 + aZ * _32;
+ _43 += aX * _13 + aY * _23 + aZ * _33;
+ _44 += aX * _14 + aY * _24 + aZ * _34;
+
+ return *this;
+ }
+
+ /**
+ * Similar to PreTranslate, but the translation is applied -after- this
+ * matrix's existing transformation instead of before it.
+ *
+ * This method is generally less used than PreTranslate since typically code
+ * wants to adjust an existing user space to device space matrix to create a
+ * transform to device space from a -new- user space (translated from the
+ * previous user space). In that case consumers will need to use the Pre*
+ * variants of the matrix methods rather than using the Post* methods, since
+ * the Post* methods add a transform to the device space end of the
+ * transformation.
+ */
+ Matrix4x4 &PostTranslate(Float aX, Float aY, Float aZ)
+ {
+ _11 += _14 * aX;
+ _21 += _24 * aX;
+ _31 += _34 * aX;
+ _41 += _44 * aX;
+ _12 += _14 * aY;
+ _22 += _24 * aY;
+ _32 += _34 * aY;
+ _42 += _44 * aY;
+ _13 += _14 * aZ;
+ _23 += _24 * aZ;
+ _33 += _34 * aZ;
+ _43 += _44 * aZ;
+
+ return *this;
+ }
+
+ static Matrix4x4 Scaling(Float aScaleX, Float aScaleY, float aScaleZ)
+ {
+ return Matrix4x4(aScaleX, 0.0f, 0.0f, 0.0f,
+ 0.0f, aScaleY, 0.0f, 0.0f,
+ 0.0f, 0.0f, aScaleZ, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f);
+ }
+
+ /**
+ * Similar to PreTranslate, but applies a scale instead of a translation.
+ */
Matrix4x4 &Scale(Float aX, Float aY, Float aZ)
{
_11 *= aX;
_12 *= aX;
_13 *= aX;
_21 *= aY;
_22 *= aY;
_23 *= aY;
_31 *= aZ;
_32 *= aZ;
_33 *= aZ;
return *this;
}
- Matrix4x4 &Translate(Float aX, Float aY, Float aZ)
+ /**
+ * Similar to PostTranslate, but applies a scale instead of a translation.
+ */
+ Matrix4x4 &PostScale(Float aScaleX, Float aScaleY, Float aScaleZ)
{
- _41 += aX * _11 + aY * _21 + aZ * _31;
- _42 += aX * _12 + aY * _22 + aZ * _32;
- _43 += aX * _13 + aY * _23 + aZ * _33;
- _44 += aX * _14 + aY * _24 + aZ * _34;
-
- return *this;
- }
-
- Rect ProjectRectBounds(const Rect& aRect) const;
-
- Matrix4x4 &PostTranslate(Float aX, Float aY, Float aZ)
- {
- _11 += _14 * aX;
- _21 += _24 * aX;
- _31 += _34 * aX;
- _41 += _44 * aX;
- _12 += _14 * aY;
- _22 += _24 * aY;
- _32 += _34 * aY;
- _42 += _44 * aY;
- _13 += _14 * aZ;
- _23 += _24 * aZ;
- _33 += _34 * aZ;
- _43 += _44 * aZ;
+ _11 *= aScaleX;
+ _21 *= aScaleX;
+ _31 *= aScaleX;
+ _41 *= aScaleX;
+ _12 *= aScaleY;
+ _22 *= aScaleY;
+ _32 *= aScaleY;
+ _42 *= aScaleY;
+ _13 *= aScaleZ;
+ _23 *= aScaleZ;
+ _33 *= aScaleZ;
+ _43 *= aScaleZ;
return *this;
}
void SkewXY(Float aSkew)
{
(*this)[1] += (*this)[0] * aSkew;
}
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -2360,17 +2360,16 @@ bool
GLContext::ResizeScreenBuffer(const IntSize& size)
{
if (!IsOffscreenSizeAllowed(size))
return false;
return mScreen->Resize(size);
}
-
void
GLContext::DestroyScreenBuffer()
{
mScreen = nullptr;
}
void
GLContext::ForceDirtyScreen()
--- a/gfx/gl/GLTextureImage.cpp
+++ b/gfx/gl/GLTextureImage.cpp
@@ -227,24 +227,37 @@ BasicTextureImage::DirectUpdate(gfx::Dat
void
BasicTextureImage::Resize(const gfx::IntSize& aSize)
{
NS_ASSERTION(!mUpdateDrawTarget, "Resize() while in update?");
mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
+ // This matches the logic in UploadImageDataToTexture so that
+ // we avoid mixing formats.
+ GLenum format;
+ GLenum type;
+ if (mGLContext->GetPreferredARGB32Format() == LOCAL_GL_BGRA) {
+ MOZ_ASSERT(!mGLContext->IsGLES());
+ format = LOCAL_GL_BGRA;
+ type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
+ } else {
+ format = LOCAL_GL_RGBA;
+ type = LOCAL_GL_UNSIGNED_BYTE;
+ }
+
mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
0,
LOCAL_GL_RGBA,
aSize.width,
aSize.height,
0,
- LOCAL_GL_RGBA,
- LOCAL_GL_UNSIGNED_BYTE,
+ format,
+ type,
nullptr);
mTextureState = Allocated;
mSize = aSize;
}
gfx::IntSize TextureImage::GetSize() const {
return mSize;
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -710,35 +710,36 @@ Layer::IsScrollInfoLayer() const
&& HasScrollableFrameMetrics()
&& !GetFirstChild();
}
const Matrix4x4
Layer::GetTransform() const
{
Matrix4x4 transform = mTransform;
+ transform.PostScale(mPostXScale, mPostYScale, 1.0f);
if (const ContainerLayer* c = AsContainerLayer()) {
transform.Scale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
}
- transform = transform * Matrix4x4().Scale(mPostXScale, mPostYScale, 1.0f);
return transform;
}
const Matrix4x4
Layer::GetLocalTransform()
{
Matrix4x4 transform;
if (LayerComposite* shadow = AsLayerComposite())
transform = shadow->GetShadowTransform();
else
transform = mTransform;
+
+ transform.PostScale(mPostXScale, mPostYScale, 1.0f);
if (ContainerLayer* c = AsContainerLayer()) {
transform.Scale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
}
- transform = transform * Matrix4x4().Scale(mPostXScale, mPostYScale, 1.0f);
return transform;
}
void
Layer::ApplyPendingUpdatesForThisTransaction()
{
if (mPendingTransform && *mPendingTransform != mTransform) {
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -2493,17 +2493,17 @@ Matrix4x4 AsyncPanZoomController::GetOve
if (mY.IsOverscrolled() && mY.GetOverscroll() > 0) {
// Overscrolled at the bottomn.
ScreenCoord overscrolledCompositionHeight = scaleY * compositionSize.height;
ScreenCoord extraCompositionHeight = overscrolledCompositionHeight - compositionSize.height;
translation.y = -extraCompositionHeight;
}
// Combine the transformations into a matrix.
- return Matrix4x4().Scale(scaleX, scaleY, 1)
+ return Matrix4x4::Scaling(scaleX, scaleY, 1)
.PostTranslate(translation.x, translation.y, 0);
}
bool AsyncPanZoomController::AdvanceAnimations(const TimeStamp& aSampleTime)
{
AssertOnCompositorThread();
// Don't send any state-change notifications until the end of the function,
@@ -2618,19 +2618,19 @@ ViewTransform AsyncPanZoomController::Ge
ScreenPoint translation = (currentScrollOffset - lastPaintScrollOffset)
* mFrameMetrics.GetZoom();
return ViewTransform(scale, -translation);
}
Matrix4x4 AsyncPanZoomController::GetNontransientAsyncTransform() const {
ReentrantMonitorAutoEnter lock(mMonitor);
- return Matrix4x4().Scale(mLastContentPaintMetrics.mResolution.scale,
- mLastContentPaintMetrics.mResolution.scale,
- 1.0f);
+ return Matrix4x4::Scaling(mLastContentPaintMetrics.mResolution.scale,
+ mLastContentPaintMetrics.mResolution.scale,
+ 1.0f);
}
Matrix4x4 AsyncPanZoomController::GetTransformToLastDispatchedPaint() const {
ReentrantMonitorAutoEnter lock(mMonitor);
// Technically we should be taking the scroll delta in the coordinate space
// of transformed layer pixels (i.e. this layer's LayerPixels, with the layer
// transform applied). However in the absence of actual CSS transforms, we
@@ -2639,18 +2639,18 @@ Matrix4x4 AsyncPanZoomController::GetTra
// to revisit this.
ParentLayerPoint scrollChange =
(mLastContentPaintMetrics.GetScrollOffset() - mLastDispatchedPaintMetrics.GetScrollOffset())
* mLastContentPaintMetrics.mDevPixelsPerCSSPixel
* mLastContentPaintMetrics.GetParentResolution();
float zoomChange = mLastContentPaintMetrics.GetZoom().scale / mLastDispatchedPaintMetrics.GetZoom().scale;
- return Matrix4x4().Translate(scrollChange.x, scrollChange.y, 0) *
- Matrix4x4().Scale(zoomChange, zoomChange, 1);
+ return Matrix4x4::Translation(scrollChange.x, scrollChange.y, 0).
+ PostScale(zoomChange, zoomChange, 1);
}
bool AsyncPanZoomController::IsCurrentlyCheckerboarding() const {
ReentrantMonitorAutoEnter lock(mMonitor);
if (!gfxPrefs::APZAllowCheckerboarding()) {
return false;
}
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -602,17 +602,17 @@ ClientLayerManager::ForwardTransaction(b
if (!sent) {
// Clear the transaction id so that it doesn't get returned
// unless we forwarded to somewhere that doesn't actually
// have a compositor.
mTransactionIdAllocator->RevokeTransactionId(mLatestTransactionId);
}
mForwarder->RemoveTexturesIfNecessary();
- mForwarder->SendPendingAsyncMessge();
+ mForwarder->SendPendingAsyncMessges();
mPhase = PHASE_NONE;
// this may result in Layers being deleted, which results in
// PLayer::Send__delete__() and DeallocShmem()
mKeepAlive.Clear();
}
ShadowableLayer*
--- a/gfx/layers/client/ClientTiledPaintedLayer.cpp
+++ b/gfx/layers/client/ClientTiledPaintedLayer.cpp
@@ -70,17 +70,17 @@ GetTransformToAncestorsParentLayer(Layer
const LayerMetricsWrapper& ancestorParent = aAncestor.GetParent();
for (LayerMetricsWrapper iter(aStart, LayerMetricsWrapper::StartAt::BOTTOM);
ancestorParent ? iter != ancestorParent : iter.IsValid();
iter = iter.GetParent()) {
transform = transform * iter.GetTransform();
// If the layer has a non-transient async transform then we need to apply it here
// because it will get applied by the APZ in the compositor as well
const FrameMetrics& metrics = iter.Metrics();
- transform = transform * gfx::Matrix4x4().Scale(metrics.mResolution.scale, metrics.mResolution.scale, 1.f);
+ transform.PostScale(metrics.mResolution.scale, metrics.mResolution.scale, 1.f);
}
return transform;
}
void
ClientTiledPaintedLayer::GetAncestorLayers(LayerMetricsWrapper* aOutScrollAncestor,
LayerMetricsWrapper* aOutDisplayPortAncestor)
{
--- a/gfx/layers/client/ClientTiledPaintedLayer.h
+++ b/gfx/layers/client/ClientTiledPaintedLayer.h
@@ -50,18 +50,19 @@ protected:
public:
// Override name to distinguish it from ClientPaintedLayer in layer dumps
virtual const char* Name() const { return "TiledPaintedLayer"; }
// PaintedLayer
virtual Layer* AsLayer() { return this; }
virtual void InvalidateRegion(const nsIntRegion& aRegion) {
mInvalidRegion.Or(mInvalidRegion, aRegion);
- mValidRegion.Sub(mValidRegion, aRegion);
- mLowPrecisionValidRegion.Sub(mLowPrecisionValidRegion, aRegion);
+ mInvalidRegion.SimplifyOutward(20);
+ mValidRegion.Sub(mValidRegion, mInvalidRegion);
+ mLowPrecisionValidRegion.Sub(mLowPrecisionValidRegion, mInvalidRegion);
}
// Shadow methods
virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs);
virtual ShadowableLayer* AsShadowableLayer() { return this; }
virtual void Disconnect()
{
--- a/gfx/layers/client/CompositableClient.cpp
+++ b/gfx/layers/client/CompositableClient.cpp
@@ -166,16 +166,20 @@ CompositableClient::Connect()
}
void
CompositableClient::Destroy()
{
if (!mCompositableChild) {
return;
}
+ // Send pending AsyncMessages before deleting CompositableChild.
+ // They might have dependency to the mCompositableChild.
+ mForwarder->SendPendingAsyncMessges();
+ // Delete CompositableChild.
mCompositableChild->mCompositableClient = nullptr;
PCompositableChild::Send__delete__(mCompositableChild);
mCompositableChild = nullptr;
}
uint64_t
CompositableClient::GetAsyncID() const
{
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -1361,17 +1361,17 @@ ClientTiledLayerBuffer::ValidateTile(Til
* transformed into the painted layer's LayerPixel coordinates, accounting
* for the compositor state.
*/
static LayerRect
GetCompositorSideCompositionBounds(const LayerMetricsWrapper& aScrollAncestor,
const Matrix4x4& aTransformToCompBounds,
const ViewTransform& aAPZTransform)
{
- Matrix4x4 nonTransientAPZUntransform = Matrix4x4().Scale(
+ Matrix4x4 nonTransientAPZUntransform = Matrix4x4::Scaling(
aScrollAncestor.Metrics().mResolution.scale,
aScrollAncestor.Metrics().mResolution.scale,
1.f);
nonTransientAPZUntransform.Invert();
// Take off the last "term" of aTransformToCompBounds, which
// is the APZ's nontransient async transform. Replace it with
// the APZ's async transform (this includes the nontransient
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -173,27 +173,26 @@ TranslateShadowLayer2D(Layer* aLayer,
// will apply the resolution scale again when computing the effective
// transform, we must apply the inverse resolution scale here.
Matrix4x4 layerTransform3D = Matrix4x4::From2D(layerTransform);
if (ContainerLayer* c = aLayer->AsContainerLayer()) {
layerTransform3D.Scale(1.0f/c->GetPreXScale(),
1.0f/c->GetPreYScale(),
1);
}
- layerTransform3D = layerTransform3D *
- Matrix4x4().Scale(1.0f/aLayer->GetPostXScale(),
- 1.0f/aLayer->GetPostYScale(),
- 1);
+ layerTransform3D.PostScale(1.0f/aLayer->GetPostXScale(),
+ 1.0f/aLayer->GetPostYScale(),
+ 1);
LayerComposite* layerComposite = aLayer->AsLayerComposite();
layerComposite->SetShadowTransform(layerTransform3D);
layerComposite->SetShadowTransformSetByAnimation(false);
if (aAdjustClipRect) {
- TransformClipRect(aLayer, Matrix4x4().Translate(aTranslation.x, aTranslation.y, 0));
+ TransformClipRect(aLayer, Matrix4x4::Translation(aTranslation.x, aTranslation.y, 0));
}
}
static bool
AccumulateLayerTransforms2D(Layer* aLayer,
Layer* aAncestor,
Matrix& aMatrix)
{
@@ -495,19 +494,17 @@ SampleAnimations(Layer* aLayer, TimeStam
{
layerComposite->SetShadowOpacity(interpolatedValue.get_float());
break;
}
case eCSSProperty_transform:
{
Matrix4x4 matrix = interpolatedValue.get_ArrayOfTransformFunction()[0].get_TransformMatrix().value();
if (ContainerLayer* c = aLayer->AsContainerLayer()) {
- matrix = matrix * Matrix4x4().Scale(c->GetInheritedXScale(),
- c->GetInheritedYScale(),
- 1);
+ matrix.PostScale(c->GetInheritedXScale(), c->GetInheritedYScale(), 1);
}
layerComposite->SetShadowTransform(matrix);
layerComposite->SetShadowTransformSetByAnimation(true);
break;
}
default:
NS_WARNING("Unhandled animated property");
}
@@ -622,19 +619,19 @@ AsyncCompositionManager::ApplyAsyncConte
// GetTransform already takes the pre- and post-scale into account. Since we
// will apply the pre- and post-scale again when computing the effective
// transform, we must apply the inverses here.
if (ContainerLayer* container = aLayer->AsContainerLayer()) {
transform.Scale(1.0f/container->GetPreXScale(),
1.0f/container->GetPreYScale(),
1);
}
- transform = transform * Matrix4x4().Scale(1.0f/aLayer->GetPostXScale(),
- 1.0f/aLayer->GetPostYScale(),
- 1);
+ transform.PostScale(1.0f/aLayer->GetPostXScale(),
+ 1.0f/aLayer->GetPostYScale(),
+ 1);
layerComposite->SetShadowTransform(transform);
NS_ASSERTION(!layerComposite->GetShadowTransformSetByAnimation(),
"overwriting animated transform!");
const FrameMetrics& bottom = LayerMetricsWrapper::BottommostScrollableMetrics(aLayer);
MOZ_ASSERT(bottom.IsScrollable()); // must be true because hasAsyncTransform is true
// Apply resolution scaling to the old transform - the layer tree as it is
@@ -710,23 +707,23 @@ ApplyAsyncTransformToScrollbarForContent
// translation (representing the scroll). This is because scrolling down, which
// translates the layer content up, should result in moving the scroll thumb down.
// The amount of the translation to the scroll thumb should be such that the ratio
// of the translation to the size of the scroll port is the same as the ratio
// of the scroll amount to the size of the scrollable rect.
Matrix4x4 scrollbarTransform;
if (aScrollbar->GetScrollbarDirection() == Layer::VERTICAL) {
float scale = metrics.CalculateCompositedSizeInCssPixels().height / metrics.mScrollableRect.height;
- scrollbarTransform = scrollbarTransform * Matrix4x4().Scale(1.f, 1.f / transientTransform._22, 1.f);
- scrollbarTransform = scrollbarTransform * Matrix4x4().Translate(0, -transientTransform._42 * scale, 0);
+ scrollbarTransform.PostScale(1.f, 1.f / transientTransform._22, 1.f);
+ scrollbarTransform.PostTranslate(0, -transientTransform._42 * scale, 0);
}
if (aScrollbar->GetScrollbarDirection() == Layer::HORIZONTAL) {
float scale = metrics.CalculateCompositedSizeInCssPixels().width / metrics.mScrollableRect.width;
- scrollbarTransform = scrollbarTransform * Matrix4x4().Scale(1.f / transientTransform._11, 1.f, 1.f);
- scrollbarTransform = scrollbarTransform * Matrix4x4().Translate(-transientTransform._41 * scale, 0, 0);
+ scrollbarTransform.PostScale(1.f / transientTransform._11, 1.f, 1.f);
+ scrollbarTransform.PostTranslate(-transientTransform._41 * scale, 0, 0);
}
Matrix4x4 transform = scrollbarTransform * aScrollbar->GetTransform();
if (aScrollbarIsDescendant) {
// If the scrollbar layer is a child of the content it is a scrollbar for, then we
// need to do an extra untransform to cancel out the transient async transform on
// the content. This is needed because otherwise that transient async transform is
@@ -755,19 +752,19 @@ ApplyAsyncTransformToScrollbarForContent
// GetTransform already takes the pre- and post-scale into account. Since we
// will apply the pre- and post-scale again when computing the effective
// transform, we must apply the inverses here.
if (ContainerLayer* container = aScrollbar->AsContainerLayer()) {
transform.Scale(1.0f/container->GetPreXScale(),
1.0f/container->GetPreYScale(),
1);
}
- transform = transform * Matrix4x4().Scale(1.0f/aScrollbar->GetPostXScale(),
- 1.0f/aScrollbar->GetPostYScale(),
- 1);
+ transform.PostScale(1.0f/aScrollbar->GetPostXScale(),
+ 1.0f/aScrollbar->GetPostYScale(),
+ 1);
aScrollbar->AsLayerComposite()->SetShadowTransform(transform);
}
static LayerMetricsWrapper
FindScrolledLayerRecursive(Layer* aScrollbar, const LayerMetricsWrapper& aSubtreeRoot)
{
if (LayerIsScrollbarTarget(aSubtreeRoot, aScrollbar)) {
return aSubtreeRoot;
--- a/gfx/layers/composite/AsyncCompositionManager.h
+++ b/gfx/layers/composite/AsyncCompositionManager.h
@@ -32,17 +32,17 @@ struct ViewTransform {
ScreenPoint aTranslation = ScreenPoint())
: mScale(aScale)
, mTranslation(aTranslation)
{}
operator gfx::Matrix4x4() const
{
return
- gfx::Matrix4x4().Scale(mScale.scale, mScale.scale, 1)
+ gfx::Matrix4x4::Scaling(mScale.scale, mScale.scale, 1)
.PostTranslate(mTranslation.x, mTranslation.y, 0);
}
// For convenience, to avoid writing the cumbersome
// "gfx::Matrix4x4(a) * gfx::Matrix4x4(b)".
friend gfx::Matrix4x4 operator*(const ViewTransform& a, const ViewTransform& b) {
return gfx::Matrix4x4(a) * gfx::Matrix4x4(b);
}
--- a/gfx/layers/ipc/CompositableForwarder.h
+++ b/gfx/layers/ipc/CompositableForwarder.h
@@ -189,16 +189,18 @@ public:
TextureClient* aTexture,
nsIntRegion* aRegion) = 0;
virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
PTextureChild* aTexture,
const FenceHandle& aFence) = 0;
+ virtual void SendPendingAsyncMessges() = 0;
+
void IdentifyTextureHost(const TextureFactoryIdentifier& aIdentifier);
virtual int32_t GetMaxTextureSize() const MOZ_OVERRIDE
{
return mTextureFactoryIdentifier.mMaxTextureSize;
}
bool IsOnCompositorSide() const MOZ_OVERRIDE { return false; }
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -550,17 +550,17 @@ ImageBridgeChild::EndTransaction()
texture->SetReleaseFenceHandle(fence);
}
break;
}
default:
NS_RUNTIMEABORT("not reached");
}
}
- SendPendingAsyncMessge();
+ SendPendingAsyncMessges();
}
PImageBridgeChild*
ImageBridgeChild::StartUpInChildProcess(Transport* aTransport,
ProcessId aOtherProcess)
{
MOZ_ASSERT(NS_IsMainThread());
@@ -959,17 +959,17 @@ void ImageBridgeChild::RemoveTexture(Tex
}
}
bool ImageBridgeChild::IsSameProcess() const
{
return OtherProcess() == ipc::kInvalidProcessHandle;
}
-void ImageBridgeChild::SendPendingAsyncMessge()
+void ImageBridgeChild::SendPendingAsyncMessges()
{
if (!IsCreated() ||
mTransactionsToRespond.empty()) {
return;
}
// Send OpReplyDeliverFence messages
InfallibleTArray<AsyncChildMessageData> replies;
replies.SetCapacity(mTransactionsToRespond.size());
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -305,17 +305,17 @@ public:
*/
virtual void DeallocShmem(mozilla::ipc::Shmem& aShmem);
virtual PTextureChild* CreateTexture(const SurfaceDescriptor& aSharedData,
TextureFlags aFlags) MOZ_OVERRIDE;
virtual bool IsSameProcess() const MOZ_OVERRIDE;
- void SendPendingAsyncMessge();
+ virtual void SendPendingAsyncMessges();
void MarkShutDown();
protected:
ImageBridgeChild();
bool DispatchAllocShmemInternal(size_t aSize,
SharedMemory::SharedMemoryType aType,
Shmem* aShmem,
bool aUnsafe);
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -853,16 +853,18 @@ bool
LayerTransactionParent::DeallocPTextureParent(PTextureParent* actor)
{
return TextureHost::DestroyIPDLActor(actor);
}
bool
LayerTransactionParent::RecvChildAsyncMessages(const InfallibleTArray<AsyncChildMessageData>& aMessages)
{
+ AutoLayerTransactionParentAsyncMessageSender autoAsyncMessageSender(this);
+
for (AsyncChildMessageArray::index_type i = 0; i < aMessages.Length(); ++i) {
const AsyncChildMessageData& message = aMessages[i];
switch (message.type()) {
case AsyncChildMessageData::TOpDeliverFenceFromChild: {
const OpDeliverFenceFromChild& op = message.get_OpDeliverFenceFromChild();
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
FenceHandle fence = FenceHandle(op.fence());
@@ -883,16 +885,40 @@ LayerTransactionParent::RecvChildAsyncMe
mozilla::unused << SendParentAsyncMessages(replies);
break;
}
case AsyncChildMessageData::TOpReplyDeliverFence: {
const OpReplyDeliverFence& op = message.get_OpReplyDeliverFence();
TransactionCompleteted(op.transactionId());
break;
}
+ case AsyncChildMessageData::TOpRemoveTextureAsync: {
+ const OpRemoveTextureAsync& op = message.get_OpRemoveTextureAsync();
+ CompositableHost* compositable = CompositableHost::FromIPDLActor(op.compositableParent());
+ RefPtr<TextureHost> tex = TextureHost::AsTextureHost(op.textureParent());
+
+ MOZ_ASSERT(tex.get());
+ compositable->RemoveTextureHost(tex);
+
+ // send FenceHandle if present via ImageBridge.
+ ImageBridgeParent::SendFenceHandleToTrackerIfPresent(
+ GetChildProcessId(),
+ op.holderId(),
+ op.transactionId(),
+ op.textureParent(),
+ compositable);
+
+ // Send message back via PImageBridge.
+ ImageBridgeParent::ReplyRemoveTexture(
+ GetChildProcessId(),
+ OpReplyRemoveTexture(true, // isMain
+ op.holderId(),
+ op.transactionId()));
+ break;
+ }
default:
NS_ERROR("unknown AsyncChildMessageData type");
return false;
}
}
return true;
}
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -487,12 +487,13 @@ union AsyncParentMessageData {
OpDeliverFenceToTracker;
OpReplyDeliverFence;
OpReplyRemoveTexture;
};
union AsyncChildMessageData {
OpDeliverFenceFromChild;
OpReplyDeliverFence;
+ OpRemoveTextureAsync;
};
} // namespace
} // namespace
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -130,16 +130,18 @@ public:
bool Empty() const {
return mCset.empty() && mPaints.empty() && mMutants.empty();
}
bool RotationChanged() const {
return mRotationChanged;
}
bool Finished() const { return !mOpen && Empty(); }
+ bool Opened() const { return mOpen; }
+
EditVector mCset;
EditVector mPaints;
ShadowableLayerSet mMutants;
nsIntRect mTargetBounds;
ScreenRotation mTargetRotation;
dom::ScreenOrientation mTargetOrientation;
bool mSwapRequired;
@@ -467,21 +469,29 @@ ShadowLayerForwarder::RemoveTextureFromC
HoldUntilTransaction(aTexture);
}
void
ShadowLayerForwarder::RemoveTextureFromCompositableAsync(AsyncTransactionTracker* aAsyncTransactionTracker,
CompositableClient* aCompositable,
TextureClient* aTexture)
{
- mTxn->AddEdit(OpRemoveTextureAsync(CompositableClient::GetTrackersHolderId(aCompositable->GetIPDLActor()),
- aAsyncTransactionTracker->GetId(),
- nullptr, aCompositable->GetIPDLActor(),
- nullptr, aTexture->GetIPDLActor()));
- // Hold AsyncTransactionTracker until receving reply
+ if (mTxn->Opened()) {
+ mTxn->AddEdit(OpRemoveTextureAsync(CompositableClient::GetTrackersHolderId(aCompositable->GetIPDLActor()),
+ aAsyncTransactionTracker->GetId(),
+ nullptr, aCompositable->GetIPDLActor(),
+ nullptr, aTexture->GetIPDLActor()));
+ } else {
+ // If the function is called outside of transaction,
+ // OpRemoveTextureAsync message is stored as pending message.
+ mPendingAsyncMessages.push_back(OpRemoveTextureAsync(CompositableClient::GetTrackersHolderId(aCompositable->GetIPDLActor()),
+ aAsyncTransactionTracker->GetId(),
+ nullptr, aCompositable->GetIPDLActor(),
+ nullptr, aTexture->GetIPDLActor()));
+ }
CompositableClient::HoldUntilComplete(aCompositable->GetIPDLActor(),
aAsyncTransactionTracker);
}
bool
ShadowLayerForwarder::InWorkerThread()
{
return GetMessageLoop()->id() == MessageLoop::current()->id();
@@ -816,50 +826,61 @@ void ShadowLayerForwarder::SetShadowMana
}
void ShadowLayerForwarder::StopReceiveAsyncParentMessge()
{
if (!HasShadowManager() ||
!mShadowManager->IPCOpen()) {
return;
}
- SendPendingAsyncMessge();
+ SendPendingAsyncMessges();
mShadowManager->SetForwarder(nullptr);
}
void ShadowLayerForwarder::ClearCachedResources()
{
if (!HasShadowManager() ||
!mShadowManager->IPCOpen()) {
return;
}
- SendPendingAsyncMessge();
+ SendPendingAsyncMessges();
mShadowManager->SendClearCachedResources();
}
void ShadowLayerForwarder::Composite()
{
if (!HasShadowManager() ||
!mShadowManager->IPCOpen()) {
return;
}
mShadowManager->SendForceComposite();
}
-void ShadowLayerForwarder::SendPendingAsyncMessge()
+void ShadowLayerForwarder::SendPendingAsyncMessges()
{
if (!HasShadowManager() ||
- !mShadowManager->IPCOpen() ||
- mTransactionsToRespond.empty()) {
+ !mShadowManager->IPCOpen()) {
+ mTransactionsToRespond.clear();
+ mPendingAsyncMessages.clear();
return;
}
- // Send OpReplyDeliverFence messages
+
+ if (mTransactionsToRespond.empty() && mPendingAsyncMessages.empty()) {
+ return;
+ }
+
InfallibleTArray<AsyncChildMessageData> replies;
replies.SetCapacity(mTransactionsToRespond.size());
+ // Prepare OpReplyDeliverFence messages.
for (size_t i = 0; i < mTransactionsToRespond.size(); i++) {
replies.AppendElement(OpReplyDeliverFence(mTransactionsToRespond[i]));
}
mTransactionsToRespond.clear();
+ // Prepare pending messages.
+ for (size_t i = 0; i < mPendingAsyncMessages.size(); i++) {
+ replies.AppendElement(mPendingAsyncMessages[i]);
+ }
+ mPendingAsyncMessages.clear();
mShadowManager->SendChildAsyncMessages(replies);
}
} // namespace layers
} // namespace mozilla
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -314,17 +314,17 @@ public:
void SetShadowManager(PLayerTransactionChild* aShadowManager);
void StopReceiveAsyncParentMessge();
void ClearCachedResources();
void Composite();
- void SendPendingAsyncMessge();
+ virtual void SendPendingAsyncMessges();
/**
* True if this is forwarding to a LayerManagerComposite.
*/
bool HasShadowManager() const { return !!mShadowManager; }
LayerTransactionChild* GetShadowManager() const { return mShadowManager.get(); }
virtual void WindowOverlayChanged() { mWindowOverlayChanged = true; }
@@ -398,16 +398,17 @@ protected:
bool InWorkerThread();
RefPtr<LayerTransactionChild> mShadowManager;
private:
Transaction* mTxn;
+ std::vector<AsyncChildMessageData> mPendingAsyncMessages;
DiagnosticTypes mDiagnosticTypes;
bool mIsFirstPaint;
bool mWindowOverlayChanged;
};
class CompositableClient;
/**
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -1696,17 +1696,17 @@ protected:
nsIntRegion(nsIntRect(0,0,100,100)),
nsIntRegion(nsIntRect(10,10,40,40)),
nsIntRegion(nsIntRect(10,60,40,40)),
nsIntRegion(nsIntRect(10,60,40,40)),
};
Matrix4x4 transforms[] = {
Matrix4x4(),
Matrix4x4(),
- Matrix4x4().Scale(2, 1, 1),
+ Matrix4x4::Scaling(2, 1, 1),
Matrix4x4(),
};
root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, lm, layers);
SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 200, 200));
SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 1, CSSRect(0, 0, 80, 80));
SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID + 2, CSSRect(0, 0, 80, 80));
}
--- a/gfx/tests/unit/xpcshell.ini
+++ b/gfx/tests/unit/xpcshell.ini
@@ -1,5 +1,6 @@
[DEFAULT]
head =
tail =
+skip-if = toolkit == 'gonk'
[test_nsIScriptableRegion.js]
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -1138,32 +1138,16 @@ gfxContext::PopGroupToSource()
Matrix mat = mTransform;
mat.Invert();
mat.PreTranslate(deviceOffset.x, deviceOffset.y); // device offset translation
CurrentState().surfTransform = mat;
}
-bool
-gfxContext::PointInFill(const gfxPoint& pt)
-{
- EnsurePath();
- return mPath->ContainsPoint(ToPoint(pt), Matrix());
-}
-
-bool
-gfxContext::PointInStroke(const gfxPoint& pt)
-{
- EnsurePath();
- return mPath->StrokeContainsPoint(CurrentState().strokeOptions,
- ToPoint(pt),
- Matrix());
-}
-
void
gfxContext::RoundedRectangle(const gfxRect& rect,
const gfxCornerSizes& corners,
bool draw_clockwise)
{
//
// For CW drawing, this looks like:
//
--- a/gfx/thebes/gfxContext.h
+++ b/gfx/thebes/gfxContext.h
@@ -586,22 +586,16 @@ public:
*/
void PushGroupAndCopyBackground(gfxContentType content = gfxContentType::COLOR);
already_AddRefed<gfxPattern> PopGroup();
void PopGroupToSource();
mozilla::TemporaryRef<mozilla::gfx::SourceSurface>
PopGroupToSurface(mozilla::gfx::Matrix* aMatrix);
- /**
- ** Hit Testing - check if given point is in the current path
- **/
- bool PointInFill(const gfxPoint& pt);
- bool PointInStroke(const gfxPoint& pt);
-
mozilla::gfx::Point GetDeviceOffset() const;
/**
** Flags
**/
enum {
/* If this flag is set, operators other than CLEAR, SOURCE, or
--- a/image/test/unit/xpcshell.ini
+++ b/image/test/unit/xpcshell.ini
@@ -1,11 +1,12 @@
[DEFAULT]
head =
tail =
+skip-if = toolkit == 'gonk'
support-files =
async_load_tests.js
bug413512.ico
bug815359.ico
image1.png
image1png16x16.jpg
image1png64x64.jpg
image2.jpg
--- a/intl/locale/tests/unit/xpcshell.ini
+++ b/intl/locale/tests/unit/xpcshell.ini
@@ -1,11 +1,12 @@
[DEFAULT]
head =
tail =
+skip-if = toolkit == 'gonk'
[test_bug22310.js]
run-if = toolkit == "windows" || toolkit == "cocoa"
[test_bug371611.js]
[test_bug374040.js]
skip-if = toolkit == "windows" || toolkit == "cocoa"
--- a/intl/strres/tests/unit/xpcshell.ini
+++ b/intl/strres/tests/unit/xpcshell.ini
@@ -1,9 +1,10 @@
[DEFAULT]
head =
tail =
+skip-if = toolkit == 'gonk'
support-files =
397093.properties
strres.properties
[test_bug378839.js]
[test_bug397093.js]
--- a/intl/uconv/tests/unit/xpcshell.ini
+++ b/intl/uconv/tests/unit/xpcshell.ini
@@ -1,11 +1,12 @@
[DEFAULT]
head =
tail =
+skip-if = toolkit == 'gonk'
support-files =
CharsetConversionTests.js
hangulTestStrings.js
data/unicode-conversion.utf16.txt
data/unicode-conversion.utf16be.txt
data/unicode-conversion.utf16le.txt
data/unicode-conversion.utf8.txt
--- a/intl/unicharutil/tests/unit/xpcshell.ini
+++ b/intl/unicharutil/tests/unit/xpcshell.ini
@@ -1,5 +1,6 @@
[DEFAULT]
head =
tail =
+skip-if = toolkit == 'gonk'
[test_bug_427350_1.js]
--- a/ipc/chromium/src/chrome/common/ipc_message.h
+++ b/ipc/chromium/src/chrome/common/ipc_message.h
@@ -48,19 +48,19 @@ class Message : public Pickle {
// Sends the given IPC message. The implementor takes ownership of the
// given Message regardless of whether or not this method succeeds. This
// is done to make this method easier to use. Returns true on success and
// false otherwise.
virtual bool Send(Message* msg) = 0;
};
enum PriorityValue {
- PRIORITY_LOW = 1,
- PRIORITY_NORMAL,
- PRIORITY_HIGH
+ PRIORITY_NORMAL = 1,
+ PRIORITY_HIGH = 2,
+ PRIORITY_URGENT = 3
};
enum MessageCompression {
COMPRESSION_NONE,
COMPRESSION_ENABLED
};
virtual ~Message();
@@ -80,36 +80,31 @@ class Message : public Pickle {
Message(const Message& other);
Message& operator=(const Message& other);
PriorityValue priority() const {
return static_cast<PriorityValue>(header()->flags & PRIORITY_MASK);
}
+ void set_priority(int prio) {
+ DCHECK((prio & ~PRIORITY_MASK) == 0);
+ header()->flags = (header()->flags & ~PRIORITY_MASK) | prio;
+ }
+
// True if this is a synchronous message.
bool is_sync() const {
return (header()->flags & SYNC_BIT) != 0;
}
// True if this is a synchronous message.
bool is_interrupt() const {
return (header()->flags & INTERRUPT_BIT) != 0;
}
- // True if this is an urgent message.
- bool is_urgent() const {
- return (header()->flags & URGENT_BIT) != 0;
- }
-
- // True if this is an RPC message.
- bool is_rpc() const {
- return (header()->flags & RPC_BIT) != 0;
- }
-
// True if compression is enabled for this message.
bool compress() const {
return (header()->flags & COMPRESS_BIT) != 0;
}
// Set this on a reply to a synchronous message.
void set_reply() {
header()->flags |= REPLY_BIT;
@@ -291,41 +286,31 @@ class Message : public Pickle {
void set_sync() {
header()->flags |= SYNC_BIT;
}
void set_interrupt() {
header()->flags |= INTERRUPT_BIT;
}
- void set_urgent() {
- header()->flags |= URGENT_BIT;
- }
-
- void set_rpc() {
- header()->flags |= RPC_BIT;
- }
-
#if !defined(OS_MACOSX)
protected:
#endif
// flags
enum {
PRIORITY_MASK = 0x0003,
SYNC_BIT = 0x0004,
REPLY_BIT = 0x0008,
REPLY_ERROR_BIT = 0x0010,
UNBLOCK_BIT = 0x0020,
PUMPING_MSGS_BIT= 0x0040,
HAS_SENT_TIME_BIT = 0x0080,
INTERRUPT_BIT = 0x0100,
COMPRESS_BIT = 0x0200,
- URGENT_BIT = 0x0400,
- RPC_BIT = 0x0800
};
struct Header : Pickle::Header {
int32_t routing; // ID of the view that this message is destined for
msgid_t type; // specifies the user-defined message type
uint32_t flags; // specifies control flags for the message
#if defined(OS_POSIX)
uint32_t num_fds; // the number of descriptors included with this message
--- a/ipc/glue/InputStreamParams.ipdlh
+++ b/ipc/glue/InputStreamParams.ipdlh
@@ -2,16 +2,19 @@
* 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/. */
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
include protocol PBlob;
include protocol PFileDescriptorSet;
+using struct nsID
+ from "nsID.h";
+
namespace mozilla {
namespace ipc {
struct StringInputStreamParams
{
nsCString data;
};
@@ -34,17 +37,17 @@ struct MultiplexInputStreamParams
InputStreamParams[] streams;
uint32_t currentStream;
nsresult status;
bool startedReadingCurrent;
};
struct RemoteInputStreamParams
{
- PBlob remoteBlob;
+ nsID id;
};
// XXX This may only be used for same-process inter-thread communication! The
// value should be reinterpret_cast'd to nsIInputStream. It carries a
// reference.
struct SameProcessInputStreamParams
{
intptr_t addRefedInputStream;
--- a/ipc/glue/InputStreamUtils.cpp
+++ b/ipc/glue/InputStreamUtils.cpp
@@ -102,27 +102,23 @@ DeserializeInputStream(const InputStream
case InputStreamParams::TMultiplexInputStreamParams:
serializable = do_CreateInstance(kMultiplexInputStreamCID);
break;
// When the input stream already exists in this process, all we need to do
// is retrieve the original instead of sending any data over the wire.
case InputStreamParams::TRemoteInputStreamParams: {
- const RemoteInputStreamParams& params =
- aParams.get_RemoteInputStreamParams();
+ if (NS_WARN_IF(XRE_GetProcessType() != GeckoProcessType_Default)) {
+ return nullptr;
+ }
- nsRefPtr<DOMFileImpl> blobImpl;
- if (params.remoteBlobParent()) {
- blobImpl =
- static_cast<BlobParent*>(params.remoteBlobParent())->GetBlobImpl();
- } else {
- blobImpl =
- static_cast<BlobChild*>(params.remoteBlobChild())->GetBlobImpl();
- }
+ const nsID& id = aParams.get_RemoteInputStreamParams().id();
+
+ nsRefPtr<DOMFileImpl> blobImpl = BlobParent::GetBlobImplForID(id);
MOZ_ASSERT(blobImpl, "Invalid blob contents");
// If fetching the internal stream fails, we ignore it and return a
// null stream.
nsCOMPtr<nsIInputStream> stream;
nsresult rv = blobImpl->GetInternalStream(getter_AddRefs(stream));
if (NS_FAILED(rv) || !stream) {
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -15,16 +15,72 @@
#include "nsISupportsImpl.h"
#include "nsContentUtils.h"
#include "prprf.h"
// Undo the damage done by mozzconf.h
#undef compress
+/*
+ * IPC design:
+ *
+ * There are three kinds of messages: async, sync, and intr. Sync and intr
+ * messages are blocking. Only intr and high-priority sync messages can nest.
+ *
+ * Terminology: To dispatch a message Foo is to run the RecvFoo code for
+ * it. This is also called "handling" the message.
+ *
+ * Sync messages have priorities while async and intr messages always have
+ * normal priority. The three possible priorities are normal, high, and urgent.
+ * The intended uses of these priorities are:
+ * NORMAL - most messages.
+ * HIGH - CPOW-related messages, which can go in either direction.
+ * URGENT - messages where we don't want to dispatch
+ * incoming CPOWs while waiting for the response.
+ *
+ * To avoid jank, the parent process is not allowed to send sync messages of
+ * normal priority. The parent also is not allowed to send urgent messages at
+ * all. When a process is waiting for a response to a sync message M0, it will
+ * dispatch an incoming message M if:
+ * 1. M has a higher priority than M0, or
+ * 2. if M has the same priority as M0 and we're in the child, or
+ * 3. if M has the same priority as M0 and it was sent by the other side
+ while dispatching M0 (nesting).
+ * The idea is that higher priority messages should take precendence, and we
+ * also want to allow nesting. The purpose of rule 2 is to handle a race where
+ * both processes send to each other simultaneously. In this case, we resolve
+ * the race in favor of the parent (so the child dispatches first).
+ *
+ * Sync messages satisfy the following properties:
+ * A. When waiting for a response to a sync message, we won't dispatch any
+ * messages of lower priority.
+ * B. Sync messages of the same priority will be dispatched roughly in the
+ * order they were sent. The exception is when the parent and child send
+ * sync messages to each other simulataneously. In this case, the parent's
+ * message is dispatched first. While it is dispatched, the child may send
+ * further nested messages, and these messages may be dispatched before the
+ * child's original message. We can consider ordering to be preserved here
+ * because we pretend that the child's original message wasn't sent until
+ * after the parent's message is finished being dispatched.
+ *
+ * Intr messages are blocking but not prioritized. While waiting for an intr
+ * response, all incoming messages are dispatched until a response is
+ * received. Intr messages also can be nested. When two intr messages race with
+ * each other, a similar scheme is used to ensure that one side wins. The
+ * winning side is chosen based on the message type.
+ *
+ * Intr messages differ from sync messages in that, while sending an intr
+ * message, we may dispatch an async message. This causes some additional
+ * complexity. One issue is that replies can be received out of order. It's also
+ * more difficult to determine whether one message is nested inside
+ * another. Consequently, intr handling uses mOutOfTurnReplies and
+ * mRemoteStackDepthGuess, which are not needed for sync messages.
+ */
+
using namespace mozilla;
using namespace std;
using mozilla::MonitorAutoLock;
using mozilla::MonitorAutoUnlock;
template<>
struct RunnableMethodTraits<mozilla::ipc::MessageChannel>
@@ -34,17 +90,17 @@ struct RunnableMethodTraits<mozilla::ipc
};
#define IPC_ASSERT(_cond, ...) \
do { \
if (!(_cond)) \
DebugAbort(__FILE__, __LINE__, #_cond,## __VA_ARGS__); \
} while (0)
-static uintptr_t gDispatchingUrgentMessageCount;
+static bool gParentIsBlocked;
namespace mozilla {
namespace ipc {
const int32_t MessageChannel::kNoTimeout = INT32_MIN;
// static
bool MessageChannel::sIsPumpingMessages = false;
@@ -190,19 +246,19 @@ private:
CxxStackFrame(const CxxStackFrame&) MOZ_DELETE;
CxxStackFrame& operator=(const CxxStackFrame&) MOZ_DELETE;
};
namespace {
class MOZ_STACK_CLASS MaybeScriptBlocker {
public:
- explicit MaybeScriptBlocker(MessageChannel *aChannel
+ explicit MaybeScriptBlocker(MessageChannel *aChannel, bool aBlock
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
- : mBlocked(aChannel->ShouldBlockScripts())
+ : mBlocked(aChannel->ShouldBlockScripts() && aBlock)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
if (mBlocked) {
nsContentUtils::AddScriptBlocker();
}
}
~MaybeScriptBlocker() {
if (mBlocked) {
@@ -222,22 +278,21 @@ MessageChannel::MessageChannel(MessageLi
mSide(UnknownSide),
mLink(nullptr),
mWorkerLoop(nullptr),
mChannelErrorTask(nullptr),
mWorkerLoopID(-1),
mTimeoutMs(kNoTimeout),
mInTimeoutSecondHalf(false),
mNextSeqno(0),
- mPendingSyncReplies(0),
- mPendingUrgentReplies(0),
- mPendingRPCReplies(0),
- mCurrentRPCTransaction(0),
+ mAwaitingSyncReply(false),
+ mAwaitingSyncReplyPriority(0),
mDispatchingSyncMessage(false),
- mDispatchingUrgentMessageCount(0),
+ mDispatchingSyncMessagePriority(0),
+ mCurrentTransaction(0),
mRemoteStackDepthGuess(false),
mSawInterruptOutMsg(false),
mAbortOnError(false),
mBlockScripts(false),
mFlags(REQUIRE_DEFAULT),
mPeerPidSet(false),
mPeerPid(-1)
{
@@ -322,18 +377,17 @@ MessageChannel::Clear()
if (mChannelErrorTask) {
mChannelErrorTask->Cancel();
mChannelErrorTask = nullptr;
}
// Free up any memory used by pending messages.
mPending.clear();
- mPendingUrgentRequest = nullptr;
- mPendingRPCCall = nullptr;
+ mRecvd = nullptr;
mOutOfTurnReplies.clear();
while (!mDeferred.empty()) {
mDeferred.pop();
}
}
bool
MessageChannel::Open(Transport* aTransport, MessageLoop* aIOLoop, Side aSide)
@@ -483,118 +537,117 @@ MessageChannel::MaybeInterceptSpecialIOM
printf("NOTE: %s process received `Goodbye', closing down\n",
(mSide == ChildSide) ? "child" : "parent");
}
return true;
}
return false;
}
+bool
+MessageChannel::ShouldDeferMessage(const Message& aMsg)
+{
+ // Never defer messages that have the highest priority, even async
+ // ones. This is safe because only the child can send these messages, so
+ // they can never nest.
+ if (aMsg.priority() == IPC::Message::PRIORITY_URGENT) {
+ MOZ_ASSERT(mSide == ParentSide);
+ return false;
+ }
+
+ // Unless they're urgent, we always defer async messages.
+ if (!aMsg.is_sync()) {
+ MOZ_ASSERT(aMsg.priority() == IPC::Message::PRIORITY_NORMAL);
+ return true;
+ }
+
+ int msgPrio = aMsg.priority();
+ int waitingPrio = AwaitingSyncReplyPriority();
+
+ // Always defer if the priority of the incoming message is less than the
+ // priority of the message we're awaiting.
+ if (msgPrio < waitingPrio)
+ return true;
+
+ // Never defer if the message has strictly greater priority.
+ if (msgPrio > waitingPrio)
+ return false;
+
+ // When both sides send sync messages of the same priority, we resolve the
+ // race by dispatching in the child and deferring the incoming message in
+ // the parent. However, the parent still needs to dispatch nested sync
+ // messages.
+ //
+ // Deferring in the parent only sort of breaks message ordering. When the
+ // child's message comes in, we can pretend the child hasn't quite
+ // finished sending it yet. Since the message is sync, we know that the
+ // child hasn't moved on yet.
+ return mSide == ParentSide && aMsg.transaction_id() != mCurrentTransaction;
+}
+
void
MessageChannel::OnMessageReceivedFromLink(const Message& aMsg)
{
AssertLinkThread();
mMonitor->AssertCurrentThreadOwns();
if (MaybeInterceptSpecialIOMessage(aMsg))
return;
- // Regardless of the Interrupt stack, if we're awaiting a sync or urgent reply,
+ // Regardless of the Interrupt stack, if we're awaiting a sync reply,
// we know that it needs to be immediately handled to unblock us.
- if ((AwaitingSyncReply() && aMsg.is_sync()) ||
- (AwaitingUrgentReply() && aMsg.is_urgent()) ||
- (AwaitingRPCReply() && aMsg.is_rpc()))
- {
+ if (AwaitingSyncReply() && aMsg.is_sync() && aMsg.is_reply()) {
+ MOZ_ASSERT(!mRecvd);
mRecvd = new Message(aMsg);
NotifyWorkerThread();
return;
}
- // Urgent messages cannot be compressed.
- MOZ_ASSERT(!aMsg.compress() || !aMsg.is_urgent());
+ // Prioritized messages cannot be compressed.
+ MOZ_ASSERT(!aMsg.compress() || aMsg.priority() == IPC::Message::PRIORITY_NORMAL);
bool compress = (aMsg.compress() && !mPending.empty() &&
mPending.back().type() == aMsg.type() &&
mPending.back().routing_id() == aMsg.routing_id());
if (compress) {
// This message type has compression enabled, and the back of the
// queue was the same message type and routed to the same destination.
// Replace it with the newer message.
MOZ_ASSERT(mPending.back().compress());
mPending.pop_back();
}
bool shouldWakeUp = AwaitingInterruptReply() ||
- // Allow incoming RPCs to be processed inside an urgent message.
- (AwaitingUrgentReply() && aMsg.is_rpc()) ||
- // Always process urgent messages while blocked.
- ((AwaitingSyncReply() || AwaitingRPCReply()) && aMsg.is_urgent());
+ (AwaitingSyncReply() && !ShouldDeferMessage(aMsg));
- // There are four cases we're concerned about, relating to the state of the
+ // There are three cases we're concerned about, relating to the state of the
// main thread:
//
- // (1) We are waiting on a sync|rpc reply - main thread is blocked on the
+ // (1) We are waiting on a sync reply - main thread is blocked on the
// IPC monitor.
// - If the message is high priority, we wake up the main thread to
- // deliver the message. Otherwise, we leave it in the mPending queue,
- // posting a task to the main event loop, where it will be processed
- // once the synchronous reply has been received.
+ // deliver the message depending on ShouldDeferMessage. Otherwise, we
+ // leave it in the mPending queue, posting a task to the main event
+ // loop, where it will be processed once the synchronous reply has been
+ // received.
//
// (2) We are waiting on an Interrupt reply - main thread is blocked on the
// IPC monitor.
// - Always notify and wake up the main thread.
//
// (3) We are not waiting on a reply.
// - We post a task to the main event loop.
//
// Note that, we may notify the main thread even though the monitor is not
// blocked. This is okay, since we always check for pending events before
// blocking again.
- if (shouldWakeUp && (AwaitingUrgentReply() && aMsg.is_rpc())) {
- // If we're receiving an RPC message while blocked on an urgent message,
- // we must defer any messages that were not sent as part of the child
- // answering the urgent message.
- //
- // We must also be sure that we will not accidentally defer any RPC
- // message that was sent while answering an urgent message. Otherwise,
- // we will deadlock.
- //
- // On the parent side, the current transaction can only transition from 0
- // to an ID, either by us issuing an urgent request while not blocked, or
- // by receiving an RPC request while not blocked. When we unblock, the
- // current transaction is reset to 0.
- //
- // When the child side receives an urgent message, any RPC messages sent
- // before issuing the urgent reply will carry the urgent message's
- // transaction ID.
- //
- // Since AwaitingUrgentReply() implies we are blocked, it also implies
- // that we are within a transaction that will not change until we are
- // completely unblocked (i.e, the transaction has completed).
- if (aMsg.transaction_id() != mCurrentRPCTransaction)
- shouldWakeUp = false;
- }
-
- if (aMsg.is_urgent()) {
- MOZ_ASSERT(!mPendingUrgentRequest);
- mPendingUrgentRequest = new Message(aMsg);
- } else if (aMsg.is_rpc() && shouldWakeUp) {
- // Only use this slot if we need to wake up for an RPC call. Otherwise
- // we treat it like a normal async or sync message.
- MOZ_ASSERT(!mPendingRPCCall);
- mPendingRPCCall = new Message(aMsg);
- } else {
- mPending.push_back(aMsg);
- }
+ mPending.push_back(aMsg);
if (shouldWakeUp) {
- // Always wake up Interrupt waiters, sync waiters for urgent messages,
- // RPC waiters for urgent messages, and urgent waiters for RPCs in the
- // same transaction.
NotifyWorkerThread();
} else {
// Worker thread is either not blocked on a reply, or this is an
// incoming Interrupt that raced with outgoing sync, and needs to be
// deferred to a later event-loop iteration.
if (!compress) {
// If we compressed away the previous message, we'll re-use
// its pending task.
@@ -602,103 +655,64 @@ MessageChannel::OnMessageReceivedFromLin
}
}
}
bool
MessageChannel::Send(Message* aMsg, Message* aReply)
{
// See comment in DispatchUrgentMessage.
- MaybeScriptBlocker scriptBlocker(this);
+ MaybeScriptBlocker scriptBlocker(this, true);
// Sanity checks.
AssertWorkerThread();
mMonitor->AssertNotCurrentThreadOwns();
#ifdef OS_WIN
SyncStackFrame frame(this, false);
#endif
CxxStackFrame f(*this, OUT_MESSAGE, aMsg);
MonitorAutoLock lock(*mMonitor);
IPC_ASSERT(aMsg->is_sync(), "can only Send() sync messages here");
- IPC_ASSERT(!DispatchingSyncMessage(), "violation of sync handler invariant");
- IPC_ASSERT(!DispatchingUrgentMessage(), "sync messages forbidden while handling urgent message");
- IPC_ASSERT(!AwaitingSyncReply(), "nested sync messages are not supported");
+ IPC_ASSERT(aMsg->priority() >= DispatchingSyncMessagePriority(),
+ "can't send sync message of a lesser priority than what's being dispatched");
+ IPC_ASSERT(mAwaitingSyncReplyPriority <= aMsg->priority(),
+ "nested sync message sends must be of increasing priority");
- AutoEnterPendingReply replies(mPendingSyncReplies);
+ AutoSetValue<bool> replies(mAwaitingSyncReply, true);
+ AutoSetValue<int> prio(mAwaitingSyncReplyPriority, aMsg->priority());
+ AutoEnterTransaction transact(this);
+ aMsg->set_transaction_id(mCurrentTransaction);
+
if (!SendAndWait(aMsg, aReply))
return false;
NS_ABORT_IF_FALSE(aReply->is_sync(), "reply is not sync");
return true;
}
-bool
-MessageChannel::UrgentCall(Message* aMsg, Message* aReply)
+struct AutoDeferMessages
{
- // See comment in DispatchUrgentMessage.
- MaybeScriptBlocker scriptBlocker(this);
-
- AssertWorkerThread();
- mMonitor->AssertNotCurrentThreadOwns();
- IPC_ASSERT(mSide == ParentSide, "cannot send urgent requests from child");
-
-#ifdef OS_WIN
- SyncStackFrame frame(this, false);
-#endif
+ typedef IPC::Message Message;
- CxxStackFrame f(*this, OUT_MESSAGE, aMsg);
-
- MonitorAutoLock lock(*mMonitor);
-
- IPC_ASSERT(!AwaitingInterruptReply(), "urgent calls cannot be issued within Interrupt calls");
- IPC_ASSERT(!AwaitingSyncReply(), "urgent calls cannot be issued within sync sends");
-
- AutoEnterRPCTransaction transact(this);
- aMsg->set_transaction_id(mCurrentRPCTransaction);
-
- AutoEnterPendingReply replies(mPendingUrgentReplies);
- if (!SendAndWait(aMsg, aReply))
- return false;
+ std::deque<Message>& mQueue;
+ mozilla::Vector<Message> mDeferred;
- NS_ABORT_IF_FALSE(aReply->is_urgent(), "reply is not urgent");
- return true;
-}
-
-bool
-MessageChannel::RPCCall(Message* aMsg, Message* aReply)
-{
- // See comment in DispatchUrgentMessage.
- MaybeScriptBlocker scriptBlocker(this);
-
- AssertWorkerThread();
- mMonitor->AssertNotCurrentThreadOwns();
- IPC_ASSERT(mSide == ChildSide, "cannot send rpc messages from parent");
+ AutoDeferMessages(std::deque<Message>& queue) : mQueue(queue) {}
+ ~AutoDeferMessages() {
+ mQueue.insert(mQueue.begin(), mDeferred.begin(), mDeferred.end());
+ }
-#ifdef OS_WIN
- SyncStackFrame frame(this, false);
-#endif
-
- CxxStackFrame f(*this, OUT_MESSAGE, aMsg);
-
- MonitorAutoLock lock(*mMonitor);
-
- AutoEnterRPCTransaction transact(this);
- aMsg->set_transaction_id(mCurrentRPCTransaction);
-
- AutoEnterPendingReply replies(mPendingRPCReplies);
- if (!SendAndWait(aMsg, aReply))
- return false;
-
- NS_ABORT_IF_FALSE(aReply->is_rpc(), "expected rpc reply");
- return true;
-}
+ void Defer(Message aMsg) {
+ mDeferred.append(aMsg);
+ }
+};
bool
MessageChannel::SendAndWait(Message* aMsg, Message* aReply)
{
mMonitor->AssertCurrentThreadOwns();
nsAutoPtr<Message> msg(aMsg);
@@ -709,80 +723,62 @@ MessageChannel::SendAndWait(Message* aMs
msg->set_seqno(NextSeqno());
DebugOnly<int32_t> replySeqno = msg->seqno();
DebugOnly<msgid_t> replyType = msg->type() + 1;
mLink->SendMessage(msg.forget());
- while (true) {
- // Wait for an event to occur.
- while (true) {
- if (mRecvd || mPendingUrgentRequest || mPendingRPCCall)
- break;
-
- bool maybeTimedOut = !WaitForSyncNotify();
+ AutoDeferMessages defer(mPending);
- if (!Connected()) {
- ReportConnectionError("MessageChannel::SendAndWait");
- return false;
- }
-
- if (maybeTimedOut && !ShouldContinueFromTimeout())
- return false;
+ while (true) {
+ while (!mPending.empty()) {
+ Message msg = mPending.front();
+ mPending.pop_front();
+ if (ShouldDeferMessage(msg))
+ defer.Defer(msg);
+ else
+ ProcessPendingRequest(msg);
}
- // We need to make sure that all messages deposited in mPendingRPCCall
- // and mPendingUrgentRequest are dispatched before we leave this
- // function. Otherwise, there's nothing to wake us up and force us to
- // dispatch them.
- while (mPendingUrgentRequest) {
- if (!ProcessPendingUrgentRequest())
- return false;
- }
-
- while (mPendingRPCCall) {
- if (!ProcessPendingRPCCall())
- return false;
- }
-
+ // See if we've received a reply.
if (mRecvd) {
- NS_ABORT_IF_FALSE(mRecvd->is_reply(), "expected reply");
+ MOZ_ASSERT(mRecvd->is_reply(), "expected reply");
if (mRecvd->is_reply_error()) {
mRecvd = nullptr;
return false;
}
- NS_ABORT_IF_FALSE(mRecvd->type() == replyType, "wrong reply type");
- NS_ABORT_IF_FALSE(mRecvd->seqno() == replySeqno, "wrong sequence number");
+ MOZ_ASSERT(mRecvd->type() == replyType, "wrong reply type");
+ MOZ_ASSERT(mRecvd->seqno() == replySeqno);
*aReply = *mRecvd;
mRecvd = nullptr;
return true;
}
+
+ bool maybeTimedOut = !WaitForSyncNotify();
+
+ if (!Connected()) {
+ ReportConnectionError("MessageChannel::SendAndWait");
+ return false;
+ }
+
+ if (maybeTimedOut && !ShouldContinueFromTimeout())
+ return false;
}
return true;
}
bool
MessageChannel::Call(Message* aMsg, Message* aReply)
{
- if (aMsg->is_urgent())
- return UrgentCall(aMsg, aReply);
- if (aMsg->is_rpc())
- return RPCCall(aMsg, aReply);
- return InterruptCall(aMsg, aReply);
-}
-
-bool
-MessageChannel::InterruptCall(Message* aMsg, Message* aReply)
-{
AssertWorkerThread();
mMonitor->AssertNotCurrentThreadOwns();
#ifdef OS_WIN
SyncStackFrame frame(this, true);
#endif
// This must come before MonitorAutoLock, as its destructor acquires the
@@ -791,39 +787,38 @@ MessageChannel::InterruptCall(Message* a
MonitorAutoLock lock(*mMonitor);
if (!Connected()) {
ReportConnectionError("MessageChannel::Call");
return false;
}
// Sanity checks.
- IPC_ASSERT(!AwaitingSyncReply() && !AwaitingUrgentReply(),
- "cannot issue Interrupt call whiel blocked on sync or urgent");
- IPC_ASSERT(!DispatchingSyncMessage() || aMsg->priority() == IPC::Message::PRIORITY_HIGH,
+ IPC_ASSERT(!AwaitingSyncReply(),
+ "cannot issue Interrupt call while blocked on sync request");
+ IPC_ASSERT(!DispatchingSyncMessage(),
"violation of sync handler invariant");
IPC_ASSERT(aMsg->is_interrupt(), "can only Call() Interrupt messages here");
-
nsAutoPtr<Message> msg(aMsg);
msg->set_seqno(NextSeqno());
msg->set_interrupt_remote_stack_depth_guess(mRemoteStackDepthGuess);
msg->set_interrupt_local_stack_depth(1 + InterruptStackDepth());
mInterruptStack.push(*msg);
mLink->SendMessage(msg.forget());
while (true) {
// if a handler invoked by *Dispatch*() spun a nested event
// loop, and the connection was broken during that loop, we
// might have already processed the OnError event. if so,
// trying another loop iteration will be futile because
// channel state will have been cleared
if (!Connected()) {
- ReportConnectionError("MessageChannel::InterruptCall");
+ ReportConnectionError("MessageChannel::Call");
return false;
}
// Now might be the time to process a message deferred because of race
// resolution.
MaybeUndeferIncall();
// Wait for an event to occur.
@@ -840,24 +835,18 @@ MessageChannel::InterruptCall(Message* a
if (maybeTimedOut && !ShouldContinueFromTimeout())
return false;
}
Message recvd;
MessageMap::iterator it;
- if (mPendingUrgentRequest) {
- recvd = *mPendingUrgentRequest;
- mPendingUrgentRequest = nullptr;
- } else if (mPendingRPCCall) {
- recvd = *mPendingRPCCall;
- mPendingRPCCall = nullptr;
- } else if ((it = mOutOfTurnReplies.find(mInterruptStack.top().seqno()))
- != mOutOfTurnReplies.end())
+ if ((it = mOutOfTurnReplies.find(mInterruptStack.top().seqno()))
+ != mOutOfTurnReplies.end())
{
recvd = it->second;
mOutOfTurnReplies.erase(it);
} else if (!mPending.empty()) {
recvd = mPending.front();
mPending.pop_front();
} else {
// because of subtleties with nested event loops, it's possible
@@ -865,21 +854,18 @@ MessageChannel::InterruptCall(Message* a
// deferred in-call that needs to be processed. either way, we
// won't break the inner while loop again until something new
// happens.
continue;
}
// If the message is not Interrupt, we can dispatch it as normal.
if (!recvd.is_interrupt()) {
- // Other side should be blocked.
- IPC_ASSERT(!recvd.is_sync() || mPending.empty(), "other side should be blocked");
-
{
- AutoEnterRPCTransaction transaction(this, &recvd);
+ AutoEnterTransaction transaction(this, &recvd);
MonitorAutoUnlock unlock(*mMonitor);
CxxStackFrame frame(*this, IN_MESSAGE, &recvd);
DispatchMessage(recvd);
}
if (!Connected()) {
ReportConnectionError("MessageChannel::DispatchMessage");
return false;
}
@@ -950,90 +936,47 @@ bool
MessageChannel::InterruptEventOccurred()
{
AssertWorkerThread();
mMonitor->AssertCurrentThreadOwns();
IPC_ASSERT(InterruptStackDepth() > 0, "not in wait loop");
return (!Connected() ||
!mPending.empty() ||
- mPendingUrgentRequest ||
- mPendingRPCCall ||
(!mOutOfTurnReplies.empty() &&
mOutOfTurnReplies.find(mInterruptStack.top().seqno()) !=
mOutOfTurnReplies.end()));
}
bool
-MessageChannel::ProcessPendingUrgentRequest()
+MessageChannel::ProcessPendingRequest(Message aUrgent)
{
AssertWorkerThread();
mMonitor->AssertCurrentThreadOwns();
// Note that it is possible we could have sent a sync message at
// the same time the parent process sent an urgent message, and
// therefore mPendingUrgentRequest is set *and* mRecvd is set as
// well, because the link thread received both before the worker
// thread woke up.
//
// In this case, we process the urgent message first, but we need
// to save the reply.
nsAutoPtr<Message> savedReply(mRecvd.forget());
- // We're the child process. We should not be receiving RPC calls.
- IPC_ASSERT(!mPendingRPCCall, "unexpected RPC call");
-
- nsAutoPtr<Message> recvd(mPendingUrgentRequest.forget());
{
// In order to send the parent RPC messages and guarantee it will
// wake up, we must re-use its transaction.
- AutoEnterRPCTransaction transaction(this, recvd);
+ AutoEnterTransaction transaction(this, &aUrgent);
MonitorAutoUnlock unlock(*mMonitor);
- DispatchUrgentMessage(*recvd);
+ DispatchMessage(aUrgent);
}
if (!Connected()) {
- ReportConnectionError("MessageChannel::DispatchUrgentMessage");
- return false;
- }
-
- // In between having dispatched our reply to the parent process, and
- // re-acquiring the monitor, the parent process could have already
- // processed that reply and sent the reply to our sync message. If so,
- // our saved reply should be empty.
- IPC_ASSERT(!mRecvd || !savedReply, "unknown reply");
- if (!mRecvd)
- mRecvd = savedReply.forget();
- return true;
-}
-
-bool
-MessageChannel::ProcessPendingRPCCall()
-{
- AssertWorkerThread();
- mMonitor->AssertCurrentThreadOwns();
-
- // See comment above re: mRecvd replies and incoming calls.
- nsAutoPtr<Message> savedReply(mRecvd.forget());
-
- IPC_ASSERT(!mPendingUrgentRequest, "unexpected urgent message");
-
- nsAutoPtr<Message> recvd(mPendingRPCCall.forget());
- {
- // If we are not currently in a transaction, this will begin one,
- // and the link thread will not wake us up for any RPC messages not
- // apart of this transaction. If we are already in a transaction,
- // then this will assert that we're still in the same transaction.
- AutoEnterRPCTransaction transaction(this, recvd);
-
- MonitorAutoUnlock unlock(*mMonitor);
- DispatchRPCMessage(*recvd);
- }
- if (!Connected()) {
- ReportConnectionError("MessageChannel::DispatchRPCMessage");
+ ReportConnectionError("MessageChannel::ProcessPendingRequest");
return false;
}
// In between having dispatched our reply to the parent process, and
// re-acquiring the monitor, the parent process could have already
// processed that reply and sent the reply to our sync message. If so,
// our saved reply should be empty.
IPC_ASSERT(!mRecvd || !savedReply, "unknown reply");
@@ -1048,28 +991,16 @@ MessageChannel::DequeueOne(Message *recv
AssertWorkerThread();
mMonitor->AssertCurrentThreadOwns();
if (!Connected()) {
ReportConnectionError("OnMaybeDequeueOne");
return false;
}
- if (mPendingUrgentRequest) {
- *recvd = *mPendingUrgentRequest;
- mPendingUrgentRequest = nullptr;
- return true;
- }
-
- if (mPendingRPCCall) {
- *recvd = *mPendingRPCCall;
- mPendingRPCCall = nullptr;
- return true;
- }
-
if (!mDeferred.empty())
MaybeUndeferIncall();
if (mPending.empty())
return false;
*recvd = mPending.front();
mPending.pop_front();
@@ -1092,152 +1023,90 @@ MessageChannel::OnMaybeDequeueOne()
// We probably just received a reply in a nested loop for an
// Interrupt call sent before entering that loop.
mOutOfTurnReplies[recvd.seqno()] = recvd;
return false;
}
{
// We should not be in a transaction yet if we're not blocked.
- MOZ_ASSERT(mCurrentRPCTransaction == 0);
- AutoEnterRPCTransaction transaction(this, &recvd);
+ MOZ_ASSERT(mCurrentTransaction == 0);
+ AutoEnterTransaction transaction(this, &recvd);
MonitorAutoUnlock unlock(*mMonitor);
CxxStackFrame frame(*this, IN_MESSAGE, &recvd);
DispatchMessage(recvd);
}
return true;
}
void
MessageChannel::DispatchMessage(const Message &aMsg)
{
if (aMsg.is_sync())
DispatchSyncMessage(aMsg);
- else if (aMsg.is_urgent())
- DispatchUrgentMessage(aMsg);
else if (aMsg.is_interrupt())
DispatchInterruptMessage(aMsg, 0);
- else if (aMsg.is_rpc())
- DispatchRPCMessage(aMsg);
else
DispatchAsyncMessage(aMsg);
}
void
MessageChannel::DispatchSyncMessage(const Message& aMsg)
{
AssertWorkerThread();
Message *reply = nullptr;
- mDispatchingSyncMessage = true;
- Result rv = mListener->OnMessageReceived(aMsg, reply);
- mDispatchingSyncMessage = false;
+ int prio = aMsg.priority();
+
+ // We don't want to run any code that might run a nested event loop here, so
+ // we avoid running event handlers. Once we've sent the response to the
+ // urgent message, it's okay to run event handlers again since the parent is
+ // no longer blocked.
+ MOZ_ASSERT_IF(prio > IPC::Message::PRIORITY_NORMAL, NS_IsMainThread());
+ MaybeScriptBlocker scriptBlocker(this, prio > IPC::Message::PRIORITY_NORMAL);
+
+ IPC_ASSERT(prio >= mDispatchingSyncMessagePriority,
+ "priority inversion while dispatching sync message");
+ IPC_ASSERT(prio >= mAwaitingSyncReplyPriority,
+ "dispatching a message of lower priority while waiting for a response");
+
+ bool dummy;
+ bool& blockingVar = ShouldBlockScripts() ? gParentIsBlocked : dummy;
+
+ Result rv;
+ {
+ AutoSetValue<bool> blocked(blockingVar, true);
+ AutoSetValue<bool> sync(mDispatchingSyncMessage, true);
+ AutoSetValue<int> prioSet(mDispatchingSyncMessagePriority, prio);
+ rv = mListener->OnMessageReceived(aMsg, reply);
+ }
if (!MaybeHandleError(rv, aMsg, "DispatchSyncMessage")) {
delete reply;
reply = new Message();
reply->set_sync();
+ reply->set_priority(aMsg.priority());
reply->set_reply();
reply->set_reply_error();
}
reply->set_seqno(aMsg.seqno());
MonitorAutoLock lock(*mMonitor);
if (ChannelConnected == mChannelState)
mLink->SendMessage(reply);
}
void
-MessageChannel::DispatchUrgentMessage(const Message& aMsg)
-{
- AssertWorkerThread();
- MOZ_ASSERT(aMsg.is_urgent());
-
- Message *reply = nullptr;
-
- MOZ_ASSERT(NS_IsMainThread());
-
- // We don't want to run any code that might run a nested event loop here, so
- // we avoid running event handlers. Once we've sent the response to the
- // urgent message, it's okay to run event handlers again since the parent is
- // no longer blocked.
- //
- // We also put script blockers at the start of every synchronous send
- // call. That way we won't run any scripts while waiting for a response to
- // another message. Running scripts could cause us to send more sync
- // messages, and the other side wouldn't know what to do if it received a
- // sync message while dispatching another sync message. (In practice, the
- // other side would queue the second sync message, while we would need it to
- // dispatch that message before sending the reply to the original sync
- // message. Otherwise the replies would come out of order.)
- //
- // We omit the script blocker for InterruptCall since interrupt messages are
- // designed to handle this sort of re-entry. (For example, if the child
- // sends an intr message to the parent, the child will process any queued
- // async messages from the parent while waiting for the intr response. In
- // doing so, the child could trigger sync messages to be sent to the parent
- // while the parent is still dispatching the intr message. If the parent
- // sends an intr reply while the child is waiting for a sync response, the
- // intr reply will be queued in mPending. Once the sync reply is received,
- // InterruptCall will find the intr reply in mPending and run it.) The
- // situation where we run event handlers while waiting for an intr reply is
- // no different than the one where we process async messages while waiting
- // for an intr reply.
- MaybeScriptBlocker scriptBlocker(this);
-
- gDispatchingUrgentMessageCount++;
- mDispatchingUrgentMessageCount++;
- Result rv = mListener->OnCallReceived(aMsg, reply);
- mDispatchingUrgentMessageCount--;
- gDispatchingUrgentMessageCount--;
-
- if (!MaybeHandleError(rv, aMsg, "DispatchUrgentMessage")) {
- delete reply;
- reply = new Message();
- reply->set_urgent();
- reply->set_reply();
- reply->set_reply_error();
- }
- reply->set_seqno(aMsg.seqno());
-
- MonitorAutoLock lock(*mMonitor);
- if (ChannelConnected == mChannelState)
- mLink->SendMessage(reply);
-}
-
-void
-MessageChannel::DispatchRPCMessage(const Message& aMsg)
-{
- AssertWorkerThread();
- MOZ_ASSERT(aMsg.is_rpc());
-
- Message *reply = nullptr;
-
- if (!MaybeHandleError(mListener->OnCallReceived(aMsg, reply), aMsg, "DispatchRPCMessage")) {
- delete reply;
- reply = new Message();
- reply->set_rpc();
- reply->set_reply();
- reply->set_reply_error();
- }
- reply->set_seqno(aMsg.seqno());
-
- MonitorAutoLock lock(*mMonitor);
- if (ChannelConnected == mChannelState)
- mLink->SendMessage(reply);
-}
-
-void
MessageChannel::DispatchAsyncMessage(const Message& aMsg)
{
AssertWorkerThread();
- MOZ_ASSERT(!aMsg.is_interrupt() && !aMsg.is_sync() && !aMsg.is_urgent());
+ MOZ_ASSERT(!aMsg.is_interrupt() && !aMsg.is_sync());
if (aMsg.routing_id() == MSG_ROUTING_NONE) {
NS_RUNTIMEABORT("unhandled special message!");
}
MaybeHandleError(mListener->OnMessageReceived(aMsg), aMsg, "DispatchAsyncMessage");
}
@@ -1341,16 +1210,17 @@ MessageChannel::MaybeUndeferIncall()
// maybe time to process this message
Message call = mDeferred.top();
mDeferred.pop();
// fix up fudge factor we added to account for race
IPC_ASSERT(0 < mRemoteStackDepthGuess, "fatal logic error");
--mRemoteStackDepthGuess;
+ MOZ_ASSERT(call.priority() == IPC::Message::PRIORITY_NORMAL);
mPending.push_back(call);
}
void
MessageChannel::FlushPendingInterruptQueue()
{
AssertWorkerThread();
mMonitor->AssertNotCurrentThreadOwns();
@@ -1613,17 +1483,17 @@ void
MessageChannel::OnChannelErrorFromLink()
{
AssertLinkThread();
mMonitor->AssertCurrentThreadOwns();
if (InterruptStackDepth() > 0)
NotifyWorkerThread();
- if (AwaitingSyncReply() || AwaitingRPCReply() || AwaitingUrgentReply())
+ if (AwaitingSyncReply())
NotifyWorkerThread();
if (ChannelClosing != mChannelState) {
if (mAbortOnError) {
NS_RUNTIMEABORT("Aborting on channel error.");
}
mChannelState = ChannelError;
mMonitor->Notify();
@@ -1851,15 +1721,15 @@ MessageChannel::DumpInterruptStack(const
mCxxStackFrames[i].Describe(&id, &dir, &sems, &name);
printf_stderr("%s[(%u) %s %s %s(actor=%d) ]\n", pfx,
i, dir, sems, name, id);
}
}
bool
-ProcessingUrgentMessages()
+ParentProcessIsBlocked()
{
- return gDispatchingUrgentMessageCount > 0;
+ return gParentIsBlocked;
}
} // ipc
} // mozilla
--- a/ipc/glue/MessageChannel.h
+++ b/ipc/glue/MessageChannel.h
@@ -221,24 +221,19 @@ class MessageChannel : HasResultCodes
// SendAndWait() expects that the worker thread owns the monitor, and that
// the message has been prepared to be sent over the link. It returns as
// soon as a reply has been received, or an error has occurred.
//
// Note that while the child is blocked waiting for a sync reply, it can wake
// up to process urgent calls from the parent.
bool SendAndWait(Message* aMsg, Message* aReply);
- bool RPCCall(Message* aMsg, Message* aReply);
- bool InterruptCall(Message* aMsg, Message* aReply);
- bool UrgentCall(Message* aMsg, Message* aReply);
-
bool InterruptEventOccurred();
- bool ProcessPendingUrgentRequest();
- bool ProcessPendingRPCCall();
+ bool ProcessPendingRequest(Message aUrgent);
void MaybeUndeferIncall();
void EnqueuePendingMessages();
// Executed on the worker thread. Dequeues one pending message.
bool OnMaybeDequeueOne();
bool DequeueOne(Message *recvd);
@@ -322,39 +317,36 @@ class MessageChannel : HasResultCodes
size_t InterruptStackDepth() const {
mMonitor->AssertCurrentThreadOwns();
return mInterruptStack.size();
}
// Returns true if we're blocking waiting for a reply.
bool AwaitingSyncReply() const {
mMonitor->AssertCurrentThreadOwns();
- return mPendingSyncReplies > 0;
+ return mAwaitingSyncReply;
}
- bool AwaitingUrgentReply() const {
+ int AwaitingSyncReplyPriority() const {
mMonitor->AssertCurrentThreadOwns();
- return mPendingUrgentReplies > 0;
- }
- bool AwaitingRPCReply() const {
- mMonitor->AssertCurrentThreadOwns();
- return mPendingRPCReplies > 0;
+ return mAwaitingSyncReplyPriority;
}
bool AwaitingInterruptReply() const {
mMonitor->AssertCurrentThreadOwns();
return !mInterruptStack.empty();
}
// Returns true if we're dispatching a sync message's callback.
bool DispatchingSyncMessage() const {
+ AssertWorkerThread();
return mDispatchingSyncMessage;
}
- // Returns true if we're dispatching an urgent message's callback.
- bool DispatchingUrgentMessage() const {
- return mDispatchingUrgentMessageCount > 0;
+ int DispatchingSyncMessagePriority() const {
+ AssertWorkerThread();
+ return mDispatchingSyncMessagePriority;
}
bool Connected() const;
private:
// Executed on the IO thread.
void NotifyWorkerThread();
@@ -362,16 +354,17 @@ class MessageChannel : HasResultCodes
// thread, in which case it shouldn't be delivered to the worker.
bool MaybeInterceptSpecialIOMessage(const Message& aMsg);
void OnChannelConnected(int32_t peer_id);
// Tell the IO thread to close the channel and wait for it to ACK.
void SynchronouslyClose();
+ bool ShouldDeferMessage(const Message& aMsg);
void OnMessageReceivedFromLink(const Message& aMsg);
void OnChannelErrorFromLink();
private:
// Run on the not current thread.
void NotifyChannelClosed();
void NotifyMaybeChannelError();
@@ -455,105 +448,100 @@ class MessageChannel : HasResultCodes
bool mInTimeoutSecondHalf;
// Worker-thread only; sequence numbers for messages that require
// synchronous replies.
int32_t mNextSeqno;
static bool sIsPumpingMessages;
- class AutoEnterPendingReply {
+ template<class T>
+ class AutoSetValue {
public:
- explicit AutoEnterPendingReply(size_t &replyVar)
- : mReplyVar(replyVar)
+ explicit AutoSetValue(T &var, const T &newValue)
+ : mVar(var), mPrev(var)
{
- mReplyVar++;
+ mVar = newValue;
}
- ~AutoEnterPendingReply() {
- mReplyVar--;
+ ~AutoSetValue() {
+ mVar = mPrev;
}
private:
- size_t& mReplyVar;
+ T& mVar;
+ T mPrev;
};
- // Worker-thread only; type we're expecting for the reply to a sync
- // out-message. This will never be greater than 1.
- size_t mPendingSyncReplies;
+ // Worker thread only.
+ bool mAwaitingSyncReply;
+ int mAwaitingSyncReplyPriority;
- // Worker-thread only; Number of urgent and rpc replies we're waiting on.
- // These are mutually exclusive since one channel cannot have outcalls of
- // both kinds.
- size_t mPendingUrgentReplies;
- size_t mPendingRPCReplies;
+ // Set while we are dispatching a synchronous message. Only for use on the
+ // worker thread.
+ bool mDispatchingSyncMessage;
+ int mDispatchingSyncMessagePriority;
// When we send an urgent request from the parent process, we could race
// with an RPC message that was issued by the child beforehand. In this
// case, if the parent were to wake up while waiting for the urgent reply,
// and process the RPC, it could send an additional urgent message. The
// child would wake up to process the urgent message (as it always will),
// then send a reply, which could be received by the parent out-of-order
// with respect to the first urgent reply.
//
// To address this problem, urgent or RPC requests are associated with a
// "transaction". Whenever one side of the channel wishes to start a
// chain of RPC/urgent messages, it allocates a new transaction ID. Any
// messages the parent receives, not apart of this transaction, are
// deferred. When issuing RPC/urgent requests on top of a started
// transaction, the initiating transaction ID is used.
- //
+ //
// To ensure IDs are unique, we use sequence numbers for transaction IDs,
// which grow in opposite directions from child to parent.
// The current transaction ID.
- int32_t mCurrentRPCTransaction;
+ int32_t mCurrentTransaction;
- class AutoEnterRPCTransaction
+ class AutoEnterTransaction
{
public:
- explicit AutoEnterRPCTransaction(MessageChannel *aChan)
+ explicit AutoEnterTransaction(MessageChannel *aChan)
: mChan(aChan),
- mOldTransaction(mChan->mCurrentRPCTransaction)
+ mOldTransaction(mChan->mCurrentTransaction)
{
mChan->mMonitor->AssertCurrentThreadOwns();
- if (mChan->mCurrentRPCTransaction == 0)
- mChan->mCurrentRPCTransaction = mChan->NextSeqno();
+ if (mChan->mCurrentTransaction == 0)
+ mChan->mCurrentTransaction = mChan->NextSeqno();
}
- AutoEnterRPCTransaction(MessageChannel *aChan, Message *message)
+ explicit AutoEnterTransaction(MessageChannel *aChan, Message *message)
: mChan(aChan),
- mOldTransaction(mChan->mCurrentRPCTransaction)
+ mOldTransaction(mChan->mCurrentTransaction)
{
mChan->mMonitor->AssertCurrentThreadOwns();
- if (!message->is_rpc() && !message->is_urgent())
+ if (!message->is_sync())
return;
- MOZ_ASSERT_IF(mChan->mSide == ParentSide,
- !mOldTransaction || mOldTransaction == message->transaction_id());
- mChan->mCurrentRPCTransaction = message->transaction_id();
+ MOZ_ASSERT_IF(mChan->mSide == ParentSide && mOldTransaction != message->transaction_id(),
+ !mOldTransaction || message->priority() > mChan->AwaitingSyncReplyPriority());
+ mChan->mCurrentTransaction = message->transaction_id();
}
- ~AutoEnterRPCTransaction() {
+ ~AutoEnterTransaction() {
mChan->mMonitor->AssertCurrentThreadOwns();
- mChan->mCurrentRPCTransaction = mOldTransaction;
+ mChan->mCurrentTransaction = mOldTransaction;
}
private:
MessageChannel *mChan;
int32_t mOldTransaction;
};
// If waiting for the reply to a sync out-message, it will be saved here
// on the I/O thread and then read and cleared by the worker thread.
nsAutoPtr<Message> mRecvd;
- // Set while we are dispatching a synchronous message.
- bool mDispatchingSyncMessage;
-
- // Count of the recursion depth of dispatching urgent messages.
- size_t mDispatchingUrgentMessageCount;
-
// Queue of all incoming messages, except for replies to sync and urgent
// messages, which are delivered directly to mRecvd, and any pending urgent
// incall, which is stored in mPendingUrgentRequest.
//
// If both this side and the other side are functioning correctly, the queue
// can only be in certain configurations. Let
//
// |A<| be an async in-message,
@@ -582,28 +570,16 @@ class MessageChannel : HasResultCodes
// then other side "finished with us," and went back to its own business.
// That business might have included sending any number of async message
// |A<*| until sending a blocking message |(S< | C<)|. If we had more than
// one Interrupt call on our stack, the other side *better* not have sent us
// another blocking message, because it's blocked on a reply from us.
//
MessageQueue mPending;
- // Note that these two pointers are mutually exclusive. One channel cannot
- // send both urgent requests (parent -> child) and RPC calls (child->parent).
- // Also note that since initiating either requires blocking, they cannot
- // queue up on the other side. One message slot is enough.
- //
- // Normally, all other message types are deferred into into mPending, and
- // only these two types have special treatment (since they wake up blocked
- // requests). However, when an RPC in-call races with an urgent out-call,
- // the RPC message will be put into mPending instead of its slot below.
- nsAutoPtr<Message> mPendingUrgentRequest;
- nsAutoPtr<Message> mPendingRPCCall;
-
// Stack of all the out-calls on which this channel is awaiting responses.
// Each stack refers to a different protocol and the stacks are mutually
// exclusive: multiple outcalls of the same kind cannot be initiated while
// another is active.
std::stack<Message> mInterruptStack;
// This is what we think the Interrupt stack depth is on the "other side" of this
// Interrupt channel. We maintain this variable so that we can detect racy Interrupt
@@ -671,14 +647,14 @@ class MessageChannel : HasResultCodes
// safely. This is necessary to be able to cancel notification if we are
// closed at the same time.
nsRefPtr<RefCountedTask> mOnChannelConnectedTask;
DebugOnly<bool> mPeerPidSet;
int32_t mPeerPid;
};
bool
-ProcessingUrgentMessages();
+ParentProcessIsBlocked();
} // namespace ipc
} // namespace mozilla
#endif // ifndef ipc_glue_MessageChannel_h
--- a/ipc/ipdl/ipdl/ast.py
+++ b/ipc/ipdl/ipdl/ast.py
@@ -1,14 +1,18 @@
# 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 sys
+NORMAL_PRIORITY = 1
+HIGH_PRIORITY = 2
+URGENT_PRIORITY = 3
+
class Visitor:
def defaultVisit(self, node):
raise Exception, "INTERNAL ERROR: no visitor for node type `%s'"% (
node.__class__.__name__)
def visitTranslationUnit(self, tu):
for cxxInc in tu.cxxIncludes:
cxxInc.accept(self)
@@ -209,18 +213,16 @@ class PrettyPrinted:
def __str__(cls): return cls.pretty
class ASYNC(PrettyPrinted):
pretty = 'async'
class INTR(PrettyPrinted):
pretty = 'intr'
class SYNC(PrettyPrinted):
pretty = 'sync'
-class RPC(PrettyPrinted):
- pretty = 'rpc'
class INOUT(PrettyPrinted):
pretty = 'inout'
class IN(PrettyPrinted):
pretty = 'in'
class OUT(PrettyPrinted):
pretty = 'out'
@@ -229,16 +231,17 @@ class Namespace(Node):
def __init__(self, loc, namespace):
Node.__init__(self, loc)
self.name = namespace
class Protocol(NamespacedNode):
def __init__(self, loc):
NamespacedNode.__init__(self, loc)
self.sendSemantics = ASYNC
+ self.priority = NORMAL_PRIORITY
self.spawnsStmts = [ ]
self.bridgesStmts = [ ]
self.opensStmts = [ ]
self.managers = [ ]
self.managesStmts = [ ]
self.messageDecls = [ ]
self.transitionStmts = [ ]
self.startStates = [ ]
@@ -288,30 +291,28 @@ class ManagesStmt(Node):
Node.__init__(self, loc)
self.name = managedName
class MessageDecl(Node):
def __init__(self, loc):
Node.__init__(self, loc)
self.name = None
self.sendSemantics = ASYNC
+ self.priority = NORMAL_PRIORITY
self.direction = None
self.inParams = [ ]
self.outParams = [ ]
self.compress = ''
def addInParams(self, inParamsList):
self.inParams += inParamsList
def addOutParams(self, outParamsList):
self.outParams += outParamsList
- def hasReply(self):
- return self.sendSemantics is SYNC or self.sendSemantics is INTR
-
class Transition(Node):
def __init__(self, loc, trigger, msg, toStates):
Node.__init__(self, loc)
self.trigger = trigger
self.msg = msg
self.toStates = toStates
def __cmp__(self, o):
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -272,23 +272,23 @@ def _putInNamespaces(cxxthing, namespace
newns = Namespace(ns.name)
innerns.addstmt(newns)
innerns = newns
innerns.addstmt(cxxthing)
return outerns
def _sendPrefix(msgtype):
"""Prefix of the name of the C++ method that sends |msgtype|."""
- if msgtype.isInterrupt() or msgtype.isRpc():
+ if msgtype.isInterrupt():
return 'Call'
return 'Send'
def _recvPrefix(msgtype):
"""Prefix of the name of the C++ method that handles |msgtype|."""
- if msgtype.isInterrupt() or msgtype.isRpc():
+ if msgtype.isInterrupt():
return 'Answer'
return 'Recv'
def _flatTypeName(ipdltype):
"""Return a 'flattened' IPDL type name that can be used as an
identifier.
E.g., |Foo[]| --> |ArrayOfFoo|."""
# NB: this logic depends heavily on what IPDL types are allowed to
@@ -2979,17 +2979,17 @@ class _GenerateProtocolActorCode(ipdl.as
Whitespace.NL ])
# Close()
closemeth = MethodDefn(MethodDecl('Close'))
closemeth.addstmt(StmtExpr(
ExprCall(ExprSelect(p.channelVar(), '.', 'Close'))))
self.cls.addstmts([ closemeth, Whitespace.NL ])
- if ptype.talksSync() or ptype.talksInterrupt():
+ if ptype.isSync() or ptype.isInterrupt():
# SetReplyTimeoutMs()
timeoutvar = ExprVar('aTimeoutMs')
settimeout = MethodDefn(MethodDecl(
'SetReplyTimeoutMs',
params=[ Decl(Type.INT32, timeoutvar.name) ]))
settimeout.addstmt(StmtExpr(
ExprCall(
ExprSelect(p.channelVar(), '.', 'SetReplyTimeoutMs'),
@@ -3048,38 +3048,40 @@ class _GenerateProtocolActorCode(ipdl.as
# for ctor recv cases, we can't read the actor ID into a PFoo*
# because it doesn't exist on this side yet. Use a "special"
# actor handle instead
handlevar = ExprVar('__handle')
self.handlevar = handlevar
msgtype = ExprCall(ExprSelect(msgvar, '.', 'type'), [ ])
self.asyncSwitch = StmtSwitch(msgtype)
- if toplevel.talksSync():
+ self.syncSwitch = None
+ self.interruptSwitch = None
+ if toplevel.isSync() or toplevel.isInterrupt():
self.syncSwitch = StmtSwitch(msgtype)
- if toplevel.talksRpc():
+ if toplevel.isInterrupt():
self.interruptSwitch = StmtSwitch(msgtype)
# implement Send*() methods and add dispatcher cases to
# message switch()es
for md in p.messageDecls:
self.visitMessageDecl(md)
# Handlers for the creation of actors when a new channel is
# opened
if len(channelOpenedActors):
self.makeChannelOpenedHandlers(channelOpenedActors)
# add default cases
default = StmtBlock()
default.addstmt(StmtReturn(_Result.NotKnown))
self.asyncSwitch.addcase(DefaultLabel(), default)
- if toplevel.talksSync():
+ if toplevel.isSync() or toplevel.isInterrupt():
self.syncSwitch.addcase(DefaultLabel(), default)
- if toplevel.talksRpc():
+ if toplevel.isInterrupt():
self.interruptSwitch.addcase(DefaultLabel(), default)
# FIXME/bug 535053: only manager protocols and non-manager
# protocols with union types need Lookup(). we'll give it to
# all for the time being (simpler)
if 1 or ptype.isManager():
self.cls.addstmts(self.implementManagerIface())
@@ -3146,20 +3148,16 @@ class _GenerateProtocolActorCode(ipdl.as
return method
dispatches = (ptype.isToplevel() and ptype.isManager())
self.cls.addstmts([
makeHandlerMethod('OnMessageReceived', self.asyncSwitch,
hasReply=0, dispatches=dispatches),
Whitespace.NL
])
- if not toplevel.talksRpc():
- self.interruptSwitch = None
- if not toplevel.talksSync():
- self.syncSwitch = None
self.cls.addstmts([
makeHandlerMethod('OnMessageReceived', self.syncSwitch,
hasReply=1, dispatches=dispatches),
Whitespace.NL
])
self.cls.addstmts([
makeHandlerMethod('OnCallReceived', self.interruptSwitch,
hasReply=1, dispatches=dispatches),
@@ -3185,17 +3183,17 @@ class _GenerateProtocolActorCode(ipdl.as
# int32_t GetProtocolTypeId() { return PFoo; }
gettypetag = MethodDefn(
MethodDecl('GetProtocolTypeId', ret=_actorTypeTagType()))
gettypetag.addstmt(StmtReturn(_protocolId(ptype)))
self.cls.addstmts([ gettypetag, Whitespace.NL ])
# OnReplyTimeout()
- if toplevel.talksSync() or toplevel.talksInterrupt():
+ if toplevel.isSync() or toplevel.isInterrupt():
ontimeout = MethodDefn(
MethodDecl('OnReplyTimeout', ret=Type.BOOL))
if ptype.isToplevel():
ontimeout.addstmt(StmtReturn(
ExprCall(p.shouldContinueFromTimeoutVar())))
else:
ontimeout.addstmts([
@@ -3273,17 +3271,17 @@ class _GenerateProtocolActorCode(ipdl.as
onconnected.addstmt(
_runtimeAbort("'OnConnected' called on non-toplevel actor"))
self.cls.addstmts([ onconnected, Whitespace.NL ])
# User-facing shmem methods
self.cls.addstmts(self.makeShmemIface())
- if (ptype.isToplevel() and ptype.talksInterrupt()):
+ if (ptype.isToplevel() and ptype.isInterrupt()):
processnative = MethodDefn(
MethodDecl('ProcessNativeEventsInInterruptCall', ret=Type.VOID))
processnative.addstmts([
CppDirective('ifdef', 'OS_WIN'),
StmtExpr(ExprCall(
ExprSelect(p.channelVar(), '.',
@@ -4775,32 +4773,32 @@ class _GenerateProtocolActorCode(ipdl.as
if this: read = ExprSelect(this, '->', read.name)
return self.maybeAddNullabilityArg(
ipdltype, ExprCall(read, args=[ expr, from_, iterexpr ]))
def visitMessageDecl(self, md):
isctor = md.decl.type.isCtor()
isdtor = md.decl.type.isDtor()
- sems = md.decl.type.sendSemantics
+ decltype = md.decl.type
sendmethod = None
helpermethod = None
recvlbl, recvcase = None, None
def addRecvCase(lbl, case):
- if sems is ipdl.ast.ASYNC:
+ if decltype.isAsync():
self.asyncSwitch.addcase(lbl, case)
- elif sems is ipdl.ast.SYNC:
+ elif decltype.isSync():
self.syncSwitch.addcase(lbl, case)
- elif sems is ipdl.ast.INTR or sems is ipdl.ast.RPC:
+ elif decltype.isInterrupt():
self.interruptSwitch.addcase(lbl, case)
else: assert 0
if self.sendsMessage(md):
- isasync = (sems is ipdl.ast.ASYNC)
+ isasync = decltype.isAsync()
if isctor:
self.cls.addstmts([ self.genHelperCtor(md), Whitespace.NL ])
if isctor and isasync:
sendmethod, (recvlbl, recvcase) = self.genAsyncCtor(md)
elif isctor:
sendmethod = self.genBlockingCtorMethod(md)
@@ -5180,31 +5178,24 @@ class _GenerateProtocolActorCode(ipdl.as
stmts = [ StmtExpr(ExprCall(
ExprSelect(var, '->', 'set_routing_id'),
args=[ routingId ])) ]
if md.decl.type.isSync():
stmts.append(StmtExpr(ExprCall(
ExprSelect(var, '->', 'set_sync'))))
- elif md.decl.type.isRpc():
- # We use urgent messages from the parent to the child and
- # RPC messages from the child to the parent. However,
- # replies should always be sent using the same semantics
- # as the original message, so we need to flip.
- if (self.side == 'parent') ^ reply:
- stmts.append(StmtExpr(ExprCall(
- ExprSelect(var, '->', 'set_urgent'))))
- else:
- stmts.append(StmtExpr(ExprCall(
- ExprSelect(var, '->', 'set_rpc'))))
elif md.decl.type.isInterrupt():
stmts.append(StmtExpr(ExprCall(
ExprSelect(var, '->', 'set_interrupt'))))
+ stmts.append(StmtExpr(ExprCall(
+ ExprSelect(var, '->', 'set_priority'),
+ args=[ ExprLiteral.Int(md.decl.type.priority) ])))
+
if reply:
stmts.append(StmtExpr(ExprCall(
ExprSelect(var, '->', 'set_reply'))))
return stmts + [ Whitespace.NL ]
def deserializeMessage(self, md, side, errfn):
--- a/ipc/ipdl/ipdl/parser.py
+++ b/ipc/ipdl/ipdl/parser.py
@@ -122,39 +122,43 @@ reserved = set((
'call',
'child',
'class',
'compress',
'__delete__',
'delete', # reserve 'delete' to prevent its use
'from',
'goto',
+ 'high',
'include',
'intr',
'manager',
'manages',
'namespace',
+ 'normal',
'nullable',
'opens',
'or',
'parent',
+ 'prio',
'protocol',
'recv',
'returns',
- 'rpc',
'send',
'spawns',
'start',
'state',
'struct',
'sync',
'union',
+ 'upto',
+ 'urgent',
'using'))
tokens = [
- 'COLONCOLON', 'ID', 'STRING'
+ 'COLONCOLON', 'ID', 'STRING',
] + [ r.upper() for r in reserved ]
t_COLONCOLON = '::'
literals = '(){}[]<>;:,~'
t_ignore = ' \f\t\v'
def t_linecomment(t):
@@ -344,21 +348,22 @@ def p_ComponentTypes(p):
| Type ';'"""
if 3 == len(p):
p[0] = [ p[1] ]
else:
p[1].append(p[2])
p[0] = p[1]
def p_ProtocolDefn(p):
- """ProtocolDefn : OptionalSendSemanticsQual PROTOCOL ID '{' ProtocolBody '}' ';'"""
+ """ProtocolDefn : OptionalProtocolSendSemanticsQual PROTOCOL ID '{' ProtocolBody '}' ';'"""
protocol = p[5]
protocol.loc = locFromTok(p, 2)
protocol.name = p[3]
- protocol.sendSemantics = p[1]
+ protocol.priorityRange = p[1][0]
+ protocol.sendSemantics = p[1][1]
p[0] = protocol
if Parser.current.type == 'header':
_error(protocol.loc, 'can\'t define a protocol in a header. Do it in a protocol spec instead.')
def p_ProtocolBody(p):
"""ProtocolBody : SpawnsStmtsOpt"""
@@ -490,17 +495,18 @@ def p_MessageDirectionLabel(p):
elif p[1] == 'both':
Parser.current.direction = INOUT
else:
assert 0
def p_MessageDecl(p):
"""MessageDecl : OptionalSendSemanticsQual MessageBody"""
msg = p[2]
- msg.sendSemantics = p[1]
+ msg.priority = p[1][0]
+ msg.sendSemantics = p[1][1]
if Parser.current.direction is None:
_error(msg.loc, 'missing message direction')
msg.direction = Parser.current.direction
p[0] = msg
def p_MessageBody(p):
@@ -610,34 +616,77 @@ def p_StateList(p):
p[0] = p[1]
def p_State(p):
"""State : ID"""
p[0] = State(locFromTok(p, 1), p[1])
##--------------------
## Minor stuff
+def p_Priority(p):
+ """Priority : NORMAL
+ | HIGH
+ | URGENT"""
+ prios = {'normal': 1,
+ 'high': 2,
+ 'urgent': 3}
+ p[0] = prios[p[1]]
+
def p_OptionalSendSemanticsQual(p):
"""OptionalSendSemanticsQual : SendSemanticsQual
| """
if 2 == len(p): p[0] = p[1]
- else: p[0] = ASYNC
+ else: p[0] = [ NORMAL_PRIORITY, ASYNC ]
def p_SendSemanticsQual(p):
"""SendSemanticsQual : ASYNC
- | INTR
- | RPC
- | SYNC"""
- s = p[1]
- if 'async' == s: p[0] = ASYNC
- elif 'intr' == s: p[0] = INTR
- elif 'sync' == s: p[0] = SYNC
- elif 'rpc' == s: p[0] = RPC
+ | SYNC
+ | PRIO '(' Priority ')' ASYNC
+ | PRIO '(' Priority ')' SYNC
+ | INTR"""
+ if p[1] == 'prio':
+ mtype = p[5]
+ prio = p[3]
else:
- assert 0
+ mtype = p[1]
+ prio = NORMAL_PRIORITY
+
+ if mtype == 'async': mtype = ASYNC
+ elif mtype == 'sync': mtype = SYNC
+ elif mtype == 'intr': mtype = INTR
+ else: assert 0
+
+ p[0] = [ prio, mtype ]
+
+def p_OptionalProtocolSendSemanticsQual(p):
+ """OptionalProtocolSendSemanticsQual : ProtocolSendSemanticsQual
+ | """
+ if 2 == len(p): p[0] = p[1]
+ else: p[0] = [ (NORMAL_PRIORITY, NORMAL_PRIORITY), ASYNC ]
+
+def p_ProtocolSendSemanticsQual(p):
+ """ProtocolSendSemanticsQual : ASYNC
+ | SYNC
+ | PRIO '(' Priority UPTO Priority ')' ASYNC
+ | PRIO '(' Priority UPTO Priority ')' SYNC
+ | PRIO '(' Priority UPTO Priority ')' INTR
+ | INTR"""
+ if p[1] == 'prio':
+ mtype = p[7]
+ prio = (p[3], p[5])
+ else:
+ mtype = p[1]
+ prio = (NORMAL_PRIORITY, NORMAL_PRIORITY)
+
+ if mtype == 'async': mtype = ASYNC
+ elif mtype == 'sync': mtype = SYNC
+ elif mtype == 'intr': mtype = INTR
+ else: assert 0
+
+ p[0] = [ prio, mtype ]
def p_ParamList(p):
"""ParamList : ParamList ',' Param
| Param
| """
if 1 == len(p):
p[0] = [ ]
elif 2 == len(p):
--- a/ipc/ipdl/ipdl/type.py
+++ b/ipc/ipdl/ipdl/type.py
@@ -1,18 +1,20 @@
# vim: set ts=4 sw=4 tw=99 et:
# 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, sys
from ipdl.ast import CxxInclude, Decl, Loc, QualifiedId, State, StructDecl, TransitionStmt
-from ipdl.ast import TypeSpec, UnionDecl, UsingStmt, Visitor, ASYNC, SYNC, INTR
-from ipdl.ast import IN, OUT, INOUT, ANSWER, CALL, RECV, SEND, RPC
+from ipdl.ast import TypeSpec, UnionDecl, UsingStmt, Visitor
+from ipdl.ast import ASYNC, SYNC, INTR
+from ipdl.ast import IN, OUT, INOUT, ANSWER, CALL, RECV, SEND
+from ipdl.ast import NORMAL_PRIORITY, HIGH_PRIORITY, URGENT_PRIORITY
import ipdl.builtin as builtin
_DELETE_MSG = '__delete__'
def _otherside(side):
if side == 'parent': return 'child'
elif side == 'child': return 'parent'
@@ -199,52 +201,59 @@ class IPDLType(Type):
def isUnion(self): return False
def isArray(self): return False
def isAtom(self): return True
def isCompound(self): return False
def isShmem(self): return False
def isChmod(self): return False
def isFD(self): return False
- def isAsync(self): return self.sendSemantics is ASYNC
- def isSync(self): return self.sendSemantics is SYNC
+ def isAsync(self): return self.sendSemantics == ASYNC
+ def isSync(self): return self.sendSemantics == SYNC
def isInterrupt(self): return self.sendSemantics is INTR
- def isRpc(self): return self.sendSemantics is RPC
+
+ def hasReply(self): return (self.isSync() or self.isInterrupt())
- def talksAsync(self): return True
- def talksSync(self): return self.isSync() or self.isRpc() or self.isInterrupt()
- def talksRpc(self): return self.isRpc() or self.isInterrupt()
- def talksInterrupt(self): return self.isInterrupt()
+ @classmethod
+ def convertsTo(cls, lesser, greater):
+ if (lesser.priorityRange[0] < greater.priorityRange[0] or
+ lesser.priorityRange[1] > greater.priorityRange[1]):
+ return False
- def hasReply(self): return (self.isSync()
- or self.isInterrupt()
- or self.isRpc())
+ if lesser.isAsync():
+ return True
+ elif lesser.isSync() and not greater.isAsync():
+ return True
+ elif greater.isInterrupt():
+ return True
+
+ return False
def needsMoreJuiceThan(self, o):
- return (o.isAsync() and not self.isAsync()
- or o.isSync() and self.isRpc()
- or o.isRpc() and self.isInterrupt())
+ return not IPDLType.convertsTo(self, o)
class StateType(IPDLType):
def __init__(self, protocol, name, start=False):
self.protocol = protocol
self.name = name
self.start = start
def isState(self): return True
def name(self):
return self.name
def fullname(self):
return self.name()
class MessageType(IPDLType):
- def __init__(self, sendSemantics, direction,
+ def __init__(self, priority, sendSemantics, direction,
ctor=False, dtor=False, cdtype=None, compress=False):
assert not (ctor and dtor)
assert not (ctor or dtor) or type is not None
+ self.priority = priority
+ self.priorityRange = (priority, priority)
self.sendSemantics = sendSemantics
self.direction = direction
self.params = [ ]
self.returns = [ ]
self.ctor = ctor
self.dtor = dtor
self.cdtype = cdtype
self.compress = compress
@@ -270,18 +279,19 @@ class Bridge:
def __cmp__(self, o):
return cmp(self.parent, o.parent) or cmp(self.child, o.child)
def __eq__(self, o):
return self.parent == o.parent and self.child == o.child
def __hash__(self):
return hash(self.parent) + hash(self.child)
class ProtocolType(IPDLType):
- def __init__(self, qname, sendSemantics, stateless=False):
+ def __init__(self, qname, priorityRange, sendSemantics, stateless=False):
self.qname = qname
+ self.priorityRange = priorityRange
self.sendSemantics = sendSemantics
self.spawns = set() # ProtocolType
self.opens = set() # ProtocolType
self.managers = [] # ProtocolType
self.manages = [ ]
self.stateless = stateless
self.hasDelete = False
self.hasReentrantDelete = False
@@ -679,17 +689,17 @@ class GatherDecls(TcheckVisitor):
# types?
qname = p.qname()
if 0 == len(qname.quals):
fullname = None
else:
fullname = str(qname)
p.decl = self.declare(
loc=p.loc,
- type=ProtocolType(qname, p.sendSemantics,
+ type=ProtocolType(qname, p.priorityRange, p.sendSemantics,
stateless=(0 == len(p.transitionStmts))),
shortname=p.name,
fullname=fullname)
# XXX ugh, this sucks. but we need this information to compute
# what friend decls we need in generated C++
p.decl.type._ast = p
@@ -1078,17 +1088,17 @@ class GatherDecls(TcheckVisitor):
if _DELETE_MSG == msgname:
isdtor = True
cdtype = self.currentProtocolDecl.type
# enter message scope
self.symtab.enterScope(md)
- msgtype = MessageType(md.sendSemantics, md.direction,
+ msgtype = MessageType(md.priority, md.sendSemantics, md.direction,
ctor=isctor, dtor=isdtor, cdtype=cdtype,
compress=(md.compress == 'compress'))
# replace inparam Param nodes with proper Decls
def paramToDecl(param):
ptname = param.typespec.basename()
ploc = param.typespec.loc
@@ -1452,17 +1462,32 @@ class CheckTypes(TcheckVisitor):
def visitMessageDecl(self, md):
mtype, mname = md.decl.type, md.decl.progname
ptype, pname = md.protocolDecl.type, md.protocolDecl.shortname
loc = md.decl.loc
- if mtype.isSync() and (mtype.isOut() or mtype.isInout()):
+ if mtype.priority == HIGH_PRIORITY and not mtype.isSync():
+ self.error(
+ loc,
+ "high priority messages must be sync (here, message `%s' in protocol `%s')",
+ mname, pname)
+
+ if mtype.priority == URGENT_PRIORITY and (mtype.isOut() or mtype.isInout()):
+ self.error(
+ loc,
+ "urgent parent-to-child messages are verboten (here, message `%s' in protocol `%s')",
+ mname, pname)
+
+ # We allow high priority sync messages to be sent from the
+ # parent. Normal and urgent sync messages can only come from
+ # the child.
+ if mtype.isSync() and mtype.priority == NORMAL_PRIORITY and (mtype.isOut() or mtype.isInout()):
self.error(
loc,
"sync parent-to-child messages are verboten (here, message `%s' in protocol `%s')",
mname, pname)
if mtype.needsMoreJuiceThan(ptype):
self.error(
loc,
--- a/ipc/ipdl/test/cxx/Makefile.in
+++ b/ipc/ipdl/test/cxx/Makefile.in
@@ -14,17 +14,17 @@ IPDLTESTHDRS = $(addprefix $(srcdir)/,$(
TESTER_TEMPLATE := $(srcdir)/IPDLUnitTests.template.cpp
GENTESTER := $(srcdir)/genIPDLUnitTests.py
include $(topsrcdir)/config/rules.mk
IPDLUNITTEST_BIN = $(DEPTH)/dist/bin/ipdlunittest$(BIN_SUFFIX)
-IPDLUnitTests.cpp : Makefile.in $(GENTESTER) $(TESTER_TEMPLATE) $(IPDLTESTHDRS)
+IPDLUnitTests.cpp : Makefile.in moz.build $(GENTESTER) $(TESTER_TEMPLATE) $(IPDLTESTHDRS)
$(PYTHON) $(GENTESTER) $(TESTER_TEMPLATE) -t $(IPDLTESTS) -e $(EXTRA_PROTOCOLS) > $@
check-proc::
@$(EXIT_ON_ERROR) \
for test in $(IPDLTESTS); do \
$(RUN_TEST_PROGRAM) $(IPDLUNITTEST_BIN) $$test ; \
done
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestHighestPrio.ipdl
@@ -0,0 +1,18 @@
+namespace mozilla {
+namespace _ipdltest {
+
+prio(normal upto urgent) sync protocol PTestHighestPrio
+{
+parent:
+ prio(urgent) async Msg1();
+ sync Msg2();
+ prio(urgent) async Msg3();
+ prio(urgent) sync Msg4();
+
+child:
+ async Start();
+ prio(high) sync StartInner();
+};
+
+}
+}
--- a/ipc/ipdl/test/cxx/PTestRPC.ipdl
+++ b/ipc/ipdl/test/cxx/PTestRPC.ipdl
@@ -1,27 +1,26 @@
namespace mozilla {
namespace _ipdltest {
-intr protocol PTestRPC
+prio(normal upto high) sync protocol PTestRPC
{
parent:
- rpc Test1_Start() returns (uint32_t result);
- rpc Test1_InnerEvent() returns (uint32_t result);
+ prio(high) sync Test1_Start() returns (uint32_t result);
+ prio(high) sync Test1_InnerEvent() returns (uint32_t result);
async Test2_Start();
- rpc Test2_OutOfOrder();
+ prio(high) sync Test2_Msg2();
+ prio(high) sync Test2_FirstUrgent();
+ prio(high) sync Test2_SecondUrgent();
sync Test3_Start() returns (uint32_t result);
- rpc Test3_InnerEvent() returns (uint32_t result);
- intr Test4_Start() returns (uint32_t result);
- rpc Test4_Inner() returns (uint32_t result);
+ prio(high) sync Test3_InnerEvent() returns (uint32_t result);
child:
async Start();
- rpc Test1_InnerQuery() returns (uint32_t result);
- rpc Test1_NoReenter() returns (uint32_t result);
- rpc Test2_FirstUrgent();
- rpc Test2_SecondUrgent();
- rpc Test3_WakeUp() returns (uint32_t result);
- rpc Test4_WakeUp() returns (uint32_t result);
+ prio(high) sync Test1_InnerQuery() returns (uint32_t result);
+ prio(high) sync Test1_NoReenter() returns (uint32_t result);
+ prio(high) sync Test2_Msg1();
+ prio(high) sync Test2_Msg3();
+ prio(high) sync Test3_WakeUp() returns (uint32_t result);
};
} // namespace _ipdltest
} // namespace mozilla
--- a/ipc/ipdl/test/cxx/PTestUrgency.ipdl
+++ b/ipc/ipdl/test/cxx/PTestUrgency.ipdl
@@ -1,19 +1,19 @@
namespace mozilla {
namespace _ipdltest {
-intr protocol PTestUrgency
+prio(normal upto high) sync protocol PTestUrgency
{
parent:
sync Test1() returns (uint32_t result);
async Test2();
sync Test3() returns (uint32_t result);
sync FinalTest_Begin();
child:
async Start();
- rpc Reply1() returns (uint32_t result);
- rpc Reply2() returns (uint32_t result);
+ prio(high) sync Reply1() returns (uint32_t result);
+ prio(high) sync Reply2() returns (uint32_t result);
};
} // namespace _ipdltest
} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestHighestPrio.cpp
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ */
+/* 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 "TestHighestPrio.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+#if defined(OS_POSIX)
+#include <unistd.h>
+#else
+#include <windows.h>
+#endif
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestHighestPrioParent::TestHighestPrioParent()
+ : msg_num_(0)
+{
+ MOZ_COUNT_CTOR(TestHighestPrioParent);
+}
+
+TestHighestPrioParent::~TestHighestPrioParent()
+{
+ MOZ_COUNT_DTOR(TestHighestPrioParent);
+}
+
+void
+TestHighestPrioParent::Main()
+{
+ if (!SendStart())
+ fail("sending Start");
+}
+
+bool
+TestHighestPrioParent::RecvMsg1()
+{
+ MOZ_ASSERT(msg_num_ == 0);
+ msg_num_ = 1;
+ return true;
+}
+
+bool
+TestHighestPrioParent::RecvMsg2()
+{
+
+ MOZ_ASSERT(msg_num_ == 1);
+ msg_num_ = 2;
+
+ if (!SendStartInner())
+ fail("sending StartInner");
+
+ return true;
+}
+
+bool
+TestHighestPrioParent::RecvMsg3()
+{
+ MOZ_ASSERT(msg_num_ == 2);
+ msg_num_ = 3;
+ return true;
+}
+
+bool
+TestHighestPrioParent::RecvMsg4()
+{
+ MOZ_ASSERT(msg_num_ == 3);
+ msg_num_ = 4;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+
+TestHighestPrioChild::TestHighestPrioChild()
+{
+ MOZ_COUNT_CTOR(TestHighestPrioChild);
+}
+
+TestHighestPrioChild::~TestHighestPrioChild()
+{
+ MOZ_COUNT_DTOR(TestHighestPrioChild);
+}
+
+bool
+TestHighestPrioChild::RecvStart()
+{
+ if (!SendMsg1())
+ fail("sending Msg1");
+
+ if (!SendMsg2())
+ fail("sending Msg2");
+
+ Close();
+ return true;
+}
+
+bool
+TestHighestPrioChild::RecvStartInner()
+{
+ if (!SendMsg3())
+ fail("sending Msg3");
+
+ if (!SendMsg4())
+ fail("sending Msg4");
+
+ return true;
+}
+
+} // namespace _ipdltest
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestHighestPrio.h
@@ -0,0 +1,68 @@
+#ifndef mozilla__ipdltest_TestHighestPrio_h
+#define mozilla__ipdltest_TestHighestPrio_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestHighestPrioParent.h"
+#include "mozilla/_ipdltest/PTestHighestPrioChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+
+class TestHighestPrioParent :
+ public PTestHighestPrioParent
+{
+public:
+ TestHighestPrioParent();
+ virtual ~TestHighestPrioParent();
+
+ static bool RunTestInProcesses() { return true; }
+ static bool RunTestInThreads() { return false; }
+
+ void Main();
+
+ bool RecvMsg1() MOZ_OVERRIDE;
+ bool RecvMsg2() MOZ_OVERRIDE;
+ bool RecvMsg3() MOZ_OVERRIDE;
+ bool RecvMsg4() MOZ_OVERRIDE;
+
+ virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE
+ {
+ if (NormalShutdown != why)
+ fail("unexpected destruction!");
+ if (msg_num_ != 4)
+ fail("missed IPC call");
+ passed("ok");
+ QuitParent();
+ }
+
+private:
+ int msg_num_;
+};
+
+
+class TestHighestPrioChild :
+ public PTestHighestPrioChild
+{
+public:
+ TestHighestPrioChild();
+ virtual ~TestHighestPrioChild();
+
+ bool RecvStart() MOZ_OVERRIDE;
+ bool RecvStartInner() MOZ_OVERRIDE;
+
+ virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE
+ {
+ if (NormalShutdown != why)
+ fail("unexpected destruction!");
+ QuitChild();
+ }
+};
+
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+
+#endif // ifndef mozilla__ipdltest_TestHighestPrio_h
--- a/ipc/ipdl/test/cxx/TestRPC.cpp
+++ b/ipc/ipdl/test/cxx/TestRPC.cpp
@@ -9,18 +9,16 @@
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// parent
TestRPCParent::TestRPCParent()
- : reentered_(false),
- resolved_first_cpow_(false)
{
MOZ_COUNT_CTOR(TestRPCParent);
}
TestRPCParent::~TestRPCParent()
{
MOZ_COUNT_DTOR(TestRPCParent);
}
@@ -28,187 +26,177 @@ TestRPCParent::~TestRPCParent()
void
TestRPCParent::Main()
{
if (!SendStart())
fail("sending Start");
}
bool
-TestRPCParent::AnswerTest1_Start(uint32_t* aResult)
+TestRPCParent::RecvTest1_Start(uint32_t* aResult)
{
uint32_t result;
- if (!CallTest1_InnerQuery(&result))
- fail("CallTest1_InnerQuery");
+ if (!SendTest1_InnerQuery(&result))
+ fail("SendTest1_InnerQuery");
if (result != 300)
fail("Wrong result (expected 300)");
*aResult = 100;
return true;
}
bool
-TestRPCParent::AnswerTest1_InnerEvent(uint32_t* aResult)
+TestRPCParent::RecvTest1_InnerEvent(uint32_t* aResult)
{
uint32_t result;
- if (!CallTest1_NoReenter(&result))
- fail("CallTest1_NoReenter");
+ if (!SendTest1_NoReenter(&result))
+ fail("SendTest1_NoReenter");
if (result != 400)
fail("Wrong result (expected 400)");
*aResult = 200;
return true;
}
bool
TestRPCParent::RecvTest2_Start()
{
- // Send a CPOW. During this time, we must NOT process the RPC message, as
- // we could start receiving CPOW replies out-of-order.
- if (!CallTest2_FirstUrgent())
- fail("CallTest2_FirstUrgent");
+ if (!SendTest2_Msg1())
+ fail("SendTest2_Msg1");
- MOZ_ASSERT(!reentered_);
- resolved_first_cpow_ = true;
return true;
}
bool
-TestRPCParent::AnswerTest2_OutOfOrder()
+TestRPCParent::RecvTest2_Msg2()
{
- // Send a CPOW. If this RPC call was initiated while waiting for the first
- // CPOW to resolve, replies will be processed out of order, and we'll crash.
- if (!CallTest2_SecondUrgent())
- fail("CallTest2_SecondUrgent");
+ if (!SendTest2_Msg3())
+ fail("SendTest2_Msg3");
+
+ return true;
+}
- reentered_ = true;
+bool
+TestRPCParent::RecvTest2_FirstUrgent()
+{
+ return true;
+}
+
+bool
+TestRPCParent::RecvTest2_SecondUrgent()
+{
return true;
}
bool
TestRPCParent::RecvTest3_Start(uint32_t* aResult)
{
- if (!CallTest3_WakeUp(aResult))
- fail("CallTest3_WakeUp");
+ if (!SendTest3_WakeUp(aResult))
+ fail("SendTest3_WakeUp");
return true;
}
bool
-TestRPCParent::AnswerTest3_InnerEvent(uint32_t* aResult)
+TestRPCParent::RecvTest3_InnerEvent(uint32_t* aResult)
{
*aResult = 200;
return true;
}
-bool
-TestRPCParent::AnswerTest4_Start(uint32_t* aResult)
-{
- if (!CallTest4_WakeUp(aResult))
- fail("CallTest4_WakeUp");
-
- return true;
-}
-
-bool
-TestRPCParent::AnswerTest4_Inner(uint32_t* aResult)
-{
- *aResult = 700;
- return true;
-}
-
//-----------------------------------------------------------------------------
// child
TestRPCChild::TestRPCChild()
+ : reentered_(false),
+ resolved_first_cpow_(false)
{
MOZ_COUNT_CTOR(TestRPCChild);
}
TestRPCChild::~TestRPCChild()
{
MOZ_COUNT_DTOR(TestRPCChild);
}
bool
TestRPCChild::RecvStart()
{
uint32_t result;
- if (!CallTest1_Start(&result))
- fail("CallTest1_Start");
+ if (!SendTest1_Start(&result))
+ fail("SendTest1_Start");
if (result != 100)
fail("Wrong result (expected 100)");
if (!SendTest2_Start())
fail("SendTest2_Start");
- if (!CallTest2_OutOfOrder())
- fail("CallTest2_OutOfOrder");
+ if (!SendTest2_Msg2())
+ fail("SendTest2_Msg2");
result = 0;
if (!SendTest3_Start(&result))
fail("SendTest3_Start");
if (result != 200)
fail("Wrong result (expected 200)");
- // See bug 937216 (RPC calls within interrupts).
- if (!CallTest4_Start(&result))
- fail("SendTest4_Start");
- if (result != 700)
- fail("Wrong result (expected 700)");
-
Close();
return true;
}
bool
-TestRPCChild::AnswerTest1_InnerQuery(uint32_t* aResult)
+TestRPCChild::RecvTest1_InnerQuery(uint32_t* aResult)
{
uint32_t result;
- if (!CallTest1_InnerEvent(&result))
- fail("CallTest1_InnerEvent");
+ if (!SendTest1_InnerEvent(&result))
+ fail("SendTest1_InnerEvent");
if (result != 200)
fail("Wrong result (expected 200)");
*aResult = 300;
return true;
}
bool
-TestRPCChild::AnswerTest1_NoReenter(uint32_t* aResult)
+TestRPCChild::RecvTest1_NoReenter(uint32_t* aResult)
{
*aResult = 400;
return true;
}
-bool
-TestRPCChild::AnswerTest2_FirstUrgent()
+bool TestRPCChild::RecvTest2_Msg1()
{
- return true;
-}
+ MOZ_ASSERT(resolved_first_cpow_);
-bool
-TestRPCChild::AnswerTest2_SecondUrgent()
-{
+ // Send a CPOW. If this RPC call was initiated while waiting for the first
+ // CPOW to resolve, replies will be processed out of order, and we'll crash.
+ if (!SendTest2_SecondUrgent())
+ fail("SendTest2_SecondUrgent");
+
+ reentered_ = true;
return true;
}
bool
-TestRPCChild::AnswerTest3_WakeUp(uint32_t* aResult)
+TestRPCChild::RecvTest2_Msg3()
{
- if (!CallTest3_InnerEvent(aResult))
- fail("CallTest3_InnerEvent");
+ // Send a CPOW. During this time, we must NOT process the RPC message, as
+ // we could start receiving CPOW replies out-of-order.
+ if (!SendTest2_FirstUrgent())
+ fail("SendTest2_FirstUrgent");
+ MOZ_ASSERT(!reentered_);
+ resolved_first_cpow_ = true;
return true;
}
bool
-TestRPCChild::AnswerTest4_WakeUp(uint32_t* aResult)
+TestRPCChild::RecvTest3_WakeUp(uint32_t* aResult)
{
- if (!CallTest4_Inner(aResult))
- fail("CallTest4_Inner");
+ if (!SendTest3_InnerEvent(aResult))
+ fail("SendTest3_InnerEvent");
return true;
}
} // namespace _ipdltest
} // namespace mozilla
--- a/ipc/ipdl/test/cxx/TestRPC.h
+++ b/ipc/ipdl/test/cxx/TestRPC.h
@@ -17,64 +17,59 @@ public:
TestRPCParent();
virtual ~TestRPCParent();
static bool RunTestInProcesses() { return true; }
static bool RunTestInThreads() { return false; }
void Main();
- bool AnswerTest1_Start(uint32_t* aResult) MOZ_OVERRIDE;
- bool AnswerTest1_InnerEvent(uint32_t* aResult) MOZ_OVERRIDE;
+ bool RecvTest1_Start(uint32_t* aResult) MOZ_OVERRIDE;
+ bool RecvTest1_InnerEvent(uint32_t* aResult) MOZ_OVERRIDE;
bool RecvTest2_Start() MOZ_OVERRIDE;
- bool AnswerTest2_OutOfOrder() MOZ_OVERRIDE;
+ bool RecvTest2_Msg2() MOZ_OVERRIDE;
+ bool RecvTest2_FirstUrgent() MOZ_OVERRIDE;
+ bool RecvTest2_SecondUrgent() MOZ_OVERRIDE;
bool RecvTest3_Start(uint32_t* aResult) MOZ_OVERRIDE;
- bool AnswerTest3_InnerEvent(uint32_t* aResult) MOZ_OVERRIDE;
- bool AnswerTest4_Start(uint32_t* aResult) MOZ_OVERRIDE;
- bool AnswerTest4_Inner(uint32_t* aResult) MOZ_OVERRIDE;
+ bool RecvTest3_InnerEvent(uint32_t* aResult) MOZ_OVERRIDE;
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE
{
if (NormalShutdown != why)
fail("unexpected destruction!");
- if (!reentered_)
- fail("never processed raced RPC call!");
- if (!resolved_first_cpow_)
- fail("never resolved first CPOW!");
passed("ok");
QuitParent();
}
-
-private:
- bool reentered_;
- bool resolved_first_cpow_;
};
class TestRPCChild :
public PTestRPCChild
{
public:
TestRPCChild();
virtual ~TestRPCChild();
bool RecvStart() MOZ_OVERRIDE;
- bool AnswerTest1_InnerQuery(uint32_t* aResult) MOZ_OVERRIDE;
- bool AnswerTest1_NoReenter(uint32_t* aResult) MOZ_OVERRIDE;
- bool AnswerTest2_FirstUrgent() MOZ_OVERRIDE;
- bool AnswerTest2_SecondUrgent() MOZ_OVERRIDE;
- bool AnswerTest3_WakeUp(uint32_t* aResult) MOZ_OVERRIDE;
- bool AnswerTest4_WakeUp(uint32_t* aResult) MOZ_OVERRIDE;
+ bool RecvTest1_InnerQuery(uint32_t* aResult) MOZ_OVERRIDE;
+ bool RecvTest1_NoReenter(uint32_t* aResult) MOZ_OVERRIDE;
+ bool RecvTest2_Msg1() MOZ_OVERRIDE;
+ bool RecvTest2_Msg3() MOZ_OVERRIDE;
+ bool RecvTest3_WakeUp(uint32_t* aResult) MOZ_OVERRIDE;
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE
{
if (NormalShutdown != why)
fail("unexpected destruction!");
QuitChild();
}
+
+private:
+ bool reentered_;
+ bool resolved_first_cpow_;
};
} // namespace _ipdltest
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_TestRPC_h
--- a/ipc/ipdl/test/cxx/TestUrgency.cpp
+++ b/ipc/ipdl/test/cxx/TestUrgency.cpp
@@ -43,29 +43,29 @@ TestUrgencyParent::Main()
{
if (!SendStart())
fail("sending Start");
}
bool
TestUrgencyParent::RecvTest1(uint32_t *value)
{
- if (!CallReply1(value))
+ if (!SendReply1(value))
fail("sending Reply1");
if (*value != 99)
fail("bad value");
return true;
}
bool
TestUrgencyParent::RecvTest2()
{
uint32_t value;
inreply_ = true;
- if (!CallReply2(&value))
+ if (!SendReply2(&value))
fail("sending Reply2");
inreply_ = false;
if (value != 500)
fail("bad value");
return true;
}
bool
@@ -125,31 +125,31 @@ TestUrgencyChild::RecvStart()
fail("Final test should have succeeded");
Close();
return true;
}
bool
-TestUrgencyChild::AnswerReply1(uint32_t *reply)
+TestUrgencyChild::RecvReply1(uint32_t *reply)
{
if (test_ != kFirstTestBegin)
- fail("wrong test # in AnswerReply1");
+ fail("wrong test # in RecvReply1");
*reply = 99;
test_ = kFirstTestGotReply;
return true;
}
bool
-TestUrgencyChild::AnswerReply2(uint32_t *reply)
+TestUrgencyChild::RecvReply2(uint32_t *reply)
{
if (test_ != kSecondTestBegin)
- fail("wrong test # in AnswerReply2");
+ fail("wrong test # in RecvReply2");
// sleep for 5 seconds so the parent process tries to deliver more messages.
Sleep(5000);
*reply = 500;
test_ = kSecondTestGotReply;
return true;
}
--- a/ipc/ipdl/test/cxx/TestUrgency.h
+++ b/ipc/ipdl/test/cxx/TestUrgency.h
@@ -47,20 +47,18 @@ private:
class TestUrgencyChild :
public PTestUrgencyChild
{
public:
TestUrgencyChild();
virtual ~TestUrgencyChild();
bool RecvStart();
- bool AnswerReply1(uint32_t *reply);
- bool AnswerReply2(uint32_t *reply);
- bool AnswerTest4_Reenter();
- bool AnswerFinalTest_Hang();
+ bool RecvReply1(uint32_t *reply);
+ bool RecvReply2(uint32_t *reply);
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE
{
QuitChild();
}
private:
uint32_t test_;
--- a/ipc/ipdl/test/cxx/moz.build
+++ b/ipc/ipdl/test/cxx/moz.build
@@ -17,16 +17,17 @@ SOURCES += [
'TestActorPunning.cpp',
'TestBadActor.cpp',
'TestBridgeMain.cpp',
'TestCrashCleanup.cpp',
'TestDataStructures.cpp',
'TestDesc.cpp',
'TestFailedCtor.cpp',
'TestHangs.cpp',
+ 'TestHighestPrio.cpp',
'TestInterruptErrorCleanup.cpp',
'TestInterruptRaces.cpp',
'TestInterruptShutdownRace.cpp',
'TestJSON.cpp',
'TestLatency.cpp',
'TestManyChildAllocs.cpp',
'TestMultiMgrs.cpp',
'TestNestedLoops.cpp',
@@ -77,16 +78,17 @@ IPDL_SOURCES += [
'PTestDesc.ipdl',
'PTestDescSub.ipdl',
'PTestDescSubsub.ipdl',
'PTestFailedCtor.ipdl',
'PTestFailedCtorSub.ipdl',
'PTestFailedCtorSubsub.ipdl',
'PTestHandle.ipdl',
'PTestHangs.ipdl',
+ 'PTestHighestPrio.ipdl',
'PTestIndirectProtocolParam.ipdlh',
'PTestIndirectProtocolParamFirst.ipdl',
'PTestIndirectProtocolParamManage.ipdl',
'PTestIndirectProtocolParamSecond.ipdl',
'PTestInterruptErrorCleanup.ipdl',
'PTestInterruptRaces.ipdl',
'PTestInterruptShutdownRace.ipdl',
'PTestJSON.ipdl',
--- a/ipc/testshell/PTestShell.ipdl
+++ b/ipc/testshell/PTestShell.ipdl
@@ -4,17 +4,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PContent;
include protocol PTestShellCommand;
namespace mozilla {
namespace ipc {
-intr protocol PTestShell
+async protocol PTestShell
{
manager PContent;
manages PTestShellCommand;
child:
__delete__();
--- a/ipc/testshell/tests/xpcshell.ini
+++ b/ipc/testshell/tests/xpcshell.ini
@@ -1,10 +1,11 @@
[DEFAULT]
head =
tail =
+skip-if = toolkit == 'android'
[test_ipcshell.js]
# Bug 676963: test fails consistently on Android
fail-if = os == "android"
skip-if = toolkit == "gonk"
reason = bug 820380
[test_ipcshell_child.js]
--- a/js/ductwork/debugger/tests/xpcshell.ini
+++ b/js/ductwork/debugger/tests/xpcshell.ini
@@ -1,7 +1,8 @@
[DEFAULT]
head = head_dbg.js
tail =
+skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_nativewrappers.js]
# Bug 685068
fail-if = os == "android"
--- a/js/ipc/JavaScriptBase.h
+++ b/js/ipc/JavaScriptBase.h
@@ -30,199 +30,199 @@ class JavaScriptBase : public WrapperOwn
virtual ~JavaScriptBase() {}
virtual void ActorDestroy(WrapperOwner::ActorDestroyReason why) {
WrapperOwner::ActorDestroy(why);
}
/*** IPC handlers ***/
- bool AnswerPreventExtensions(const uint64_t &objId, ReturnStatus *rs) {
- return Answer::AnswerPreventExtensions(ObjectId::deserialize(objId), rs);
+ bool RecvPreventExtensions(const uint64_t &objId, ReturnStatus *rs) {
+ return Answer::RecvPreventExtensions(ObjectId::deserialize(objId), rs);
}
- bool AnswerGetPropertyDescriptor(const uint64_t &objId, const JSIDVariant &id,
+ bool RecvGetPropertyDescriptor(const uint64_t &objId, const JSIDVariant &id,
ReturnStatus *rs,
PPropertyDescriptor *out) {
- return Answer::AnswerGetPropertyDescriptor(ObjectId::deserialize(objId), id, rs, out);
+ return Answer::RecvGetPropertyDescriptor(ObjectId::deserialize(objId), id, rs, out);
}
- bool AnswerGetOwnPropertyDescriptor(const uint64_t &objId,
+ bool RecvGetOwnPropertyDescriptor(const uint64_t &objId,
const JSIDVariant &id,
ReturnStatus *rs,
PPropertyDescriptor *out) {
- return Answer::AnswerGetOwnPropertyDescriptor(ObjectId::deserialize(objId), id, rs, out);
+ return Answer::RecvGetOwnPropertyDescriptor(ObjectId::deserialize(objId), id, rs, out);
}
- bool AnswerDefineProperty(const uint64_t &objId, const JSIDVariant &id,
+ bool RecvDefineProperty(const uint64_t &objId, const JSIDVariant &id,
const PPropertyDescriptor &flags,
ReturnStatus *rs) {
- return Answer::AnswerDefineProperty(ObjectId::deserialize(objId), id, flags, rs);
+ return Answer::RecvDefineProperty(ObjectId::deserialize(objId), id, flags, rs);
}
- bool AnswerDelete(const uint64_t &objId, const JSIDVariant &id,
+ bool RecvDelete(const uint64_t &objId, const JSIDVariant &id,
ReturnStatus *rs, bool *success) {
- return Answer::AnswerDelete(ObjectId::deserialize(objId), id, rs, success);
+ return Answer::RecvDelete(ObjectId::deserialize(objId), id, rs, success);
}
- bool AnswerHas(const uint64_t &objId, const JSIDVariant &id,
+ bool RecvHas(const uint64_t &objId, const JSIDVariant &id,
ReturnStatus *rs, bool *bp) {
- return Answer::AnswerHas(ObjectId::deserialize(objId), id, rs, bp);
+ return Answer::RecvHas(ObjectId::deserialize(objId), id, rs, bp);
}
- bool AnswerHasOwn(const uint64_t &objId, const JSIDVariant &id,
+ bool RecvHasOwn(const uint64_t &objId, const JSIDVariant &id,
ReturnStatus *rs, bool *bp) {
- return Answer::AnswerHasOwn(ObjectId::deserialize(objId), id, rs, bp);
+ return Answer::RecvHasOwn(ObjectId::deserialize(objId), id, rs, bp);
}
- bool AnswerGet(const uint64_t &objId, const ObjectVariant &receiverVar,
+ bool RecvGet(const uint64_t &objId, const ObjectVariant &receiverVar,
const JSIDVariant &id,
ReturnStatus *rs, JSVariant *result) {
- return Answer::AnswerGet(ObjectId::deserialize(objId), receiverVar, id, rs, result);
+ return Answer::RecvGet(ObjectId::deserialize(objId), receiverVar, id, rs, result);
}
- bool AnswerSet(const uint64_t &objId, const ObjectVariant &receiverVar,
+ bool RecvSet(const uint64_t &objId, const ObjectVariant &receiverVar,
const JSIDVariant &id, const bool &strict,
const JSVariant &value, ReturnStatus *rs, JSVariant *result) {
- return Answer::AnswerSet(ObjectId::deserialize(objId), receiverVar, id, strict, value, rs, result);
+ return Answer::RecvSet(ObjectId::deserialize(objId), receiverVar, id, strict, value, rs, result);
}
- bool AnswerIsExtensible(const uint64_t &objId, ReturnStatus *rs,
+ bool RecvIsExtensible(const uint64_t &objId, ReturnStatus *rs,
bool *result) {
- return Answer::AnswerIsExtensible(ObjectId::deserialize(objId), rs, result);
+ return Answer::RecvIsExtensible(ObjectId::deserialize(objId), rs, result);
}
- bool AnswerCallOrConstruct(const uint64_t &objId, const nsTArray<JSParam> &argv,
+ bool RecvCallOrConstruct(const uint64_t &objId, const nsTArray<JSParam> &argv,
const bool &construct, ReturnStatus *rs, JSVariant *result,
nsTArray<JSParam> *outparams) {
- return Answer::AnswerCallOrConstruct(ObjectId::deserialize(objId), argv, construct, rs, result, outparams);
+ return Answer::RecvCallOrConstruct(ObjectId::deserialize(objId), argv, construct, rs, result, outparams);
}
- bool AnswerHasInstance(const uint64_t &objId, const JSVariant &v, ReturnStatus *rs, bool *bp) {
- return Answer::AnswerHasInstance(ObjectId::deserialize(objId), v, rs, bp);
+ bool RecvHasInstance(const uint64_t &objId, const JSVariant &v, ReturnStatus *rs, bool *bp) {
+ return Answer::RecvHasInstance(ObjectId::deserialize(objId), v, rs, bp);
}
- bool AnswerObjectClassIs(const uint64_t &objId, const uint32_t &classValue,
+ bool RecvObjectClassIs(const uint64_t &objId, const uint32_t &classValue,
bool *result) {
- return Answer::AnswerObjectClassIs(ObjectId::deserialize(objId), classValue, result);
+ return Answer::RecvObjectClassIs(ObjectId::deserialize(objId), classValue, result);
}
- bool AnswerClassName(const uint64_t &objId, nsString *result) {
- return Answer::AnswerClassName(ObjectId::deserialize(objId), result);
+ bool RecvClassName(const uint64_t &objId, nsString *result) {
+ return Answer::RecvClassName(ObjectId::deserialize(objId), result);
}
- bool AnswerRegExpToShared(const uint64_t &objId, ReturnStatus *rs, nsString *source, uint32_t *flags) {
- return Answer::AnswerRegExpToShared(ObjectId::deserialize(objId), rs, source, flags);
+ bool RecvRegExpToShared(const uint64_t &objId, ReturnStatus *rs, nsString *source, uint32_t *flags) {
+ return Answer::RecvRegExpToShared(ObjectId::deserialize(objId), rs, source, flags);
}
- bool AnswerGetPropertyNames(const uint64_t &objId, const uint32_t &flags,
+ bool RecvGetPropertyNames(const uint64_t &objId, const uint32_t &flags,
ReturnStatus *rs, nsTArray<nsString> *names) {
- return Answer::AnswerGetPropertyNames(ObjectId::deserialize(objId), flags, rs, names);
+ return Answer::RecvGetPropertyNames(ObjectId::deserialize(objId), flags, rs, names);
}
- bool AnswerInstanceOf(const uint64_t &objId, const JSIID &iid,
+ bool RecvInstanceOf(const uint64_t &objId, const JSIID &iid,
ReturnStatus *rs, bool *instanceof) {
- return Answer::AnswerInstanceOf(ObjectId::deserialize(objId), iid, rs, instanceof);
+ return Answer::RecvInstanceOf(ObjectId::deserialize(objId), iid, rs, instanceof);
}
- bool AnswerDOMInstanceOf(const uint64_t &objId, const int &prototypeID, const int &depth,
+ bool RecvDOMInstanceOf(const uint64_t &objId, const int &prototypeID, const int &depth,
ReturnStatus *rs, bool *instanceof) {
- return Answer::AnswerDOMInstanceOf(ObjectId::deserialize(objId), prototypeID, depth, rs, instanceof);
+ return Answer::RecvDOMInstanceOf(ObjectId::deserialize(objId), prototypeID, depth, rs, instanceof);
}
- bool AnswerIsCallable(const uint64_t &objId, bool *result) {
- return Answer::AnswerIsCallable(ObjectId::deserialize(objId), result);
+ bool RecvIsCallable(const uint64_t &objId, bool *result) {
+ return Answer::RecvIsCallable(ObjectId::deserialize(objId), result);
}
- bool AnswerIsConstructor(const uint64_t &objId, bool *result) {
- return Answer::AnswerIsConstructor(ObjectId::deserialize(objId), result);
+ bool RecvIsConstructor(const uint64_t &objId, bool *result) {
+ return Answer::RecvIsConstructor(ObjectId::deserialize(objId), result);
}
bool RecvDropObject(const uint64_t &objId) {
return Answer::RecvDropObject(ObjectId::deserialize(objId));
}
/*** Dummy call handlers ***/
bool SendDropObject(const ObjectId &objId) {
return Base::SendDropObject(objId.serialize());
}
- bool CallPreventExtensions(const ObjectId &objId, ReturnStatus *rs) {
- return Base::CallPreventExtensions(objId.serialize(), rs);
+ bool SendPreventExtensions(const ObjectId &objId, ReturnStatus *rs) {
+ return Base::SendPreventExtensions(objId.serialize(), rs);
}
- bool CallGetPropertyDescriptor(const ObjectId &objId, const JSIDVariant &id,
+ bool SendGetPropertyDescriptor(const ObjectId &objId, const JSIDVariant &id,
ReturnStatus *rs,
PPropertyDescriptor *out) {
- return Base::CallGetPropertyDescriptor(objId.serialize(), id, rs, out);
+ return Base::SendGetPropertyDescriptor(objId.serialize(), id, rs, out);
}
- bool CallGetOwnPropertyDescriptor(const ObjectId &objId,
+ bool SendGetOwnPropertyDescriptor(const ObjectId &objId,
const JSIDVariant &id,
ReturnStatus *rs,
PPropertyDescriptor *out) {
- return Base::CallGetOwnPropertyDescriptor(objId.serialize(), id, rs, out);
+ return Base::SendGetOwnPropertyDescriptor(objId.serialize(), id, rs, out);
}
- bool CallDefineProperty(const ObjectId &objId, const JSIDVariant &id,
+ bool SendDefineProperty(const ObjectId &objId, const JSIDVariant &id,
const PPropertyDescriptor &flags,
ReturnStatus *rs) {
- return Base::CallDefineProperty(objId.serialize(), id, flags, rs);
+ return Base::SendDefineProperty(objId.serialize(), id, flags, rs);
}
- bool CallDelete(const ObjectId &objId, const JSIDVariant &id,
+ bool SendDelete(const ObjectId &objId, const JSIDVariant &id,
ReturnStatus *rs, bool *success) {
- return Base::CallDelete(objId.serialize(), id, rs, success);
+ return Base::SendDelete(objId.serialize(), id, rs, success);
}
- bool CallHas(const ObjectId &objId, const JSIDVariant &id,
+ bool SendHas(const ObjectId &objId, const JSIDVariant &id,
ReturnStatus *rs, bool *bp) {
- return Base::CallHas(objId.serialize(), id, rs, bp);
+ return Base::SendHas(objId.serialize(), id, rs, bp);
}
- bool CallHasOwn(const ObjectId &objId, const JSIDVariant &id,
+ bool SendHasOwn(const ObjectId &objId, const JSIDVariant &id,
ReturnStatus *rs, bool *bp) {
- return Base::CallHasOwn(objId.serialize(), id, rs, bp);
+ return Base::SendHasOwn(objId.serialize(), id, rs, bp);
}
- bool CallGet(const ObjectId &objId, const ObjectVariant &receiverVar,
+ bool SendGet(const ObjectId &objId, const ObjectVariant &receiverVar,
const JSIDVariant &id,
ReturnStatus *rs, JSVariant *result) {
- return Base::CallGet(objId.serialize(), receiverVar, id, rs, result);
+ return Base::SendGet(objId.serialize(), receiverVar, id, rs, result);
}
- bool CallSet(const ObjectId &objId, const ObjectVariant &receiverVar,
+ bool SendSet(const ObjectId &objId, const ObjectVariant &receiverVar,
const JSIDVariant &id, const bool &strict,
const JSVariant &value, ReturnStatus *rs, JSVariant *result) {
- return Base::CallSet(objId.serialize(), receiverVar, id, strict, value, rs, result);
+ return Base::SendSet(objId.serialize(), receiverVar, id, strict, value, rs, result);
}
- bool CallIsExtensible(const ObjectId &objId, ReturnStatus *rs,
+ bool SendIsExtensible(const ObjectId &objId, ReturnStatus *rs,
bool *result) {
- return Base::CallIsExtensible(objId.serialize(), rs, result);
+ return Base::SendIsExtensible(objId.serialize(), rs, result);
}
- bool CallCallOrConstruct(const ObjectId &objId, const nsTArray<JSParam> &argv,
+ bool SendCallOrConstruct(const ObjectId &objId, const nsTArray<JSParam> &argv,
const bool &construct, ReturnStatus *rs, JSVariant *result,
nsTArray<JSParam> *outparams) {
- return Base::CallCallOrConstruct(objId.serialize(), argv, construct, rs, result, outparams);
+ return Base::SendCallOrConstruct(objId.serialize(), argv, construct, rs, result, outparams);
}
- bool CallHasInstance(const ObjectId &objId, const JSVariant &v, ReturnStatus *rs, bool *bp) {
- return Base::CallHasInstance(objId.serialize(), v, rs, bp);
+ bool SendHasInstance(const ObjectId &objId, const JSVariant &v, ReturnStatus *rs, bool *bp) {
+ return Base::SendHasInstance(objId.serialize(), v, rs, bp);
}
- bool CallObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
+ bool SendObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
bool *result) {
- return Base::CallObjectClassIs(objId.serialize(), classValue, result);
+ return Base::SendObjectClassIs(objId.serialize(), classValue, result);
}
- bool CallClassName(const ObjectId &objId, nsString *result) {
- return Base::CallClassName(objId.serialize(), result);
+ bool SendClassName(const ObjectId &objId, nsString *result) {
+ return Base::SendClassName(objId.serialize(), result);
}
- bool CallRegExpToShared(const ObjectId &objId, ReturnStatus *rs,
+ bool SendRegExpToShared(const ObjectId &objId, ReturnStatus *rs,
nsString *source, uint32_t *flags) {
- return Base::CallRegExpToShared(objId.serialize(), rs, source, flags);
+ return Base::SendRegExpToShared(objId.serialize(), rs, source, flags);
}
- bool CallGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
+ bool SendGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
ReturnStatus *rs, nsTArray<nsString> *names) {
- return Base::CallGetPropertyNames(objId.serialize(), flags, rs, names);
+ return Base::SendGetPropertyNames(objId.serialize(), flags, rs, names);
}
- bool CallInstanceOf(const ObjectId &objId, const JSIID &iid,
+ bool SendInstanceOf(const ObjectId &objId, const JSIID &iid,
ReturnStatus *rs, bool *instanceof) {
- return Base::CallInstanceOf(objId.serialize(), iid, rs, instanceof);
+ return Base::SendInstanceOf(objId.serialize(), iid, rs, instanceof);
}
- bool CallDOMInstanceOf(const ObjectId &objId, const int &prototypeID, const int &depth,
+ bool SendDOMInstanceOf(const ObjectId &objId, const int &prototypeID, const int &depth,
ReturnStatus *rs, bool *instanceof) {
- return Base::CallDOMInstanceOf(objId.serialize(), prototypeID, depth, rs, instanceof);
+ return Base::SendDOMInstanceOf(objId.serialize(), prototypeID, depth, rs, instanceof);
}
- bool CallIsCallable(const ObjectId &objId, bool *result) {
- return Base::CallIsCallable(objId.serialize(), result);
+ bool SendIsCallable(const ObjectId &objId, bool *result) {
+ return Base::SendIsCallable(objId.serialize(), result);
}
- bool CallIsConstructor(const ObjectId &objId, bool *result) {
- return Base::CallIsConstructor(objId.serialize(), result);
+ bool SendIsConstructor(const ObjectId &objId, bool *result) {
+ return Base::SendIsConstructor(objId.serialize(), result);
}
/* The following code is needed to suppress a bogus MSVC warning (C4250). */
virtual bool toObjectVariant(JSContext *cx, JSObject *obj, ObjectVariant *objVarp) {
return WrapperOwner::toObjectVariant(cx, obj, objVarp);
}
virtual JSObject *fromObjectVariant(JSContext *cx, ObjectVariant objVar) {
--- a/js/ipc/PJavaScript.ipdl
+++ b/js/ipc/PJavaScript.ipdl
@@ -10,48 +10,48 @@ include protocol PContentBridge;
include DOMTypes;
include JavaScriptTypes;
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
namespace mozilla {
namespace jsipc {
-intr protocol PJavaScript
+prio(normal upto high) sync protocol PJavaScript
{
manager PContent or PContentBridge;
both:
// Sent when a CPOW has been finalized and table entries can be freed up.
async DropObject(uint64_t objId);
// These roughly map to the ProxyHandler hooks that CPOWs need.
- rpc PreventExtensions(uint64_t objId) returns (ReturnStatus rs);
- rpc GetPropertyDescriptor(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, PPropertyDescriptor result);
- rpc GetOwnPropertyDescriptor(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, PPropertyDescriptor result);
- rpc DefineProperty(uint64_t objId, JSIDVariant id, PPropertyDescriptor descriptor) returns (ReturnStatus rs);
- rpc Delete(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool successful);
+ prio(high) sync PreventExtensions(uint64_t objId) returns (ReturnStatus rs);
+ prio(high) sync GetPropertyDescriptor(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, PPropertyDescriptor result);
+ prio(high) sync GetOwnPropertyDescriptor(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, PPropertyDescriptor result);
+ prio(high) sync DefineProperty(uint64_t objId, JSIDVariant id, PPropertyDescriptor descriptor) returns (ReturnStatus rs);
+ prio(high) sync Delete(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool successful);
- rpc Has(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has);
- rpc HasOwn(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has);
- rpc Get(uint64_t objId, ObjectVariant receiver, JSIDVariant id) returns (ReturnStatus rs, JSVariant result);
- rpc Set(uint64_t objId, ObjectVariant receiver, JSIDVariant id, bool strict, JSVariant value) returns (ReturnStatus rs, JSVariant result);
+ prio(high) sync Has(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has);
+ prio(high) sync HasOwn(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has);
+ prio(high) sync Get(uint64_t objId, ObjectVariant receiver, JSIDVariant id) returns (ReturnStatus rs, JSVariant result);
+ prio(high) sync Set(uint64_t objId, ObjectVariant receiver, JSIDVariant id, bool strict, JSVariant value) returns (ReturnStatus rs, JSVariant result);
- rpc IsExtensible(uint64_t objId) returns (ReturnStatus rs, bool result);
- rpc CallOrConstruct(uint64_t objId, JSParam[] argv, bool construct) returns (ReturnStatus rs, JSVariant result, JSParam[] outparams);
- rpc HasInstance(uint64_t objId, JSVariant v) returns (ReturnStatus rs, bool has);
- rpc ObjectClassIs(uint64_t objId, uint32_t classValue) returns (bool result);
- rpc ClassName(uint64_t objId) returns (nsString name);
- rpc RegExpToShared(uint64_t objId) returns (ReturnStatus rs, nsString source, uint32_t flags);
+ prio(high) sync IsExtensible(uint64_t objId) returns (ReturnStatus rs, bool result);
+ prio(high) sync CallOrConstruct(uint64_t objId, JSParam[] argv, bool construct) returns (ReturnStatus rs, JSVariant result, JSParam[] outparams);
+ prio(high) sync HasInstance(uint64_t objId, JSVariant v) returns (ReturnStatus rs, bool has);
+ prio(high) sync ObjectClassIs(uint64_t objId, uint32_t classValue) returns (bool result);
+ prio(high) sync ClassName(uint64_t objId) returns (nsString name);
+ prio(high) sync RegExpToShared(uint64_t objId) returns (ReturnStatus rs, nsString source, uint32_t flags);
- rpc GetPropertyNames(uint64_t objId, uint32_t flags) returns (ReturnStatus rs, nsString[] names);
- rpc InstanceOf(uint64_t objId, JSIID iid) returns (ReturnStatus rs, bool instanceof);
- rpc DOMInstanceOf(uint64_t objId, int prototypeID, int depth) returns (ReturnStatus rs, bool instanceof);
+ prio(high) sync GetPropertyNames(uint64_t objId, uint32_t flags) returns (ReturnStatus rs, nsString[] names);
+ prio(high) sync InstanceOf(uint64_t objId, JSIID iid) returns (ReturnStatus rs, bool instanceof);
+ prio(high) sync DOMInstanceOf(uint64_t objId, int prototypeID, int depth) returns (ReturnStatus rs, bool instanceof);
- rpc IsCallable(uint64_t objId) returns (bool result);
- rpc IsConstructor(uint64_t objId) returns (bool result);
+ prio(high) sync IsCallable(uint64_t objId) returns (bool result);
+ prio(high) sync IsConstructor(uint64_t objId) returns (bool result);
parent:
async __delete__();
};
}
}
--- a/js/ipc/WrapperAnswer.cpp
+++ b/js/ipc/WrapperAnswer.cpp
@@ -53,17 +53,17 @@ WrapperAnswer::fail(JSContext *cx, Retur
bool
WrapperAnswer::ok(ReturnStatus *rs)
{
*rs = ReturnStatus(ReturnSuccess());
return true;
}
bool
-WrapperAnswer::AnswerPreventExtensions(const ObjectId &objId, ReturnStatus *rs)
+WrapperAnswer::RecvPreventExtensions(const ObjectId &objId, ReturnStatus *rs)
{
AutoSafeJSContext cx;
JSAutoRequest request(cx);
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(cx, rs);
@@ -82,18 +82,18 @@ EmptyDesc(PPropertyDescriptor *desc)
desc->obj() = LocalObject(0);
desc->attrs() = 0;
desc->value() = UndefinedVariant();
desc->getter() = 0;
desc->setter() = 0;
}
bool
-WrapperAnswer::AnswerGetPropertyDescriptor(const ObjectId &objId, const JSIDVariant &idVar,
- ReturnStatus *rs, PPropertyDescriptor *out)
+WrapperAnswer::RecvGetPropertyDescriptor(const ObjectId &objId, const JSIDVariant &idVar,
+ ReturnStatus *rs, PPropertyDescriptor *out)
{
AutoSafeJSContext cx;
JSAutoRequest request(cx);
EmptyDesc(out);
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
@@ -116,18 +116,18 @@ WrapperAnswer::AnswerGetPropertyDescript
if (!fromDescriptor(cx, desc, out))
return fail(cx, rs);
return ok(rs);
}
bool
-WrapperAnswer::AnswerGetOwnPropertyDescriptor(const ObjectId &objId, const JSIDVariant &idVar,
- ReturnStatus *rs, PPropertyDescriptor *out)
+WrapperAnswer::RecvGetOwnPropertyDescriptor(const ObjectId &objId, const JSIDVariant &idVar,
+ ReturnStatus *rs, PPropertyDescriptor *out)
{
AutoSafeJSContext cx;
JSAutoRequest request(cx);
EmptyDesc(out);
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
@@ -150,18 +150,18 @@ WrapperAnswer::AnswerGetOwnPropertyDescr
if (!fromDescriptor(cx, desc, out))
return fail(cx, rs);
return ok(rs);
}
bool
-WrapperAnswer::AnswerDefineProperty(const ObjectId &objId, const JSIDVariant &idVar,
- const PPropertyDescriptor &descriptor, ReturnStatus *rs)
+WrapperAnswer::RecvDefineProperty(const ObjectId &objId, const JSIDVariant &idVar,
+ const PPropertyDescriptor &descriptor, ReturnStatus *rs)
{
AutoSafeJSContext cx;
JSAutoRequest request(cx);
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(cx, rs);
@@ -188,18 +188,18 @@ WrapperAnswer::AnswerDefineProperty(cons
{
return fail(cx, rs);
}
return ok(rs);
}
bool
-WrapperAnswer::AnswerDelete(const ObjectId &objId, const JSIDVariant &idVar, ReturnStatus *rs,
- bool *success)
+WrapperAnswer::RecvDelete(const ObjectId &objId, const JSIDVariant &idVar, ReturnStatus *rs,
+ bool *success)
{
AutoSafeJSContext cx;
JSAutoRequest request(cx);
*success = false;
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
@@ -215,17 +215,17 @@ WrapperAnswer::AnswerDelete(const Object
if (!JS_DeletePropertyById2(cx, obj, id, success))
return fail(cx, rs);
return ok(rs);
}
bool
-WrapperAnswer::AnswerHas(const ObjectId &objId, const JSIDVariant &idVar, ReturnStatus *rs, bool *bp)
+WrapperAnswer::RecvHas(const ObjectId &objId, const JSIDVariant &idVar, ReturnStatus *rs, bool *bp)
{
AutoSafeJSContext cx;
JSAutoRequest request(cx);
*bp = false;
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
@@ -243,18 +243,18 @@ WrapperAnswer::AnswerHas(const ObjectId
if (!JS_HasPropertyById(cx, obj, id, &found))
return fail(cx, rs);
*bp = !!found;
return ok(rs);
}
bool
-WrapperAnswer::AnswerHasOwn(const ObjectId &objId, const JSIDVariant &idVar, ReturnStatus *rs,
- bool *bp)
+WrapperAnswer::RecvHasOwn(const ObjectId &objId, const JSIDVariant &idVar, ReturnStatus *rs,
+ bool *bp)
{
AutoSafeJSContext cx;
JSAutoRequest request(cx);
*bp = false;
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
@@ -272,18 +272,18 @@ WrapperAnswer::AnswerHasOwn(const Object
if (!JS_GetPropertyDescriptorById(cx, obj, id, &desc))
return fail(cx, rs);
*bp = (desc.object() == obj);
return ok(rs);
}
bool
-WrapperAnswer::AnswerGet(const ObjectId &objId, const ObjectVariant &receiverVar,
- const JSIDVariant &idVar, ReturnStatus *rs, JSVariant *result)
+WrapperAnswer::RecvGet(const ObjectId &objId, const ObjectVariant &receiverVar,
+ const JSIDVariant &idVar, ReturnStatus *rs, JSVariant *result)
{
AutoSafeJSContext cx;
JSAutoRequest request(cx);
// The outparam will be written to the buffer, so it must be set even if
// the parent won't read it.
*result = UndefinedVariant();
@@ -309,19 +309,19 @@ WrapperAnswer::AnswerGet(const ObjectId
return fail(cx, rs);
LOG("get %s.%s = %s", ReceiverObj(objId), Identifier(idVar), OutVariant(*result));
return ok(rs);
}
bool
-WrapperAnswer::AnswerSet(const ObjectId &objId, const ObjectVariant &receiverVar,
- const JSIDVariant &idVar, const bool &strict, const JSVariant &value,
- ReturnStatus *rs, JSVariant *result)
+WrapperAnswer::RecvSet(const ObjectId &objId, const ObjectVariant &receiverVar,
+ const JSIDVariant &idVar, const bool &strict, const JSVariant &value,
+ ReturnStatus *rs, JSVariant *result)
{
AutoSafeJSContext cx;
JSAutoRequest request(cx);
// The outparam will be written to the buffer, so it must be set even if
// the parent won't read it.
*result = UndefinedVariant();
@@ -352,17 +352,17 @@ WrapperAnswer::AnswerSet(const ObjectId
if (!toVariant(cx, val, result))
return fail(cx, rs);
return ok(rs);
}
bool
-WrapperAnswer::AnswerIsExtensible(const ObjectId &objId, ReturnStatus *rs, bool *result)
+WrapperAnswer::RecvIsExtensible(const ObjectId &objId, ReturnStatus *rs, bool *result)
{
AutoSafeJSContext cx;
JSAutoRequest request(cx);
*result = false;
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
@@ -376,22 +376,22 @@ WrapperAnswer::AnswerIsExtensible(const
if (!JS_IsExtensible(cx, obj, &extensible))
return fail(cx, rs);
*result = !!extensible;
return ok(rs);
}
bool
-WrapperAnswer::AnswerCallOrConstruct(const ObjectId &objId,
- const nsTArray<JSParam> &argv,
- const bool &construct,
- ReturnStatus *rs,
- JSVariant *result,
- nsTArray<JSParam> *outparams)
+WrapperAnswer::RecvCallOrConstruct(const ObjectId &objId,
+ const nsTArray<JSParam> &argv,
+ const bool &construct,
+ ReturnStatus *rs,
+ JSVariant *result,
+ nsTArray<JSParam> *outparams)
{
AutoSafeJSContext cx;
JSAutoRequest request(cx);
// The outparam will be written to the buffer, so it must be set even if
// the parent won't read it.
*result = UndefinedVariant();
@@ -483,17 +483,17 @@ WrapperAnswer::AnswerCallOrConstruct(con
}
LOG("%s.call(%s) = %s", ReceiverObj(objId), argv, OutVariant(*result));
return ok(rs);
}
bool
-WrapperAnswer::AnswerHasInstance(const ObjectId &objId, const JSVariant &vVar, ReturnStatus *rs, bool *bp)
+WrapperAnswer::RecvHasInstance(const ObjectId &objId, const JSVariant &vVar, ReturnStatus *rs, bool *bp)
{
AutoSafeJSContext cx;
JSAutoRequest request(cx);
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(cx, rs);
@@ -507,18 +507,18 @@ WrapperAnswer::AnswerHasInstance(const O
if (!JS_HasInstance(cx, obj, val, bp))
return fail(cx, rs);
return ok(rs);
}
bool
-WrapperAnswer::AnswerObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
- bool *result)
+WrapperAnswer::RecvObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
+ bool *result)
{
AutoSafeJSContext cx;
JSAutoRequest request(cx);
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj) {
// This is very unfortunate, but we have no choice.
*result = false;
@@ -529,17 +529,17 @@ WrapperAnswer::AnswerObjectClassIs(const
LOG("%s.objectClassIs()", ReceiverObj(objId));
*result = js_ObjectClassIs(cx, obj, (js::ESClassValue)classValue);
return true;
}
bool
-WrapperAnswer::AnswerClassName(const ObjectId &objId, nsString *name)
+WrapperAnswer::RecvClassName(const ObjectId &objId, nsString *name)
{
AutoSafeJSContext cx;
JSAutoRequest request(cx);
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj) {
// This is very unfortunate, but we have no choice.
return "<dead CPOW>";
@@ -549,18 +549,18 @@ WrapperAnswer::AnswerClassName(const Obj
LOG("%s.className()", ReceiverObj(objId));
*name = NS_ConvertASCIItoUTF16(js_ObjectClassName(cx, obj));
return true;
}
bool
-WrapperAnswer::AnswerRegExpToShared(const ObjectId &objId, ReturnStatus *rs,
- nsString *source, uint32_t *flags)
+WrapperAnswer::RecvRegExpToShared(const ObjectId &objId, ReturnStatus *rs,
+ nsString *source, uint32_t *flags)
{
AutoSafeJSContext cx;
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(cx, rs);
JSAutoCompartment ac(cx, obj);
MOZ_RELEASE_ASSERT(JS_ObjectIsRegExp(cx, obj));
@@ -574,18 +574,18 @@ WrapperAnswer::AnswerRegExpToShared(cons
source->Assign(sourceStr);
*flags = JS_GetRegExpFlags(cx, obj);
return ok(rs);
}
bool
-WrapperAnswer::AnswerGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
- ReturnStatus *rs, nsTArray<nsString> *names)
+WrapperAnswer::RecvGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
+ ReturnStatus *rs, nsTArray<nsString> *names)
{
AutoSafeJSContext cx;
JSAutoRequest request(cx);
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(cx, rs);
@@ -604,18 +604,18 @@ WrapperAnswer::AnswerGetPropertyNames(co
names->AppendElement(name);
}
return ok(rs);
}
bool
-WrapperAnswer::AnswerInstanceOf(const ObjectId &objId, const JSIID &iid, ReturnStatus *rs,
- bool *instanceof)
+WrapperAnswer::RecvInstanceOf(const ObjectId &objId, const JSIID &iid, ReturnStatus *rs,
+ bool *instanceof)
{
AutoSafeJSContext cx;
JSAutoRequest request(cx);
*instanceof = false;
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
@@ -631,18 +631,18 @@ WrapperAnswer::AnswerInstanceOf(const Ob
nsresult rv = xpc::HasInstance(cx, obj, &nsiid, instanceof);
if (rv != NS_OK)
return fail(cx, rs);
return ok(rs);
}
bool
-WrapperAnswer::AnswerDOMInstanceOf(const ObjectId &objId, const int &prototypeID,
- const int &depth, ReturnStatus *rs, bool *instanceof)
+WrapperAnswer::RecvDOMInstanceOf(const ObjectId &objId, const int &prototypeID,
+ const int &depth, ReturnStatus *rs, bool *instanceof)
{
AutoSafeJSContext cx;
JSAutoRequest request(cx);
*instanceof = false;
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
@@ -656,17 +656,17 @@ WrapperAnswer::AnswerDOMInstanceOf(const
if (!mozilla::dom::InterfaceHasInstance(cx, prototypeID, depth, obj, &tmp))
return fail(cx, rs);
*instanceof = tmp;
return ok(rs);
}
bool
-WrapperAnswer::AnswerIsCallable(const ObjectId &objId, bool *result)
+WrapperAnswer::RecvIsCallable(const ObjectId &objId, bool *result)
{
AutoSafeJSContext cx;
JSAutoRequest request(cx);
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj) {
// This is very unfortunate, but we have no choice.
*result = false;
@@ -676,17 +676,17 @@ WrapperAnswer::AnswerIsCallable(const Ob
LOG("%s.isCallable()", ReceiverObj(objId));
*result = JS::IsCallable(obj);
return true;
}
bool
-WrapperAnswer::AnswerIsConstructor(const ObjectId &objId, bool *result)
+WrapperAnswer::RecvIsConstructor(const ObjectId &objId, bool *result)
{
AutoSafeJSContext cx;
JSAutoRequest request(cx);
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj) {
// This is very unfortunate, but we have no choice.
*result = false;
--- a/js/ipc/WrapperAnswer.h
+++ b/js/ipc/WrapperAnswer.h
@@ -13,61 +13,61 @@
namespace mozilla {
namespace jsipc {
class WrapperAnswer : public virtual JavaScriptShared
{
public:
explicit WrapperAnswer(JSRuntime *rt) : JavaScriptShared(rt) {}
- bool AnswerPreventExtensions(const ObjectId &objId, ReturnStatus *rs);
- bool AnswerGetPropertyDescriptor(const ObjectId &objId, const JSIDVariant &id,
- ReturnStatus *rs,
- PPropertyDescriptor *out);
- bool AnswerGetOwnPropertyDescriptor(const ObjectId &objId,
- const JSIDVariant &id,
- ReturnStatus *rs,
- PPropertyDescriptor *out);
- bool AnswerDefineProperty(const ObjectId &objId, const JSIDVariant &id,
- const PPropertyDescriptor &flags,
- ReturnStatus *rs);
- bool AnswerDelete(const ObjectId &objId, const JSIDVariant &id,
- ReturnStatus *rs, bool *success);
+ bool RecvPreventExtensions(const ObjectId &objId, ReturnStatus *rs);
+ bool RecvGetPropertyDescriptor(const ObjectId &objId, const JSIDVariant &id,
+ ReturnStatus *rs,
+ PPropertyDescriptor *out);
+ bool RecvGetOwnPropertyDescriptor(const ObjectId &objId,
+ const JSIDVariant &id,
+ ReturnStatus *rs,
+ PPropertyDescriptor *out);
+ bool RecvDefineProperty(const ObjectId &objId, const JSIDVariant &id,
+ const PPropertyDescriptor &flags,
+ ReturnStatus *rs);
+ bool Recv