зеркало из https://github.com/mozilla/pjs.git
Merge last PGO-green changeset of mozilla-inbound to mozilla-central
This commit is contained in:
Коммит
782a0ab08c
|
@ -53,6 +53,7 @@ _TEST_FILES =\
|
|||
test_contextmenu.xul \
|
||||
test_doc.html \
|
||||
test_gencontent.html \
|
||||
test_hidden.html \
|
||||
test_list_editabledoc.html \
|
||||
test_list.html \
|
||||
test_menu.xul \
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>@hidden attribute testing</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="../common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../role.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../events.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Invokers
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Set @hidden attribute
|
||||
*/
|
||||
function setHiddenAttr(aContainerID, aChildID)
|
||||
{
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_REORDER, getNode(aContainerID))
|
||||
];
|
||||
|
||||
this.invoke = function setHiddenAttr_invoke()
|
||||
{
|
||||
var tree =
|
||||
{ SECTION: [
|
||||
{ ENTRY: [
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree(aContainerID, tree);
|
||||
|
||||
getNode(aChildID).setAttribute("hidden", "true");
|
||||
}
|
||||
|
||||
this.finalCheck = function setHiddenAttr_finalCheck()
|
||||
{
|
||||
var tree =
|
||||
{ SECTION: [
|
||||
] };
|
||||
testAccessibleTree(aContainerID, tree);
|
||||
}
|
||||
|
||||
this.getID = function setHiddenAttr_getID()
|
||||
{
|
||||
return "Set @hidden attribute on input and test accessible tree for div";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove @hidden attribute
|
||||
*/
|
||||
function removeHiddenAttr(aContainerID, aChildID)
|
||||
{
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_REORDER, getNode(aContainerID))
|
||||
];
|
||||
|
||||
this.invoke = function removeHiddenAttr_invoke()
|
||||
{
|
||||
var tree =
|
||||
{ SECTION: [
|
||||
] };
|
||||
testAccessibleTree(aContainerID, tree);
|
||||
|
||||
getNode(aChildID).removeAttribute("hidden");
|
||||
}
|
||||
|
||||
this.finalCheck = function removeHiddenAttr_finalCheck()
|
||||
{
|
||||
var tree =
|
||||
{ SECTION: [
|
||||
{ ENTRY: [
|
||||
] }
|
||||
] };
|
||||
testAccessibleTree(aContainerID, tree);
|
||||
}
|
||||
|
||||
this.getID = function removeHiddenAttr_getID()
|
||||
{
|
||||
return "Remove @hidden attribute on input and test accessible tree for div";
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Test
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//gA11yEventDumpID = "eventdump"; // debug stuff
|
||||
//gA11yEventDumpToConsole = true;
|
||||
|
||||
var gQueue = null;
|
||||
|
||||
function doTest()
|
||||
{
|
||||
gQueue = new eventQueue();
|
||||
|
||||
gQueue.push(new setHiddenAttr("container", "child"));
|
||||
gQueue.push(new removeHiddenAttr("container", "child"));
|
||||
|
||||
gQueue.invoke(); // SimpleTest.finish() will be called in the end
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<div id="container"><input id="child"></div>
|
||||
|
||||
<div id="eventdump"></div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -389,6 +389,7 @@
|
|||
@BINPATH@/components/nsWifiWorker.manifest
|
||||
#endif
|
||||
@BINPATH@/components/BrowserProfileMigrators.manifest
|
||||
@BINPATH@/components/ProfileMigrator.js
|
||||
@BINPATH@/components/ChromeProfileMigrator.js
|
||||
@BINPATH@/components/FirefoxProfileMigrator.js
|
||||
#ifdef XP_MACOSX
|
||||
|
|
|
@ -57,6 +57,8 @@ namespace std {
|
|||
template ostream& ostream::_M_insert(double);
|
||||
template ostream& ostream::_M_insert(long);
|
||||
template ostream& ostream::_M_insert(unsigned long);
|
||||
template ostream& ostream::_M_insert(long long);
|
||||
template ostream& ostream::_M_insert(unsigned long long);
|
||||
#ifdef DEBUG
|
||||
template ostream& ostream::_M_insert(const void*);
|
||||
#endif
|
||||
|
|
|
@ -7308,7 +7308,11 @@ if test "${OS_TARGET}" = "Android"; then
|
|||
:
|
||||
elif test "${OS_TARGET}" = "WINNT" -o "${OS_TARGET}" = "Darwin" -o "${OS_TARGET}" = "OS2"; then
|
||||
dnl On Windows, OSX and OS2, we want to link all our binaries against mozglue
|
||||
MOZ_GLUE_LDFLAGS='$(call EXPAND_LIBNAME_PATH,mozglue,$(LIBXUL_DIST)/lib)'
|
||||
if test -z "$GNU_CC"; then
|
||||
MOZ_GLUE_LDFLAGS='$(call EXPAND_LIBNAME_PATH,mozglue,$(LIBXUL_DIST)/lib)'
|
||||
else
|
||||
MOZ_GLUE_LDFLAGS='-L$(LIBXUL_DIST)/lib $(call EXPAND_LIBNAME,mozglue)'
|
||||
fi
|
||||
else
|
||||
dnl On other Unix systems, we only want to link executables against mozglue
|
||||
MOZ_GLUE_PROGRAM_LDFLAGS='$(MKSHLIB_FORCE_ALL) $(call EXPAND_LIBNAME_PATH,mozglue,$(LIBXUL_DIST)/lib) $(MKSHLIB_UNFORCE_ALL)'
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
|
||||
#include "nsIContent.h"
|
||||
#include "nsEventStates.h"
|
||||
#include "nsDOMMemoryReporter.h"
|
||||
|
||||
class nsEventStateManager;
|
||||
class nsGlobalWindow;
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
#include "nsChangeHint.h"
|
||||
#include "nsINode.h"
|
||||
#include "nsIDocument.h" // for IsInHTMLDocument
|
||||
#include "nsDOMMemoryReporter.h"
|
||||
|
||||
// Forward declarations
|
||||
class nsIAtom;
|
||||
|
|
|
@ -68,7 +68,6 @@
|
|||
#include "nsEventStates.h"
|
||||
#include "nsIStructuredCloneContainer.h"
|
||||
#include "nsIBFCacheEntry.h"
|
||||
#include "nsDOMMemoryReporter.h"
|
||||
|
||||
class nsIContent;
|
||||
class nsPresContext;
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
#include "nsDOMError.h"
|
||||
#include "nsDOMString.h"
|
||||
#include "jspubtd.h"
|
||||
#include "nsDOMMemoryReporter.h"
|
||||
#include "nsWindowMemoryReporter.h"
|
||||
#include "nsIVariant.h"
|
||||
#include "nsGkAtoms.h"
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ interface nsIObjectLoadingContent : nsISupports
|
|||
* account. The MIME type is required as some plugins (java) calculate
|
||||
* this differently.
|
||||
*/
|
||||
nsIURI GetObjectBaseURI(in ACString aMimeType);
|
||||
nsIURI getObjectBaseURI(in ACString aMimeType);
|
||||
|
||||
/**
|
||||
* Returns the plugin instance if it has already been instantiated. This
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
#include "nsCOMPtr.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsGenericElement.h" // DOMCI_NODE_DATA
|
||||
#include "nsDOMMemoryReporter.h"
|
||||
|
||||
class nsCommentNode : public nsGenericDOMDataNode,
|
||||
public nsIDOMComment
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
*/
|
||||
|
||||
#include "nsDOMSettableTokenList.h"
|
||||
#include "dombindings.h"
|
||||
|
||||
|
||||
nsDOMSettableTokenList::nsDOMSettableTokenList(nsGenericElement *aElement, nsIAtom* aAttrAtom)
|
||||
|
@ -78,3 +79,10 @@ nsDOMSettableTokenList::SetValue(const nsAString& aValue)
|
|||
return mElement->SetAttr(kNameSpaceID_None, mAttrAtom, aValue, true);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
nsDOMSettableTokenList::WrapObject(JSContext *cx, XPCWrappedNativeScope *scope,
|
||||
bool *triedToWrap)
|
||||
{
|
||||
return mozilla::dom::binding::DOMSettableTokenList::create(cx, scope, this,
|
||||
triedToWrap);
|
||||
}
|
||||
|
|
|
@ -59,6 +59,9 @@ public:
|
|||
|
||||
nsDOMSettableTokenList(nsGenericElement* aElement, nsIAtom* aAttrAtom);
|
||||
|
||||
virtual JSObject* WrapObject(JSContext *cx, XPCWrappedNativeScope *scope,
|
||||
bool *triedToWrap);
|
||||
|
||||
protected:
|
||||
virtual ~nsDOMSettableTokenList();
|
||||
};
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "nsContentUtils.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "nsGenericElement.h"
|
||||
#include "dombindings.h"
|
||||
|
||||
|
||||
nsDOMTokenList::nsDOMTokenList(nsGenericElement *aElement, nsIAtom* aAttrAtom)
|
||||
|
@ -52,21 +53,34 @@ nsDOMTokenList::nsDOMTokenList(nsGenericElement *aElement, nsIAtom* aAttrAtom)
|
|||
{
|
||||
// We don't add a reference to our element. If it goes away,
|
||||
// we'll be told to drop our reference
|
||||
SetIsProxy();
|
||||
}
|
||||
|
||||
nsDOMTokenList::~nsDOMTokenList() { }
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMTokenList)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMTokenList)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMTokenList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMTokenList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
DOMCI_DATA(DOMTokenList, nsDOMTokenList)
|
||||
|
||||
NS_INTERFACE_TABLE_HEAD(nsDOMTokenList)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_TABLE1(nsDOMTokenList,
|
||||
nsIDOMDOMTokenList)
|
||||
NS_INTERFACE_TABLE_TO_MAP_SEGUE
|
||||
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsDOMTokenList)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DOMTokenList)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_ADDREF(nsDOMTokenList)
|
||||
NS_IMPL_RELEASE(nsDOMTokenList)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMTokenList)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMTokenList)
|
||||
|
||||
void
|
||||
nsDOMTokenList::DropReference()
|
||||
|
@ -293,3 +307,12 @@ nsDOMTokenList::ToString(nsAString& aResult)
|
|||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
nsDOMTokenList::WrapObject(JSContext *cx, XPCWrappedNativeScope *scope,
|
||||
bool *triedToWrap)
|
||||
{
|
||||
return mozilla::dom::binding::DOMTokenList::create(cx, scope, this,
|
||||
triedToWrap);
|
||||
}
|
||||
|
||||
|
|
|
@ -46,16 +46,26 @@
|
|||
|
||||
class nsAttrValue;
|
||||
|
||||
class nsDOMTokenList : public nsIDOMDOMTokenList
|
||||
class nsDOMTokenList : public nsIDOMDOMTokenList,
|
||||
public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMTokenList)
|
||||
NS_DECL_NSIDOMDOMTOKENLIST
|
||||
|
||||
nsDOMTokenList(nsGenericElement* aElement, nsIAtom* aAttrAtom);
|
||||
|
||||
void DropReference();
|
||||
|
||||
virtual JSObject* WrapObject(JSContext *cx, XPCWrappedNativeScope *scope,
|
||||
bool *triedToWrap);
|
||||
|
||||
nsINode *GetParentObject()
|
||||
{
|
||||
return mElement;
|
||||
}
|
||||
|
||||
protected:
|
||||
~nsDOMTokenList();
|
||||
|
||||
|
|
|
@ -9149,6 +9149,13 @@ nsIDocument::DocSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const
|
|||
aWindowSizes->mDOM +=
|
||||
nsINode::SizeOfExcludingThis(aWindowSizes->mMallocSizeOf);
|
||||
|
||||
if (mPresShell) {
|
||||
mPresShell->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf,
|
||||
&aWindowSizes->mLayoutArenas,
|
||||
&aWindowSizes->mLayoutStyleSets,
|
||||
&aWindowSizes->mLayoutTextRuns);
|
||||
}
|
||||
|
||||
// Measurement of the following members may be added later if DMD finds it
|
||||
// is worthwhile:
|
||||
// - many!
|
||||
|
|
|
@ -50,7 +50,6 @@
|
|||
#include "nsEventListenerManager.h"
|
||||
#include "nsGenericElement.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsDOMMemoryReporter.h"
|
||||
|
||||
#include "nsISMILAttr.h"
|
||||
|
||||
|
|
|
@ -152,7 +152,6 @@
|
|||
#include "prprf.h"
|
||||
|
||||
#include "nsSVGFeatures.h"
|
||||
#include "nsDOMMemoryReporter.h"
|
||||
#include "nsWrapperCacheInlines.h"
|
||||
#include "nsCycleCollector.h"
|
||||
#include "xpcpublic.h"
|
||||
|
@ -1981,7 +1980,7 @@ nsGenericElement::GetChildrenList()
|
|||
return slots->mChildrenList;
|
||||
}
|
||||
|
||||
nsIDOMDOMTokenList*
|
||||
nsDOMTokenList*
|
||||
nsGenericElement::GetClassList(nsresult *aResult)
|
||||
{
|
||||
*aResult = NS_ERROR_OUT_OF_MEMORY;
|
||||
|
@ -2469,6 +2468,9 @@ nsGenericElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb, b
|
|||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mChildrenList");
|
||||
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mChildrenList));
|
||||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mClassList");
|
||||
cb.NoteXPCOMChild(mClassList.get());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2483,6 +2485,10 @@ nsGenericElement::nsDOMSlots::Unlink(bool aIsXUL)
|
|||
if (aIsXUL)
|
||||
NS_IF_RELEASE(mControllers);
|
||||
mChildrenList = nsnull;
|
||||
if (mClassList) {
|
||||
mClassList->DropReference();
|
||||
mClassList = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
nsGenericElement::nsGenericElement(already_AddRefed<nsINodeInfo> aNodeInfo)
|
||||
|
|
|
@ -597,7 +597,7 @@ public:
|
|||
nsIContent* GetLastElementChild();
|
||||
nsIContent* GetPreviousElementSibling();
|
||||
nsIContent* GetNextElementSibling();
|
||||
nsIDOMDOMTokenList* GetClassList(nsresult *aResult);
|
||||
nsDOMTokenList* GetClassList(nsresult *aResult);
|
||||
bool MozMatchesSelector(const nsAString& aSelector, nsresult* aResult);
|
||||
|
||||
/**
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
#define NS_MAPPEDATTRIBUTEELEMENT_H_
|
||||
|
||||
#include "nsStyledElement.h"
|
||||
#include "nsDOMMemoryReporter.h"
|
||||
|
||||
class nsMappedAttributes;
|
||||
struct nsRuleData;
|
||||
|
|
|
@ -1871,9 +1871,18 @@ nsObjectLoadingContent::GetObjectBaseURI(const nsACString & aMimeType, nsIURI**
|
|||
codebase.AssignLiteral("/");
|
||||
}
|
||||
|
||||
nsContentUtils::NewURIWithDocumentCharset(aURI, codebase,
|
||||
thisContent->OwnerDoc(),
|
||||
baseURI);
|
||||
if (!codebase.IsEmpty()) {
|
||||
nsresult rv = nsContentUtils::NewURIWithDocumentCharset(aURI, codebase,
|
||||
thisContent->OwnerDoc(),
|
||||
baseURI);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
return rv;
|
||||
NS_WARNING("GetObjectBaseURI: Could not resolve plugin's codebase to a URI, using baseURI instead");
|
||||
}
|
||||
|
||||
// Codebase empty or build URI failed, just use baseURI
|
||||
*aURI = NULL;
|
||||
baseURI.swap(*aURI);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -108,7 +108,6 @@ nsPlainTextSerializer::nsPlainTextSerializer()
|
|||
mCiteQuoteLevel = 0;
|
||||
mStructs = true; // will be read from prefs later
|
||||
mHeaderStrategy = 1 /*indent increasingly*/; // ditto
|
||||
mQuotesPreformatted = false; // ditto
|
||||
mDontWrapAnyQuotes = false; // ditto
|
||||
mHasWrittenCiteBlockquote = false;
|
||||
mSpanLevel = 0;
|
||||
|
@ -210,10 +209,6 @@ nsPlainTextSerializer::Init(PRUint32 aFlags, PRUint32 aWrapColumn,
|
|||
mHeaderStrategy =
|
||||
Preferences::GetInt(PREF_HEADER_STRATEGY, mHeaderStrategy);
|
||||
|
||||
// The quotesPreformatted pref is a temporary measure. See bug 69638.
|
||||
mQuotesPreformatted =
|
||||
Preferences::GetBool("editor.quotesPreformatted", mQuotesPreformatted);
|
||||
|
||||
// DontWrapAnyQuotes is set according to whether plaintext mail
|
||||
// is wrapping to window width -- see bug 134439.
|
||||
// We'll only want this if we're wrapping and formatted.
|
||||
|
@ -1636,7 +1631,7 @@ nsPlainTextSerializer::Write(const nsAString& aStr)
|
|||
// that does normal formatted text. The one for preformatted text calls
|
||||
// Output directly while the other code path goes through AddToLine.
|
||||
if ((mPreFormatted && !mWrapColumn) || IsInPre()
|
||||
|| ((((!mQuotesPreformatted && mSpanLevel > 0) || mDontWrapAnyQuotes))
|
||||
|| ((mSpanLevel > 0 || mDontWrapAnyQuotes)
|
||||
&& mEmptyLines >= 0 && str.First() == PRUnichar('>'))) {
|
||||
// No intelligent wrapping.
|
||||
|
||||
|
|
|
@ -176,11 +176,9 @@ protected:
|
|||
// Quotes need to be wrapped differently from non-quoted text,
|
||||
// because quoted text has a few extra characters (e.g. ">> ")
|
||||
// which makes the line length longer.
|
||||
// Mail can represent quotes in different ways: it can wrap
|
||||
// quotes in a <pre> (if editor.quotesPreformatted is set),
|
||||
// or not wrapped in any special tag (if mail.compose.wrap_to_window_width)
|
||||
// or in a <span> (if neither of the above are set).
|
||||
bool mQuotesPreformatted; // expect quotes wrapped in <pre>
|
||||
// Mail can represent quotes in different ways:
|
||||
// Not wrapped in any special tag (if mail.compose.wrap_to_window_width)
|
||||
// or in a <span>.
|
||||
bool mDontWrapAnyQuotes; // no special quote markers
|
||||
|
||||
bool mStructs; // Output structs (pref)
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
|
||||
#include "nsString.h"
|
||||
#include "nsGenericElement.h"
|
||||
#include "nsDOMMemoryReporter.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
#include "nsString.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsTraceRefcnt.h"
|
||||
#include "nsDOMMemoryReporter.h"
|
||||
|
||||
class nsString;
|
||||
class nsCString;
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
#include "nsIAttribute.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsDOMMemoryReporter.h"
|
||||
|
||||
/**
|
||||
* Class used to implement DOM text nodes
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
#include "Layers.h"
|
||||
|
||||
#include "CheckedInt.h"
|
||||
#include "nsDataHashtable.h"
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include "ForceDiscreteGPUHelperCGL.h"
|
||||
|
@ -1627,16 +1628,25 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
struct WebGLMappedIdentifier {
|
||||
nsCString original, mapped; // ASCII strings
|
||||
WebGLMappedIdentifier(const nsACString& o, const nsACString& m) : original(o), mapped(m) {}
|
||||
};
|
||||
|
||||
class WebGLShader MOZ_FINAL
|
||||
: public nsIWebGLShader
|
||||
, public WebGLRefCountedObject<WebGLShader>
|
||||
, public WebGLContextBoundObject
|
||||
{
|
||||
friend class WebGLContext;
|
||||
friend class WebGLProgram;
|
||||
|
||||
public:
|
||||
WebGLShader(WebGLContext *context, WebGLenum stype)
|
||||
: WebGLContextBoundObject(context)
|
||||
, mType(stype)
|
||||
, mNeedsTranslation(true)
|
||||
, mAttribMaxNameLength(0)
|
||||
{
|
||||
mContext->MakeContextCurrent();
|
||||
mGLName = mContext->gl->fCreateShader(mType);
|
||||
|
@ -1693,11 +1703,45 @@ protected:
|
|||
WebGLuint mGLName;
|
||||
WebGLenum mType;
|
||||
nsString mSource;
|
||||
nsCString mTranslationLog;
|
||||
nsCString mTranslationLog; // The translation log should contain only ASCII characters
|
||||
bool mNeedsTranslation;
|
||||
WebGLMonotonicHandle mMonotonicHandle;
|
||||
nsTArray<WebGLMappedIdentifier> mAttributes;
|
||||
nsTArray<WebGLMappedIdentifier> mUniforms;
|
||||
int mAttribMaxNameLength;
|
||||
};
|
||||
|
||||
/** Takes an ASCII string like "foo[i]", turns it into "foo" and returns "[i]" in bracketPart
|
||||
*
|
||||
* \param string input/output: the string to split, becomes the string without the bracket part
|
||||
* \param bracketPart output: gets the bracket part.
|
||||
*
|
||||
* Notice that if there are multiple brackets like "foo[i].bar[j]", only the last bracket is split.
|
||||
*/
|
||||
static bool SplitLastSquareBracket(nsACString& string, nsCString& bracketPart)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(bracketPart.Length() == 0, "SplitLastSquareBracket must be called with empty bracketPart string");
|
||||
char *string_start = string.BeginWriting();
|
||||
char *s = string_start + string.Length() - 1;
|
||||
|
||||
if (*s != ']')
|
||||
return false;
|
||||
|
||||
while (*s != '[' && s != string_start)
|
||||
s--;
|
||||
|
||||
if (*s != '[')
|
||||
return false;
|
||||
|
||||
bracketPart.Assign(s);
|
||||
*s = 0;
|
||||
string.EndWriting();
|
||||
string.SetLength(s - string_start);
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef nsDataHashtable<nsCStringHashKey, nsCString> CStringHash;
|
||||
|
||||
class WebGLProgram MOZ_FINAL
|
||||
: public nsIWebGLProgram
|
||||
, public WebGLRefCountedObject<WebGLProgram>
|
||||
|
@ -1708,10 +1752,7 @@ public:
|
|||
: WebGLContextBoundObject(context)
|
||||
, mLinkStatus(false)
|
||||
, mGeneration(0)
|
||||
, mUniformMaxNameLength(0)
|
||||
, mAttribMaxNameLength(0)
|
||||
, mUniformCount(0)
|
||||
, mAttribCount(0)
|
||||
{
|
||||
mContext->MakeContextCurrent();
|
||||
mGLName = mContext->gl->fCreateProgram();
|
||||
|
@ -1790,15 +1831,107 @@ public:
|
|||
}
|
||||
|
||||
/* Called only after LinkProgram */
|
||||
bool UpdateInfo(gl::GLContext *gl);
|
||||
bool UpdateInfo();
|
||||
|
||||
/* Getters for cached program info */
|
||||
WebGLint UniformMaxNameLength() const { return mUniformMaxNameLength; }
|
||||
WebGLint AttribMaxNameLength() const { return mAttribMaxNameLength; }
|
||||
WebGLint UniformCount() const { return mUniformCount; }
|
||||
WebGLint AttribCount() const { return mAttribCount; }
|
||||
bool IsAttribInUse(unsigned i) const { return mAttribsInUse[i]; }
|
||||
|
||||
/* Maps identifier |name| to the mapped identifier |*mappedName|
|
||||
* Both are ASCII strings.
|
||||
*/
|
||||
void MapIdentifier(const nsACString& name, nsCString *mappedName) {
|
||||
if (!mIdentifierMap) {
|
||||
// if the identifier map doesn't exist yet, build it now
|
||||
mIdentifierMap = new CStringHash;
|
||||
mIdentifierMap->Init();
|
||||
for (size_t i = 0; i < mAttachedShaders.Length(); i++) {
|
||||
for (size_t j = 0; j < mAttachedShaders[i]->mAttributes.Length(); j++) {
|
||||
const WebGLMappedIdentifier& attrib = mAttachedShaders[i]->mAttributes[j];
|
||||
mIdentifierMap->Put(attrib.original, attrib.mapped);
|
||||
}
|
||||
for (size_t j = 0; j < mAttachedShaders[i]->mUniforms.Length(); j++) {
|
||||
const WebGLMappedIdentifier& uniform = mAttachedShaders[i]->mUniforms[j];
|
||||
mIdentifierMap->Put(uniform.original, uniform.mapped);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsCString mutableName(name);
|
||||
nsCString bracketPart;
|
||||
bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart);
|
||||
if (hadBracketPart)
|
||||
mutableName.AppendLiteral("[0]");
|
||||
|
||||
if (mIdentifierMap->Get(mutableName, mappedName)) {
|
||||
if (hadBracketPart) {
|
||||
nsCString mappedBracketPart;
|
||||
bool mappedHadBracketPart = SplitLastSquareBracket(*mappedName, mappedBracketPart);
|
||||
if (mappedHadBracketPart)
|
||||
mappedName->Append(bracketPart);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// not found? We might be in the situation we have a uniform array name and the GL's glGetActiveUniform
|
||||
// returned its name without [0], as is allowed by desktop GL but not in ES. Let's then try with [0].
|
||||
mutableName.AppendLiteral("[0]");
|
||||
if (mIdentifierMap->Get(mutableName, mappedName))
|
||||
return;
|
||||
|
||||
// not found? return name unchanged. This case happens e.g. on bad user input, or when
|
||||
// we're not using identifier mapping, or if we didn't store an identifier in the map because
|
||||
// e.g. its mapping is trivial (as happens for short identifiers)
|
||||
mappedName->Assign(name);
|
||||
}
|
||||
|
||||
/* Un-maps mapped identifier |name| to the original identifier |*reverseMappedName|
|
||||
* Both are ASCII strings.
|
||||
*/
|
||||
void ReverseMapIdentifier(const nsACString& name, nsCString *reverseMappedName) {
|
||||
if (!mIdentifierReverseMap) {
|
||||
// if the identifier reverse map doesn't exist yet, build it now
|
||||
mIdentifierReverseMap = new CStringHash;
|
||||
mIdentifierReverseMap->Init();
|
||||
for (size_t i = 0; i < mAttachedShaders.Length(); i++) {
|
||||
for (size_t j = 0; j < mAttachedShaders[i]->mAttributes.Length(); j++) {
|
||||
const WebGLMappedIdentifier& attrib = mAttachedShaders[i]->mAttributes[j];
|
||||
mIdentifierReverseMap->Put(attrib.mapped, attrib.original);
|
||||
}
|
||||
for (size_t j = 0; j < mAttachedShaders[i]->mUniforms.Length(); j++) {
|
||||
const WebGLMappedIdentifier& uniform = mAttachedShaders[i]->mUniforms[j];
|
||||
mIdentifierReverseMap->Put(uniform.mapped, uniform.original);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsCString mutableName(name);
|
||||
nsCString bracketPart;
|
||||
bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart);
|
||||
if (hadBracketPart)
|
||||
mutableName.AppendLiteral("[0]");
|
||||
|
||||
if (mIdentifierReverseMap->Get(mutableName, reverseMappedName)) {
|
||||
if (hadBracketPart) {
|
||||
nsCString reverseMappedBracketPart;
|
||||
bool reverseMappedHadBracketPart = SplitLastSquareBracket(*reverseMappedName, reverseMappedBracketPart);
|
||||
if (reverseMappedHadBracketPart)
|
||||
reverseMappedName->Append(bracketPart);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// not found? We might be in the situation we have a uniform array name and the GL's glGetActiveUniform
|
||||
// returned its name without [0], as is allowed by desktop GL but not in ES. Let's then try with [0].
|
||||
mutableName.AppendLiteral("[0]");
|
||||
if (mIdentifierReverseMap->Get(mutableName, reverseMappedName))
|
||||
return;
|
||||
|
||||
// not found? return name unchanged. This case happens e.g. on bad user input, or when
|
||||
// we're not using identifier mapping, or if we didn't store an identifier in the map because
|
||||
// e.g. its mapping is trivial (as happens for short identifiers)
|
||||
reverseMappedName->Assign(name);
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIWEBGLPROGRAM
|
||||
|
||||
|
@ -1811,13 +1944,10 @@ protected:
|
|||
CheckedUint32 mGeneration;
|
||||
|
||||
// post-link data
|
||||
|
||||
GLint mUniformMaxNameLength;
|
||||
GLint mAttribMaxNameLength;
|
||||
GLint mUniformCount;
|
||||
GLint mAttribCount;
|
||||
std::vector<bool> mAttribsInUse;
|
||||
WebGLMonotonicHandle mMonotonicHandle;
|
||||
nsAutoPtr<CStringHash> mIdentifierMap, mIdentifierReverseMap;
|
||||
int mAttribMaxNameLength;
|
||||
};
|
||||
|
||||
class WebGLRenderbuffer MOZ_FINAL
|
||||
|
@ -2366,12 +2496,11 @@ class WebGLActiveInfo MOZ_FINAL
|
|||
: public nsIWebGLActiveInfo
|
||||
{
|
||||
public:
|
||||
WebGLActiveInfo(WebGLint size, WebGLenum type, const char *nameptr, PRUint32 namelength) :
|
||||
WebGLActiveInfo(WebGLint size, WebGLenum type, const nsACString& name) :
|
||||
mSize(size),
|
||||
mType(type)
|
||||
{
|
||||
mName.AssignASCII(nameptr, namelength);
|
||||
}
|
||||
mType(type),
|
||||
mName(NS_ConvertASCIItoUTF16(name))
|
||||
{}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIWEBGLACTIVEINFO
|
||||
|
|
|
@ -121,7 +121,6 @@ NS_IMETHODIMP WebGLContext::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6) { \
|
|||
MakeContextCurrent(); gl->f##glname(a1,a2,a3,a4,a5,a6); return NS_OK; \
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// WebGL API
|
||||
//
|
||||
|
@ -181,7 +180,8 @@ WebGLContext::BindAttribLocation(nsIWebGLProgram *pobj, WebGLuint location, cons
|
|||
return NS_OK;
|
||||
|
||||
WebGLuint progname;
|
||||
if (!GetGLName<WebGLProgram>("bindAttribLocation: program", pobj, &progname))
|
||||
WebGLProgram *prog;
|
||||
if (!GetConcreteObjectAndGLName("bindAttribLocation: program", pobj, &prog, &progname))
|
||||
return NS_OK;
|
||||
|
||||
if (!ValidateGLSLVariableName(name, "bindAttribLocation"))
|
||||
|
@ -190,10 +190,12 @@ WebGLContext::BindAttribLocation(nsIWebGLProgram *pobj, WebGLuint location, cons
|
|||
if (!ValidateAttribIndex(location, "bindAttribLocation"))
|
||||
return NS_OK;
|
||||
|
||||
NS_LossyConvertUTF16toASCII cname(name);
|
||||
nsCString mappedName;
|
||||
prog->MapIdentifier(cname, &mappedName);
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
gl->fBindAttribLocation(progname, location, NS_LossyConvertUTF16toASCII(name).get());
|
||||
|
||||
gl->fBindAttribLocation(progname, location, mappedName.get());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1852,7 +1854,8 @@ WebGLContext::GetActiveAttrib(nsIWebGLProgram *pobj, PRUint32 index, nsIWebGLAct
|
|||
*retval = nsnull;
|
||||
|
||||
WebGLuint progname;
|
||||
if (!GetGLName<WebGLProgram>("getActiveAttrib: program", pobj, &progname))
|
||||
WebGLProgram *prog;
|
||||
if (!GetConcreteObjectAndGLName("getActiveAttrib: program", pobj, &prog, &progname))
|
||||
return NS_OK;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
@ -1872,7 +1875,10 @@ WebGLContext::GetActiveAttrib(nsIWebGLProgram *pobj, PRUint32 index, nsIWebGLAct
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
WebGLActiveInfo *retActiveInfo = new WebGLActiveInfo(attrsize, attrtype, name.get(), len);
|
||||
nsCString reverseMappedName;
|
||||
prog->ReverseMapIdentifier(nsDependentCString(name), &reverseMappedName);
|
||||
|
||||
WebGLActiveInfo *retActiveInfo = new WebGLActiveInfo(attrsize, attrtype, reverseMappedName);
|
||||
NS_ADDREF(*retval = retActiveInfo);
|
||||
|
||||
return NS_OK;
|
||||
|
@ -1916,7 +1922,8 @@ WebGLContext::GetActiveUniform(nsIWebGLProgram *pobj, PRUint32 index, nsIWebGLAc
|
|||
*retval = nsnull;
|
||||
|
||||
WebGLuint progname;
|
||||
if (!GetGLName<WebGLProgram>("getActiveUniform: program", pobj, &progname))
|
||||
WebGLProgram *prog;
|
||||
if (!GetConcreteObjectAndGLName("getActiveUniform: program", pobj, &prog, &progname))
|
||||
return NS_OK;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
@ -1926,17 +1933,20 @@ WebGLContext::GetActiveUniform(nsIWebGLProgram *pobj, PRUint32 index, nsIWebGLAc
|
|||
if (len == 0)
|
||||
*retval = nsnull;
|
||||
|
||||
nsAutoArrayPtr<char> name(new char[len + 3]); // +3 because we might have to append "[0]", see below
|
||||
nsAutoArrayPtr<char> name(new char[len]);
|
||||
|
||||
GLint attrsize = 0;
|
||||
GLuint attrtype = 0;
|
||||
GLint usize = 0;
|
||||
GLuint utype = 0;
|
||||
|
||||
gl->fGetActiveUniform(progname, index, len, &len, &attrsize, &attrtype, name);
|
||||
if (len == 0 || attrsize == 0 || attrtype == 0) {
|
||||
gl->fGetActiveUniform(progname, index, len, &len, &usize, &utype, name);
|
||||
if (len == 0 || usize == 0 || utype == 0) {
|
||||
*retval = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCString reverseMappedName;
|
||||
prog->ReverseMapIdentifier(nsDependentCString(name), &reverseMappedName);
|
||||
|
||||
// OpenGL ES 2.0 specifies that if foo is a uniform array, GetActiveUniform returns its name as "foo[0]".
|
||||
// See section 2.10 page 35 in the OpenGL ES 2.0.24 specification:
|
||||
//
|
||||
|
@ -1950,16 +1960,11 @@ WebGLContext::GetActiveUniform(nsIWebGLProgram *pobj, PRUint32 index, nsIWebGLAc
|
|||
// In principle we don't need to do that on OpenGL ES, but this is such a tricky difference between the ES and non-ES
|
||||
// specs that it seems probable that some ES implementers will overlook it. Since the work-around is quite cheap,
|
||||
// we do it unconditionally.
|
||||
if (attrsize > 1 && name[len-1] != ']') {
|
||||
name[len++] = '[';
|
||||
name[len++] = '0';
|
||||
name[len++] = ']';
|
||||
}
|
||||
|
||||
WebGLActiveInfo *retActiveInfo = new WebGLActiveInfo(attrsize, attrtype, name.get(), len);
|
||||
if (usize > 1 && reverseMappedName.CharAt(reverseMappedName.Length()-1) != ']')
|
||||
reverseMappedName.AppendLiteral("[0]");
|
||||
|
||||
WebGLActiveInfo *retActiveInfo = new WebGLActiveInfo(usize, utype, reverseMappedName);
|
||||
NS_ADDREF(*retval = retActiveInfo);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -2009,23 +2014,25 @@ WebGLContext::GetAttribLocation(nsIWebGLProgram *pobj,
|
|||
const nsAString& name,
|
||||
PRInt32 *retval)
|
||||
{
|
||||
if (!IsContextStable())
|
||||
{
|
||||
*retval = -1;
|
||||
return NS_OK;
|
||||
}
|
||||
*retval = -1;
|
||||
|
||||
*retval = 0;
|
||||
if (!IsContextStable())
|
||||
return NS_OK;
|
||||
|
||||
WebGLuint progname;
|
||||
if (!GetGLName<WebGLProgram>("getAttribLocation: program", pobj, &progname))
|
||||
WebGLProgram *prog;
|
||||
if (!GetConcreteObjectAndGLName("getAttribLocation: program", pobj, &prog, &progname))
|
||||
return NS_OK;
|
||||
|
||||
if (!ValidateGLSLVariableName(name, "getAttribLocation"))
|
||||
return NS_OK;
|
||||
|
||||
NS_LossyConvertUTF16toASCII cname(name);
|
||||
nsCString mappedName;
|
||||
prog->MapIdentifier(cname, &mappedName);
|
||||
|
||||
MakeContextCurrent();
|
||||
*retval = gl->fGetAttribLocation(progname, NS_LossyConvertUTF16toASCII(name).get());
|
||||
*retval = gl->fGetAttribLocation(progname, mappedName.get());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -2980,11 +2987,14 @@ WebGLContext::GetUniformLocation(nsIWebGLProgram *pobj, const nsAString& name, n
|
|||
return NS_OK;
|
||||
|
||||
if (!ValidateGLSLVariableName(name, "getUniformLocation"))
|
||||
return NS_OK;
|
||||
return NS_OK;
|
||||
|
||||
NS_LossyConvertUTF16toASCII cname(name);
|
||||
nsCString mappedName;
|
||||
prog->MapIdentifier(cname, &mappedName);
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
GLint intlocation = gl->fGetUniformLocation(progname, NS_LossyConvertUTF16toASCII(name).get());
|
||||
GLint intlocation = gl->fGetUniformLocation(progname, mappedName.get());
|
||||
|
||||
WebGLUniformLocation *loc = nsnull;
|
||||
if (intlocation >= 0)
|
||||
|
@ -3251,18 +3261,16 @@ WebGLContext::LinkProgram(nsIWebGLProgram *pobj)
|
|||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
gl->fLinkProgram(progname);
|
||||
|
||||
GLint ok;
|
||||
gl->fGetProgramiv(progname, LOCAL_GL_LINK_STATUS, &ok);
|
||||
if (ok) {
|
||||
program->SetLinkStatus(true);
|
||||
program->UpdateInfo(gl);
|
||||
bool updateInfoSucceeded = program->UpdateInfo();
|
||||
program->SetLinkStatus(updateInfoSucceeded);
|
||||
} else {
|
||||
program->SetLinkStatus(false);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -4387,6 +4395,20 @@ WebGLContext::CompileShader(nsIWebGLShader *sobj)
|
|||
|
||||
MakeContextCurrent();
|
||||
|
||||
ShShaderOutput targetShaderSourceLanguage = gl->IsGLES2() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT;
|
||||
bool useShaderSourceTranslation = true;
|
||||
|
||||
#ifdef ANDROID
|
||||
// see bug 709947. On Android, we can't use the ESSL backend because of strange crashes (might be
|
||||
// an allocator mismatch). So we use the GLSL backend, and discard the output, instead just passing
|
||||
// the original WebGL shader source to the GL (since that's ESSL already). The problem is that means
|
||||
// we can't use shader translations on Android, in particular we can't use long identifier shortening,
|
||||
// which means we can't reach 100% conformance. We need to fix that by debugging the ESSL backend
|
||||
// memory crashes.
|
||||
targetShaderSourceLanguage = SH_GLSL_OUTPUT;
|
||||
useShaderSourceTranslation = false;
|
||||
#endif
|
||||
|
||||
#if defined(USE_ANGLE)
|
||||
if (shader->NeedsTranslation() && mShaderValidation) {
|
||||
ShHandle compiler = 0;
|
||||
|
@ -4404,20 +4426,6 @@ WebGLContext::CompileShader(nsIWebGLShader *sobj)
|
|||
if (mEnabledExtensions[WebGL_OES_standard_derivatives])
|
||||
resources.OES_standard_derivatives = 1;
|
||||
|
||||
// notice that on Android, we always use SH_GLSL_OUTPUT, we never use the ESSL backend.
|
||||
// see bug 709947, the reason is that 1) we dont really need a ESSL backend since the
|
||||
// source is already ESSL, and 2) we ran into massive Android crashes when we used the ESSL backend.
|
||||
// But if we wanted to use shader transformations on ES platforms, we would have to use the
|
||||
// ESSL backend
|
||||
compiler = ShConstructCompiler((ShShaderType) shader->ShaderType(),
|
||||
SH_WEBGL_SPEC,
|
||||
#ifdef ANDROID
|
||||
SH_GLSL_OUTPUT,
|
||||
#else
|
||||
gl->IsGLES2() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT,
|
||||
#endif
|
||||
&resources);
|
||||
|
||||
// We're storing an actual instance of StripComments because, if we don't, the
|
||||
// cleanSource nsAString instance will be destroyed before the reference is
|
||||
// actually used.
|
||||
|
@ -4431,20 +4439,29 @@ WebGLContext::CompileShader(nsIWebGLShader *sobj)
|
|||
// shaderSource() already checks that the source stripped of comments is in the
|
||||
// 7-bit ASCII range, so we can skip the NS_IsAscii() check.
|
||||
const nsCString& sourceCString = NS_LossyConvertUTF16toASCII(flatSource);
|
||||
|
||||
|
||||
const PRUint32 maxSourceLength = (PRUint32(1)<<18) - 1;
|
||||
if (sourceCString.Length() > maxSourceLength)
|
||||
return ErrorInvalidValue("compileShader: source has more than %d characters", maxSourceLength);
|
||||
|
||||
const char *s = sourceCString.get();
|
||||
|
||||
int compileOptions = SH_OBJECT_CODE;
|
||||
|
||||
|
||||
compiler = ShConstructCompiler((ShShaderType) shader->ShaderType(),
|
||||
SH_WEBGL_SPEC,
|
||||
targetShaderSourceLanguage,
|
||||
&resources);
|
||||
|
||||
int compileOptions = 0;
|
||||
if (useShaderSourceTranslation) {
|
||||
compileOptions |= SH_OBJECT_CODE
|
||||
| SH_MAP_LONG_VARIABLE_NAMES
|
||||
| SH_ATTRIBUTES_UNIFORMS;
|
||||
#ifdef XP_MACOSX
|
||||
// work around bug 665578
|
||||
if (!nsCocoaFeatures::OnLionOrLater() && gl->Vendor() == gl::GLContext::VendorATI)
|
||||
compileOptions |= SH_EMULATE_BUILT_IN_FUNCTIONS;
|
||||
// work around bug 665578
|
||||
if (!nsCocoaFeatures::OnLionOrLater() && gl->Vendor() == gl::GLContext::VendorATI)
|
||||
compileOptions |= SH_EMULATE_BUILT_IN_FUNCTIONS;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!ShCompile(compiler, &s, 1, compileOptions)) {
|
||||
int len = 0;
|
||||
|
@ -4462,11 +4479,50 @@ WebGLContext::CompileShader(nsIWebGLShader *sobj)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/* If the GL context is really GLES2, we want to use the original provided code,
|
||||
* since it's actually GLES2. We still need to validate it however, which is
|
||||
* why we ran it through the above, but we don't want the desktop GLSL.
|
||||
*/
|
||||
if (!gl->IsGLES2()) {
|
||||
int num_attributes = 0;
|
||||
ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTES, &num_attributes);
|
||||
int num_uniforms = 0;
|
||||
ShGetInfo(compiler, SH_ACTIVE_UNIFORMS, &num_uniforms);
|
||||
int attrib_max_length = 0;
|
||||
ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &attrib_max_length);
|
||||
int uniform_max_length = 0;
|
||||
ShGetInfo(compiler, SH_ACTIVE_UNIFORM_MAX_LENGTH, &uniform_max_length);
|
||||
int mapped_max_length = 0;
|
||||
ShGetInfo(compiler, SH_MAPPED_NAME_MAX_LENGTH, &mapped_max_length);
|
||||
|
||||
shader->mAttribMaxNameLength = attrib_max_length;
|
||||
|
||||
shader->mAttributes.Clear();
|
||||
shader->mUniforms.Clear();
|
||||
nsAutoArrayPtr<char> attribute_name(new char[attrib_max_length+1]);
|
||||
nsAutoArrayPtr<char> uniform_name(new char[uniform_max_length+1]);
|
||||
nsAutoArrayPtr<char> mapped_name(new char[mapped_max_length+1]);
|
||||
|
||||
if (useShaderSourceTranslation) {
|
||||
for (int i = 0; i < num_attributes; i++) {
|
||||
int length, size;
|
||||
ShDataType type;
|
||||
ShGetActiveAttrib(compiler, i,
|
||||
&length, &size, &type,
|
||||
attribute_name,
|
||||
mapped_name);
|
||||
shader->mAttributes.AppendElement(WebGLMappedIdentifier(
|
||||
nsDependentCString(attribute_name),
|
||||
nsDependentCString(mapped_name)));
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_uniforms; i++) {
|
||||
int length, size;
|
||||
ShDataType type;
|
||||
ShGetActiveUniform(compiler, i,
|
||||
&length, &size, &type,
|
||||
uniform_name,
|
||||
mapped_name);
|
||||
shader->mUniforms.AppendElement(WebGLMappedIdentifier(
|
||||
nsDependentCString(uniform_name),
|
||||
nsDependentCString(mapped_name)));
|
||||
}
|
||||
|
||||
int len = 0;
|
||||
ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &len);
|
||||
|
||||
|
@ -4478,7 +4534,10 @@ WebGLContext::CompileShader(nsIWebGLShader *sobj)
|
|||
const char *ts = translatedSrc2.get();
|
||||
|
||||
gl->fShaderSource(shadername, 1, &ts, NULL);
|
||||
} else {
|
||||
} else { // not useShaderSourceTranslation
|
||||
// we just pass the raw untranslated shader source. We then can't use ANGLE idenfier mapping.
|
||||
// that's really bad, as that means we can't be 100% conformant. We should work towards always
|
||||
// using ANGLE identifier mapping.
|
||||
gl->fShaderSource(shadername, 1, &s, NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -49,38 +49,46 @@
|
|||
#include "angle/ShaderLang.h"
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
/*
|
||||
* Pull all the data out of the program that will be used by validate later on
|
||||
* Pull data out of the program, post-linking
|
||||
*/
|
||||
bool
|
||||
WebGLProgram::UpdateInfo(gl::GLContext *gl)
|
||||
WebGLProgram::UpdateInfo()
|
||||
{
|
||||
gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &mAttribMaxNameLength);
|
||||
gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH, &mUniformMaxNameLength);
|
||||
gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_UNIFORMS, &mUniformCount);
|
||||
gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES, &mAttribCount);
|
||||
mIdentifierMap = nsnull;
|
||||
mIdentifierReverseMap = nsnull;
|
||||
|
||||
GLint numVertexAttribs;
|
||||
if (mContext->MinCapabilityMode()) {
|
||||
numVertexAttribs = MINVALUE_GL_MAX_VERTEX_ATTRIBS;
|
||||
} else {
|
||||
gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, &numVertexAttribs);
|
||||
}
|
||||
mAttribsInUse.clear();
|
||||
mAttribsInUse.resize(numVertexAttribs);
|
||||
mAttribMaxNameLength = 0;
|
||||
|
||||
for (size_t i = 0; i < mAttachedShaders.Length(); i++)
|
||||
mAttribMaxNameLength = NS_MAX(mAttribMaxNameLength, mAttachedShaders[i]->mAttribMaxNameLength);
|
||||
|
||||
GLint attribCount;
|
||||
mContext->gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES, &attribCount);
|
||||
|
||||
mAttribsInUse.resize(mContext->mGLMaxVertexAttribs);
|
||||
std::fill(mAttribsInUse.begin(), mAttribsInUse.end(), false);
|
||||
|
||||
nsAutoArrayPtr<char> nameBuf(new char[mAttribMaxNameLength]);
|
||||
|
||||
for (int i = 0; i < mAttribCount; ++i) {
|
||||
for (int i = 0; i < attribCount; ++i) {
|
||||
GLint attrnamelen;
|
||||
GLint attrsize;
|
||||
GLenum attrtype;
|
||||
gl->fGetActiveAttrib(mGLName, i, mAttribMaxNameLength, &attrnamelen, &attrsize, &attrtype, nameBuf);
|
||||
mContext->gl->fGetActiveAttrib(mGLName, i, mAttribMaxNameLength, &attrnamelen, &attrsize, &attrtype, nameBuf);
|
||||
if (attrnamelen > 0) {
|
||||
GLint loc = gl->fGetAttribLocation(mGLName, nameBuf);
|
||||
mAttribsInUse[loc] = true;
|
||||
GLint loc = mContext->gl->fGetAttribLocation(mGLName, nameBuf);
|
||||
NS_ABORT_IF_FALSE(loc >= 0, "major oops in managing the attributes of a WebGL program");
|
||||
if (loc < mContext->mGLMaxVertexAttribs) {
|
||||
mAttribsInUse[loc] = true;
|
||||
} else {
|
||||
mContext->ErrorInvalidOperation("program exceeds MAX_VERTEX_ATTRIBS");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -334,7 +342,7 @@ bool WebGLContext::ValidateDrawModeEnum(WebGLenum mode, const char *info)
|
|||
|
||||
bool WebGLContext::ValidateGLSLVariableName(const nsAString& name, const char *info)
|
||||
{
|
||||
const PRUint32 maxSize = 255;
|
||||
const PRUint32 maxSize = 256;
|
||||
if (name.Length() > maxSize) {
|
||||
ErrorInvalidValue("%s: identifier is %d characters long, exceeds the maximum allowed length of %d characters",
|
||||
info, name.Length(), maxSize);
|
||||
|
|
|
@ -1,13 +1,7 @@
|
|||
conformance/context/premultiplyalpha-test.html
|
||||
conformance/glsl/misc/glsl-long-variable-names.html
|
||||
conformance/glsl/misc/shader-with-256-character-identifier.frag.html
|
||||
conformance/glsl/misc/shader-with-long-line.html
|
||||
conformance/misc/uninitialized-test.html
|
||||
conformance/programs/gl-get-active-attribute.html
|
||||
conformance/textures/texture-mips.html
|
||||
conformance/uniforms/gl-uniform-bool.html
|
||||
conformance/more/conformance/quickCheckAPI-S_V.html
|
||||
conformance/more/functions/uniformfArrayLen1.html
|
||||
conformance/glsl/misc/attrib-location-length-limits.html
|
||||
conformance/glsl/misc/uniform-location-length-limits.html
|
||||
conformance/renderbuffers/framebuffer-object-attachment.html
|
|
@ -1,11 +1,6 @@
|
|||
conformance/context/premultiplyalpha-test.html
|
||||
conformance/glsl/misc/glsl-function-nodes.html
|
||||
conformance/glsl/misc/glsl-long-variable-names.html
|
||||
conformance/glsl/misc/shader-with-256-character-identifier.frag.html
|
||||
conformance/glsl/misc/shader-with-long-line.html
|
||||
conformance/more/conformance/quickCheckAPI-S_V.html
|
||||
conformance/glsl/misc/attrib-location-length-limits.html
|
||||
conformance/glsl/misc/uniform-location-length-limits.html
|
||||
conformance/programs/program-test.html
|
||||
conformance/textures/texture-mips.html
|
||||
conformance/textures/texture-npot.html
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
conformance/context/premultiplyalpha-test.html
|
||||
conformance/glsl/functions/glsl-function-atan.html
|
||||
conformance/glsl/functions/glsl-function-atan-xy.html
|
||||
conformance/glsl/misc/glsl-long-variable-names.html
|
||||
conformance/glsl/misc/shader-with-256-character-identifier.frag.html
|
||||
conformance/glsl/misc/shader-with-long-line.html
|
||||
conformance/more/conformance/quickCheckAPI-S_V.html
|
||||
conformance/more/functions/uniformfArrayLen1.html
|
||||
conformance/glsl/misc/attrib-location-length-limits.html
|
||||
conformance/glsl/misc/struct-nesting-under-maximum.html
|
||||
conformance/glsl/misc/uniform-location-length-limits.html
|
||||
conformance/more/functions/uniformfArrayLen1.html
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
#include "nsFrameLoader.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsContentCreatorFunctions.h"
|
||||
#include "nsDOMMemoryReporter.h"
|
||||
|
||||
class nsIDOMAttr;
|
||||
class nsIDOMEventListener;
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "nsWeakPtr.h"
|
||||
#include "nsVariant.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMMemoryReporter.h"
|
||||
#include "nsEventDispatcher.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsAsyncDOMEvent.h"
|
||||
|
|
|
@ -51,7 +51,6 @@
|
|||
#include "nsIDocument.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsHTMLDNSPrefetch.h"
|
||||
#include "nsDOMMemoryReporter.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
#include "nsGkAtoms.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsMappedAttributes.h"
|
||||
#include "nsDOMMemoryReporter.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
|
|
|
@ -100,8 +100,8 @@ public:
|
|||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsHTMLOutputElement,
|
||||
nsGenericHTMLFormElement)
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLOutputElement,
|
||||
nsGenericHTMLFormElement)
|
||||
|
||||
virtual nsXPCClassInfo* GetClassInfo();
|
||||
protected:
|
||||
|
@ -136,13 +136,26 @@ nsHTMLOutputElement::~nsHTMLOutputElement()
|
|||
}
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLOutputElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsHTMLOutputElement,
|
||||
nsGenericHTMLFormElement)
|
||||
if (tmp->mTokenList) {
|
||||
tmp->mTokenList->DropReference();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTokenList)
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLOutputElement,
|
||||
nsGenericHTMLFormElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mTokenList,
|
||||
nsDOMTokenList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(nsHTMLOutputElement, nsGenericElement)
|
||||
NS_IMPL_RELEASE_INHERITED(nsHTMLOutputElement, nsGenericElement)
|
||||
|
||||
DOMCI_NODE_DATA(HTMLOutputElement, nsHTMLOutputElement)
|
||||
|
||||
NS_INTERFACE_TABLE_HEAD(nsHTMLOutputElement)
|
||||
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLOutputElement)
|
||||
NS_HTML_CONTENT_INTERFACE_TABLE3(nsHTMLOutputElement,
|
||||
nsIDOMHTMLOutputElement,
|
||||
nsIMutationObserver,
|
||||
|
|
|
@ -41,7 +41,6 @@
|
|||
#include "nsStyleConsts.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsRuleData.h"
|
||||
#include "nsDOMMemoryReporter.h"
|
||||
|
||||
class nsHTMLSpanElement : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLElement
|
||||
|
|
|
@ -49,7 +49,6 @@
|
|||
#include "nsChangeHint.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsDOMMemoryReporter.h"
|
||||
#include "nsError.h"
|
||||
#include "nsGenericElement.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
|
|
@ -40,8 +40,6 @@
|
|||
#include "nsGkAtoms.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMMemoryReporter.h"
|
||||
|
||||
|
||||
class nsXMLCDATASection : public nsGenericDOMDataNode,
|
||||
public nsIDOMCDATASection
|
||||
|
|
|
@ -104,7 +104,7 @@ EXPORTS = \
|
|||
nsWrapperCache.h \
|
||||
nsContentPermissionHelper.h \
|
||||
nsStructuredCloneContainer.h \
|
||||
nsDOMMemoryReporter.h \
|
||||
nsWindowMemoryReporter.h \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS_NAMESPACES = mozilla/dom
|
||||
|
@ -139,7 +139,7 @@ CPPSRCS = \
|
|||
nsStructuredCloneContainer.cpp \
|
||||
nsDOMNavigationTiming.cpp \
|
||||
nsPerformance.cpp \
|
||||
nsDOMMemoryReporter.cpp \
|
||||
nsWindowMemoryReporter.cpp \
|
||||
DOMError.cpp \
|
||||
DOMRequest.cpp \
|
||||
Navigator.cpp \
|
||||
|
|
|
@ -140,7 +140,6 @@
|
|||
#include "nsDOMError.h"
|
||||
#include "nsIDOMDOMException.h"
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsIDOMNodeList.h"
|
||||
#include "nsIDOMNamedNodeMap.h"
|
||||
#include "nsIDOMDOMStringList.h"
|
||||
#include "nsIDOMDOMTokenList.h"
|
||||
|
@ -152,8 +151,6 @@
|
|||
#include "nsIForm.h"
|
||||
#include "nsIFormControl.h"
|
||||
#include "nsIDOMHTMLFormElement.h"
|
||||
#include "nsIDOMHTMLCollection.h"
|
||||
#include "nsIHTMLCollection.h"
|
||||
#include "nsHTMLDocument.h"
|
||||
|
||||
// Constraint Validation API helper includes
|
||||
|
@ -168,12 +165,7 @@
|
|||
#include "nsIObjectLoadingContent.h"
|
||||
#include "nsIPluginHost.h"
|
||||
|
||||
// HTMLOptionsCollection includes
|
||||
#include "nsIDOMHTMLOptionElement.h"
|
||||
#include "nsIDOMHTMLOptionsCollection.h"
|
||||
|
||||
// ContentList includes
|
||||
#include "nsContentList.h"
|
||||
#include "nsGenericElement.h"
|
||||
|
||||
// Event related includes
|
||||
|
@ -785,7 +777,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
|||
NS_DEFINE_CLASSINFO_DATA(CDATASection, nsNodeSH, NODE_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(ProcessingInstruction, nsNodeSH,
|
||||
NODE_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(NodeList, nsNodeListSH, ARRAY_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(NodeList, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(NamedNodeMap, nsNamedNodeMapSH,
|
||||
ARRAY_SCRIPTABLE_FLAGS)
|
||||
|
||||
|
@ -824,13 +817,10 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
|||
NS_DEFINE_CLASSINFO_DATA(HTMLDocument, nsHTMLDocumentSH,
|
||||
DOCUMENT_SCRIPTABLE_FLAGS |
|
||||
nsIXPCScriptable::WANT_GETPROPERTY)
|
||||
NS_DEFINE_CLASSINFO_DATA(HTMLOptionsCollection,
|
||||
nsHTMLOptionsCollectionSH,
|
||||
ARRAY_SCRIPTABLE_FLAGS |
|
||||
nsIXPCScriptable::WANT_SETPROPERTY)
|
||||
NS_DEFINE_CLASSINFO_DATA(HTMLCollection,
|
||||
nsHTMLCollectionSH,
|
||||
ARRAY_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(HTMLOptionsCollection, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(HTMLCollection, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
|
||||
// HTML element classes
|
||||
NS_DEFINE_CLASSINFO_DATA(HTMLElement, nsElementSH,
|
||||
|
@ -1041,7 +1031,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
|||
ARRAY_SCRIPTABLE_FLAGS)
|
||||
|
||||
NS_DEFINE_CLASSINFO_DATA_WITH_NAME(ContentList, HTMLCollection,
|
||||
nsContentListSH, ARRAY_SCRIPTABLE_FLAGS)
|
||||
nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
|
||||
NS_DEFINE_CLASSINFO_DATA(XMLStylesheetProcessingInstruction, nsNodeSH,
|
||||
NODE_SCRIPTABLE_FLAGS)
|
||||
|
@ -4460,7 +4451,7 @@ nsDOMClassInfo::GetArrayIndexFromId(JSContext *cx, jsid id, bool *aIsNumber)
|
|||
*aIsNumber = false;
|
||||
}
|
||||
|
||||
jsint i;
|
||||
int i;
|
||||
if (JSID_IS_INT(id)) {
|
||||
i = JSID_TO_INT(id);
|
||||
} else {
|
||||
|
@ -8020,74 +8011,6 @@ nsArraySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
|||
}
|
||||
|
||||
|
||||
// NodeList scriptable helper
|
||||
|
||||
nsresult
|
||||
nsNodeListSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
|
||||
JSObject *globalObj, JSObject **parentObj)
|
||||
{
|
||||
nsINodeList* list = static_cast<nsINodeList*>(nativeObj);
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<nsINodeList> list_qi = do_QueryInterface(nativeObj);
|
||||
|
||||
// If this assertion fires the QI implementation for the object in
|
||||
// question doesn't use the nsINodeList pointer as the nsISupports
|
||||
// pointer. That must be fixed, or we'll crash...
|
||||
NS_ASSERTION(list_qi == list, "Uh, fix QI!");
|
||||
}
|
||||
#endif
|
||||
|
||||
nsINode* native_parent = list->GetParentObject();
|
||||
|
||||
nsresult rv =
|
||||
WrapNativeParent(cx, globalObj, native_parent, native_parent, parentObj);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_SUCCESS_ALLOW_SLIM_WRAPPERS;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsNodeListSH::GetLength(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj, PRUint32 *length)
|
||||
{
|
||||
nsINodeList* list = static_cast<nsINodeList*>(GetNative(wrapper, obj));
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<nsINodeList> list_qi = do_QueryWrappedNative(wrapper, obj);
|
||||
|
||||
// If this assertion fires the QI implementation for the object in
|
||||
// question doesn't use the nsINodeList pointer as the nsISupports
|
||||
// pointer. That must be fixed, or we'll crash...
|
||||
NS_ABORT_IF_FALSE(list_qi == list, "Uh, fix QI!");
|
||||
}
|
||||
#endif
|
||||
|
||||
return list->GetLength(length);
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
nsNodeListSH::GetItemAt(nsISupports *aNative, PRUint32 aIndex,
|
||||
nsWrapperCache **aCache, nsresult *aResult)
|
||||
{
|
||||
nsINodeList* list = static_cast<nsINodeList*>(aNative);
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<nsINodeList> list_qi = do_QueryInterface(aNative);
|
||||
|
||||
// If this assertion fires the QI implementation for the object in
|
||||
// question doesn't use the nsINodeList pointer as the nsISupports
|
||||
// pointer. That must be fixed, or we'll crash...
|
||||
NS_ABORT_IF_FALSE(list_qi == list, "Uh, fix QI!");
|
||||
}
|
||||
#endif
|
||||
|
||||
nsINode *node;
|
||||
*aCache = node = list->GetNodeAt(aIndex);
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
// StringList scriptable helper
|
||||
|
||||
nsresult
|
||||
|
@ -8248,146 +8171,6 @@ nsNamedNodeMapSH::GetNamedItem(nsISupports *aNative, const nsAString& aName,
|
|||
}
|
||||
|
||||
|
||||
// HTMLCollection helper
|
||||
|
||||
nsresult
|
||||
nsHTMLCollectionSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
|
||||
JSObject *globalObj, JSObject **parentObj)
|
||||
{
|
||||
nsIHTMLCollection* list = static_cast<nsIHTMLCollection*>(nativeObj);
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<nsIHTMLCollection> list_qi = do_QueryInterface(nativeObj);
|
||||
|
||||
// If this assertion fires the QI implementation for the object in
|
||||
// question doesn't use the nsIHTMLCollection pointer as the nsISupports
|
||||
// pointer. That must be fixed, or we'll crash...
|
||||
NS_ASSERTION(list_qi == list, "Uh, fix QI!");
|
||||
}
|
||||
#endif
|
||||
|
||||
nsINode* native_parent = list->GetParentObject();
|
||||
|
||||
nsresult rv =
|
||||
WrapNativeParent(cx, globalObj, native_parent, native_parent, parentObj);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_SUCCESS_ALLOW_SLIM_WRAPPERS;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLCollectionSH::GetLength(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj, PRUint32 *length)
|
||||
{
|
||||
nsIHTMLCollection* collection =
|
||||
static_cast<nsIHTMLCollection*>(GetNative(wrapper, obj));
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<nsIHTMLCollection> collection_qi =
|
||||
do_QueryWrappedNative(wrapper, obj);
|
||||
|
||||
// If this assertion fires the QI implementation for the object in
|
||||
// question doesn't use the nsIHTMLCollection pointer as the nsISupports
|
||||
// pointer. That must be fixed, or we'll crash...
|
||||
NS_ABORT_IF_FALSE(collection_qi == collection, "Uh, fix QI!");
|
||||
}
|
||||
#endif
|
||||
|
||||
return collection->GetLength(length);
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
nsHTMLCollectionSH::GetItemAt(nsISupports *aNative, PRUint32 aIndex,
|
||||
nsWrapperCache **aCache, nsresult *aResult)
|
||||
{
|
||||
nsIHTMLCollection* collection = static_cast<nsIHTMLCollection*>(aNative);
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<nsIHTMLCollection> collection_qi = do_QueryInterface(aNative);
|
||||
|
||||
// If this assertion fires the QI implementation for the object in
|
||||
// question doesn't use the nsIHTMLCollection pointer as the nsISupports
|
||||
// pointer. That must be fixed, or we'll crash...
|
||||
NS_ABORT_IF_FALSE(collection_qi == collection, "Uh, fix QI!");
|
||||
}
|
||||
#endif
|
||||
|
||||
nsINode *item;
|
||||
*aCache = item = collection->GetNodeAt(aIndex);
|
||||
return item;
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
nsHTMLCollectionSH::GetNamedItem(nsISupports *aNative,
|
||||
const nsAString& aName,
|
||||
nsWrapperCache **aCache,
|
||||
nsresult *aResult)
|
||||
{
|
||||
nsIHTMLCollection* collection = static_cast<nsIHTMLCollection*>(aNative);
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<nsIHTMLCollection> collection_qi = do_QueryInterface(aNative);
|
||||
|
||||
// If this assertion fires the QI implementation for the object in
|
||||
// question doesn't use the nsIHTMLCollection pointer as the nsISupports
|
||||
// pointer. That must be fixed, or we'll crash...
|
||||
NS_ABORT_IF_FALSE(collection_qi == collection, "Uh, fix QI!");
|
||||
}
|
||||
#endif
|
||||
|
||||
return collection->GetNamedItem(aName, aCache);
|
||||
}
|
||||
|
||||
|
||||
// ContentList helper
|
||||
nsresult
|
||||
nsContentListSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
|
||||
JSObject *globalObj, JSObject **parentObj)
|
||||
{
|
||||
nsContentList *contentList = nsContentList::FromSupports(nativeObj);
|
||||
nsINode *native_parent = contentList->GetParentObject();
|
||||
|
||||
if (!native_parent) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv =
|
||||
WrapNativeParent(cx, globalObj, native_parent, native_parent, parentObj);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_SUCCESS_ALLOW_SLIM_WRAPPERS;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContentListSH::GetLength(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj, PRUint32 *length)
|
||||
{
|
||||
nsContentList *list =
|
||||
nsContentList::FromSupports(GetNative(wrapper, obj));
|
||||
|
||||
return list->GetLength(length);
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
nsContentListSH::GetItemAt(nsISupports *aNative, PRUint32 aIndex,
|
||||
nsWrapperCache **aCache, nsresult *aResult)
|
||||
{
|
||||
nsContentList *list = nsContentList::FromSupports(aNative);
|
||||
|
||||
nsIContent *item;
|
||||
*aCache = item = list->GetNodeAt(aIndex);
|
||||
return item;
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
nsContentListSH::GetNamedItem(nsISupports *aNative, const nsAString& aName,
|
||||
nsWrapperCache **aCache, nsresult *aResult)
|
||||
{
|
||||
nsContentList *list = nsContentList::FromSupports(aNative);
|
||||
|
||||
return list->GetNamedItem(aName, aCache);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMStringMapSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj, jsid id, PRUint32 flags,
|
||||
|
@ -9917,31 +9700,6 @@ nsHTMLPluginObjElementSH::NewResolve(nsIXPConnectWrappedNative *wrapper,
|
|||
_retval);
|
||||
}
|
||||
|
||||
// HTMLOptionsCollection helper
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLOptionsCollectionSH::SetProperty(nsIXPConnectWrappedNative *wrapper,
|
||||
JSContext *cx, JSObject *obj, jsid id,
|
||||
jsval *vp, bool *_retval)
|
||||
{
|
||||
PRInt32 n = GetArrayIndexFromId(cx, id);
|
||||
|
||||
if (n < 0) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMHTMLOptionsCollection> oc =
|
||||
do_QueryWrappedNative(wrapper, obj);
|
||||
NS_ENSURE_TRUE(oc, NS_ERROR_UNEXPECTED);
|
||||
|
||||
nsresult rv = nsHTMLSelectElementSH::SetOption(cx, vp, n, oc);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = NS_SUCCESS_I_DID_SOMETHING;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
// Plugin helper
|
||||
|
||||
nsISupports*
|
||||
|
|
|
@ -61,7 +61,6 @@ class DOMSVGTransformList;
|
|||
class nsGlobalWindow;
|
||||
class nsIDOMDocument;
|
||||
class nsIDOMHTMLOptionsCollection;
|
||||
class nsIDOMNodeList;
|
||||
class nsIDOMSVGLength;
|
||||
class nsIDOMSVGLengthList;
|
||||
class nsIDOMSVGNumber;
|
||||
|
@ -624,31 +623,6 @@ private:
|
|||
};
|
||||
|
||||
|
||||
// NodeList scriptable helper
|
||||
|
||||
class nsNodeListSH : public nsArraySH
|
||||
{
|
||||
protected:
|
||||
nsNodeListSH(nsDOMClassInfoData* aData) : nsArraySH(aData)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
|
||||
JSObject *globalObj, JSObject **parentObj);
|
||||
|
||||
virtual nsresult GetLength(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj, PRUint32 *length);
|
||||
virtual nsISupports* GetItemAt(nsISupports *aNative, PRUint32 aIndex,
|
||||
nsWrapperCache **aCache, nsresult *aResult);
|
||||
|
||||
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
|
||||
{
|
||||
return new nsNodeListSH(aData);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// NamedArray helper
|
||||
|
||||
class nsNamedArraySH : public nsArraySH
|
||||
|
@ -711,70 +685,6 @@ public:
|
|||
};
|
||||
|
||||
|
||||
// HTMLCollection helper
|
||||
|
||||
class nsHTMLCollectionSH : public nsNamedArraySH
|
||||
{
|
||||
protected:
|
||||
nsHTMLCollectionSH(nsDOMClassInfoData* aData) : nsNamedArraySH(aData)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~nsHTMLCollectionSH()
|
||||
{
|
||||
}
|
||||
|
||||
virtual nsresult GetLength(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj, PRUint32 *length);
|
||||
virtual nsISupports* GetItemAt(nsISupports *aNative, PRUint32 aIndex,
|
||||
nsWrapperCache **aCache, nsresult *aResult);
|
||||
|
||||
// Override nsNamedArraySH::GetNamedItem()
|
||||
virtual nsISupports* GetNamedItem(nsISupports *aNative,
|
||||
const nsAString& aName,
|
||||
nsWrapperCache **cache,
|
||||
nsresult *aResult);
|
||||
|
||||
public:
|
||||
NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
|
||||
JSObject *globalObj, JSObject **parentObj);
|
||||
|
||||
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
|
||||
{
|
||||
return new nsHTMLCollectionSH(aData);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// ContentList helper
|
||||
|
||||
class nsContentListSH : public nsNamedArraySH
|
||||
{
|
||||
protected:
|
||||
nsContentListSH(nsDOMClassInfoData* aData) : nsNamedArraySH(aData)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
|
||||
JSObject *globalObj, JSObject **parentObj);
|
||||
|
||||
virtual nsresult GetLength(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj, PRUint32 *length);
|
||||
virtual nsISupports* GetItemAt(nsISupports *aNative, PRUint32 aIndex,
|
||||
nsWrapperCache **aCache, nsresult *aResult);
|
||||
virtual nsISupports* GetNamedItem(nsISupports *aNative,
|
||||
const nsAString& aName,
|
||||
nsWrapperCache **cache,
|
||||
nsresult *aResult);
|
||||
|
||||
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
|
||||
{
|
||||
return new nsContentListSH(aData);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// DOMStringMap helper for .dataset property on elements.
|
||||
|
||||
class nsDOMStringMapSH : public nsDOMGenericSH
|
||||
|
@ -1007,31 +917,6 @@ public:
|
|||
};
|
||||
|
||||
|
||||
// HTMLOptionsCollection helper
|
||||
|
||||
class nsHTMLOptionsCollectionSH : public nsHTMLCollectionSH
|
||||
{
|
||||
protected:
|
||||
nsHTMLOptionsCollectionSH(nsDOMClassInfoData* aData)
|
||||
: nsHTMLCollectionSH(aData)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~nsHTMLOptionsCollectionSH()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj, jsid id, jsval *vp, bool *_retval);
|
||||
|
||||
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
|
||||
{
|
||||
return new nsHTMLOptionsCollectionSH(aData);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Plugin helper
|
||||
|
||||
class nsPluginSH : public nsNamedArraySH
|
||||
|
|
|
@ -35,22 +35,22 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsDOMMemoryReporter.h"
|
||||
#include "nsWindowMemoryReporter.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
|
||||
|
||||
nsDOMMemoryMultiReporter::nsDOMMemoryMultiReporter()
|
||||
nsWindowMemoryReporter::nsWindowMemoryReporter()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsDOMMemoryMultiReporter, nsIMemoryMultiReporter)
|
||||
NS_IMPL_ISUPPORTS1(nsWindowMemoryReporter, nsIMemoryMultiReporter)
|
||||
|
||||
/* static */
|
||||
void
|
||||
nsDOMMemoryMultiReporter::Init()
|
||||
nsWindowMemoryReporter::Init()
|
||||
{
|
||||
// The memory reporter manager is going to own this object.
|
||||
NS_RegisterMemoryMultiReporter(new nsDOMMemoryMultiReporter());
|
||||
NS_RegisterMemoryMultiReporter(new nsWindowMemoryReporter());
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -88,18 +88,11 @@ AppendWindowURI(nsGlobalWindow *aWindow, nsACString& aStr)
|
|||
return true;
|
||||
}
|
||||
|
||||
struct WindowTotals
|
||||
{
|
||||
WindowTotals() : mDom(0), mStyleSheets(0) {}
|
||||
size_t mDom;
|
||||
size_t mStyleSheets;
|
||||
};
|
||||
|
||||
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(DOMStyleMallocSizeOf, "dom+style")
|
||||
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(DOMStyleMallocSizeOf, "windows")
|
||||
|
||||
static void
|
||||
CollectWindowReports(nsGlobalWindow *aWindow,
|
||||
WindowTotals *aWindowTotals,
|
||||
nsWindowSizes *aWindowTotalSizes,
|
||||
nsIMemoryMultiReporterCallback *aCb,
|
||||
nsISupports *aClosure)
|
||||
{
|
||||
|
@ -126,7 +119,7 @@ CollectWindowReports(nsGlobalWindow *aWindow,
|
|||
// The path we give to the reporter callback for inner windows are
|
||||
// as follows:
|
||||
//
|
||||
// explicit/dom+style/window-objects/<category>/top=<top-outer-id> (inner=<top-inner-id>)/inner-window(id=<id>, uri=<uri>)
|
||||
// explicit/window-objects/<category>/top=<top-outer-id> (inner=<top-inner-id>)/inner-window(id=<id>, uri=<uri>)
|
||||
//
|
||||
// Where:
|
||||
// - <category> is active, cached, or other, as described above.
|
||||
|
@ -145,12 +138,12 @@ CollectWindowReports(nsGlobalWindow *aWindow,
|
|||
//
|
||||
// For outer windows we simply use:
|
||||
//
|
||||
// explicit/dom+style/window-objects/<category>/outer-windows
|
||||
// explicit/window-objects/<category>/outer-windows
|
||||
//
|
||||
// Which gives us simple counts of how many outer windows (and their
|
||||
// combined sizes) per category.
|
||||
|
||||
nsCAutoString windowPath("explicit/dom+style/window-objects/");
|
||||
nsCAutoString windowPath("explicit/window-objects/");
|
||||
|
||||
nsIDocShell *docShell = aWindow->GetDocShell();
|
||||
|
||||
|
@ -199,28 +192,40 @@ CollectWindowReports(nsGlobalWindow *aWindow,
|
|||
windowPath += NS_LITERAL_CSTRING("outer-windows");
|
||||
}
|
||||
|
||||
if (windowSizes.mDOM > 0) {
|
||||
nsCAutoString domPath(windowPath);
|
||||
domPath += "/dom";
|
||||
NS_NAMED_LITERAL_CSTRING(kWindowDesc,
|
||||
"Memory used by a window and the DOM within it.");
|
||||
aCb->Callback(EmptyCString(), domPath, nsIMemoryReporter::KIND_HEAP,
|
||||
nsIMemoryReporter::UNITS_BYTES, windowSizes.mDOM,
|
||||
kWindowDesc, aClosure);
|
||||
aWindowTotals->mDom += windowSizes.mDOM;
|
||||
}
|
||||
#define REPORT(_path1, _path2, _amount, _desc) \
|
||||
do { \
|
||||
if (_amount > 0) { \
|
||||
nsCAutoString path(_path1); \
|
||||
path += _path2; \
|
||||
aCb->Callback(EmptyCString(), path, nsIMemoryReporter::KIND_HEAP, \
|
||||
nsIMemoryReporter::UNITS_BYTES, _amount, \
|
||||
NS_LITERAL_CSTRING(_desc), aClosure); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
if (windowSizes.mStyleSheets > 0) {
|
||||
nsCAutoString styleSheetsPath(windowPath);
|
||||
styleSheetsPath += "/style-sheets";
|
||||
NS_NAMED_LITERAL_CSTRING(kStyleSheetsDesc,
|
||||
"Memory used by style sheets within a window.");
|
||||
aCb->Callback(EmptyCString(), styleSheetsPath,
|
||||
nsIMemoryReporter::KIND_HEAP,
|
||||
nsIMemoryReporter::UNITS_BYTES, windowSizes.mStyleSheets,
|
||||
kStyleSheetsDesc, aClosure);
|
||||
aWindowTotals->mStyleSheets += windowSizes.mStyleSheets;
|
||||
}
|
||||
REPORT(windowPath, "/dom", windowSizes.mDOM,
|
||||
"Memory used by a window and the DOM within it.");
|
||||
aWindowTotalSizes->mDOM += windowSizes.mDOM;
|
||||
|
||||
REPORT(windowPath, "/style-sheets", windowSizes.mStyleSheets,
|
||||
"Memory used by style sheets within a window.");
|
||||
aWindowTotalSizes->mStyleSheets += windowSizes.mStyleSheets;
|
||||
|
||||
REPORT(windowPath, "/layout/arenas", windowSizes.mLayoutArenas,
|
||||
"Memory used by layout PresShell, PresContext, and other related "
|
||||
"areas within a window.");
|
||||
aWindowTotalSizes->mLayoutArenas += windowSizes.mLayoutArenas;
|
||||
|
||||
REPORT(windowPath, "/layout/style-sets", windowSizes.mLayoutStyleSets,
|
||||
"Memory used by style sets within a window.");
|
||||
aWindowTotalSizes->mLayoutStyleSets += windowSizes.mLayoutStyleSets;
|
||||
|
||||
REPORT(windowPath, "/layout/text-runs", windowSizes.mLayoutTextRuns,
|
||||
"Memory used for text-runs (glyph layout) in the PresShell's frame "
|
||||
"tree, within a window.");
|
||||
aWindowTotalSizes->mLayoutTextRuns += windowSizes.mLayoutTextRuns;
|
||||
|
||||
#undef REPORT
|
||||
}
|
||||
|
||||
typedef nsTArray< nsRefPtr<nsGlobalWindow> > WindowArray;
|
||||
|
@ -235,15 +240,15 @@ GetWindows(const PRUint64& aId, nsGlobalWindow*& aWindow, void* aClosure)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMMemoryMultiReporter::GetName(nsACString &aName)
|
||||
nsWindowMemoryReporter::GetName(nsACString &aName)
|
||||
{
|
||||
aName.AssignLiteral("dom+style");
|
||||
aName.AssignLiteral("window-objects");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMMemoryMultiReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb,
|
||||
nsISupports* aClosure)
|
||||
nsWindowMemoryReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb,
|
||||
nsISupports* aClosure)
|
||||
{
|
||||
nsGlobalWindow::WindowByIdTable* windowsById =
|
||||
nsGlobalWindow::GetWindowsTable();
|
||||
|
@ -257,32 +262,47 @@ nsDOMMemoryMultiReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb,
|
|||
// Collect window memory usage.
|
||||
nsRefPtr<nsGlobalWindow> *w = windows.Elements();
|
||||
nsRefPtr<nsGlobalWindow> *end = w + windows.Length();
|
||||
WindowTotals windowTotals;
|
||||
nsWindowSizes windowTotalSizes(NULL);
|
||||
for (; w != end; ++w) {
|
||||
CollectWindowReports(*w, &windowTotals, aCb, aClosure);
|
||||
CollectWindowReports(*w, &windowTotalSizes, aCb, aClosure);
|
||||
}
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(kDomTotalWindowsDesc,
|
||||
"Memory used for the DOM within windows. This is the sum of all windows' "
|
||||
"'dom' numbers.");
|
||||
aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING("dom-total-window"),
|
||||
nsIMemoryReporter::KIND_OTHER,
|
||||
nsIMemoryReporter::UNITS_BYTES, windowTotals.mDom,
|
||||
kDomTotalWindowsDesc, aClosure);
|
||||
#define REPORT(_path, _amount, _desc) \
|
||||
do { \
|
||||
aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \
|
||||
nsIMemoryReporter::KIND_OTHER, \
|
||||
nsIMemoryReporter::UNITS_BYTES, _amount, \
|
||||
NS_LITERAL_CSTRING(_desc), aClosure); \
|
||||
} while (0)
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(kLayoutTotalWindowStyleSheetsDesc,
|
||||
"Memory used for style sheets within windows. This is the sum of all windows' "
|
||||
"'style-sheets' numbers.");
|
||||
aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING("style-sheets-total-window"),
|
||||
nsIMemoryReporter::KIND_OTHER,
|
||||
nsIMemoryReporter::UNITS_BYTES, windowTotals.mStyleSheets,
|
||||
kLayoutTotalWindowStyleSheetsDesc, aClosure);
|
||||
REPORT("window-objects-dom", windowTotalSizes.mDOM,
|
||||
"Memory used for the DOM within windows. "
|
||||
"This is the sum of all windows' 'dom' numbers.");
|
||||
|
||||
REPORT("window-objects-style-sheets", windowTotalSizes.mStyleSheets,
|
||||
"Memory used for style sheets within windows. "
|
||||
"This is the sum of all windows' 'style-sheets' numbers.");
|
||||
|
||||
REPORT("window-objects-layout-arenas", windowTotalSizes.mLayoutArenas,
|
||||
"Memory used by layout PresShell, PresContext, and other related "
|
||||
"areas within windows. This is the sum of all windows' "
|
||||
"'layout/arenas' numbers.");
|
||||
|
||||
REPORT("window-objects-layout-style-sets", windowTotalSizes.mLayoutStyleSets,
|
||||
"Memory used for style sets within windows. "
|
||||
"This is the sum of all windows' 'layout/style-sets' numbers.");
|
||||
|
||||
REPORT("window-objects-layout-text-runs", windowTotalSizes.mLayoutTextRuns,
|
||||
"Memory used for text runs within windows. "
|
||||
"This is the sum of all windows' 'layout/text-runs' numbers.");
|
||||
|
||||
#undef REPORT
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMMemoryMultiReporter::GetExplicitNonHeap(PRInt64* aAmount)
|
||||
nsWindowMemoryReporter::GetExplicitNonHeap(PRInt64* aAmount)
|
||||
{
|
||||
// This reporter only measures heap memory.
|
||||
*aAmount = 0;
|
|
@ -35,8 +35,8 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsDOMMemoryReporter_h__
|
||||
#define nsDOMMemoryReporter_h__
|
||||
#ifndef nsWindowMemoryReporter_h__
|
||||
#define nsWindowMemoryReporter_h__
|
||||
|
||||
#include "nsIMemoryReporter.h"
|
||||
|
||||
|
@ -49,17 +49,19 @@
|
|||
|
||||
class nsWindowSizes {
|
||||
public:
|
||||
nsWindowSizes(nsMallocSizeOfFun aMallocSizeOf)
|
||||
: mMallocSizeOf(aMallocSizeOf),
|
||||
mDOM(0),
|
||||
mStyleSheets(0)
|
||||
{}
|
||||
nsWindowSizes(nsMallocSizeOfFun aMallocSizeOf) {
|
||||
memset(this, 0, sizeof(nsWindowSizes));
|
||||
mMallocSizeOf = aMallocSizeOf;
|
||||
}
|
||||
nsMallocSizeOfFun mMallocSizeOf;
|
||||
size_t mDOM;
|
||||
size_t mStyleSheets;
|
||||
size_t mLayoutArenas;
|
||||
size_t mLayoutStyleSets;
|
||||
size_t mLayoutTextRuns;
|
||||
};
|
||||
|
||||
class nsDOMMemoryMultiReporter: public nsIMemoryMultiReporter
|
||||
class nsWindowMemoryReporter: public nsIMemoryMultiReporter
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
@ -69,8 +71,8 @@ public:
|
|||
|
||||
private:
|
||||
// Protect ctor, use Init() instead.
|
||||
nsDOMMemoryMultiReporter();
|
||||
nsWindowMemoryReporter();
|
||||
};
|
||||
|
||||
#endif // nsDOMMemoryReporter_h__
|
||||
#endif // nsWindowMemoryReporter_h__
|
||||
|
|
@ -49,11 +49,11 @@ interface nsIDOMDOMTokenList : nsISupports
|
|||
{
|
||||
readonly attribute unsigned long length;
|
||||
|
||||
DOMString item(in unsigned long index);
|
||||
[getter] DOMString item(in unsigned long index);
|
||||
boolean contains([Null(Stringify)] in DOMString token);
|
||||
void add([Null(Stringify)] in DOMString token);
|
||||
void remove([Null(Stringify)] in DOMString token);
|
||||
boolean toggle([Null(Stringify)] in DOMString token);
|
||||
|
||||
DOMString toString();
|
||||
[stringifier] DOMString toString();
|
||||
};
|
||||
|
|
|
@ -457,7 +457,7 @@ JSValToNPVariant(NPP npp, JSContext *cx, jsval val, NPVariant *variant)
|
|||
INT32_TO_NPVARIANT(JSVAL_TO_INT(val), *variant);
|
||||
} else if (JSVAL_IS_DOUBLE(val)) {
|
||||
double d = JSVAL_TO_DOUBLE(val);
|
||||
jsint i;
|
||||
int i;
|
||||
if (JS_DoubleIsInt32(d, &i)) {
|
||||
INT32_TO_NPVARIANT(i, *variant);
|
||||
} else {
|
||||
|
|
|
@ -157,14 +157,14 @@ NPIdentifierIsInt(NPIdentifier id)
|
|||
return JSID_IS_INT(NPIdentifierToJSId(id));
|
||||
}
|
||||
|
||||
inline jsint
|
||||
inline int
|
||||
NPIdentifierToInt(NPIdentifier id)
|
||||
{
|
||||
return JSID_TO_INT(NPIdentifierToJSId(id));
|
||||
}
|
||||
|
||||
inline NPIdentifier
|
||||
IntToNPIdentifier(jsint i)
|
||||
IntToNPIdentifier(int i)
|
||||
{
|
||||
return JSIdToNPIdentifier(INT_TO_JSID(i));
|
||||
}
|
||||
|
|
|
@ -94,16 +94,19 @@ function startTest()
|
|||
// add a second key
|
||||
localStorage.setItem("key2", "value2");
|
||||
is(localStorage.length, 2, "The storage has two key-value pairs");
|
||||
is(localStorage.key(1), "key1"); // This test might not be accurate because order is not preserved
|
||||
is(localStorage.key(0), "key2");
|
||||
is(localStorage.getItem("key1"), "value1");
|
||||
is(localStorage.getItem("key2"), "value2");
|
||||
var firstKey = localStorage.key(0);
|
||||
var secondKey = localStorage.key(1);
|
||||
ok((firstKey == 'key1' && secondKey == 'key2') ||
|
||||
(firstKey == 'key2' && secondKey == 'key1'),
|
||||
'Both keys should be present.');
|
||||
|
||||
// change the second key
|
||||
localStorage.setItem("key2", "value2-2");
|
||||
is(localStorage.length, 2, "The storage has two key-value pairs");
|
||||
is(localStorage.key(1), "key1"); // After key value changes the order must be preserved
|
||||
is(localStorage.key(0), "key2");
|
||||
is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
|
||||
is(localStorage.key(1), secondKey);
|
||||
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
|
||||
checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
|
||||
is(localStorage.getItem("key1"), "value1");
|
||||
|
@ -112,8 +115,8 @@ function startTest()
|
|||
// change the first key
|
||||
localStorage.setItem("key1", "value1-2");
|
||||
is(localStorage.length, 2, "The storage has two key-value pairs");
|
||||
is(localStorage.key(1), "key1"); // After key value changes the order must be preserved
|
||||
is(localStorage.key(0), "key2");
|
||||
is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
|
||||
is(localStorage.key(1), secondKey);
|
||||
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
|
||||
checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
|
||||
is(localStorage.getItem("key1"), "value1-2");
|
||||
|
|
|
@ -113,16 +113,19 @@ function doTest()
|
|||
// add a second key
|
||||
localStorage.setItem("key2", "value2");
|
||||
is(localStorage.length, 2, "The storage has two key-value pairs");
|
||||
is(localStorage.key(1), "key1"); // This test might not be accurate because order is not preserved
|
||||
is(localStorage.key(0), "key2");
|
||||
is(localStorage.getItem("key1"), "value1");
|
||||
is(localStorage.getItem("key2"), "value2");
|
||||
var firstKey = localStorage.key(0);
|
||||
var secondKey = localStorage.key(1);
|
||||
ok((firstKey == 'key1' && secondKey == 'key2') ||
|
||||
(firstKey == 'key2' && secondKey == 'key1'),
|
||||
'Both keys should be present.');
|
||||
|
||||
// change the second key
|
||||
localStorage.setItem("key2", "value2-2");
|
||||
is(localStorage.length, 2, "The storage has two key-value pairs");
|
||||
is(localStorage.key(1), "key1"); // After key value changes the order must be preserved
|
||||
is(localStorage.key(0), "key2");
|
||||
is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
|
||||
is(localStorage.key(1), secondKey);
|
||||
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
|
||||
checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
|
||||
is(localStorage.getItem("key1"), "value1");
|
||||
|
@ -131,8 +134,8 @@ function doTest()
|
|||
// change the first key
|
||||
localStorage.setItem("key1", "value1-2");
|
||||
is(localStorage.length, 2, "The storage has two key-value pairs");
|
||||
is(localStorage.key(1), "key1"); // After key value changes the order must be preserved
|
||||
is(localStorage.key(0), "key2");
|
||||
is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
|
||||
is(localStorage.key(1), secondKey);
|
||||
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
|
||||
checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
|
||||
is(localStorage.getItem("key1"), "value1-2");
|
||||
|
|
|
@ -104,16 +104,19 @@ function startTest()
|
|||
// add a second key
|
||||
localStorage.setItem("key2", "value2");
|
||||
is(localStorage.length, 2, "The storage has two key-value pairs");
|
||||
is(localStorage.key(1), "key1"); // This test might not be accurate because order is not preserved
|
||||
is(localStorage.key(0), "key2");
|
||||
is(localStorage.getItem("key1"), "value1");
|
||||
is(localStorage.getItem("key2"), "value2");
|
||||
var firstKey = localStorage.key(0);
|
||||
var secondKey = localStorage.key(1);
|
||||
ok((firstKey == 'key1' && secondKey == 'key2') ||
|
||||
(firstKey == 'key2' && secondKey == 'key1'),
|
||||
'Both keys should be present.');
|
||||
|
||||
// change the second key
|
||||
localStorage.setItem("key2", "value2-2");
|
||||
is(localStorage.length, 2, "The storage has two key-value pairs");
|
||||
is(localStorage.key(1), "key1"); // After key value changes the order must be preserved
|
||||
is(localStorage.key(0), "key2");
|
||||
is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
|
||||
is(localStorage.key(1), secondKey);
|
||||
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
|
||||
checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
|
||||
is(localStorage.getItem("key1"), "value1");
|
||||
|
@ -122,8 +125,8 @@ function startTest()
|
|||
// change the first key
|
||||
localStorage.setItem("key1", "value1-2");
|
||||
is(localStorage.length, 2, "The storage has two key-value pairs");
|
||||
is(localStorage.key(1), "key1"); // After key value changes the order must be preserved
|
||||
is(localStorage.key(0), "key2");
|
||||
is(localStorage.key(0), firstKey); // After key value changes the order must be preserved
|
||||
is(localStorage.key(1), secondKey);
|
||||
checkException(function() {localStorage.key(-1);}, INDEX_SIZE_ERR);
|
||||
checkException(function() {localStorage.key(2);}, INDEX_SIZE_ERR);
|
||||
is(localStorage.getItem("key1"), "value1-2");
|
||||
|
|
|
@ -96,16 +96,19 @@ function startTest()
|
|||
// add a second key
|
||||
sessionStorage.setItem("key2", "value2");
|
||||
is(sessionStorage.length, 2, "The storage has two key-value pairs");
|
||||
is(sessionStorage.key(1), "key1"); // This test might not be accurate because order is not preserved
|
||||
is(sessionStorage.key(0), "key2");
|
||||
is(sessionStorage.getItem("key1"), "value1");
|
||||
is(sessionStorage.getItem("key2"), "value2");
|
||||
var firstKey = sessionStorage.key(0);
|
||||
var secondKey = sessionStorage.key(1);
|
||||
ok((firstKey == 'key1' && secondKey == 'key2') ||
|
||||
(firstKey == 'key2' && secondKey == 'key1'),
|
||||
'Both keys should be present.');
|
||||
|
||||
// change the second key
|
||||
sessionStorage.setItem("key2", "value2-2");
|
||||
is(sessionStorage.length, 2, "The storage has two key-value pairs");
|
||||
is(sessionStorage.key(1), "key1"); // After key value changes the order must be preserved
|
||||
is(sessionStorage.key(0), "key2");
|
||||
is(sessionStorage.key(0), firstKey); // After key value changes the order must be preserved
|
||||
is(sessionStorage.key(1), secondKey);
|
||||
checkException(function() {sessionStorage.key(-1);}, INDEX_SIZE_ERR);
|
||||
checkException(function() {sessionStorage.key(2);}, INDEX_SIZE_ERR);
|
||||
is(sessionStorage.getItem("key1"), "value1");
|
||||
|
@ -114,8 +117,8 @@ function startTest()
|
|||
// change the first key
|
||||
sessionStorage.setItem("key1", "value1-2");
|
||||
is(sessionStorage.length, 2, "The storage has two key-value pairs");
|
||||
is(sessionStorage.key(1), "key1"); // After key value changes the order must be preserved
|
||||
is(sessionStorage.key(0), "key2");
|
||||
is(sessionStorage.key(0), firstKey); // After key value changes the order must be preserved
|
||||
is(sessionStorage.key(1), secondKey);
|
||||
checkException(function() {sessionStorage.key(-1);}, INDEX_SIZE_ERR);
|
||||
checkException(function() {sessionStorage.key(2);}, INDEX_SIZE_ERR);
|
||||
is(sessionStorage.getItem("key1"), "value1-2");
|
||||
|
|
|
@ -46,7 +46,6 @@ nsComposeTxtSrvFilter::nsComposeTxtSrvFilter() :
|
|||
{
|
||||
|
||||
mBlockQuoteAtom = do_GetAtom("blockquote");
|
||||
mPreAtom = do_GetAtom("pre");
|
||||
mSpanAtom = do_GetAtom("span");
|
||||
mTableAtom = do_GetAtom("table");
|
||||
mMozQuoteAtom = do_GetAtom("_moz_quote");
|
||||
|
@ -79,7 +78,7 @@ nsComposeTxtSrvFilter::Skip(nsIDOMNode* aNode, bool *_retval)
|
|||
*_retval = content->AttrValueIs(kNameSpaceID_None, mTypeAtom,
|
||||
mCiteAtom, eIgnoreCase);
|
||||
}
|
||||
} else if (tag == mPreAtom || tag == mSpanAtom) {
|
||||
} else if (tag == mSpanAtom) {
|
||||
if (mIsForMail) {
|
||||
*_retval = content->AttrValueIs(kNameSpaceID_None, mMozQuoteAtom,
|
||||
mTrueAtom, eIgnoreCase);
|
||||
|
|
|
@ -66,8 +66,7 @@ public:
|
|||
protected:
|
||||
bool mIsForMail;
|
||||
nsCOMPtr<nsIAtom> mBlockQuoteAtom;
|
||||
nsCOMPtr<nsIAtom> mPreAtom; // mail plain text quotes are wrapped in pre tags
|
||||
nsCOMPtr<nsIAtom> mSpanAtom; //or they may be wrapped in span tags (editor.quotesPreformatted).
|
||||
nsCOMPtr<nsIAtom> mSpanAtom; // mail plain text quotes are wrapped in span tags
|
||||
nsCOMPtr<nsIAtom> mMozQuoteAtom; // _moz_quote_
|
||||
nsCOMPtr<nsIAtom> mTableAtom;
|
||||
nsCOMPtr<nsIAtom> mClassAtom;
|
||||
|
|
|
@ -1968,94 +1968,63 @@ nsHTMLEditor::InsertAsPlaintextQuotation(const nsAString & aQuotedText,
|
|||
if (mWrapToWindow)
|
||||
return nsPlaintextEditor::InsertAsQuotation(aQuotedText, aNodeInserted);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
// The quotesPreformatted pref is a temporary measure. See bug 69638.
|
||||
// Eventually we'll pick one way or the other.
|
||||
bool quotesInPre = false;
|
||||
nsCOMPtr<nsIPrefBranch> prefBranch =
|
||||
do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
|
||||
if (NS_SUCCEEDED(rv) && prefBranch)
|
||||
prefBranch->GetBoolPref("editor.quotesPreformatted", "esInPre);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> preNode;
|
||||
// get selection
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
rv = GetSelection(getter_AddRefs(selection));
|
||||
nsresult rv = GetSelection(getter_AddRefs(selection));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!selection)
|
||||
{
|
||||
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
|
||||
}
|
||||
else
|
||||
{
|
||||
nsAutoEditBatch beginBatching(this);
|
||||
nsAutoRules beginRulesSniffing(this, kOpInsertQuotation, nsIEditor::eNext);
|
||||
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
|
||||
|
||||
// give rules a chance to handle or cancel
|
||||
nsTextRulesInfo ruleInfo(nsTextEditRules::kInsertElement);
|
||||
bool cancel, handled;
|
||||
rv = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (cancel) return NS_OK; // rules canceled the operation
|
||||
if (!handled)
|
||||
nsAutoEditBatch beginBatching(this);
|
||||
nsAutoRules beginRulesSniffing(this, kOpInsertQuotation, nsIEditor::eNext);
|
||||
|
||||
// give rules a chance to handle or cancel
|
||||
nsTextRulesInfo ruleInfo(nsTextEditRules::kInsertElement);
|
||||
bool cancel, handled;
|
||||
rv = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (cancel) return NS_OK; // rules canceled the operation
|
||||
if (!handled)
|
||||
{
|
||||
// Wrap the inserted quote in a <span> so it won't be wrapped:
|
||||
rv = DeleteSelectionAndCreateNode(NS_LITERAL_STRING("span"), getter_AddRefs(preNode));
|
||||
|
||||
// If this succeeded, then set selection inside the pre
|
||||
// so the inserted text will end up there.
|
||||
// If it failed, we don't care what the return value was,
|
||||
// but we'll fall through and try to insert the text anyway.
|
||||
if (NS_SUCCEEDED(rv) && preNode)
|
||||
{
|
||||
// Wrap the inserted quote in a <pre> so it won't be wrapped:
|
||||
nsAutoString tag;
|
||||
if (quotesInPre)
|
||||
tag.AssignLiteral("pre");
|
||||
else
|
||||
tag.AssignLiteral("span");
|
||||
|
||||
rv = DeleteSelectionAndCreateNode(tag, getter_AddRefs(preNode));
|
||||
|
||||
// If this succeeded, then set selection inside the pre
|
||||
// so the inserted text will end up there.
|
||||
// If it failed, we don't care what the return value was,
|
||||
// but we'll fall through and try to insert the text anyway.
|
||||
if (NS_SUCCEEDED(rv) && preNode)
|
||||
// Add an attribute on the pre node so we'll know it's a quotation.
|
||||
// Do this after the insertion, so that
|
||||
nsCOMPtr<nsIDOMElement> preElement(do_QueryInterface(preNode));
|
||||
if (preElement)
|
||||
{
|
||||
// Add an attribute on the pre node so we'll know it's a quotation.
|
||||
// Do this after the insertion, so that
|
||||
nsCOMPtr<nsIDOMElement> preElement (do_QueryInterface(preNode));
|
||||
if (preElement)
|
||||
{
|
||||
preElement->SetAttribute(NS_LITERAL_STRING("_moz_quote"),
|
||||
NS_LITERAL_STRING("true"));
|
||||
if (quotesInPre)
|
||||
{
|
||||
// set style to not have unwanted vertical margins
|
||||
preElement->SetAttribute(NS_LITERAL_STRING("style"),
|
||||
NS_LITERAL_STRING("margin: 0 0 0 0px;"));
|
||||
}
|
||||
else
|
||||
{
|
||||
// turn off wrapping on spans
|
||||
preElement->SetAttribute(NS_LITERAL_STRING("style"),
|
||||
NS_LITERAL_STRING("white-space: pre;"));
|
||||
}
|
||||
}
|
||||
|
||||
// and set the selection inside it:
|
||||
selection->Collapse(preNode, 0);
|
||||
preElement->SetAttribute(NS_LITERAL_STRING("_moz_quote"),
|
||||
NS_LITERAL_STRING("true"));
|
||||
// turn off wrapping on spans
|
||||
preElement->SetAttribute(NS_LITERAL_STRING("style"),
|
||||
NS_LITERAL_STRING("white-space: pre;"));
|
||||
}
|
||||
// and set the selection inside it:
|
||||
selection->Collapse(preNode, 0);
|
||||
}
|
||||
|
||||
if (aAddCites)
|
||||
rv = nsPlaintextEditor::InsertAsQuotation(aQuotedText, aNodeInserted);
|
||||
else
|
||||
rv = nsPlaintextEditor::InsertText(aQuotedText);
|
||||
// Note that if !aAddCites, aNodeInserted isn't set.
|
||||
// That's okay because the routines that use aAddCites
|
||||
// don't need to know the inserted node.
|
||||
if (aAddCites)
|
||||
rv = nsPlaintextEditor::InsertAsQuotation(aQuotedText, aNodeInserted);
|
||||
else
|
||||
rv = nsPlaintextEditor::InsertText(aQuotedText);
|
||||
// Note that if !aAddCites, aNodeInserted isn't set.
|
||||
// That's okay because the routines that use aAddCites
|
||||
// don't need to know the inserted node.
|
||||
|
||||
if (aNodeInserted && NS_SUCCEEDED(rv))
|
||||
{
|
||||
*aNodeInserted = preNode;
|
||||
NS_IF_ADDREF(*aNodeInserted);
|
||||
}
|
||||
if (aNodeInserted && NS_SUCCEEDED(rv))
|
||||
{
|
||||
*aNodeInserted = preNode;
|
||||
NS_IF_ADDREF(*aNodeInserted);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Set the selection to just after the inserted node:
|
||||
if (NS_SUCCEEDED(rv) && preNode)
|
||||
{
|
||||
|
|
|
@ -106,8 +106,7 @@ nsTransactionItem::AddChild(nsTransactionItem *aTransactionItem)
|
|||
NS_ENSURE_TRUE(aTransactionItem, NS_ERROR_NULL_POINTER);
|
||||
|
||||
if (!mUndoStack) {
|
||||
mUndoStack = new nsTransactionStack();
|
||||
NS_ENSURE_TRUE(mUndoStack, NS_ERROR_OUT_OF_MEMORY);
|
||||
mUndoStack = new nsTransactionStack(nsTransactionStack::FOR_UNDO);
|
||||
}
|
||||
|
||||
mUndoStack->Push(aTransactionItem);
|
||||
|
@ -187,7 +186,9 @@ nsTransactionItem::GetChild(PRInt32 aIndex, nsTransactionItem **aChild)
|
|||
if (numItems > 0 && aIndex < numItems) {
|
||||
NS_ENSURE_TRUE(mUndoStack, NS_ERROR_FAILURE);
|
||||
|
||||
return mUndoStack->GetItem(aIndex, aChild);
|
||||
nsRefPtr<nsTransactionItem> child = mUndoStack->GetItem(aIndex);
|
||||
child.forget(aChild);
|
||||
return *aChild ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Adjust the index for the redo stack:
|
||||
|
@ -200,7 +201,9 @@ nsTransactionItem::GetChild(PRInt32 aIndex, nsTransactionItem **aChild)
|
|||
|
||||
NS_ENSURE_TRUE(mRedoStack && numItems != 0 && aIndex < numItems, NS_ERROR_FAILURE);
|
||||
|
||||
return mRedoStack->GetItem(numItems - aIndex - 1, aChild);
|
||||
nsRefPtr<nsTransactionItem> child = mRedoStack->GetItem(aIndex);
|
||||
child.forget(aChild);
|
||||
return *aChild ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -243,20 +246,17 @@ nsTransactionItem::UndoChildren(nsTransactionManager *aTxMgr)
|
|||
|
||||
if (mUndoStack) {
|
||||
if (!mRedoStack && mUndoStack) {
|
||||
mRedoStack = new nsTransactionRedoStack();
|
||||
NS_ENSURE_TRUE(mRedoStack, NS_ERROR_OUT_OF_MEMORY);
|
||||
mRedoStack = new nsTransactionStack(nsTransactionStack::FOR_REDO);
|
||||
}
|
||||
|
||||
/* Undo all of the transaction items children! */
|
||||
result = mUndoStack->GetSize(&sz);
|
||||
|
||||
NS_ENSURE_SUCCESS(result, result);
|
||||
sz = mUndoStack->GetSize();
|
||||
|
||||
while (sz-- > 0) {
|
||||
result = mUndoStack->Peek(getter_AddRefs(item));
|
||||
item = mUndoStack->Peek();
|
||||
|
||||
if (NS_FAILED(result) || !item) {
|
||||
return result;
|
||||
if (!item) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsITransaction> t;
|
||||
|
@ -282,15 +282,8 @@ nsTransactionItem::UndoChildren(nsTransactionManager *aTxMgr)
|
|||
result = item->UndoTransaction(aTxMgr);
|
||||
|
||||
if (NS_SUCCEEDED(result)) {
|
||||
result = mUndoStack->Pop(getter_AddRefs(item));
|
||||
|
||||
if (NS_SUCCEEDED(result)) {
|
||||
result = mRedoStack->Push(item);
|
||||
|
||||
/* XXX: If we got an error here, I doubt we can recover!
|
||||
* XXX: Should we just push the item back on the undo stack?
|
||||
*/
|
||||
}
|
||||
item = mUndoStack->Pop();
|
||||
mRedoStack->Push(item);
|
||||
}
|
||||
|
||||
nsresult result2 = aTxMgr->DidUndoNotify(t, result);
|
||||
|
@ -331,22 +324,18 @@ nsTransactionItem::RedoChildren(nsTransactionManager *aTxMgr)
|
|||
{
|
||||
nsRefPtr<nsTransactionItem> item;
|
||||
nsresult result = NS_OK;
|
||||
PRInt32 sz = 0;
|
||||
|
||||
if (!mRedoStack)
|
||||
return NS_OK;
|
||||
|
||||
/* Redo all of the transaction items children! */
|
||||
result = mRedoStack->GetSize(&sz);
|
||||
|
||||
NS_ENSURE_SUCCESS(result, result);
|
||||
|
||||
PRInt32 sz = mRedoStack->GetSize();
|
||||
|
||||
while (sz-- > 0) {
|
||||
result = mRedoStack->Peek(getter_AddRefs(item));
|
||||
item = mRedoStack->Peek();
|
||||
|
||||
if (NS_FAILED(result) || !item) {
|
||||
return result;
|
||||
if (!item) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsITransaction> t;
|
||||
|
@ -372,14 +361,8 @@ nsTransactionItem::RedoChildren(nsTransactionManager *aTxMgr)
|
|||
result = item->RedoTransaction(aTxMgr);
|
||||
|
||||
if (NS_SUCCEEDED(result)) {
|
||||
result = mRedoStack->Pop(getter_AddRefs(item));
|
||||
|
||||
if (NS_SUCCEEDED(result)) {
|
||||
result = mUndoStack->Push(item);
|
||||
|
||||
// XXX: If we got an error here, I doubt we can recover!
|
||||
// XXX: Should we just push the item back on the redo stack?
|
||||
}
|
||||
item = mRedoStack->Pop();
|
||||
mUndoStack->Push(item);
|
||||
}
|
||||
|
||||
nsresult result2 = aTxMgr->DidUndoNotify(t, result);
|
||||
|
@ -402,7 +385,8 @@ nsTransactionItem::GetNumberOfUndoItems(PRInt32 *aNumItems)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
return mUndoStack->GetSize(aNumItems);
|
||||
*aNumItems = mUndoStack->GetSize();
|
||||
return *aNumItems ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -415,7 +399,8 @@ nsTransactionItem::GetNumberOfRedoItems(PRInt32 *aNumItems)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
return mRedoStack->GetSize(aNumItems);
|
||||
*aNumItems = mRedoStack->GetSize();
|
||||
return *aNumItems ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -43,14 +43,13 @@
|
|||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
class nsTransactionStack;
|
||||
class nsTransactionRedoStack;
|
||||
class nsTransactionManager;
|
||||
|
||||
class nsTransactionItem
|
||||
{
|
||||
nsCOMPtr<nsITransaction> mTransaction;
|
||||
nsTransactionStack *mUndoStack;
|
||||
nsTransactionRedoStack *mRedoStack;
|
||||
nsTransactionStack *mRedoStack;
|
||||
nsAutoRefCnt mRefCnt;
|
||||
|
||||
public:
|
||||
|
|
|
@ -75,10 +75,10 @@ NS_IMETHODIMP nsTransactionList::GetNumItems(PRInt32 *aNumItems)
|
|||
|
||||
NS_ENSURE_TRUE(txMgr, NS_ERROR_FAILURE);
|
||||
|
||||
nsresult result = NS_ERROR_FAILURE;
|
||||
nsresult result = NS_OK;
|
||||
|
||||
if (mTxnStack)
|
||||
result = mTxnStack->GetSize(aNumItems);
|
||||
*aNumItems = mTxnStack->GetSize();
|
||||
else if (mTxnItem)
|
||||
result = mTxnItem->GetNumberOfChildren(aNumItems);
|
||||
|
||||
|
@ -98,10 +98,10 @@ NS_IMETHODIMP nsTransactionList::ItemIsBatch(PRInt32 aIndex, bool *aIsBatch)
|
|||
|
||||
nsRefPtr<nsTransactionItem> item;
|
||||
|
||||
nsresult result = NS_ERROR_FAILURE;
|
||||
nsresult result = NS_OK;
|
||||
|
||||
if (mTxnStack)
|
||||
result = mTxnStack->GetItem(aIndex, getter_AddRefs(item));
|
||||
item = mTxnStack->GetItem(aIndex);
|
||||
else if (mTxnItem)
|
||||
result = mTxnItem->GetChild(aIndex, getter_AddRefs(item));
|
||||
|
||||
|
@ -125,10 +125,10 @@ NS_IMETHODIMP nsTransactionList::GetItem(PRInt32 aIndex, nsITransaction **aItem)
|
|||
|
||||
nsRefPtr<nsTransactionItem> item;
|
||||
|
||||
nsresult result = NS_ERROR_FAILURE;
|
||||
nsresult result = NS_OK;
|
||||
|
||||
if (mTxnStack)
|
||||
result = mTxnStack->GetItem(aIndex, getter_AddRefs(item));
|
||||
item = mTxnStack->GetItem(aIndex);
|
||||
else if (mTxnItem)
|
||||
result = mTxnItem->GetChild(aIndex, getter_AddRefs(item));
|
||||
|
||||
|
@ -152,10 +152,10 @@ NS_IMETHODIMP nsTransactionList::GetNumChildrenForItem(PRInt32 aIndex, PRInt32 *
|
|||
|
||||
nsRefPtr<nsTransactionItem> item;
|
||||
|
||||
nsresult result = NS_ERROR_FAILURE;
|
||||
nsresult result = NS_OK;
|
||||
|
||||
if (mTxnStack)
|
||||
result = mTxnStack->GetItem(aIndex, getter_AddRefs(item));
|
||||
item = mTxnStack->GetItem(aIndex);
|
||||
else if (mTxnItem)
|
||||
result = mTxnItem->GetChild(aIndex, getter_AddRefs(item));
|
||||
|
||||
|
@ -179,10 +179,10 @@ NS_IMETHODIMP nsTransactionList::GetChildListForItem(PRInt32 aIndex, nsITransact
|
|||
|
||||
nsRefPtr<nsTransactionItem> item;
|
||||
|
||||
nsresult result = NS_ERROR_FAILURE;
|
||||
nsresult result = NS_OK;
|
||||
|
||||
if (mTxnStack)
|
||||
result = mTxnStack->GetItem(aIndex, getter_AddRefs(item));
|
||||
item = mTxnStack->GetItem(aIndex);
|
||||
else if (mTxnItem)
|
||||
result = mTxnItem->GetChild(aIndex, getter_AddRefs(item));
|
||||
|
||||
|
|
|
@ -48,6 +48,9 @@
|
|||
|
||||
nsTransactionManager::nsTransactionManager(PRInt32 aMaxTransactionCount)
|
||||
: mMaxTransactionCount(aMaxTransactionCount)
|
||||
, mDoStack(nsTransactionStack::FOR_UNDO)
|
||||
, mUndoStack(nsTransactionStack::FOR_UNDO)
|
||||
, mRedoStack(nsTransactionStack::FOR_REDO)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -120,17 +123,12 @@ NS_IMETHODIMP
|
|||
nsTransactionManager::UndoTransaction()
|
||||
{
|
||||
nsresult result = NS_OK;
|
||||
nsRefPtr<nsTransactionItem> tx;
|
||||
|
||||
// It is illegal to call UndoTransaction() while the transaction manager is
|
||||
// executing a transaction's DoTransaction() method! If this happens,
|
||||
// the UndoTransaction() request is ignored, and we return NS_ERROR_FAILURE.
|
||||
|
||||
result = mDoStack.Peek(getter_AddRefs(tx));
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
nsRefPtr<nsTransactionItem> tx = mDoStack.Peek();
|
||||
|
||||
if (tx) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -138,11 +136,7 @@ nsTransactionManager::UndoTransaction()
|
|||
|
||||
// Peek at the top of the undo stack. Don't remove the transaction
|
||||
// until it has successfully completed.
|
||||
result = mUndoStack.Peek(getter_AddRefs(tx));
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
tx = mUndoStack.Peek();
|
||||
|
||||
// Bail if there's nothing on the stack.
|
||||
if (!tx) {
|
||||
|
@ -172,10 +166,8 @@ nsTransactionManager::UndoTransaction()
|
|||
result = tx->UndoTransaction(this);
|
||||
|
||||
if (NS_SUCCEEDED(result)) {
|
||||
result = mUndoStack.Pop(getter_AddRefs(tx));
|
||||
|
||||
if (NS_SUCCEEDED(result))
|
||||
result = mRedoStack.Push(tx);
|
||||
tx = mUndoStack.Pop();
|
||||
mRedoStack.Push(tx);
|
||||
}
|
||||
|
||||
nsresult result2 = DidUndoNotify(t, result);
|
||||
|
@ -190,17 +182,12 @@ NS_IMETHODIMP
|
|||
nsTransactionManager::RedoTransaction()
|
||||
{
|
||||
nsresult result = NS_OK;
|
||||
nsRefPtr<nsTransactionItem> tx;
|
||||
|
||||
// It is illegal to call RedoTransaction() while the transaction manager is
|
||||
// executing a transaction's DoTransaction() method! If this happens,
|
||||
// the RedoTransaction() request is ignored, and we return NS_ERROR_FAILURE.
|
||||
|
||||
result = mDoStack.Peek(getter_AddRefs(tx));
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
nsRefPtr<nsTransactionItem> tx = mDoStack.Peek();
|
||||
|
||||
if (tx) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -208,11 +195,7 @@ nsTransactionManager::RedoTransaction()
|
|||
|
||||
// Peek at the top of the redo stack. Don't remove the transaction
|
||||
// until it has successfully completed.
|
||||
result = mRedoStack.Peek(getter_AddRefs(tx));
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
tx = mRedoStack.Peek();
|
||||
|
||||
// Bail if there's nothing on the stack.
|
||||
if (!tx) {
|
||||
|
@ -242,10 +225,8 @@ nsTransactionManager::RedoTransaction()
|
|||
result = tx->RedoTransaction(this);
|
||||
|
||||
if (NS_SUCCEEDED(result)) {
|
||||
result = mRedoStack.Pop(getter_AddRefs(tx));
|
||||
|
||||
if (NS_SUCCEEDED(result))
|
||||
result = mUndoStack.Push(tx);
|
||||
tx = mRedoStack.Pop();
|
||||
mUndoStack.Push(tx);
|
||||
}
|
||||
|
||||
nsresult result2 = DidRedoNotify(t, result);
|
||||
|
@ -307,7 +288,6 @@ nsTransactionManager::BeginBatch()
|
|||
NS_IMETHODIMP
|
||||
nsTransactionManager::EndBatch()
|
||||
{
|
||||
nsRefPtr<nsTransactionItem> tx;
|
||||
nsCOMPtr<nsITransaction> ti;
|
||||
nsresult result;
|
||||
|
||||
|
@ -322,11 +302,7 @@ nsTransactionManager::EndBatch()
|
|||
// future when we allow users to execute a transaction when beginning
|
||||
// a batch!!!!
|
||||
|
||||
result = mDoStack.Peek(getter_AddRefs(tx));
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
nsRefPtr<nsTransactionItem> tx = mDoStack.Peek();
|
||||
|
||||
if (tx)
|
||||
tx->GetTransaction(getter_AddRefs(ti));
|
||||
|
@ -360,13 +336,15 @@ nsTransactionManager::EndBatch()
|
|||
NS_IMETHODIMP
|
||||
nsTransactionManager::GetNumberOfUndoItems(PRInt32 *aNumItems)
|
||||
{
|
||||
return mUndoStack.GetSize(aNumItems);
|
||||
*aNumItems = mUndoStack.GetSize();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTransactionManager::GetNumberOfRedoItems(PRInt32 *aNumItems)
|
||||
{
|
||||
return mRedoStack.GetSize(aNumItems);
|
||||
*aNumItems = mRedoStack.GetSize();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -383,8 +361,6 @@ NS_IMETHODIMP
|
|||
nsTransactionManager::SetMaxTransactionCount(PRInt32 aMaxCount)
|
||||
{
|
||||
PRInt32 numUndoItems = 0, numRedoItems = 0, total = 0;
|
||||
nsRefPtr<nsTransactionItem> tx;
|
||||
nsresult result;
|
||||
|
||||
// It is illegal to call SetMaxTransactionCount() while the transaction
|
||||
// manager is executing a transaction's DoTransaction() method because
|
||||
|
@ -392,11 +368,7 @@ nsTransactionManager::SetMaxTransactionCount(PRInt32 aMaxCount)
|
|||
// SetMaxTransactionCount() request is ignored, and we return
|
||||
// NS_ERROR_FAILURE.
|
||||
|
||||
result = mDoStack.Peek(getter_AddRefs(tx));
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
nsRefPtr<nsTransactionItem> tx = mDoStack.Peek();
|
||||
|
||||
if (tx) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -407,20 +379,12 @@ nsTransactionManager::SetMaxTransactionCount(PRInt32 aMaxCount)
|
|||
|
||||
if (aMaxCount < 0) {
|
||||
mMaxTransactionCount = -1;
|
||||
return result;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
result = mUndoStack.GetSize(&numUndoItems);
|
||||
numUndoItems = mUndoStack.GetSize();
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = mRedoStack.GetSize(&numRedoItems);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
numRedoItems = mRedoStack.GetSize();
|
||||
|
||||
total = numUndoItems + numRedoItems;
|
||||
|
||||
|
@ -430,17 +394,17 @@ nsTransactionManager::SetMaxTransactionCount(PRInt32 aMaxCount)
|
|||
|
||||
if (aMaxCount > total ) {
|
||||
mMaxTransactionCount = aMaxCount;
|
||||
return result;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Try getting rid of some transactions on the undo stack! Start at
|
||||
// the bottom of the stack and pop towards the top.
|
||||
|
||||
while (numUndoItems > 0 && (numRedoItems + numUndoItems) > aMaxCount) {
|
||||
result = mUndoStack.PopBottom(getter_AddRefs(tx));
|
||||
tx = mUndoStack.PopBottom();
|
||||
|
||||
if (NS_FAILED(result) || !tx) {
|
||||
return result;
|
||||
if (!tx) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
--numUndoItems;
|
||||
|
@ -450,10 +414,10 @@ nsTransactionManager::SetMaxTransactionCount(PRInt32 aMaxCount)
|
|||
// the bottom of the stack and pop towards the top.
|
||||
|
||||
while (numRedoItems > 0 && (numRedoItems + numUndoItems) > aMaxCount) {
|
||||
result = mRedoStack.PopBottom(getter_AddRefs(tx));
|
||||
tx = mRedoStack.PopBottom();
|
||||
|
||||
if (NS_FAILED(result) || !tx) {
|
||||
return result;
|
||||
if (!tx) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
--numRedoItems;
|
||||
|
@ -461,23 +425,22 @@ nsTransactionManager::SetMaxTransactionCount(PRInt32 aMaxCount)
|
|||
|
||||
mMaxTransactionCount = aMaxCount;
|
||||
|
||||
return result;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTransactionManager::PeekUndoStack(nsITransaction **aTransaction)
|
||||
{
|
||||
nsRefPtr<nsTransactionItem> tx;
|
||||
nsresult result;
|
||||
|
||||
NS_ENSURE_TRUE(aTransaction, NS_ERROR_NULL_POINTER);
|
||||
|
||||
*aTransaction = 0;
|
||||
|
||||
result = mUndoStack.Peek(getter_AddRefs(tx));
|
||||
nsRefPtr<nsTransactionItem> tx = mUndoStack.Peek();
|
||||
|
||||
if (NS_FAILED(result) || !tx) {
|
||||
return result;
|
||||
if (!tx) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
result = tx->GetTransaction(aTransaction);
|
||||
|
@ -488,17 +451,16 @@ nsTransactionManager::PeekUndoStack(nsITransaction **aTransaction)
|
|||
NS_IMETHODIMP
|
||||
nsTransactionManager::PeekRedoStack(nsITransaction **aTransaction)
|
||||
{
|
||||
nsRefPtr<nsTransactionItem> tx;
|
||||
nsresult result;
|
||||
|
||||
NS_ENSURE_TRUE(aTransaction, NS_ERROR_NULL_POINTER);
|
||||
|
||||
*aTransaction = 0;
|
||||
|
||||
result = mRedoStack.Peek(getter_AddRefs(tx));
|
||||
nsRefPtr<nsTransactionItem> tx = mRedoStack.Peek();
|
||||
|
||||
if (NS_FAILED(result) || !tx) {
|
||||
return result;
|
||||
if (!tx) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
result = tx->GetTransaction(aTransaction);
|
||||
|
@ -549,13 +511,15 @@ nsTransactionManager::RemoveListener(nsITransactionListener *aListener)
|
|||
nsresult
|
||||
nsTransactionManager::ClearUndoStack()
|
||||
{
|
||||
return mUndoStack.Clear();
|
||||
mUndoStack.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTransactionManager::ClearRedoStack()
|
||||
{
|
||||
return mRedoStack.Clear();
|
||||
mRedoStack.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -802,16 +766,12 @@ nsTransactionManager::BeginTransaction(nsITransaction *aTransaction)
|
|||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
result = mDoStack.Push(tx);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
mDoStack.Push(tx);
|
||||
|
||||
result = tx->DoTransaction();
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
mDoStack.Pop(getter_AddRefs(tx));
|
||||
tx = mDoStack.Pop();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -822,13 +782,12 @@ nsresult
|
|||
nsTransactionManager::EndTransaction()
|
||||
{
|
||||
nsCOMPtr<nsITransaction> tint;
|
||||
nsRefPtr<nsTransactionItem> tx;
|
||||
nsresult result = NS_OK;
|
||||
|
||||
result = mDoStack.Pop(getter_AddRefs(tx));
|
||||
nsRefPtr<nsTransactionItem> tx = mDoStack.Pop();
|
||||
|
||||
if (NS_FAILED(result) || !tx)
|
||||
return result;
|
||||
if (!tx)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
result = tx->GetTransaction(getter_AddRefs(tint));
|
||||
|
||||
|
@ -864,13 +823,11 @@ nsTransactionManager::EndTransaction()
|
|||
return result;
|
||||
}
|
||||
|
||||
nsRefPtr<nsTransactionItem> top;
|
||||
|
||||
// Check if there is a transaction on the do stack. If there is,
|
||||
// the current transaction is a "sub" transaction, and should
|
||||
// be added to the transaction at the top of the do stack.
|
||||
|
||||
result = mDoStack.Peek(getter_AddRefs(top));
|
||||
nsRefPtr<nsTransactionItem> top = mDoStack.Peek();
|
||||
if (top) {
|
||||
result = top->AddChild(tx);
|
||||
|
||||
|
@ -890,8 +847,7 @@ nsTransactionManager::EndTransaction()
|
|||
// Check if we can coalesce this transaction with the one at the top
|
||||
// of the undo stack.
|
||||
|
||||
top = 0;
|
||||
result = mUndoStack.Peek(getter_AddRefs(top));
|
||||
top = mUndoStack.Peek();
|
||||
|
||||
if (tint && top) {
|
||||
bool didMerge = false;
|
||||
|
@ -929,27 +885,16 @@ nsTransactionManager::EndTransaction()
|
|||
// Check to see if we've hit the max level of undo. If so,
|
||||
// pop the bottom transaction off the undo stack and release it!
|
||||
|
||||
PRInt32 sz = 0;
|
||||
|
||||
result = mUndoStack.GetSize(&sz);
|
||||
PRInt32 sz = mUndoStack.GetSize();
|
||||
|
||||
if (mMaxTransactionCount > 0 && sz >= mMaxTransactionCount) {
|
||||
nsRefPtr<nsTransactionItem> overflow;
|
||||
|
||||
result = mUndoStack.PopBottom(getter_AddRefs(overflow));
|
||||
|
||||
// XXX: What do we do in the case where this fails?
|
||||
nsRefPtr<nsTransactionItem> overflow = mUndoStack.PopBottom();
|
||||
}
|
||||
|
||||
// Push the transaction on the undo stack:
|
||||
|
||||
result = mUndoStack.Push(tx);
|
||||
mUndoStack.Push(tx);
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
// XXX: What do we do in the case where a clear fails?
|
||||
// Remove the transaction from the stack, and release it?
|
||||
}
|
||||
|
||||
return result;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,6 @@ class nsITransaction;
|
|||
class nsITransactionListener;
|
||||
class nsTransactionItem;
|
||||
class nsTransactionStack;
|
||||
class nsTransactionRedoStack;
|
||||
|
||||
/** implementation of a transaction manager object.
|
||||
*
|
||||
|
@ -61,7 +60,7 @@ private:
|
|||
PRInt32 mMaxTransactionCount;
|
||||
nsTransactionStack mDoStack;
|
||||
nsTransactionStack mUndoStack;
|
||||
nsTransactionRedoStack mRedoStack;
|
||||
nsTransactionStack mRedoStack;
|
||||
nsCOMArray<nsITransactionListener> mListeners;
|
||||
|
||||
public:
|
||||
|
|
|
@ -41,115 +41,82 @@
|
|||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "mozilla/Util.h"
|
||||
|
||||
nsTransactionStack::nsTransactionStack()
|
||||
nsTransactionStack::nsTransactionStack(nsTransactionStack::Type aType)
|
||||
: mQue(0)
|
||||
, mType(aType)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
nsTransactionStack::~nsTransactionStack()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
nsresult
|
||||
void
|
||||
nsTransactionStack::Push(nsTransactionItem *aTransaction)
|
||||
{
|
||||
NS_ENSURE_TRUE(aTransaction, NS_ERROR_NULL_POINTER);
|
||||
if (!aTransaction) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* nsDeque's Push() method adds new items at the back
|
||||
* of the deque.
|
||||
*/
|
||||
NS_ADDREF(aTransaction);
|
||||
mQue.Push(aTransaction);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTransactionStack::Pop(nsTransactionItem **aTransaction)
|
||||
already_AddRefed<nsTransactionItem>
|
||||
nsTransactionStack::Pop()
|
||||
{
|
||||
NS_ENSURE_TRUE(aTransaction, NS_ERROR_NULL_POINTER);
|
||||
|
||||
/* nsDeque is a FIFO, so the top of our stack is actually
|
||||
* the back of the deque.
|
||||
*/
|
||||
*aTransaction = (nsTransactionItem *)mQue.Pop();
|
||||
|
||||
return NS_OK;
|
||||
return static_cast<nsTransactionItem*> (mQue.Pop());
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTransactionStack::PopBottom(nsTransactionItem **aTransaction)
|
||||
already_AddRefed<nsTransactionItem>
|
||||
nsTransactionStack::PopBottom()
|
||||
{
|
||||
NS_ENSURE_TRUE(aTransaction, NS_ERROR_NULL_POINTER);
|
||||
|
||||
/* nsDeque is a FIFO, so the bottom of our stack is actually
|
||||
* the front of the deque.
|
||||
*/
|
||||
*aTransaction = (nsTransactionItem *)mQue.PopFront();
|
||||
|
||||
return NS_OK;
|
||||
return static_cast<nsTransactionItem*> (mQue.PopFront());
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTransactionStack::Peek(nsTransactionItem **aTransaction)
|
||||
already_AddRefed<nsTransactionItem>
|
||||
nsTransactionStack::Peek()
|
||||
{
|
||||
NS_ENSURE_TRUE(aTransaction, NS_ERROR_NULL_POINTER);
|
||||
|
||||
if (!mQue.GetSize()) {
|
||||
*aTransaction = 0;
|
||||
return NS_OK;
|
||||
nsTransactionItem* transaction = nsnull;
|
||||
if (mQue.GetSize()) {
|
||||
NS_IF_ADDREF(transaction = static_cast<nsTransactionItem*>(mQue.Last()));
|
||||
}
|
||||
|
||||
NS_IF_ADDREF(*aTransaction = static_cast<nsTransactionItem*>(mQue.Last()));
|
||||
|
||||
return NS_OK;
|
||||
return transaction;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTransactionStack::GetItem(PRInt32 aIndex, nsTransactionItem **aTransaction)
|
||||
already_AddRefed<nsTransactionItem>
|
||||
nsTransactionStack::GetItem(PRInt32 aIndex)
|
||||
{
|
||||
NS_ENSURE_TRUE(aTransaction, NS_ERROR_NULL_POINTER);
|
||||
nsTransactionItem* transaction = nsnull;
|
||||
if (aIndex >= 0 && aIndex < mQue.GetSize()) {
|
||||
NS_IF_ADDREF(transaction =
|
||||
static_cast<nsTransactionItem*>(mQue.ObjectAt(aIndex)));
|
||||
}
|
||||
|
||||
if (aIndex < 0 || aIndex >= mQue.GetSize())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
NS_IF_ADDREF(*aTransaction =
|
||||
static_cast<nsTransactionItem*>(mQue.ObjectAt(aIndex)));
|
||||
|
||||
return NS_OK;
|
||||
return transaction;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTransactionStack::Clear(void)
|
||||
void
|
||||
nsTransactionStack::Clear()
|
||||
{
|
||||
nsRefPtr<nsTransactionItem> tx;
|
||||
nsresult result = NS_OK;
|
||||
|
||||
/* Pop all transactions off the stack and release them. */
|
||||
|
||||
result = Pop(getter_AddRefs(tx));
|
||||
|
||||
NS_ENSURE_SUCCESS(result, result);
|
||||
|
||||
while (tx) {
|
||||
result = Pop(getter_AddRefs(tx));
|
||||
|
||||
NS_ENSURE_SUCCESS(result, result);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTransactionStack::GetSize(PRInt32 *aStackSize)
|
||||
{
|
||||
NS_ENSURE_TRUE(aStackSize, NS_ERROR_NULL_POINTER);
|
||||
|
||||
*aStackSize = mQue.GetSize();
|
||||
|
||||
return NS_OK;
|
||||
do {
|
||||
tx = mType == FOR_UNDO ? Pop() : PopBottom();
|
||||
} while (tx);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -164,32 +131,3 @@ nsTransactionStack::DoTraverse(nsCycleCollectionTraversalCallback &cb)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsTransactionRedoStack::~nsTransactionRedoStack()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTransactionRedoStack::Clear(void)
|
||||
{
|
||||
nsRefPtr<nsTransactionItem> tx;
|
||||
nsresult result = NS_OK;
|
||||
|
||||
/* When clearing a Redo stack, we have to clear from the
|
||||
* bottom of the stack towards the top!
|
||||
*/
|
||||
|
||||
result = PopBottom(getter_AddRefs(tx));
|
||||
|
||||
NS_ENSURE_SUCCESS(result, result);
|
||||
|
||||
while (tx) {
|
||||
result = PopBottom(getter_AddRefs(tx));
|
||||
|
||||
NS_ENSURE_SUCCESS(result, result);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,36 +39,32 @@
|
|||
#define nsTransactionStack_h__
|
||||
|
||||
#include "nsDeque.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsTransactionItem;
|
||||
|
||||
class nsTransactionStack
|
||||
{
|
||||
nsDeque mQue;
|
||||
|
||||
public:
|
||||
enum Type { FOR_UNDO, FOR_REDO };
|
||||
|
||||
nsTransactionStack();
|
||||
virtual ~nsTransactionStack();
|
||||
explicit nsTransactionStack(Type aType);
|
||||
~nsTransactionStack();
|
||||
|
||||
virtual nsresult Push(nsTransactionItem *aTransactionItem);
|
||||
virtual nsresult Pop(nsTransactionItem **aTransactionItem);
|
||||
virtual nsresult PopBottom(nsTransactionItem **aTransactionItem);
|
||||
virtual nsresult Peek(nsTransactionItem **aTransactionItem);
|
||||
virtual nsresult GetItem(PRInt32 aIndex, nsTransactionItem **aTransactionItem);
|
||||
virtual nsresult Clear(void);
|
||||
virtual nsresult GetSize(PRInt32 *aStackSize);
|
||||
void Push(nsTransactionItem *aTransactionItem);
|
||||
already_AddRefed<nsTransactionItem> Pop();
|
||||
already_AddRefed<nsTransactionItem> PopBottom();
|
||||
already_AddRefed<nsTransactionItem> Peek();
|
||||
already_AddRefed<nsTransactionItem> GetItem(PRInt32 aIndex);
|
||||
void Clear();
|
||||
PRInt32 GetSize() { return mQue.GetSize(); }
|
||||
|
||||
void DoUnlink() { Clear(); }
|
||||
void DoTraverse(nsCycleCollectionTraversalCallback &cb);
|
||||
};
|
||||
|
||||
class nsTransactionRedoStack: public nsTransactionStack
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~nsTransactionRedoStack();
|
||||
virtual nsresult Clear(void);
|
||||
private:
|
||||
nsDeque mQue;
|
||||
const Type mType;
|
||||
};
|
||||
|
||||
#endif // nsTransactionStack_h__
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef MOZILLA_GFX_USERDATA_H_
|
||||
#define MOZILLA_GFX_USERDATA_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "mozilla/mozalloc.h"
|
||||
|
@ -56,6 +58,9 @@ public:
|
|||
/* Attaches untyped userData associated with key. destroy is called on destruction */
|
||||
void Add(UserDataKey *key, void *userData, destroyFunc destroy)
|
||||
{
|
||||
// XXX we should really warn if user data with key has already been added,
|
||||
// since in that case Get() will return the old user data!
|
||||
|
||||
// We could keep entries in a std::vector instead of managing it by hand
|
||||
// but that would propagate an stl dependency out which we'd rather not
|
||||
// do (see bug 666609). Plus, the entries array is expect to stay small
|
||||
|
@ -69,7 +74,22 @@ public:
|
|||
count++;
|
||||
}
|
||||
|
||||
//XXX: we probably want to add a way to remove Keys
|
||||
/* Remove and return user data associated with key, without destroying it */
|
||||
void* Remove(UserDataKey *key)
|
||||
{
|
||||
for (int i=0; i<count; i++) {
|
||||
if (key == entries[i].key) {
|
||||
void *userData = entries[i].userData;
|
||||
// decrement before looping so entries[i+1] doesn't read past the end:
|
||||
--count;
|
||||
for (;i<count; i++) {
|
||||
entries[i] = entries[i+1];
|
||||
}
|
||||
return userData;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Retrives the userData for the associated key */
|
||||
void *Get(UserDataKey *key)
|
||||
|
@ -105,4 +125,4 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* MOZILLA_GFX_USERDATA_H_ */
|
||||
|
|
|
@ -84,6 +84,7 @@ CPPSRCS = \
|
|||
ValidateLimitations.cpp \
|
||||
ForLoopUnroll.cpp \
|
||||
MapLongVariableNames.cpp \
|
||||
spooky.cpp \
|
||||
BuiltInFunctionEmulator.cpp \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
@ -7,11 +7,11 @@ Current revision: r963
|
|||
In this order:
|
||||
angle-renaming-debug.patch - rename debug.h to compilerdebug.h to avoid conflict in our makefiles
|
||||
angle-intrinsic-msvc2005.patch - work around a MSVC 2005 compile error
|
||||
angle-limit-identifiers-to-250-chars.patch - see bug 675625
|
||||
angle-use-xmalloc.patch - see bug 680840. Can drop this patch whenever the new preprocessor lands.
|
||||
angle-castrate-bug-241.patch - see bug 699033 / angle bug 241
|
||||
angle-enforce-readpixels-spec.patch - see bug 724476.
|
||||
angle-impl-read-bgra.patch - see bug 724476.
|
||||
gfx/angle/angle-long-identifier-hash-spooky.patch - see bug 676071
|
||||
|
||||
In addition to these patches, the Makefile.in files are ours, they're not present in upsteam ANGLE.
|
||||
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
# HG changeset patch
|
||||
# Parent 761ca19e4ce1afe03e58beaea20149ba1ef243c4
|
||||
diff --git a/gfx/angle/src/compiler/preprocessor/length_limits.h b/gfx/angle/src/compiler/preprocessor/length_limits.h
|
||||
--- a/gfx/angle/src/compiler/preprocessor/length_limits.h
|
||||
+++ b/gfx/angle/src/compiler/preprocessor/length_limits.h
|
||||
@@ -10,12 +10,14 @@
|
||||
|
||||
#if !defined(__LENGTH_LIMITS_H)
|
||||
#define __LENGTH_LIMITS_H 1
|
||||
|
||||
// These constants are factored out from the rest of the headers to
|
||||
// make it easier to reference them from the compiler sources.
|
||||
|
||||
// These lengths do not include the NULL terminator.
|
||||
-#define MAX_SYMBOL_NAME_LEN 256
|
||||
+// see bug 675625: NVIDIA driver crash with lengths >= 253
|
||||
+// this is only an interim fix, the real fix is name mapping, see ANGLE bug 144 / r619
|
||||
+#define MAX_SYMBOL_NAME_LEN 250
|
||||
#define MAX_STRING_LEN 511
|
||||
|
||||
#endif // !(defined(__LENGTH_LIMITS_H)
|
|
@ -0,0 +1,756 @@
|
|||
# HG changeset patch
|
||||
# Parent 69255fe4cb94f1681bc9200db37c0ad3de171abc
|
||||
|
||||
diff --git a/gfx/angle/Makefile.in b/gfx/angle/Makefile.in
|
||||
--- a/gfx/angle/Makefile.in
|
||||
+++ b/gfx/angle/Makefile.in
|
||||
@@ -79,16 +79,17 @@ CPPSRCS = \
|
||||
SymbolTable.cpp \
|
||||
VariableInfo.cpp \
|
||||
compilerdebug.cpp \
|
||||
ossource_nspr.cpp \
|
||||
util.cpp \
|
||||
ValidateLimitations.cpp \
|
||||
ForLoopUnroll.cpp \
|
||||
MapLongVariableNames.cpp \
|
||||
+ spooky.cpp \
|
||||
BuiltInFunctionEmulator.cpp \
|
||||
$(NULL)
|
||||
|
||||
# flex/yacc generated files
|
||||
CPPSRCS += \
|
||||
glslang_lex.cpp \
|
||||
glslang_tab.cpp \
|
||||
$(NULL)
|
||||
diff --git a/gfx/angle/src/compiler/MapLongVariableNames.cpp b/gfx/angle/src/compiler/MapLongVariableNames.cpp
|
||||
--- a/gfx/angle/src/compiler/MapLongVariableNames.cpp
|
||||
+++ b/gfx/angle/src/compiler/MapLongVariableNames.cpp
|
||||
@@ -1,27 +1,30 @@
|
||||
//
|
||||
// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
|
||||
#include "compiler/MapLongVariableNames.h"
|
||||
+#include "spooky.h"
|
||||
|
||||
namespace {
|
||||
|
||||
TString mapLongName(int id, const TString& name, bool isGlobal)
|
||||
{
|
||||
ASSERT(name.size() > MAX_SHORTENED_IDENTIFIER_SIZE);
|
||||
TStringStream stream;
|
||||
- stream << "webgl_";
|
||||
- if (isGlobal)
|
||||
- stream << "g";
|
||||
- stream << id << "_";
|
||||
- stream << name.substr(0, MAX_SHORTENED_IDENTIFIER_SIZE - stream.str().size());
|
||||
+ uint64 hash = SpookyHash::Hash64(name.data(), name.length(), 0);
|
||||
+ stream << "webgl_"
|
||||
+ << name.substr(0, 9)
|
||||
+ << "_"
|
||||
+ << std::hex
|
||||
+ << hash;
|
||||
+ ASSERT(stream.str().length() == MAX_SHORTENED_IDENTIFIER_SIZE);
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
LongNameMap* gLongNameMapInstance = NULL;
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
LongNameMap::LongNameMap()
|
||||
diff --git a/gfx/angle/src/compiler/spooky.cpp b/gfx/angle/src/compiler/spooky.cpp
|
||||
new file mode 100644
|
||||
--- /dev/null
|
||||
+++ b/gfx/angle/src/compiler/spooky.cpp
|
||||
@@ -0,0 +1,348 @@
|
||||
+// Spooky Hash
|
||||
+// A 128-bit noncryptographic hash, for checksums and table lookup
|
||||
+// By Bob Jenkins. Public domain.
|
||||
+// Oct 31 2010: published framework, disclaimer ShortHash isn't right
|
||||
+// Nov 7 2010: disabled ShortHash
|
||||
+// Oct 31 2011: replace End, ShortMix, ShortEnd, enable ShortHash again
|
||||
+
|
||||
+#include <memory.h>
|
||||
+#include <string.h>
|
||||
+#include "spooky.h"
|
||||
+
|
||||
+#define ALLOW_UNALIGNED_READS 1
|
||||
+
|
||||
+//
|
||||
+// short hash ... it could be used on any message,
|
||||
+// but it's used by Spooky just for short messages.
|
||||
+//
|
||||
+void SpookyHash::Short(
|
||||
+ const void *message,
|
||||
+ size_t length,
|
||||
+ uint64 *hash1,
|
||||
+ uint64 *hash2)
|
||||
+{
|
||||
+ uint64 buf[sc_numVars];
|
||||
+ union
|
||||
+ {
|
||||
+ const uint8 *p8;
|
||||
+ uint32 *p32;
|
||||
+ uint64 *p64;
|
||||
+ size_t i;
|
||||
+ } u;
|
||||
+
|
||||
+ u.p8 = (const uint8 *)message;
|
||||
+
|
||||
+ if (!ALLOW_UNALIGNED_READS && (u.i & 0x7))
|
||||
+ {
|
||||
+ memcpy(buf, message, length);
|
||||
+ u.p64 = buf;
|
||||
+ }
|
||||
+
|
||||
+ size_t remainder = length%32;
|
||||
+ uint64 a=*hash1;
|
||||
+ uint64 b=*hash2;
|
||||
+ uint64 c=sc_const;
|
||||
+ uint64 d=sc_const;
|
||||
+
|
||||
+ if (length > 15)
|
||||
+ {
|
||||
+ const uint64 *end = u.p64 + (length/32)*4;
|
||||
+
|
||||
+ // handle all complete sets of 32 bytes
|
||||
+ for (; u.p64 < end; u.p64 += 4)
|
||||
+ {
|
||||
+ c += u.p64[0];
|
||||
+ d += u.p64[1];
|
||||
+ ShortMix(a,b,c,d);
|
||||
+ a += u.p64[2];
|
||||
+ b += u.p64[3];
|
||||
+ }
|
||||
+
|
||||
+ //Handle the case of 16+ remaining bytes.
|
||||
+ if (remainder >= 16)
|
||||
+ {
|
||||
+ c += u.p64[0];
|
||||
+ d += u.p64[1];
|
||||
+ ShortMix(a,b,c,d);
|
||||
+ u.p64 += 2;
|
||||
+ remainder -= 16;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // Handle the last 0..15 bytes, and its length
|
||||
+ d = ((uint64)length) << 56;
|
||||
+ switch (remainder)
|
||||
+ {
|
||||
+ case 15:
|
||||
+ d += ((uint64)u.p8[14]) << 48;
|
||||
+ case 14:
|
||||
+ d += ((uint64)u.p8[13]) << 40;
|
||||
+ case 13:
|
||||
+ d += ((uint64)u.p8[12]) << 32;
|
||||
+ case 12:
|
||||
+ d += u.p32[2];
|
||||
+ c += u.p64[0];
|
||||
+ break;
|
||||
+ case 11:
|
||||
+ d += ((uint64)u.p8[10]) << 16;
|
||||
+ case 10:
|
||||
+ d += ((uint64)u.p8[9]) << 8;
|
||||
+ case 9:
|
||||
+ d += (uint64)u.p8[8];
|
||||
+ case 8:
|
||||
+ c += u.p64[0];
|
||||
+ break;
|
||||
+ case 7:
|
||||
+ c += ((uint64)u.p8[6]) << 48;
|
||||
+ case 6:
|
||||
+ c += ((uint64)u.p8[5]) << 40;
|
||||
+ case 5:
|
||||
+ c += ((uint64)u.p8[4]) << 32;
|
||||
+ case 4:
|
||||
+ c += u.p32[0];
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ c += ((uint64)u.p8[2]) << 16;
|
||||
+ case 2:
|
||||
+ c += ((uint64)u.p8[1]) << 8;
|
||||
+ case 1:
|
||||
+ c += (uint64)u.p8[0];
|
||||
+ break;
|
||||
+ case 0:
|
||||
+ c += sc_const;
|
||||
+ d += sc_const;
|
||||
+ }
|
||||
+ ShortEnd(a,b,c,d);
|
||||
+ *hash1 = a;
|
||||
+ *hash2 = b;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+
|
||||
+
|
||||
+// do the whole hash in one call
|
||||
+void SpookyHash::Hash128(
|
||||
+ const void *message,
|
||||
+ size_t length,
|
||||
+ uint64 *hash1,
|
||||
+ uint64 *hash2)
|
||||
+{
|
||||
+ if (length < sc_bufSize)
|
||||
+ {
|
||||
+ Short(message, length, hash1, hash2);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ uint64 h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11;
|
||||
+ uint64 buf[sc_numVars];
|
||||
+ uint64 *end;
|
||||
+ union
|
||||
+ {
|
||||
+ const uint8 *p8;
|
||||
+ uint64 *p64;
|
||||
+ size_t i;
|
||||
+ } u;
|
||||
+ size_t remainder;
|
||||
+
|
||||
+ h0=h3=h6=h9 = *hash1;
|
||||
+ h1=h4=h7=h10 = *hash2;
|
||||
+ h2=h5=h8=h11 = sc_const;
|
||||
+
|
||||
+ u.p8 = (const uint8 *)message;
|
||||
+ end = u.p64 + (length/sc_blockSize)*sc_numVars;
|
||||
+
|
||||
+ // handle all whole sc_blockSize blocks of bytes
|
||||
+ if (ALLOW_UNALIGNED_READS || ((u.i & 0x7) == 0))
|
||||
+ {
|
||||
+ while (u.p64 < end)
|
||||
+ {
|
||||
+ Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
+ u.p64 += sc_numVars;
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ while (u.p64 < end)
|
||||
+ {
|
||||
+ memcpy(buf, u.p64, sc_blockSize);
|
||||
+ Mix(buf, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
+ u.p64 += sc_numVars;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // handle the last partial block of sc_blockSize bytes
|
||||
+ remainder = (length - ((const uint8 *)end-(const uint8 *)message));
|
||||
+ memcpy(buf, end, remainder);
|
||||
+ memset(((uint8 *)buf)+remainder, 0, sc_blockSize-remainder);
|
||||
+ ((uint8 *)buf)[sc_blockSize-1] = remainder;
|
||||
+ Mix(buf, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
+
|
||||
+ // do some final mixing
|
||||
+ End(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
+ *hash1 = h0;
|
||||
+ *hash2 = h1;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+
|
||||
+// init spooky state
|
||||
+void SpookyHash::Init(uint64 seed1, uint64 seed2)
|
||||
+{
|
||||
+ m_length = 0;
|
||||
+ m_remainder = 0;
|
||||
+ m_state[0] = seed1;
|
||||
+ m_state[1] = seed2;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+// add a message fragment to the state
|
||||
+void SpookyHash::Update(const void *message, size_t length)
|
||||
+{
|
||||
+ uint64 h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11;
|
||||
+ size_t newLength = length + m_remainder;
|
||||
+ uint8 remainder;
|
||||
+ union
|
||||
+ {
|
||||
+ const uint8 *p8;
|
||||
+ uint64 *p64;
|
||||
+ size_t i;
|
||||
+ } u;
|
||||
+ const uint64 *end;
|
||||
+
|
||||
+ // Is this message fragment too short? If it is, stuff it away.
|
||||
+ if (newLength < sc_bufSize)
|
||||
+ {
|
||||
+ memcpy(&((uint8 *)m_data)[m_remainder], message, length);
|
||||
+ m_length = length + m_length;
|
||||
+ m_remainder = (uint8)newLength;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ // init the variables
|
||||
+ if (m_length < sc_bufSize)
|
||||
+ {
|
||||
+ h0=h3=h6=h9 = m_state[0];
|
||||
+ h1=h4=h7=h10 = m_state[1];
|
||||
+ h2=h5=h8=h11 = sc_const;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ h0 = m_state[0];
|
||||
+ h1 = m_state[1];
|
||||
+ h2 = m_state[2];
|
||||
+ h3 = m_state[3];
|
||||
+ h4 = m_state[4];
|
||||
+ h5 = m_state[5];
|
||||
+ h6 = m_state[6];
|
||||
+ h7 = m_state[7];
|
||||
+ h8 = m_state[8];
|
||||
+ h9 = m_state[9];
|
||||
+ h10 = m_state[10];
|
||||
+ h11 = m_state[11];
|
||||
+ }
|
||||
+ m_length = length + m_length;
|
||||
+
|
||||
+ // if we've got anything stuffed away, use it now
|
||||
+ if (m_remainder)
|
||||
+ {
|
||||
+ uint8 prefix = sc_bufSize-m_remainder;
|
||||
+ memcpy(&(((uint8 *)m_data)[m_remainder]), message, prefix);
|
||||
+ u.p64 = m_data;
|
||||
+ Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
+ Mix(&u.p64[sc_numVars], h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
+ u.p8 = ((const uint8 *)message) + prefix;
|
||||
+ length -= prefix;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ u.p8 = (const uint8 *)message;
|
||||
+ }
|
||||
+
|
||||
+ // handle all whole blocks of sc_blockSize bytes
|
||||
+ end = u.p64 + (length/sc_blockSize)*sc_numVars;
|
||||
+ remainder = (uint8)(length-((const uint8 *)end-u.p8));
|
||||
+ if (ALLOW_UNALIGNED_READS || (u.i & 0x7) == 0)
|
||||
+ {
|
||||
+ while (u.p64 < end)
|
||||
+ {
|
||||
+ Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
+ u.p64 += sc_numVars;
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ while (u.p64 < end)
|
||||
+ {
|
||||
+ memcpy(m_data, u.p8, sc_blockSize);
|
||||
+ Mix(m_data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
+ u.p64 += sc_numVars;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // stuff away the last few bytes
|
||||
+ m_remainder = remainder;
|
||||
+ memcpy(m_data, end, remainder);
|
||||
+
|
||||
+ // stuff away the variables
|
||||
+ m_state[0] = h0;
|
||||
+ m_state[1] = h1;
|
||||
+ m_state[2] = h2;
|
||||
+ m_state[3] = h3;
|
||||
+ m_state[4] = h4;
|
||||
+ m_state[5] = h5;
|
||||
+ m_state[6] = h6;
|
||||
+ m_state[7] = h7;
|
||||
+ m_state[8] = h8;
|
||||
+ m_state[9] = h9;
|
||||
+ m_state[10] = h10;
|
||||
+ m_state[11] = h11;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+// report the hash for the concatenation of all message fragments so far
|
||||
+void SpookyHash::Final(uint64 *hash1, uint64 *hash2)
|
||||
+{
|
||||
+ // init the variables
|
||||
+ if (m_length < sc_bufSize)
|
||||
+ {
|
||||
+ Short( m_data, m_length, hash1, hash2);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ const uint64 *data = (const uint64 *)m_data;
|
||||
+ uint8 remainder = m_remainder;
|
||||
+
|
||||
+ uint64 h0 = m_state[0];
|
||||
+ uint64 h1 = m_state[1];
|
||||
+ uint64 h2 = m_state[2];
|
||||
+ uint64 h3 = m_state[3];
|
||||
+ uint64 h4 = m_state[4];
|
||||
+ uint64 h5 = m_state[5];
|
||||
+ uint64 h6 = m_state[6];
|
||||
+ uint64 h7 = m_state[7];
|
||||
+ uint64 h8 = m_state[8];
|
||||
+ uint64 h9 = m_state[9];
|
||||
+ uint64 h10 = m_state[10];
|
||||
+ uint64 h11 = m_state[11];
|
||||
+
|
||||
+ if (remainder >= sc_blockSize)
|
||||
+ {
|
||||
+ // m_data can contain two blocks; handle any whole first block
|
||||
+ Mix(data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
+ data += sc_numVars;
|
||||
+ remainder -= sc_blockSize;
|
||||
+ }
|
||||
+
|
||||
+ // mix in the last partial block, and the length mod sc_blockSize
|
||||
+ memset(&((uint8 *)data)[remainder], 0, (sc_blockSize-remainder));
|
||||
+
|
||||
+ ((uint8 *)data)[sc_blockSize-1] = remainder;
|
||||
+ Mix(data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
+
|
||||
+ // do some final mixing
|
||||
+ End(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
+
|
||||
+ *hash1 = h0;
|
||||
+ *hash2 = h1;
|
||||
+}
|
||||
+
|
||||
diff --git a/gfx/angle/src/compiler/spooky.h b/gfx/angle/src/compiler/spooky.h
|
||||
new file mode 100644
|
||||
--- /dev/null
|
||||
+++ b/gfx/angle/src/compiler/spooky.h
|
||||
@@ -0,0 +1,293 @@
|
||||
+//
|
||||
+// SpookyHash: a 128-bit noncryptographic hash function
|
||||
+// By Bob Jenkins, public domain
|
||||
+// Oct 31 2010: alpha, framework + SpookyHash::Mix appears right
|
||||
+// Oct 31 2011: alpha again, Mix only good to 2^^69 but rest appears right
|
||||
+// Dec 31 2011: beta, improved Mix, tested it for 2-bit deltas
|
||||
+// Feb 2 2012: production, same bits as beta
|
||||
+// Feb 5 2012: adjusted definitions of uint* to be more portable
|
||||
+//
|
||||
+// Up to 4 bytes/cycle for long messages. Reasonably fast for short messages.
|
||||
+// All 1 or 2 bit deltas achieve avalanche within 1% bias per output bit.
|
||||
+//
|
||||
+// This was developed for and tested on 64-bit x86-compatible processors.
|
||||
+// It assumes the processor is little-endian. There is a macro
|
||||
+// controlling whether unaligned reads are allowed (by default they are).
|
||||
+// This should be an equally good hash on big-endian machines, but it will
|
||||
+// compute different results on them than on little-endian machines.
|
||||
+//
|
||||
+// Google's CityHash has similar specs to SpookyHash, and CityHash is faster
|
||||
+// on some platforms. MD4 and MD5 also have similar specs, but they are orders
|
||||
+// of magnitude slower. CRCs are two or more times slower, but unlike
|
||||
+// SpookyHash, they have nice math for combining the CRCs of pieces to form
|
||||
+// the CRCs of wholes. There are also cryptographic hashes, but those are even
|
||||
+// slower than MD5.
|
||||
+//
|
||||
+
|
||||
+#include <stddef.h>
|
||||
+
|
||||
+#ifdef _MSC_VER
|
||||
+# define INLINE __forceinline
|
||||
+ typedef unsigned __int64 uint64;
|
||||
+ typedef unsigned __int32 uint32;
|
||||
+ typedef unsigned __int16 uint16;
|
||||
+ typedef unsigned __int8 uint8;
|
||||
+#else
|
||||
+# include <stdint.h>
|
||||
+# define INLINE inline
|
||||
+ typedef uint64_t uint64;
|
||||
+ typedef uint32_t uint32;
|
||||
+ typedef uint16_t uint16;
|
||||
+ typedef uint8_t uint8;
|
||||
+#endif
|
||||
+
|
||||
+
|
||||
+class SpookyHash
|
||||
+{
|
||||
+public:
|
||||
+ //
|
||||
+ // SpookyHash: hash a single message in one call, produce 128-bit output
|
||||
+ //
|
||||
+ static void Hash128(
|
||||
+ const void *message, // message to hash
|
||||
+ size_t length, // length of message in bytes
|
||||
+ uint64 *hash1, // in/out: in seed 1, out hash value 1
|
||||
+ uint64 *hash2); // in/out: in seed 2, out hash value 2
|
||||
+
|
||||
+ //
|
||||
+ // Hash64: hash a single message in one call, return 64-bit output
|
||||
+ //
|
||||
+ static uint64 Hash64(
|
||||
+ const void *message, // message to hash
|
||||
+ size_t length, // length of message in bytes
|
||||
+ uint64 seed) // seed
|
||||
+ {
|
||||
+ uint64 hash1 = seed;
|
||||
+ Hash128(message, length, &hash1, &seed);
|
||||
+ return hash1;
|
||||
+ }
|
||||
+
|
||||
+ //
|
||||
+ // Hash32: hash a single message in one call, produce 32-bit output
|
||||
+ //
|
||||
+ static uint32 Hash32(
|
||||
+ const void *message, // message to hash
|
||||
+ size_t length, // length of message in bytes
|
||||
+ uint32 seed) // seed
|
||||
+ {
|
||||
+ uint64 hash1 = seed, hash2 = seed;
|
||||
+ Hash128(message, length, &hash1, &hash2);
|
||||
+ return (uint32)hash1;
|
||||
+ }
|
||||
+
|
||||
+ //
|
||||
+ // Init: initialize the context of a SpookyHash
|
||||
+ //
|
||||
+ void Init(
|
||||
+ uint64 seed1, // any 64-bit value will do, including 0
|
||||
+ uint64 seed2); // different seeds produce independent hashes
|
||||
+
|
||||
+ //
|
||||
+ // Update: add a piece of a message to a SpookyHash state
|
||||
+ //
|
||||
+ void Update(
|
||||
+ const void *message, // message fragment
|
||||
+ size_t length); // length of message fragment in bytes
|
||||
+
|
||||
+
|
||||
+ //
|
||||
+ // Final: compute the hash for the current SpookyHash state
|
||||
+ //
|
||||
+ // This does not modify the state; you can keep updating it afterward
|
||||
+ //
|
||||
+ // The result is the same as if SpookyHash() had been called with
|
||||
+ // all the pieces concatenated into one message.
|
||||
+ //
|
||||
+ void Final(
|
||||
+ uint64 *hash1, // out only: first 64 bits of hash value.
|
||||
+ uint64 *hash2); // out only: second 64 bits of hash value.
|
||||
+
|
||||
+ //
|
||||
+ // left rotate a 64-bit value by k bytes
|
||||
+ //
|
||||
+ static INLINE uint64 Rot64(uint64 x, int k)
|
||||
+ {
|
||||
+ return (x << k) | (x >> (64 - k));
|
||||
+ }
|
||||
+
|
||||
+ //
|
||||
+ // This is used if the input is 96 bytes long or longer.
|
||||
+ //
|
||||
+ // The internal state is fully overwritten every 96 bytes.
|
||||
+ // Every input bit appears to cause at least 128 bits of entropy
|
||||
+ // before 96 other bytes are combined, when run forward or backward
|
||||
+ // For every input bit,
|
||||
+ // Two inputs differing in just that input bit
|
||||
+ // Where "differ" means xor or subtraction
|
||||
+ // And the base value is random
|
||||
+ // When run forward or backwards one Mix
|
||||
+ // I tried 3 pairs of each; they all differed by at least 212 bits.
|
||||
+ //
|
||||
+ static INLINE void Mix(
|
||||
+ const uint64 *data,
|
||||
+ uint64 &s0, uint64 &s1, uint64 &s2, uint64 &s3,
|
||||
+ uint64 &s4, uint64 &s5, uint64 &s6, uint64 &s7,
|
||||
+ uint64 &s8, uint64 &s9, uint64 &s10,uint64 &s11)
|
||||
+ {
|
||||
+ s0 += data[0]; s2 ^= s10; s11 ^= s0; s0 = Rot64(s0,11); s11 += s1;
|
||||
+ s1 += data[1]; s3 ^= s11; s0 ^= s1; s1 = Rot64(s1,32); s0 += s2;
|
||||
+ s2 += data[2]; s4 ^= s0; s1 ^= s2; s2 = Rot64(s2,43); s1 += s3;
|
||||
+ s3 += data[3]; s5 ^= s1; s2 ^= s3; s3 = Rot64(s3,31); s2 += s4;
|
||||
+ s4 += data[4]; s6 ^= s2; s3 ^= s4; s4 = Rot64(s4,17); s3 += s5;
|
||||
+ s5 += data[5]; s7 ^= s3; s4 ^= s5; s5 = Rot64(s5,28); s4 += s6;
|
||||
+ s6 += data[6]; s8 ^= s4; s5 ^= s6; s6 = Rot64(s6,39); s5 += s7;
|
||||
+ s7 += data[7]; s9 ^= s5; s6 ^= s7; s7 = Rot64(s7,57); s6 += s8;
|
||||
+ s8 += data[8]; s10 ^= s6; s7 ^= s8; s8 = Rot64(s8,55); s7 += s9;
|
||||
+ s9 += data[9]; s11 ^= s7; s8 ^= s9; s9 = Rot64(s9,54); s8 += s10;
|
||||
+ s10 += data[10]; s0 ^= s8; s9 ^= s10; s10 = Rot64(s10,22); s9 += s11;
|
||||
+ s11 += data[11]; s1 ^= s9; s10 ^= s11; s11 = Rot64(s11,46); s10 += s0;
|
||||
+ }
|
||||
+
|
||||
+ //
|
||||
+ // Mix all 12 inputs together so that h0, h1 are a hash of them all.
|
||||
+ //
|
||||
+ // For two inputs differing in just the input bits
|
||||
+ // Where "differ" means xor or subtraction
|
||||
+ // And the base value is random, or a counting value starting at that bit
|
||||
+ // The final result will have each bit of h0, h1 flip
|
||||
+ // For every input bit,
|
||||
+ // with probability 50 +- .3%
|
||||
+ // For every pair of input bits,
|
||||
+ // with probability 50 +- 3%
|
||||
+ //
|
||||
+ // This does not rely on the last Mix() call having already mixed some.
|
||||
+ // Two iterations was almost good enough for a 64-bit result, but a
|
||||
+ // 128-bit result is reported, so End() does three iterations.
|
||||
+ //
|
||||
+ static INLINE void EndPartial(
|
||||
+ uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3,
|
||||
+ uint64 &h4, uint64 &h5, uint64 &h6, uint64 &h7,
|
||||
+ uint64 &h8, uint64 &h9, uint64 &h10,uint64 &h11)
|
||||
+ {
|
||||
+ h11+= h1; h2 ^= h11; h1 = Rot64(h1,44);
|
||||
+ h0 += h2; h3 ^= h0; h2 = Rot64(h2,15);
|
||||
+ h1 += h3; h4 ^= h1; h3 = Rot64(h3,34);
|
||||
+ h2 += h4; h5 ^= h2; h4 = Rot64(h4,21);
|
||||
+ h3 += h5; h6 ^= h3; h5 = Rot64(h5,38);
|
||||
+ h4 += h6; h7 ^= h4; h6 = Rot64(h6,33);
|
||||
+ h5 += h7; h8 ^= h5; h7 = Rot64(h7,10);
|
||||
+ h6 += h8; h9 ^= h6; h8 = Rot64(h8,13);
|
||||
+ h7 += h9; h10^= h7; h9 = Rot64(h9,38);
|
||||
+ h8 += h10; h11^= h8; h10= Rot64(h10,53);
|
||||
+ h9 += h11; h0 ^= h9; h11= Rot64(h11,42);
|
||||
+ h10+= h0; h1 ^= h10; h0 = Rot64(h0,54);
|
||||
+ }
|
||||
+
|
||||
+ static INLINE void End(
|
||||
+ uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3,
|
||||
+ uint64 &h4, uint64 &h5, uint64 &h6, uint64 &h7,
|
||||
+ uint64 &h8, uint64 &h9, uint64 &h10,uint64 &h11)
|
||||
+ {
|
||||
+ EndPartial(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
+ EndPartial(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
+ EndPartial(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
+ }
|
||||
+
|
||||
+ //
|
||||
+ // The goal is for each bit of the input to expand into 128 bits of
|
||||
+ // apparent entropy before it is fully overwritten.
|
||||
+ // n trials both set and cleared at least m bits of h0 h1 h2 h3
|
||||
+ // n: 2 m: 29
|
||||
+ // n: 3 m: 46
|
||||
+ // n: 4 m: 57
|
||||
+ // n: 5 m: 107
|
||||
+ // n: 6 m: 146
|
||||
+ // n: 7 m: 152
|
||||
+ // when run forwards or backwards
|
||||
+ // for all 1-bit and 2-bit diffs
|
||||
+ // with diffs defined by either xor or subtraction
|
||||
+ // with a base of all zeros plus a counter, or plus another bit, or random
|
||||
+ //
|
||||
+ static INLINE void ShortMix(uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3)
|
||||
+ {
|
||||
+ h2 = Rot64(h2,50); h2 += h3; h0 ^= h2;
|
||||
+ h3 = Rot64(h3,52); h3 += h0; h1 ^= h3;
|
||||
+ h0 = Rot64(h0,30); h0 += h1; h2 ^= h0;
|
||||
+ h1 = Rot64(h1,41); h1 += h2; h3 ^= h1;
|
||||
+ h2 = Rot64(h2,54); h2 += h3; h0 ^= h2;
|
||||
+ h3 = Rot64(h3,48); h3 += h0; h1 ^= h3;
|
||||
+ h0 = Rot64(h0,38); h0 += h1; h2 ^= h0;
|
||||
+ h1 = Rot64(h1,37); h1 += h2; h3 ^= h1;
|
||||
+ h2 = Rot64(h2,62); h2 += h3; h0 ^= h2;
|
||||
+ h3 = Rot64(h3,34); h3 += h0; h1 ^= h3;
|
||||
+ h0 = Rot64(h0,5); h0 += h1; h2 ^= h0;
|
||||
+ h1 = Rot64(h1,36); h1 += h2; h3 ^= h1;
|
||||
+ }
|
||||
+
|
||||
+ //
|
||||
+ // Mix all 4 inputs together so that h0, h1 are a hash of them all.
|
||||
+ //
|
||||
+ // For two inputs differing in just the input bits
|
||||
+ // Where "differ" means xor or subtraction
|
||||
+ // And the base value is random, or a counting value starting at that bit
|
||||
+ // The final result will have each bit of h0, h1 flip
|
||||
+ // For every input bit,
|
||||
+ // with probability 50 +- .3% (it is probably better than that)
|
||||
+ // For every pair of input bits,
|
||||
+ // with probability 50 +- .75% (the worst case is approximately that)
|
||||
+ //
|
||||
+ static INLINE void ShortEnd(uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3)
|
||||
+ {
|
||||
+ h3 ^= h2; h2 = Rot64(h2,15); h3 += h2;
|
||||
+ h0 ^= h3; h3 = Rot64(h3,52); h0 += h3;
|
||||
+ h1 ^= h0; h0 = Rot64(h0,26); h1 += h0;
|
||||
+ h2 ^= h1; h1 = Rot64(h1,51); h2 += h1;
|
||||
+ h3 ^= h2; h2 = Rot64(h2,28); h3 += h2;
|
||||
+ h0 ^= h3; h3 = Rot64(h3,9); h0 += h3;
|
||||
+ h1 ^= h0; h0 = Rot64(h0,47); h1 += h0;
|
||||
+ h2 ^= h1; h1 = Rot64(h1,54); h2 += h1;
|
||||
+ h3 ^= h2; h2 = Rot64(h2,32); h3 += h2;
|
||||
+ h0 ^= h3; h3 = Rot64(h3,25); h0 += h3;
|
||||
+ h1 ^= h0; h0 = Rot64(h0,63); h1 += h0;
|
||||
+ }
|
||||
+
|
||||
+private:
|
||||
+
|
||||
+ //
|
||||
+ // Short is used for messages under 192 bytes in length
|
||||
+ // Short has a low startup cost, the normal mode is good for long
|
||||
+ // keys, the cost crossover is at about 192 bytes. The two modes were
|
||||
+ // held to the same quality bar.
|
||||
+ //
|
||||
+ static void Short(
|
||||
+ const void *message,
|
||||
+ size_t length,
|
||||
+ uint64 *hash1,
|
||||
+ uint64 *hash2);
|
||||
+
|
||||
+ // number of uint64's in internal state
|
||||
+ static const size_t sc_numVars = 12;
|
||||
+
|
||||
+ // size of the internal state
|
||||
+ static const size_t sc_blockSize = sc_numVars*8;
|
||||
+
|
||||
+ // size of buffer of unhashed data, in bytes
|
||||
+ static const size_t sc_bufSize = 2*sc_blockSize;
|
||||
+
|
||||
+ //
|
||||
+ // sc_const: a constant which:
|
||||
+ // * is not zero
|
||||
+ // * is odd
|
||||
+ // * is a not-very-regular mix of 1's and 0's
|
||||
+ // * does not need any other special mathematical properties
|
||||
+ //
|
||||
+ static const uint64 sc_const = 0xdeadbeefdeadbeefLL;
|
||||
+
|
||||
+ uint64 m_data[2*sc_numVars]; // unhashed data, for partial messages
|
||||
+ uint64 m_state[sc_numVars]; // internal state of the hash
|
||||
+ size_t m_length; // total length of the input so far
|
||||
+ uint8 m_remainder; // length of unhashed data stashed in m_data
|
||||
+};
|
||||
+
|
||||
+
|
||||
+
|
||||
diff --git a/gfx/angle/src/libEGL/Makefile.in b/gfx/angle/src/libEGL/Makefile.in
|
||||
--- a/gfx/angle/src/libEGL/Makefile.in
|
||||
+++ b/gfx/angle/src/libEGL/Makefile.in
|
||||
@@ -91,16 +91,17 @@ CPPSRCS = \
|
||||
SymbolTable.cpp \
|
||||
VariableInfo.cpp \
|
||||
compilerdebug.cpp \
|
||||
ossource_win.cpp \
|
||||
util.cpp \
|
||||
ValidateLimitations.cpp \
|
||||
ForLoopUnroll.cpp \
|
||||
MapLongVariableNames.cpp \
|
||||
+ spooky.cpp \
|
||||
BuiltInFunctionEmulator.cpp \
|
||||
$(NULL)
|
||||
|
||||
# flex/yacc generated files
|
||||
CPPSRCS += \
|
||||
glslang_lex.cpp \
|
||||
glslang_tab.cpp \
|
||||
$(NULL)
|
||||
diff --git a/gfx/angle/src/libGLESv2/Makefile.in b/gfx/angle/src/libGLESv2/Makefile.in
|
||||
--- a/gfx/angle/src/libGLESv2/Makefile.in
|
||||
+++ b/gfx/angle/src/libGLESv2/Makefile.in
|
||||
@@ -91,16 +91,17 @@ CPPSRCS = \
|
||||
SymbolTable.cpp \
|
||||
VariableInfo.cpp \
|
||||
compilerdebug.cpp \
|
||||
ossource_win.cpp \
|
||||
util.cpp \
|
||||
ValidateLimitations.cpp \
|
||||
ForLoopUnroll.cpp \
|
||||
MapLongVariableNames.cpp \
|
||||
+ spooky.cpp \
|
||||
BuiltInFunctionEmulator.cpp \
|
||||
$(NULL)
|
||||
|
||||
# flex/yacc generated files
|
||||
CPPSRCS += \
|
||||
glslang_lex.cpp \
|
||||
glslang_tab.cpp \
|
||||
$(NULL)
|
|
@ -5,6 +5,7 @@
|
|||
//
|
||||
|
||||
#include "compiler/MapLongVariableNames.h"
|
||||
#include "spooky.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -12,11 +13,13 @@ TString mapLongName(int id, const TString& name, bool isGlobal)
|
|||
{
|
||||
ASSERT(name.size() > MAX_SHORTENED_IDENTIFIER_SIZE);
|
||||
TStringStream stream;
|
||||
stream << "webgl_";
|
||||
if (isGlobal)
|
||||
stream << "g";
|
||||
stream << id << "_";
|
||||
stream << name.substr(0, MAX_SHORTENED_IDENTIFIER_SIZE - stream.str().size());
|
||||
uint64 hash = SpookyHash::Hash64(name.data(), name.length(), 0);
|
||||
stream << "webgl_"
|
||||
<< name.substr(0, 9)
|
||||
<< "_"
|
||||
<< std::hex
|
||||
<< hash;
|
||||
ASSERT(stream.str().length() == MAX_SHORTENED_IDENTIFIER_SIZE);
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
|
|
|
@ -15,9 +15,7 @@
|
|||
// make it easier to reference them from the compiler sources.
|
||||
|
||||
// These lengths do not include the NULL terminator.
|
||||
// see bug 675625: NVIDIA driver crash with lengths >= 253
|
||||
// this is only an interim fix, the real fix is name mapping, see ANGLE bug 144 / r619
|
||||
#define MAX_SYMBOL_NAME_LEN 250
|
||||
#define MAX_SYMBOL_NAME_LEN 256
|
||||
#define MAX_STRING_LEN 511
|
||||
|
||||
#endif // !(defined(__LENGTH_LIMITS_H)
|
||||
|
|
|
@ -0,0 +1,348 @@
|
|||
// Spooky Hash
|
||||
// A 128-bit noncryptographic hash, for checksums and table lookup
|
||||
// By Bob Jenkins. Public domain.
|
||||
// Oct 31 2010: published framework, disclaimer ShortHash isn't right
|
||||
// Nov 7 2010: disabled ShortHash
|
||||
// Oct 31 2011: replace End, ShortMix, ShortEnd, enable ShortHash again
|
||||
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
#include "spooky.h"
|
||||
|
||||
#define ALLOW_UNALIGNED_READS 1
|
||||
|
||||
//
|
||||
// short hash ... it could be used on any message,
|
||||
// but it's used by Spooky just for short messages.
|
||||
//
|
||||
void SpookyHash::Short(
|
||||
const void *message,
|
||||
size_t length,
|
||||
uint64 *hash1,
|
||||
uint64 *hash2)
|
||||
{
|
||||
uint64 buf[sc_numVars];
|
||||
union
|
||||
{
|
||||
const uint8 *p8;
|
||||
uint32 *p32;
|
||||
uint64 *p64;
|
||||
size_t i;
|
||||
} u;
|
||||
|
||||
u.p8 = (const uint8 *)message;
|
||||
|
||||
if (!ALLOW_UNALIGNED_READS && (u.i & 0x7))
|
||||
{
|
||||
memcpy(buf, message, length);
|
||||
u.p64 = buf;
|
||||
}
|
||||
|
||||
size_t remainder = length%32;
|
||||
uint64 a=*hash1;
|
||||
uint64 b=*hash2;
|
||||
uint64 c=sc_const;
|
||||
uint64 d=sc_const;
|
||||
|
||||
if (length > 15)
|
||||
{
|
||||
const uint64 *end = u.p64 + (length/32)*4;
|
||||
|
||||
// handle all complete sets of 32 bytes
|
||||
for (; u.p64 < end; u.p64 += 4)
|
||||
{
|
||||
c += u.p64[0];
|
||||
d += u.p64[1];
|
||||
ShortMix(a,b,c,d);
|
||||
a += u.p64[2];
|
||||
b += u.p64[3];
|
||||
}
|
||||
|
||||
//Handle the case of 16+ remaining bytes.
|
||||
if (remainder >= 16)
|
||||
{
|
||||
c += u.p64[0];
|
||||
d += u.p64[1];
|
||||
ShortMix(a,b,c,d);
|
||||
u.p64 += 2;
|
||||
remainder -= 16;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the last 0..15 bytes, and its length
|
||||
d = ((uint64)length) << 56;
|
||||
switch (remainder)
|
||||
{
|
||||
case 15:
|
||||
d += ((uint64)u.p8[14]) << 48;
|
||||
case 14:
|
||||
d += ((uint64)u.p8[13]) << 40;
|
||||
case 13:
|
||||
d += ((uint64)u.p8[12]) << 32;
|
||||
case 12:
|
||||
d += u.p32[2];
|
||||
c += u.p64[0];
|
||||
break;
|
||||
case 11:
|
||||
d += ((uint64)u.p8[10]) << 16;
|
||||
case 10:
|
||||
d += ((uint64)u.p8[9]) << 8;
|
||||
case 9:
|
||||
d += (uint64)u.p8[8];
|
||||
case 8:
|
||||
c += u.p64[0];
|
||||
break;
|
||||
case 7:
|
||||
c += ((uint64)u.p8[6]) << 48;
|
||||
case 6:
|
||||
c += ((uint64)u.p8[5]) << 40;
|
||||
case 5:
|
||||
c += ((uint64)u.p8[4]) << 32;
|
||||
case 4:
|
||||
c += u.p32[0];
|
||||
break;
|
||||
case 3:
|
||||
c += ((uint64)u.p8[2]) << 16;
|
||||
case 2:
|
||||
c += ((uint64)u.p8[1]) << 8;
|
||||
case 1:
|
||||
c += (uint64)u.p8[0];
|
||||
break;
|
||||
case 0:
|
||||
c += sc_const;
|
||||
d += sc_const;
|
||||
}
|
||||
ShortEnd(a,b,c,d);
|
||||
*hash1 = a;
|
||||
*hash2 = b;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// do the whole hash in one call
|
||||
void SpookyHash::Hash128(
|
||||
const void *message,
|
||||
size_t length,
|
||||
uint64 *hash1,
|
||||
uint64 *hash2)
|
||||
{
|
||||
if (length < sc_bufSize)
|
||||
{
|
||||
Short(message, length, hash1, hash2);
|
||||
return;
|
||||
}
|
||||
|
||||
uint64 h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11;
|
||||
uint64 buf[sc_numVars];
|
||||
uint64 *end;
|
||||
union
|
||||
{
|
||||
const uint8 *p8;
|
||||
uint64 *p64;
|
||||
size_t i;
|
||||
} u;
|
||||
size_t remainder;
|
||||
|
||||
h0=h3=h6=h9 = *hash1;
|
||||
h1=h4=h7=h10 = *hash2;
|
||||
h2=h5=h8=h11 = sc_const;
|
||||
|
||||
u.p8 = (const uint8 *)message;
|
||||
end = u.p64 + (length/sc_blockSize)*sc_numVars;
|
||||
|
||||
// handle all whole sc_blockSize blocks of bytes
|
||||
if (ALLOW_UNALIGNED_READS || ((u.i & 0x7) == 0))
|
||||
{
|
||||
while (u.p64 < end)
|
||||
{
|
||||
Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
u.p64 += sc_numVars;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (u.p64 < end)
|
||||
{
|
||||
memcpy(buf, u.p64, sc_blockSize);
|
||||
Mix(buf, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
u.p64 += sc_numVars;
|
||||
}
|
||||
}
|
||||
|
||||
// handle the last partial block of sc_blockSize bytes
|
||||
remainder = (length - ((const uint8 *)end-(const uint8 *)message));
|
||||
memcpy(buf, end, remainder);
|
||||
memset(((uint8 *)buf)+remainder, 0, sc_blockSize-remainder);
|
||||
((uint8 *)buf)[sc_blockSize-1] = remainder;
|
||||
Mix(buf, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
|
||||
// do some final mixing
|
||||
End(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
*hash1 = h0;
|
||||
*hash2 = h1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// init spooky state
|
||||
void SpookyHash::Init(uint64 seed1, uint64 seed2)
|
||||
{
|
||||
m_length = 0;
|
||||
m_remainder = 0;
|
||||
m_state[0] = seed1;
|
||||
m_state[1] = seed2;
|
||||
}
|
||||
|
||||
|
||||
// add a message fragment to the state
|
||||
void SpookyHash::Update(const void *message, size_t length)
|
||||
{
|
||||
uint64 h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11;
|
||||
size_t newLength = length + m_remainder;
|
||||
uint8 remainder;
|
||||
union
|
||||
{
|
||||
const uint8 *p8;
|
||||
uint64 *p64;
|
||||
size_t i;
|
||||
} u;
|
||||
const uint64 *end;
|
||||
|
||||
// Is this message fragment too short? If it is, stuff it away.
|
||||
if (newLength < sc_bufSize)
|
||||
{
|
||||
memcpy(&((uint8 *)m_data)[m_remainder], message, length);
|
||||
m_length = length + m_length;
|
||||
m_remainder = (uint8)newLength;
|
||||
return;
|
||||
}
|
||||
|
||||
// init the variables
|
||||
if (m_length < sc_bufSize)
|
||||
{
|
||||
h0=h3=h6=h9 = m_state[0];
|
||||
h1=h4=h7=h10 = m_state[1];
|
||||
h2=h5=h8=h11 = sc_const;
|
||||
}
|
||||
else
|
||||
{
|
||||
h0 = m_state[0];
|
||||
h1 = m_state[1];
|
||||
h2 = m_state[2];
|
||||
h3 = m_state[3];
|
||||
h4 = m_state[4];
|
||||
h5 = m_state[5];
|
||||
h6 = m_state[6];
|
||||
h7 = m_state[7];
|
||||
h8 = m_state[8];
|
||||
h9 = m_state[9];
|
||||
h10 = m_state[10];
|
||||
h11 = m_state[11];
|
||||
}
|
||||
m_length = length + m_length;
|
||||
|
||||
// if we've got anything stuffed away, use it now
|
||||
if (m_remainder)
|
||||
{
|
||||
uint8 prefix = sc_bufSize-m_remainder;
|
||||
memcpy(&(((uint8 *)m_data)[m_remainder]), message, prefix);
|
||||
u.p64 = m_data;
|
||||
Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
Mix(&u.p64[sc_numVars], h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
u.p8 = ((const uint8 *)message) + prefix;
|
||||
length -= prefix;
|
||||
}
|
||||
else
|
||||
{
|
||||
u.p8 = (const uint8 *)message;
|
||||
}
|
||||
|
||||
// handle all whole blocks of sc_blockSize bytes
|
||||
end = u.p64 + (length/sc_blockSize)*sc_numVars;
|
||||
remainder = (uint8)(length-((const uint8 *)end-u.p8));
|
||||
if (ALLOW_UNALIGNED_READS || (u.i & 0x7) == 0)
|
||||
{
|
||||
while (u.p64 < end)
|
||||
{
|
||||
Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
u.p64 += sc_numVars;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (u.p64 < end)
|
||||
{
|
||||
memcpy(m_data, u.p8, sc_blockSize);
|
||||
Mix(m_data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
u.p64 += sc_numVars;
|
||||
}
|
||||
}
|
||||
|
||||
// stuff away the last few bytes
|
||||
m_remainder = remainder;
|
||||
memcpy(m_data, end, remainder);
|
||||
|
||||
// stuff away the variables
|
||||
m_state[0] = h0;
|
||||
m_state[1] = h1;
|
||||
m_state[2] = h2;
|
||||
m_state[3] = h3;
|
||||
m_state[4] = h4;
|
||||
m_state[5] = h5;
|
||||
m_state[6] = h6;
|
||||
m_state[7] = h7;
|
||||
m_state[8] = h8;
|
||||
m_state[9] = h9;
|
||||
m_state[10] = h10;
|
||||
m_state[11] = h11;
|
||||
}
|
||||
|
||||
|
||||
// report the hash for the concatenation of all message fragments so far
|
||||
void SpookyHash::Final(uint64 *hash1, uint64 *hash2)
|
||||
{
|
||||
// init the variables
|
||||
if (m_length < sc_bufSize)
|
||||
{
|
||||
Short( m_data, m_length, hash1, hash2);
|
||||
return;
|
||||
}
|
||||
|
||||
const uint64 *data = (const uint64 *)m_data;
|
||||
uint8 remainder = m_remainder;
|
||||
|
||||
uint64 h0 = m_state[0];
|
||||
uint64 h1 = m_state[1];
|
||||
uint64 h2 = m_state[2];
|
||||
uint64 h3 = m_state[3];
|
||||
uint64 h4 = m_state[4];
|
||||
uint64 h5 = m_state[5];
|
||||
uint64 h6 = m_state[6];
|
||||
uint64 h7 = m_state[7];
|
||||
uint64 h8 = m_state[8];
|
||||
uint64 h9 = m_state[9];
|
||||
uint64 h10 = m_state[10];
|
||||
uint64 h11 = m_state[11];
|
||||
|
||||
if (remainder >= sc_blockSize)
|
||||
{
|
||||
// m_data can contain two blocks; handle any whole first block
|
||||
Mix(data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
data += sc_numVars;
|
||||
remainder -= sc_blockSize;
|
||||
}
|
||||
|
||||
// mix in the last partial block, and the length mod sc_blockSize
|
||||
memset(&((uint8 *)data)[remainder], 0, (sc_blockSize-remainder));
|
||||
|
||||
((uint8 *)data)[sc_blockSize-1] = remainder;
|
||||
Mix(data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
|
||||
// do some final mixing
|
||||
End(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
|
||||
*hash1 = h0;
|
||||
*hash2 = h1;
|
||||
}
|
||||
|
|
@ -0,0 +1,293 @@
|
|||
//
|
||||
// SpookyHash: a 128-bit noncryptographic hash function
|
||||
// By Bob Jenkins, public domain
|
||||
// Oct 31 2010: alpha, framework + SpookyHash::Mix appears right
|
||||
// Oct 31 2011: alpha again, Mix only good to 2^^69 but rest appears right
|
||||
// Dec 31 2011: beta, improved Mix, tested it for 2-bit deltas
|
||||
// Feb 2 2012: production, same bits as beta
|
||||
// Feb 5 2012: adjusted definitions of uint* to be more portable
|
||||
//
|
||||
// Up to 4 bytes/cycle for long messages. Reasonably fast for short messages.
|
||||
// All 1 or 2 bit deltas achieve avalanche within 1% bias per output bit.
|
||||
//
|
||||
// This was developed for and tested on 64-bit x86-compatible processors.
|
||||
// It assumes the processor is little-endian. There is a macro
|
||||
// controlling whether unaligned reads are allowed (by default they are).
|
||||
// This should be an equally good hash on big-endian machines, but it will
|
||||
// compute different results on them than on little-endian machines.
|
||||
//
|
||||
// Google's CityHash has similar specs to SpookyHash, and CityHash is faster
|
||||
// on some platforms. MD4 and MD5 also have similar specs, but they are orders
|
||||
// of magnitude slower. CRCs are two or more times slower, but unlike
|
||||
// SpookyHash, they have nice math for combining the CRCs of pieces to form
|
||||
// the CRCs of wholes. There are also cryptographic hashes, but those are even
|
||||
// slower than MD5.
|
||||
//
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define INLINE __forceinline
|
||||
typedef unsigned __int64 uint64;
|
||||
typedef unsigned __int32 uint32;
|
||||
typedef unsigned __int16 uint16;
|
||||
typedef unsigned __int8 uint8;
|
||||
#else
|
||||
# include <stdint.h>
|
||||
# define INLINE inline
|
||||
typedef uint64_t uint64;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint8_t uint8;
|
||||
#endif
|
||||
|
||||
|
||||
class SpookyHash
|
||||
{
|
||||
public:
|
||||
//
|
||||
// SpookyHash: hash a single message in one call, produce 128-bit output
|
||||
//
|
||||
static void Hash128(
|
||||
const void *message, // message to hash
|
||||
size_t length, // length of message in bytes
|
||||
uint64 *hash1, // in/out: in seed 1, out hash value 1
|
||||
uint64 *hash2); // in/out: in seed 2, out hash value 2
|
||||
|
||||
//
|
||||
// Hash64: hash a single message in one call, return 64-bit output
|
||||
//
|
||||
static uint64 Hash64(
|
||||
const void *message, // message to hash
|
||||
size_t length, // length of message in bytes
|
||||
uint64 seed) // seed
|
||||
{
|
||||
uint64 hash1 = seed;
|
||||
Hash128(message, length, &hash1, &seed);
|
||||
return hash1;
|
||||
}
|
||||
|
||||
//
|
||||
// Hash32: hash a single message in one call, produce 32-bit output
|
||||
//
|
||||
static uint32 Hash32(
|
||||
const void *message, // message to hash
|
||||
size_t length, // length of message in bytes
|
||||
uint32 seed) // seed
|
||||
{
|
||||
uint64 hash1 = seed, hash2 = seed;
|
||||
Hash128(message, length, &hash1, &hash2);
|
||||
return (uint32)hash1;
|
||||
}
|
||||
|
||||
//
|
||||
// Init: initialize the context of a SpookyHash
|
||||
//
|
||||
void Init(
|
||||
uint64 seed1, // any 64-bit value will do, including 0
|
||||
uint64 seed2); // different seeds produce independent hashes
|
||||
|
||||
//
|
||||
// Update: add a piece of a message to a SpookyHash state
|
||||
//
|
||||
void Update(
|
||||
const void *message, // message fragment
|
||||
size_t length); // length of message fragment in bytes
|
||||
|
||||
|
||||
//
|
||||
// Final: compute the hash for the current SpookyHash state
|
||||
//
|
||||
// This does not modify the state; you can keep updating it afterward
|
||||
//
|
||||
// The result is the same as if SpookyHash() had been called with
|
||||
// all the pieces concatenated into one message.
|
||||
//
|
||||
void Final(
|
||||
uint64 *hash1, // out only: first 64 bits of hash value.
|
||||
uint64 *hash2); // out only: second 64 bits of hash value.
|
||||
|
||||
//
|
||||
// left rotate a 64-bit value by k bytes
|
||||
//
|
||||
static INLINE uint64 Rot64(uint64 x, int k)
|
||||
{
|
||||
return (x << k) | (x >> (64 - k));
|
||||
}
|
||||
|
||||
//
|
||||
// This is used if the input is 96 bytes long or longer.
|
||||
//
|
||||
// The internal state is fully overwritten every 96 bytes.
|
||||
// Every input bit appears to cause at least 128 bits of entropy
|
||||
// before 96 other bytes are combined, when run forward or backward
|
||||
// For every input bit,
|
||||
// Two inputs differing in just that input bit
|
||||
// Where "differ" means xor or subtraction
|
||||
// And the base value is random
|
||||
// When run forward or backwards one Mix
|
||||
// I tried 3 pairs of each; they all differed by at least 212 bits.
|
||||
//
|
||||
static INLINE void Mix(
|
||||
const uint64 *data,
|
||||
uint64 &s0, uint64 &s1, uint64 &s2, uint64 &s3,
|
||||
uint64 &s4, uint64 &s5, uint64 &s6, uint64 &s7,
|
||||
uint64 &s8, uint64 &s9, uint64 &s10,uint64 &s11)
|
||||
{
|
||||
s0 += data[0]; s2 ^= s10; s11 ^= s0; s0 = Rot64(s0,11); s11 += s1;
|
||||
s1 += data[1]; s3 ^= s11; s0 ^= s1; s1 = Rot64(s1,32); s0 += s2;
|
||||
s2 += data[2]; s4 ^= s0; s1 ^= s2; s2 = Rot64(s2,43); s1 += s3;
|
||||
s3 += data[3]; s5 ^= s1; s2 ^= s3; s3 = Rot64(s3,31); s2 += s4;
|
||||
s4 += data[4]; s6 ^= s2; s3 ^= s4; s4 = Rot64(s4,17); s3 += s5;
|
||||
s5 += data[5]; s7 ^= s3; s4 ^= s5; s5 = Rot64(s5,28); s4 += s6;
|
||||
s6 += data[6]; s8 ^= s4; s5 ^= s6; s6 = Rot64(s6,39); s5 += s7;
|
||||
s7 += data[7]; s9 ^= s5; s6 ^= s7; s7 = Rot64(s7,57); s6 += s8;
|
||||
s8 += data[8]; s10 ^= s6; s7 ^= s8; s8 = Rot64(s8,55); s7 += s9;
|
||||
s9 += data[9]; s11 ^= s7; s8 ^= s9; s9 = Rot64(s9,54); s8 += s10;
|
||||
s10 += data[10]; s0 ^= s8; s9 ^= s10; s10 = Rot64(s10,22); s9 += s11;
|
||||
s11 += data[11]; s1 ^= s9; s10 ^= s11; s11 = Rot64(s11,46); s10 += s0;
|
||||
}
|
||||
|
||||
//
|
||||
// Mix all 12 inputs together so that h0, h1 are a hash of them all.
|
||||
//
|
||||
// For two inputs differing in just the input bits
|
||||
// Where "differ" means xor or subtraction
|
||||
// And the base value is random, or a counting value starting at that bit
|
||||
// The final result will have each bit of h0, h1 flip
|
||||
// For every input bit,
|
||||
// with probability 50 +- .3%
|
||||
// For every pair of input bits,
|
||||
// with probability 50 +- 3%
|
||||
//
|
||||
// This does not rely on the last Mix() call having already mixed some.
|
||||
// Two iterations was almost good enough for a 64-bit result, but a
|
||||
// 128-bit result is reported, so End() does three iterations.
|
||||
//
|
||||
static INLINE void EndPartial(
|
||||
uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3,
|
||||
uint64 &h4, uint64 &h5, uint64 &h6, uint64 &h7,
|
||||
uint64 &h8, uint64 &h9, uint64 &h10,uint64 &h11)
|
||||
{
|
||||
h11+= h1; h2 ^= h11; h1 = Rot64(h1,44);
|
||||
h0 += h2; h3 ^= h0; h2 = Rot64(h2,15);
|
||||
h1 += h3; h4 ^= h1; h3 = Rot64(h3,34);
|
||||
h2 += h4; h5 ^= h2; h4 = Rot64(h4,21);
|
||||
h3 += h5; h6 ^= h3; h5 = Rot64(h5,38);
|
||||
h4 += h6; h7 ^= h4; h6 = Rot64(h6,33);
|
||||
h5 += h7; h8 ^= h5; h7 = Rot64(h7,10);
|
||||
h6 += h8; h9 ^= h6; h8 = Rot64(h8,13);
|
||||
h7 += h9; h10^= h7; h9 = Rot64(h9,38);
|
||||
h8 += h10; h11^= h8; h10= Rot64(h10,53);
|
||||
h9 += h11; h0 ^= h9; h11= Rot64(h11,42);
|
||||
h10+= h0; h1 ^= h10; h0 = Rot64(h0,54);
|
||||
}
|
||||
|
||||
static INLINE void End(
|
||||
uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3,
|
||||
uint64 &h4, uint64 &h5, uint64 &h6, uint64 &h7,
|
||||
uint64 &h8, uint64 &h9, uint64 &h10,uint64 &h11)
|
||||
{
|
||||
EndPartial(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
EndPartial(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
EndPartial(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
|
||||
}
|
||||
|
||||
//
|
||||
// The goal is for each bit of the input to expand into 128 bits of
|
||||
// apparent entropy before it is fully overwritten.
|
||||
// n trials both set and cleared at least m bits of h0 h1 h2 h3
|
||||
// n: 2 m: 29
|
||||
// n: 3 m: 46
|
||||
// n: 4 m: 57
|
||||
// n: 5 m: 107
|
||||
// n: 6 m: 146
|
||||
// n: 7 m: 152
|
||||
// when run forwards or backwards
|
||||
// for all 1-bit and 2-bit diffs
|
||||
// with diffs defined by either xor or subtraction
|
||||
// with a base of all zeros plus a counter, or plus another bit, or random
|
||||
//
|
||||
static INLINE void ShortMix(uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3)
|
||||
{
|
||||
h2 = Rot64(h2,50); h2 += h3; h0 ^= h2;
|
||||
h3 = Rot64(h3,52); h3 += h0; h1 ^= h3;
|
||||
h0 = Rot64(h0,30); h0 += h1; h2 ^= h0;
|
||||
h1 = Rot64(h1,41); h1 += h2; h3 ^= h1;
|
||||
h2 = Rot64(h2,54); h2 += h3; h0 ^= h2;
|
||||
h3 = Rot64(h3,48); h3 += h0; h1 ^= h3;
|
||||
h0 = Rot64(h0,38); h0 += h1; h2 ^= h0;
|
||||
h1 = Rot64(h1,37); h1 += h2; h3 ^= h1;
|
||||
h2 = Rot64(h2,62); h2 += h3; h0 ^= h2;
|
||||
h3 = Rot64(h3,34); h3 += h0; h1 ^= h3;
|
||||
h0 = Rot64(h0,5); h0 += h1; h2 ^= h0;
|
||||
h1 = Rot64(h1,36); h1 += h2; h3 ^= h1;
|
||||
}
|
||||
|
||||
//
|
||||
// Mix all 4 inputs together so that h0, h1 are a hash of them all.
|
||||
//
|
||||
// For two inputs differing in just the input bits
|
||||
// Where "differ" means xor or subtraction
|
||||
// And the base value is random, or a counting value starting at that bit
|
||||
// The final result will have each bit of h0, h1 flip
|
||||
// For every input bit,
|
||||
// with probability 50 +- .3% (it is probably better than that)
|
||||
// For every pair of input bits,
|
||||
// with probability 50 +- .75% (the worst case is approximately that)
|
||||
//
|
||||
static INLINE void ShortEnd(uint64 &h0, uint64 &h1, uint64 &h2, uint64 &h3)
|
||||
{
|
||||
h3 ^= h2; h2 = Rot64(h2,15); h3 += h2;
|
||||
h0 ^= h3; h3 = Rot64(h3,52); h0 += h3;
|
||||
h1 ^= h0; h0 = Rot64(h0,26); h1 += h0;
|
||||
h2 ^= h1; h1 = Rot64(h1,51); h2 += h1;
|
||||
h3 ^= h2; h2 = Rot64(h2,28); h3 += h2;
|
||||
h0 ^= h3; h3 = Rot64(h3,9); h0 += h3;
|
||||
h1 ^= h0; h0 = Rot64(h0,47); h1 += h0;
|
||||
h2 ^= h1; h1 = Rot64(h1,54); h2 += h1;
|
||||
h3 ^= h2; h2 = Rot64(h2,32); h3 += h2;
|
||||
h0 ^= h3; h3 = Rot64(h3,25); h0 += h3;
|
||||
h1 ^= h0; h0 = Rot64(h0,63); h1 += h0;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//
|
||||
// Short is used for messages under 192 bytes in length
|
||||
// Short has a low startup cost, the normal mode is good for long
|
||||
// keys, the cost crossover is at about 192 bytes. The two modes were
|
||||
// held to the same quality bar.
|
||||
//
|
||||
static void Short(
|
||||
const void *message,
|
||||
size_t length,
|
||||
uint64 *hash1,
|
||||
uint64 *hash2);
|
||||
|
||||
// number of uint64's in internal state
|
||||
static const size_t sc_numVars = 12;
|
||||
|
||||
// size of the internal state
|
||||
static const size_t sc_blockSize = sc_numVars*8;
|
||||
|
||||
// size of buffer of unhashed data, in bytes
|
||||
static const size_t sc_bufSize = 2*sc_blockSize;
|
||||
|
||||
//
|
||||
// sc_const: a constant which:
|
||||
// * is not zero
|
||||
// * is odd
|
||||
// * is a not-very-regular mix of 1's and 0's
|
||||
// * does not need any other special mathematical properties
|
||||
//
|
||||
static const uint64 sc_const = 0xdeadbeefdeadbeefLL;
|
||||
|
||||
uint64 m_data[2*sc_numVars]; // unhashed data, for partial messages
|
||||
uint64 m_state[sc_numVars]; // internal state of the hash
|
||||
size_t m_length; // total length of the input so far
|
||||
uint8 m_remainder; // length of unhashed data stashed in m_data
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -96,6 +96,7 @@ CPPSRCS = \
|
|||
ValidateLimitations.cpp \
|
||||
ForLoopUnroll.cpp \
|
||||
MapLongVariableNames.cpp \
|
||||
spooky.cpp \
|
||||
BuiltInFunctionEmulator.cpp \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
@ -96,6 +96,7 @@ CPPSRCS = \
|
|||
ValidateLimitations.cpp \
|
||||
ForLoopUnroll.cpp \
|
||||
MapLongVariableNames.cpp \
|
||||
spooky.cpp \
|
||||
BuiltInFunctionEmulator.cpp \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
* License.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* Portions created by the Initial Developer are Copyright (C) 2012
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
|
|
|
@ -253,7 +253,6 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
|||
{ (PRFuncPtr*) &mSymbols.fTexParameteri, { "TexParameteri", NULL } },
|
||||
{ (PRFuncPtr*) &mSymbols.fTexParameterf, { "TexParameterf", NULL } },
|
||||
{ (PRFuncPtr*) &mSymbols.fGetString, { "GetString", NULL } },
|
||||
{ (PRFuncPtr*) &mSymbols.fGetTexLevelParameteriv, { "GetTexLevelParameteriv", NULL } },
|
||||
{ (PRFuncPtr*) &mSymbols.fGetTexParameterfv, { "GetTexParameterfv", NULL } },
|
||||
{ (PRFuncPtr*) &mSymbols.fGetTexParameteriv, { "GetTexParameteriv", NULL } },
|
||||
{ (PRFuncPtr*) &mSymbols.fGetUniformfv, { "GetUniformfv", "GetUniformfvARB", NULL } },
|
||||
|
@ -499,6 +498,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
|||
// Load developer symbols, don't fail if we can't find them.
|
||||
SymLoadStruct auxSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", NULL } },
|
||||
{ (PRFuncPtr*) &mSymbols.fGetTexLevelParameteriv, { "GetTexLevelParameteriv", NULL } },
|
||||
{ NULL, { NULL } },
|
||||
};
|
||||
LoadSymbols(&auxSymbols[0], trygl, prefix);
|
||||
|
|
|
@ -2136,6 +2136,10 @@ public:
|
|||
|
||||
void fGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params)
|
||||
{
|
||||
if (!mSymbols.fGetTexLevelParameteriv) {
|
||||
*params = 0;
|
||||
return;
|
||||
}
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fGetTexLevelParameteriv(target, level, pname, params);
|
||||
AFTER_GL_CALL;
|
||||
|
|
|
@ -2630,11 +2630,7 @@ GLContextProviderEGL::CreateOffscreen(const gfxIntSize& aSize,
|
|||
if (!glContext) {
|
||||
return nsnull;
|
||||
}
|
||||
if (!glContext->GetSharedContext()) {
|
||||
// no point in returning anything if sharing failed, we can't
|
||||
// render from this
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
if (!gUseBackingSurface && !glContext->ResizeOffscreenFBO(glContext->OffscreenActualSize(), true)) {
|
||||
// we weren't able to create the initial
|
||||
// offscreen FBO, so this is dead
|
||||
|
|
|
@ -50,7 +50,7 @@ RenderColorLayer(ColorLayer* aLayer, LayerManagerOGL *aManager,
|
|||
// XXX we might be able to improve performance by using glClear
|
||||
|
||||
nsIntRect visibleRect = aLayer->GetEffectiveVisibleRegion().GetBounds();
|
||||
|
||||
|
||||
/* Multiply color by the layer opacity, as the shader
|
||||
* ignores layer opacity and expects a final color to
|
||||
* write to the color buffer. This saves a needless
|
||||
|
@ -77,14 +77,14 @@ void
|
|||
ColorLayerOGL::RenderLayer(int,
|
||||
const nsIntPoint& aOffset)
|
||||
{
|
||||
return RenderColorLayer(this, mOGLManager, aOffset);
|
||||
RenderColorLayer(this, mOGLManager, aOffset);
|
||||
}
|
||||
|
||||
void
|
||||
ShadowColorLayerOGL::RenderLayer(int,
|
||||
const nsIntPoint& aOffset)
|
||||
{
|
||||
return RenderColorLayer(this, mOGLManager, aOffset);
|
||||
RenderColorLayer(this, mOGLManager, aOffset);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "nsColor.h"
|
||||
#include "nsCoord.h"
|
||||
#include "gfxContext.h"
|
||||
#include "mozilla/gfx/UserData.h"
|
||||
|
||||
struct nsPoint;
|
||||
class nsIntRegion;
|
||||
|
@ -58,6 +59,9 @@ typedef enum {
|
|||
|
||||
class nsRenderingContext
|
||||
{
|
||||
typedef mozilla::gfx::UserData UserData;
|
||||
typedef mozilla::gfx::UserDataKey UserDataKey;
|
||||
|
||||
public:
|
||||
nsRenderingContext() : mP2A(0.) {}
|
||||
// ~nsRenderingContext() {}
|
||||
|
@ -136,6 +140,16 @@ public:
|
|||
void DrawString(const PRUnichar *aString, PRUint32 aLength,
|
||||
nscoord aX, nscoord aY);
|
||||
|
||||
void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) {
|
||||
mUserData.Add(key, userData, destroy);
|
||||
}
|
||||
void *GetUserData(UserDataKey *key) {
|
||||
return mUserData.Get(key);
|
||||
}
|
||||
void *RemoveUserData(UserDataKey *key) {
|
||||
return mUserData.Remove(key);
|
||||
}
|
||||
|
||||
protected:
|
||||
PRInt32 GetMaxChunkLength();
|
||||
|
||||
|
@ -144,6 +158,8 @@ protected:
|
|||
nsRefPtr<nsFontMetrics> mFontMetrics;
|
||||
|
||||
double mP2A; // cached app units per device pixel value
|
||||
|
||||
UserData mUserData;
|
||||
};
|
||||
|
||||
#endif // NSRENDERINGCONTEXT__H__
|
||||
|
|
|
@ -1718,12 +1718,19 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
|
|||
// request.
|
||||
nsCOMPtr<nsIStreamListener> listener = pl;
|
||||
if (corsmode != imgIRequest::CORS_NONE) {
|
||||
PR_LOG(gImgLog, PR_LOG_DEBUG,
|
||||
("[this=%p] imgLoader::LoadImage -- Setting up a CORS load",
|
||||
this));
|
||||
bool withCredentials = corsmode == imgIRequest::CORS_USE_CREDENTIALS;
|
||||
|
||||
nsCOMPtr<nsIStreamListener> corsproxy =
|
||||
new nsCORSListenerProxy(pl, aLoadingPrincipal, newChannel,
|
||||
withCredentials, &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
PR_LOG(gImgLog, PR_LOG_DEBUG,
|
||||
("[this=%p] imgLoader::LoadImage -- nsCORSListenerProxy "
|
||||
"creation failed: 0x%x\n", this, rv));
|
||||
request->CancelAndAbort(rv);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
<!DOCTYPE html>
|
||||
<img crossorigin src="data:a/a,">
|
|
@ -25,3 +25,4 @@ HTTP load delayedframe.sjs
|
|||
|
||||
load 681190.html
|
||||
load 694165-1.xhtml
|
||||
load 732319-1.html
|
||||
|
|
|
@ -1141,7 +1141,7 @@ static JS_ALWAYS_INLINE bool IsNegative(Type i)
|
|||
return IsNegativeImpl<Type, numeric_limits<Type>::is_signed>::Test(i);
|
||||
}
|
||||
|
||||
// Implicitly convert val to bool, allowing JSBool, jsint, and double
|
||||
// Implicitly convert val to bool, allowing JSBool, int, and double
|
||||
// arguments numerically equal to 0 or 1.
|
||||
static bool
|
||||
jsvalToBool(JSContext* cx, jsval val, bool* result)
|
||||
|
@ -1151,7 +1151,7 @@ jsvalToBool(JSContext* cx, jsval val, bool* result)
|
|||
return true;
|
||||
}
|
||||
if (JSVAL_IS_INT(val)) {
|
||||
jsint i = JSVAL_TO_INT(val);
|
||||
int32_t i = JSVAL_TO_INT(val);
|
||||
*result = i != 0;
|
||||
return i == 0 || i == 1;
|
||||
}
|
||||
|
@ -1165,7 +1165,7 @@ jsvalToBool(JSContext* cx, jsval val, bool* result)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Implicitly convert val to IntegerType, allowing JSBool, jsint, double,
|
||||
// Implicitly convert val to IntegerType, allowing JSBool, int, double,
|
||||
// Int64, UInt64, and CData integer types 't' where all values of 't' are
|
||||
// representable by IntegerType.
|
||||
template<class IntegerType>
|
||||
|
@ -1177,7 +1177,7 @@ jsvalToInteger(JSContext* cx, jsval val, IntegerType* result)
|
|||
if (JSVAL_IS_INT(val)) {
|
||||
// Make sure the integer fits in the alotted precision, and has the right
|
||||
// sign.
|
||||
jsint i = JSVAL_TO_INT(val);
|
||||
int32_t i = JSVAL_TO_INT(val);
|
||||
return ConvertExact(i, result);
|
||||
}
|
||||
if (JSVAL_IS_DOUBLE(val)) {
|
||||
|
@ -1246,7 +1246,7 @@ jsvalToInteger(JSContext* cx, jsval val, IntegerType* result)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Implicitly convert val to FloatType, allowing jsint, double,
|
||||
// Implicitly convert val to FloatType, allowing int, double,
|
||||
// Int64, UInt64, and CData numeric types 't' where all values of 't' are
|
||||
// representable by FloatType.
|
||||
template<class FloatType>
|
||||
|
@ -1359,7 +1359,7 @@ StringToInteger(JSContext* cx, JSString* string, IntegerType* result)
|
|||
return true;
|
||||
}
|
||||
|
||||
// Implicitly convert val to IntegerType, allowing jsint, double,
|
||||
// Implicitly convert val to IntegerType, allowing int, double,
|
||||
// Int64, UInt64, and optionally a decimal or hexadecimal string argument.
|
||||
// (This is common code shared by jsvalToSize and the Int64/UInt64 constructors.)
|
||||
template<class IntegerType>
|
||||
|
@ -1374,7 +1374,7 @@ jsvalToBigInteger(JSContext* cx,
|
|||
if (JSVAL_IS_INT(val)) {
|
||||
// Make sure the integer fits in the alotted precision, and has the right
|
||||
// sign.
|
||||
jsint i = JSVAL_TO_INT(val);
|
||||
int32_t i = JSVAL_TO_INT(val);
|
||||
return ConvertExact(i, result);
|
||||
}
|
||||
if (JSVAL_IS_DOUBLE(val)) {
|
||||
|
@ -1421,7 +1421,7 @@ jsvalToSize(JSContext* cx, jsval val, bool allowString, size_t* result)
|
|||
return Convert<size_t>(double(*result)) == *result;
|
||||
}
|
||||
|
||||
// Implicitly convert val to IntegerType, allowing jsint, double,
|
||||
// Implicitly convert val to IntegerType, allowing int, double,
|
||||
// Int64, UInt64, and optionally a decimal or hexadecimal string argument.
|
||||
// (This is common code shared by jsvalToSize and the Int64/UInt64 constructors.)
|
||||
template<class IntegerType>
|
||||
|
@ -1436,7 +1436,7 @@ jsidToBigInteger(JSContext* cx,
|
|||
if (JSID_IS_INT(val)) {
|
||||
// Make sure the integer fits in the alotted precision, and has the right
|
||||
// sign.
|
||||
jsint i = JSID_TO_INT(val);
|
||||
int32_t i = JSID_TO_INT(val);
|
||||
return ConvertExact(i, result);
|
||||
}
|
||||
if (allowString && JSID_IS_STRING(val)) {
|
||||
|
@ -1525,9 +1525,9 @@ static bool
|
|||
jsvalToPtrExplicit(JSContext* cx, jsval val, uintptr_t* result)
|
||||
{
|
||||
if (JSVAL_IS_INT(val)) {
|
||||
// jsint always fits in intptr_t. If the integer is negative, cast through
|
||||
// int32_t always fits in intptr_t. If the integer is negative, cast through
|
||||
// an intptr_t intermediate to sign-extend.
|
||||
jsint i = JSVAL_TO_INT(val);
|
||||
int32_t i = JSVAL_TO_INT(val);
|
||||
*result = i < 0 ? uintptr_t(intptr_t(i)) : uintptr_t(i);
|
||||
return true;
|
||||
}
|
||||
|
@ -1650,7 +1650,7 @@ ConvertToJS(JSContext* cx,
|
|||
case TYPE_##name: { \
|
||||
type value = *static_cast<type*>(data); \
|
||||
if (sizeof(type) < 4) \
|
||||
*result = INT_TO_JSVAL(jsint(value)); \
|
||||
*result = INT_TO_JSVAL(int32_t(value)); \
|
||||
else if (!JS_NewNumberValue(cx, double(value), result)) \
|
||||
return false; \
|
||||
break; \
|
||||
|
@ -2929,7 +2929,7 @@ CType::GetSafeSize(JSObject* obj, size_t* result)
|
|||
|
||||
jsval size = JS_GetReservedSlot(obj, SLOT_SIZE);
|
||||
|
||||
// The "size" property can be a jsint, a double, or JSVAL_VOID
|
||||
// The "size" property can be an int, a double, or JSVAL_VOID
|
||||
// (for arrays of undefined length), and must always fit in a size_t.
|
||||
if (JSVAL_IS_INT(size)) {
|
||||
*result = JSVAL_TO_INT(size);
|
||||
|
@ -2953,7 +2953,7 @@ CType::GetSize(JSObject* obj)
|
|||
|
||||
JS_ASSERT(!JSVAL_IS_VOID(size));
|
||||
|
||||
// The "size" property can be a jsint, a double, or JSVAL_VOID
|
||||
// The "size" property can be an int, a double, or JSVAL_VOID
|
||||
// (for arrays of undefined length), and must always fit in a size_t.
|
||||
// For callers who know it can never be JSVAL_VOID, return a size_t directly.
|
||||
if (JSVAL_IS_INT(size))
|
||||
|
@ -2968,7 +2968,7 @@ CType::IsSizeDefined(JSObject* obj)
|
|||
|
||||
jsval size = JS_GetReservedSlot(obj, SLOT_SIZE);
|
||||
|
||||
// The "size" property can be a jsint, a double, or JSVAL_VOID
|
||||
// The "size" property can be an int, a double, or JSVAL_VOID
|
||||
// (for arrays of undefined length), and must always fit in a size_t.
|
||||
JS_ASSERT(JSVAL_IS_INT(size) || JSVAL_IS_DOUBLE(size) || JSVAL_IS_VOID(size));
|
||||
return !JSVAL_IS_VOID(size);
|
||||
|
@ -3599,7 +3599,7 @@ ArrayType::CreateInternal(JSContext* cx,
|
|||
jsval sizeVal = JSVAL_VOID;
|
||||
jsval lengthVal = JSVAL_VOID;
|
||||
if (lengthDefined) {
|
||||
// Check for overflow, and convert to a jsint or double as required.
|
||||
// Check for overflow, and convert to an int or double as required.
|
||||
size_t size = length * baseSize;
|
||||
if (length > 0 && size / length != baseSize) {
|
||||
JS_ReportError(cx, "size overflow");
|
||||
|
@ -3750,7 +3750,7 @@ ArrayType::GetSafeLength(JSObject* obj, size_t* result)
|
|||
|
||||
jsval length = JS_GetReservedSlot(obj, SLOT_LENGTH);
|
||||
|
||||
// The "length" property can be a jsint, a double, or JSVAL_VOID
|
||||
// The "length" property can be an int, a double, or JSVAL_VOID
|
||||
// (for arrays of undefined length), and must always fit in a size_t.
|
||||
if (JSVAL_IS_INT(length)) {
|
||||
*result = JSVAL_TO_INT(length);
|
||||
|
@ -3775,7 +3775,7 @@ ArrayType::GetLength(JSObject* obj)
|
|||
|
||||
JS_ASSERT(!JSVAL_IS_VOID(length));
|
||||
|
||||
// The "length" property can be a jsint, a double, or JSVAL_VOID
|
||||
// The "length" property can be an int, a double, or JSVAL_VOID
|
||||
// (for arrays of undefined length), and must always fit in a size_t.
|
||||
// For callers who know it can never be JSVAL_VOID, return a size_t directly.
|
||||
if (JSVAL_IS_INT(length))
|
||||
|
|
|
@ -775,7 +775,7 @@ frontend::DefineCompileTimeConstant(JSContext *cx, BytecodeEmitter *bce, JSAtom
|
|||
}
|
||||
|
||||
StmtInfo *
|
||||
frontend::LexicalLookup(TreeContext *tc, JSAtom *atom, jsint *slotp, StmtInfo *stmt)
|
||||
frontend::LexicalLookup(TreeContext *tc, JSAtom *atom, int *slotp, StmtInfo *stmt)
|
||||
{
|
||||
if (!stmt)
|
||||
stmt = tc->topScopeStmt;
|
||||
|
@ -1007,8 +1007,8 @@ BytecodeEmitter::shouldNoteClosedName(ParseNode *pn)
|
|||
*
|
||||
* The function returns -1 on failures.
|
||||
*/
|
||||
static jsint
|
||||
AdjustBlockSlot(JSContext *cx, BytecodeEmitter *bce, jsint slot)
|
||||
static int
|
||||
AdjustBlockSlot(JSContext *cx, BytecodeEmitter *bce, int slot)
|
||||
{
|
||||
JS_ASSERT((jsuint) slot < bce->maxStackDepth);
|
||||
if (bce->inFunction()) {
|
||||
|
@ -1160,7 +1160,7 @@ BindKnownGlobal(JSContext *cx, BytecodeEmitter *bce, ParseNode *dn, ParseNode *p
|
|||
|
||||
// Otherwise, find the atom's index by using the originating bce's
|
||||
// global use table.
|
||||
index = globalbce->globalUses[dn->pn_cookie.asInteger()].slot;
|
||||
index = globalbce->globalUses[dn->pn_cookie.slot()].slot;
|
||||
}
|
||||
|
||||
if (!bce->addGlobalUse(atom, index, &pn->pn_cookie))
|
||||
|
@ -1350,7 +1350,7 @@ BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
}
|
||||
|
||||
/* Optimize accesses to undeclared globals. */
|
||||
if (!bce->mightAliasLocals() && !TryConvertToGname(bce, pn, &op))
|
||||
if (!TryConvertToGname(bce, pn, &op))
|
||||
return JS_TRUE;
|
||||
|
||||
jsatomid _;
|
||||
|
@ -1852,7 +1852,7 @@ EmitNameOp(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSBool callContex
|
|||
} else {
|
||||
if (!pn->pn_cookie.isFree()) {
|
||||
JS_ASSERT(JOF_OPTYPE(op) != JOF_ATOM);
|
||||
EMIT_UINT16_IMM_OP(op, pn->pn_cookie.asInteger());
|
||||
EMIT_UINT16_IMM_OP(op, pn->pn_cookie.slot());
|
||||
} else {
|
||||
if (!EmitAtomOp(cx, pn, op, bce))
|
||||
return JS_FALSE;
|
||||
|
@ -2261,7 +2261,7 @@ EmitNumberOp(JSContext *cx, double dval, BytecodeEmitter *bce)
|
|||
return Emit1(cx, bce, JSOP_ZERO) >= 0;
|
||||
if (ival == 1)
|
||||
return Emit1(cx, bce, JSOP_ONE) >= 0;
|
||||
if ((jsint)(int8_t)ival == ival)
|
||||
if ((int)(int8_t)ival == ival)
|
||||
return Emit2(cx, bce, JSOP_INT8, (jsbytecode)(int8_t)ival) >= 0;
|
||||
|
||||
u = (uint32_t)ival;
|
||||
|
@ -2474,7 +2474,7 @@ EmitSwitch(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
continue;
|
||||
}
|
||||
i = pn3->pn_pval->toInt32();
|
||||
if ((jsuint)(i + (jsint)JS_BIT(15)) >= (jsuint)JS_BIT(16)) {
|
||||
if ((jsuint)(i + (int)JS_BIT(15)) >= (jsuint)JS_BIT(16)) {
|
||||
switchOp = JSOP_LOOKUPSWITCH;
|
||||
continue;
|
||||
}
|
||||
|
@ -2684,7 +2684,7 @@ EmitSwitch(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
savepc = bce->next();
|
||||
bce->current->next = pc + 1;
|
||||
if (switchOp == JSOP_TABLESWITCH) {
|
||||
for (i = 0; i < (jsint)tableLength; i++) {
|
||||
for (i = 0; i < (int)tableLength; i++) {
|
||||
pn3 = table[i];
|
||||
if (pn3 &&
|
||||
(pn4 = pn3->pn_left) != NULL &&
|
||||
|
@ -2764,7 +2764,7 @@ EmitSwitch(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
pc += 2 * JUMP_OFFSET_LEN;
|
||||
|
||||
/* Fill in the jump table, if there is one. */
|
||||
for (i = 0; i < (jsint)tableLength; i++) {
|
||||
for (i = 0; i < (int)tableLength; i++) {
|
||||
pn3 = table[i];
|
||||
off = pn3 ? pn3->pn_offset - top : 0;
|
||||
SET_JUMP_OFFSET(pc, off);
|
||||
|
@ -3019,14 +3019,14 @@ EmitDestructuringLHS(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmit
|
|||
|
||||
case JSOP_SETLOCAL:
|
||||
{
|
||||
jsuint slot = pn->pn_cookie.asInteger();
|
||||
uint16_t slot = pn->pn_cookie.slot();
|
||||
EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, slot);
|
||||
break;
|
||||
}
|
||||
|
||||
case JSOP_SETARG:
|
||||
{
|
||||
jsuint slot = pn->pn_cookie.asInteger();
|
||||
uint16_t slot = pn->pn_cookie.slot();
|
||||
EMIT_UINT16_IMM_OP(pn->getOp(), slot);
|
||||
if (Emit1(cx, bce, JSOP_POP) < 0)
|
||||
return JS_FALSE;
|
||||
|
@ -3334,7 +3334,7 @@ EmitGroupAssignment(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp,
|
|||
for (pn = lhs->pn_head; pn; pn = pn->pn_next, ++i) {
|
||||
/* MaybeEmitGroupAssignment requires lhs->pn_count <= rhs->pn_count. */
|
||||
JS_ASSERT(i < limit);
|
||||
jsint slot = AdjustBlockSlot(cx, bce, i);
|
||||
int slot = AdjustBlockSlot(cx, bce, i);
|
||||
if (slot < 0)
|
||||
return JS_FALSE;
|
||||
EMIT_UINT16_IMM_OP(JSOP_GETLOCAL, slot);
|
||||
|
@ -3658,7 +3658,8 @@ EmitAssignment(JSContext *cx, BytecodeEmitter *bce, ParseNode *lhs, JSOp op, Par
|
|||
if (!BindNameToSlot(cx, bce, lhs))
|
||||
return false;
|
||||
if (!lhs->pn_cookie.isFree()) {
|
||||
atomIndex = lhs->pn_cookie.asInteger();
|
||||
JS_ASSERT(lhs->pn_cookie.level() == 0);
|
||||
atomIndex = lhs->pn_cookie.slot();
|
||||
} else {
|
||||
if (!bce->makeAtomIndex(lhs->pn_atom, &atomIndex))
|
||||
return false;
|
||||
|
@ -6507,7 +6508,7 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
#endif /* JS_HAS_BLOCK_SCOPE */
|
||||
#if JS_HAS_GENERATORS
|
||||
case PNK_ARRAYPUSH: {
|
||||
jsint slot;
|
||||
int slot;
|
||||
|
||||
/*
|
||||
* The array object's stack index is in bce->arrayCompDepth. See below
|
||||
|
|
|
@ -168,7 +168,7 @@ struct StmtInfo {
|
|||
#define TCF_IN_FOR_INIT 0x10 /* parsing init expr of for; exclude 'in' */
|
||||
#define TCF_FUN_SETS_OUTER_NAME 0x20 /* function set outer name (lexical or free) */
|
||||
#define TCF_FUN_PARAM_ARGUMENTS 0x40 /* function has parameter named arguments */
|
||||
#define TCF_FUN_LOCAL_ARGUMENTS 0x80 /* function has local named arguments */
|
||||
#define TCF_FUN_LOCAL_ARGUMENTS 0x80 /* function may contain a local named arguments */
|
||||
#define TCF_FUN_USES_ARGUMENTS 0x100 /* function uses arguments except as a
|
||||
parameter name */
|
||||
#define TCF_FUN_HEAVYWEIGHT 0x200 /* function needs Call object per call */
|
||||
|
@ -789,7 +789,7 @@ DefineCompileTimeConstant(JSContext *cx, BytecodeEmitter *bce, JSAtom *atom, Par
|
|||
* found. Otherwise return null.
|
||||
*/
|
||||
StmtInfo *
|
||||
LexicalLookup(TreeContext *tc, JSAtom *atom, jsint *slotp, StmtInfo *stmt = NULL);
|
||||
LexicalLookup(TreeContext *tc, JSAtom *atom, int *slotp, StmtInfo *stmt = NULL);
|
||||
|
||||
/*
|
||||
* Emit code into bce for the tree rooted at pn.
|
||||
|
|
|
@ -6080,6 +6080,9 @@ Parser::qualifiedSuffix(ParseNode *pn)
|
|||
if (!pn2)
|
||||
return NULL;
|
||||
|
||||
/* This qualifiedSuffice may refer to 'arguments'. */
|
||||
tc->flags |= (TCF_FUN_HEAVYWEIGHT | TCF_FUN_LOCAL_ARGUMENTS);
|
||||
|
||||
/* Left operand of :: must be evaluated if it is an identifier. */
|
||||
if (pn->isOp(JSOP_QNAMEPART))
|
||||
pn->setOp(JSOP_NAME);
|
||||
|
@ -6124,7 +6127,7 @@ Parser::qualifiedIdentifier()
|
|||
return NULL;
|
||||
if (tokenStream.matchToken(TOK_DBLCOLON)) {
|
||||
/* Hack for bug 496316. Slowing down E4X won't make it go away, alas. */
|
||||
tc->flags |= TCF_FUN_HEAVYWEIGHT;
|
||||
tc->flags |= (TCF_FUN_HEAVYWEIGHT | TCF_FUN_LOCAL_ARGUMENTS);
|
||||
pn = qualifiedSuffix(pn);
|
||||
}
|
||||
return pn;
|
||||
|
@ -6639,7 +6642,7 @@ Parser::propertyQualifiedIdentifier()
|
|||
JS_ASSERT(tokenStream.peekToken() == TOK_DBLCOLON);
|
||||
|
||||
/* Deoptimize QualifiedIdentifier properties to avoid tricky analysis. */
|
||||
tc->flags |= TCF_FUN_HEAVYWEIGHT;
|
||||
tc->flags |= (TCF_FUN_HEAVYWEIGHT | TCF_FUN_LOCAL_ARGUMENTS);
|
||||
|
||||
PropertyName *name = tokenStream.currentToken().name();
|
||||
ParseNode *node = NameNode::create(PNK_NAME, name, tc);
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
function g(s) {
|
||||
return eval(s)
|
||||
}
|
||||
f = g("(function(){({x:function::arguments})})")
|
||||
f()
|
|
@ -0,0 +1,5 @@
|
|||
function h(s) {
|
||||
return eval(s)
|
||||
}
|
||||
f = h("(function(){function::arguments=[]})")
|
||||
for (a in f()) {}
|
|
@ -0,0 +1,29 @@
|
|||
// When multiple frames have onPop handlers, they are called in the correct order.
|
||||
var g = newGlobal('new-compartment');
|
||||
g.eval("function f() { debugger; }");
|
||||
g.eval("function g() { f(); }");
|
||||
g.eval("function h() { g(); }");
|
||||
g.eval("function i() { h(); }");
|
||||
|
||||
var dbg = new Debugger(g);
|
||||
var log;
|
||||
function logger(frame, mark) {
|
||||
return function (completion) {
|
||||
assertEq(this, frame);
|
||||
assertEq('return' in completion, true);
|
||||
log += mark;
|
||||
};
|
||||
}
|
||||
dbg.onEnterFrame = function handleEnter(f) {
|
||||
log += "(" + f.callee.name;
|
||||
// Note that this establishes a distinct function object as each
|
||||
// frame's onPop handler. Thus, a pass proves that each frame is
|
||||
// remembering its handler separately.
|
||||
f.onPop = logger(f, f.callee.name + ")");
|
||||
};
|
||||
dbg.onDebuggerStatement = function handleDebugger(f) {
|
||||
log += 'd';
|
||||
};
|
||||
log = '';
|
||||
g.i();
|
||||
assertEq(log, "(i(h(g(fdf)g)h)i)");
|
|
@ -0,0 +1,20 @@
|
|||
// Clearing a frame's onPop handler works.
|
||||
var g = newGlobal('new-compartment');
|
||||
g.eval("function f() { debugger; }");
|
||||
var dbg = new Debugger(g);
|
||||
|
||||
var log;
|
||||
dbg.onEnterFrame = function handleEnter(f) {
|
||||
log += "(";
|
||||
f.onPop = function handlePop() {
|
||||
assertEq("handlePop was called", "handlePop should never be called");
|
||||
};
|
||||
};
|
||||
dbg.onDebuggerStatement = function handleDebugger(f) {
|
||||
log += "d";
|
||||
assertEq(typeof f.onPop, "function");
|
||||
f.onPop = undefined;
|
||||
};
|
||||
log = '';
|
||||
g.f();
|
||||
assertEq(log, "(d");
|
|
@ -0,0 +1,32 @@
|
|||
// When an exception is propagated out of multiple frames, their onPop
|
||||
// and onExceptionUnwind handlers are called in the correct order.
|
||||
var g = newGlobal('new-compartment');
|
||||
g.eval("function f() { throw 'mud'; }");
|
||||
g.eval("function g() { f(); }");
|
||||
g.eval("function h() { g(); }");
|
||||
g.eval("function i() { h(); }");
|
||||
|
||||
var dbg = new Debugger(g);
|
||||
var log;
|
||||
function makePopHandler(label) {
|
||||
return function handlePop(completion) {
|
||||
log += label;
|
||||
assertEq(completion.throw, "mud");
|
||||
};
|
||||
}
|
||||
dbg.onEnterFrame = function handleEnter(f) {
|
||||
log += "(" + f.callee.name;
|
||||
f.onPop = makePopHandler(")" + f.callee.name);
|
||||
};
|
||||
dbg.onExceptionUnwind = function handleExceptionUnwind(f, x) {
|
||||
assertEq(x, 'mud');
|
||||
log += "u" + f.callee.name;
|
||||
};
|
||||
log = '';
|
||||
try {
|
||||
g.i();
|
||||
} catch (x) {
|
||||
log += 'c';
|
||||
assertEq(x, "mud");
|
||||
}
|
||||
assertEq(log, "(i(h(g(fuf)fug)guh)hui)ic");
|
|
@ -0,0 +1,30 @@
|
|||
// When a termination is propagated out of multiple frames, their onPop
|
||||
// handlers are called in the correct order, and no onExceptionUnwind
|
||||
// handlers are called.
|
||||
var g = newGlobal('new-compartment');
|
||||
g.eval("function f() { terminate(); }");
|
||||
g.eval("function g() { f(); }");
|
||||
g.eval("function h() { g(); }");
|
||||
g.eval("function i() { h(); }");
|
||||
|
||||
var dbg = new Debugger(g);
|
||||
var log;
|
||||
var count = 0;
|
||||
function makePopHandler(label, resumption) {
|
||||
return function handlePop(completion) {
|
||||
log += label;
|
||||
assertEq(completion, null);
|
||||
return resumption;
|
||||
};
|
||||
}
|
||||
dbg.onEnterFrame = function handleEnter(f) {
|
||||
log += "(" + f.callee.name;
|
||||
f.onPop = makePopHandler(f.callee.name + ")",
|
||||
count++ == 0 ? { return: 'king' } : undefined);
|
||||
};
|
||||
dbg.onExceptionUnwind = function handleExceptionUnwind(f, x) {
|
||||
log += 'u';
|
||||
};
|
||||
log = '';
|
||||
assertEq(g.i(), 'king');
|
||||
assertEq(log, "(i(h(g(ff)g)h)i)");
|
|
@ -0,0 +1,25 @@
|
|||
var g = newGlobal('new-compartment');
|
||||
var dbg = new Debugger(g);
|
||||
g.debuggerGlobal = this;
|
||||
var log;
|
||||
|
||||
dbg.onEnterFrame = function handleEnter(f) {
|
||||
log += '(';
|
||||
f.onPop = function handlePop(c) {
|
||||
log += ')';
|
||||
assertEq(c.throw, "election");
|
||||
};
|
||||
};
|
||||
dbg.onExceptionUnwind = function handleExceptionUnwind(f, x) {
|
||||
log += 'u';
|
||||
assertEq(x, "election");
|
||||
};
|
||||
|
||||
log = '';
|
||||
try {
|
||||
g.eval("try { throw 'election'; } finally { debuggerGlobal.log += 'f'; }");
|
||||
} catch (x) {
|
||||
log += 'c';
|
||||
assertEq(x, 'election');
|
||||
}
|
||||
assertEq(log, '(ufu)c');
|
|
@ -0,0 +1,19 @@
|
|||
// dbg.getNewestFrame in an onPop handler returns the frame being popped.
|
||||
var g = newGlobal('new-compartment');
|
||||
g.eval("function f() { debugger; }");
|
||||
g.eval("function g() { f(); }");
|
||||
g.eval("function h() { g(); }");
|
||||
g.eval("function i() { h(); }");
|
||||
|
||||
var dbg = new Debugger(g);
|
||||
var log;
|
||||
dbg.onEnterFrame = function handleEnter(f) {
|
||||
log += "(" + f.callee.name;
|
||||
f.onPop = function handlePop(c) {
|
||||
log += ")" + f.callee.name;
|
||||
assertEq(dbg.getNewestFrame(), this);
|
||||
};
|
||||
};
|
||||
log = '';
|
||||
g.i();
|
||||
assertEq(log, "(i(h(g(f)f)g)h)i");
|
|
@ -0,0 +1,30 @@
|
|||
// Trying to set an onPop handler on a dead frame throws an exception.
|
||||
var g = newGlobal('new-compartment');
|
||||
g.eval("function f() { }");
|
||||
g.eval("function g() { f(); }");
|
||||
g.eval("function h() { g(); }");
|
||||
g.eval("function i() { h(); }");
|
||||
var dbg = new Debugger(g);
|
||||
var log;
|
||||
|
||||
var frames = [];
|
||||
dbg.onEnterFrame = function handleEnter(f) {
|
||||
log += "(";
|
||||
assertEq(f.live, true);
|
||||
frames.push(f);
|
||||
};
|
||||
log = '';
|
||||
g.i();
|
||||
assertEq(log, "((((");
|
||||
assertEq(frames.length, 4);
|
||||
for (i = 0; i < frames.length; i++) {
|
||||
assertEq(frames[i].live, false);
|
||||
var set = false;
|
||||
try {
|
||||
frames[i].onPop = function unappreciated() { };
|
||||
set = true; // don't assert in a 'try' block
|
||||
} catch (x) {
|
||||
assertEq(x instanceof Error, true);
|
||||
}
|
||||
assertEq(set, false);
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
// Setting onPop handlers from a 'debugger' statement handler works.
|
||||
var g = newGlobal('new-compartment');
|
||||
var dbg = new Debugger(g);
|
||||
var log;
|
||||
|
||||
dbg.onDebuggerStatement = function handleDebugger(frame) {
|
||||
assertEq(frame.type, "eval");
|
||||
log += 'd';
|
||||
frame.onPop = function handlePop(c) {
|
||||
log += ')';
|
||||
};
|
||||
};
|
||||
|
||||
log = '';
|
||||
g.eval('debugger;');
|
||||
assertEq(log, 'd)');
|
|
@ -0,0 +1,23 @@
|
|||
// Setting onPop handlers from an onExceptionUnwind handler works.
|
||||
var g = newGlobal('new-compartment');
|
||||
var dbg = new Debugger(g);
|
||||
var log;
|
||||
|
||||
dbg.onExceptionUnwind = function handleUnwind(frame) {
|
||||
log += 'u';
|
||||
assertEq(frame.type, "eval");
|
||||
frame.onPop = function handleCallPop(c) {
|
||||
log += ')';
|
||||
assertEq(c.throw, 'up');
|
||||
};
|
||||
};
|
||||
|
||||
log = "";
|
||||
try {
|
||||
g.eval("throw 'up';");
|
||||
log += '-';
|
||||
} catch (x) {
|
||||
log += 'c';
|
||||
assertEq(x, 'up');
|
||||
}
|
||||
assertEq(log, 'u)c');
|
|
@ -0,0 +1,22 @@
|
|||
// Setting onPop handlers from an onStep handler works.
|
||||
var g = newGlobal('new-compartment');
|
||||
var dbg = new Debugger(g);
|
||||
var log;
|
||||
|
||||
dbg.onDebuggerStatement = function handleDebugger(frame) {
|
||||
log += 'd';
|
||||
assertEq(frame.type, "eval");
|
||||
frame.onStep = function handleStep() {
|
||||
log += 's';
|
||||
this.onStep = undefined;
|
||||
this.onPop = function handlePop() {
|
||||
log += ')';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
log = "";
|
||||
g.flag = false;
|
||||
g.eval('debugger; flag = true');
|
||||
assertEq(log, 'ds)');
|
||||
assertEq(g.flag, true);
|
|
@ -0,0 +1,22 @@
|
|||
// Setting onPop handlers from breakpoint handlers works.
|
||||
var g = newGlobal('new-compartment');
|
||||
g.eval("function f(){ return 'to normalcy'; }");
|
||||
var dbg = new Debugger(g);
|
||||
var log;
|
||||
|
||||
// Set a breakpoint at the start of g.f
|
||||
var gf = dbg.addDebuggee(g.f); // addDebuggee used as Debugger.Object factory
|
||||
var fStartOffset = gf.script.getLineOffsets(gf.script.startLine)[0];
|
||||
gf.script.setBreakpoint(fStartOffset, {
|
||||
hit: function handleHit(frame) {
|
||||
log += 'b';
|
||||
frame.onPop = function handlePop(c) {
|
||||
log += ')';
|
||||
assertEq(c.return, "to normalcy");
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
log = "";
|
||||
assertEq(g.f(), "to normalcy");
|
||||
assertEq(log, "b)");
|
|
@ -0,0 +1,21 @@
|
|||
// Setting an onPop handler from an onPop handler doesn't throw, but the
|
||||
// new handler doesn't fire.
|
||||
var g = newGlobal('new-compartment');
|
||||
var dbg = new Debugger(g);
|
||||
var log;
|
||||
|
||||
dbg.onDebuggerStatement = function handleDebugger(frame) {
|
||||
log += 'd';
|
||||
assertEq(frame.type, "eval");
|
||||
frame.onPop = function firstHandlePop(c) {
|
||||
log +=')';
|
||||
assertEq(c.return, 'on investment');
|
||||
this.onPop = function secondHandlePop(c) {
|
||||
assertEq("secondHandlePop was called", "secondHandlePop should never be called");
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
log = "";
|
||||
g.eval("debugger; 'on investment';");
|
||||
assertEq(log, 'd)');
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче