mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
merge mozilla-inbound to mozilla-central
This commit is contained in:
commit
61cb55cfb0
2
CLOBBER
2
CLOBBER
@ -22,4 +22,4 @@
|
||||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 994964 apparently requires a clobber, unclear why
|
||||
Bug 999651 et al. apparently require a clobber, unclear why
|
||||
|
@ -429,6 +429,9 @@ HyperTextAccessible::FindOffset(uint32_t aOffset, nsDirection aDirection,
|
||||
nsSelectionAmount aAmount,
|
||||
EWordMovementType aWordMovementType)
|
||||
{
|
||||
NS_ASSERTION(aDirection == eDirPrevious || aAmount != eSelectBeginLine,
|
||||
"eSelectBeginLine should only be used with eDirPrevious");
|
||||
|
||||
// Find a leaf accessible frame to start with. PeekOffset wants this.
|
||||
HyperTextAccessible* text = this;
|
||||
Accessible* child = nullptr;
|
||||
@ -447,22 +450,32 @@ HyperTextAccessible::FindOffset(uint32_t aOffset, nsDirection aDirection,
|
||||
if (text->IsHTMLListItem()) {
|
||||
HTMLLIAccessible* li = text->AsHTMLListItem();
|
||||
if (child == li->Bullet()) {
|
||||
// It works only when the bullet is one single char.
|
||||
if (aDirection == eDirPrevious)
|
||||
return text != this ? TransformOffset(text, 0, false) : 0;
|
||||
|
||||
if (aAmount == eSelectEndLine || aAmount == eSelectLine) {
|
||||
if (text != this)
|
||||
return TransformOffset(text, 1, true);
|
||||
|
||||
// Ask a text leaf next (if not empty) to the bullet for an offset
|
||||
// since list item may be multiline.
|
||||
return aOffset + 1 < CharacterCount() ?
|
||||
FindOffset(aOffset + 1, aDirection, aAmount, aWordMovementType) : 1;
|
||||
// XXX: the logic is broken for multichar bullets in moving by
|
||||
// char/cluster/word cases.
|
||||
if (text != this) {
|
||||
return aDirection == eDirPrevious ?
|
||||
TransformOffset(text, 0, false) :
|
||||
TransformOffset(text, 1, true);
|
||||
}
|
||||
if (aDirection == eDirPrevious)
|
||||
return 0;
|
||||
|
||||
// Case of word and char boundaries.
|
||||
return text != this ? TransformOffset(text, 1, true) : 1;
|
||||
uint32_t nextOffset = GetChildOffset(1);
|
||||
if (nextOffset == 0)
|
||||
return 0;
|
||||
|
||||
switch (aAmount) {
|
||||
case eSelectLine:
|
||||
case eSelectEndLine:
|
||||
// Ask a text leaf next (if not empty) to the bullet for an offset
|
||||
// since list item may be multiline.
|
||||
return nextOffset < CharacterCount() ?
|
||||
FindOffset(nextOffset, aDirection, aAmount, aWordMovementType) :
|
||||
nextOffset;
|
||||
|
||||
default:
|
||||
return nextOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -521,8 +534,12 @@ HyperTextAccessible::FindOffset(uint32_t aOffset, nsDirection aDirection,
|
||||
return 0;
|
||||
|
||||
// PeekOffset stops right before bullet so return 0 to workaround it.
|
||||
if (IsHTMLListItem() && aAmount == eSelectBeginLine && hyperTextOffset == 1)
|
||||
return 0;
|
||||
if (IsHTMLListItem() && aAmount == eSelectBeginLine &&
|
||||
hyperTextOffset > 0) {
|
||||
Accessible* prevOffsetChild = GetChildAtOffset(hyperTextOffset - 1);
|
||||
if (prevOffsetChild == AsHTMLListItem()->Bullet())
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return hyperTextOffset;
|
||||
|
@ -126,11 +126,34 @@
|
||||
[ 8, 11, "and ", 8, 12 ] ]);
|
||||
testTextAtOffset([ "li4" ], BOUNDARY_LINE_START,
|
||||
[ [ 0, 6, kDiscBulletChar + "a " + kEmbedChar + " c", 0, 6 ] ]);
|
||||
testTextAtOffset([ "li5" ], BOUNDARY_LINE_START,
|
||||
[ [ 0, 1, kDiscBulletChar + "\n", 0, 2 ],
|
||||
[ 2, 6, "hello", 2, 7 ] ]);
|
||||
testTextAtOffset([ "ul1" ], BOUNDARY_LINE_START,
|
||||
[ [ 0, 0, kEmbedChar, 0, 1 ],
|
||||
[ 1, 1, kEmbedChar, 1, 2 ],
|
||||
[ 2, 2, kEmbedChar, 2, 3 ],
|
||||
[ 3, 4, kEmbedChar, 3, 4 ] ]);
|
||||
[ 3, 3, kEmbedChar, 3, 4 ],
|
||||
[ 4, 5, kEmbedChar, 4, 5 ] ]);
|
||||
|
||||
testTextAtOffset([ "li6" ], BOUNDARY_LINE_START,
|
||||
[ [ 0, 6, "1.Item", 0, 6 ] ]);
|
||||
testTextAtOffset([ "li7" ], BOUNDARY_LINE_START,
|
||||
[ [ 0, 2, "2.", 0, 2 ] ]);
|
||||
testTextAtOffset([ "li8" ], BOUNDARY_LINE_START,
|
||||
[ [ 0, 8, "3.a long ", 0, 9 ],
|
||||
[ 9, 12, "and ", 9, 13 ] ]);
|
||||
testTextAtOffset([ "li9" ], BOUNDARY_LINE_START,
|
||||
[ [ 0, 7, "4.a " + kEmbedChar + " c", 0, 7 ] ]);
|
||||
testTextAtOffset([ "li10" ], BOUNDARY_LINE_START,
|
||||
[ [ 0, 2, "5.\n", 0, 3 ],
|
||||
[ 3, 7, "hello", 3, 8 ] ]);
|
||||
testTextAtOffset([ "ol1" ], BOUNDARY_LINE_START,
|
||||
[ [ 0, 0, kEmbedChar, 0, 1 ],
|
||||
[ 1, 1, kEmbedChar, 1, 2 ],
|
||||
[ 2, 2, kEmbedChar, 2, 3 ],
|
||||
[ 3, 3, kEmbedChar, 3, 4 ],
|
||||
[ 4, 5, kEmbedChar, 4, 5 ] ]);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Nested hypertexts
|
||||
@ -210,8 +233,17 @@ two words
|
||||
<li id="li2"></li>
|
||||
<li id="li3" style="width:10ex; font-family:monospace; font-size:10pt;">a long and winding road that lead me to your door</li>
|
||||
<li id="li4">a <a href=''>b</a> c</li>
|
||||
<li id="li5"><br>hello</li>
|
||||
</ul>
|
||||
|
||||
<ol id="ol1">
|
||||
<li id="li6">Item</li>
|
||||
<li id="li7"></li>
|
||||
<li id="li8" style="width:10ex; font-family:monospace; font-size:10pt;">a long and winding road that lead me to your door</li>
|
||||
<li id="li9">a <a href=''>b</a> c</li>
|
||||
<li id="li10"><br>hello</li>
|
||||
</ol>
|
||||
|
||||
<div id="ht_5">
|
||||
<div>
|
||||
<p>sectiounus</p>
|
||||
|
@ -784,7 +784,8 @@ var gBrowserInit = {
|
||||
gPageStyleMenu.init();
|
||||
LanguageDetectionListener.init();
|
||||
|
||||
messageManager.loadFrameScript("chrome://browser/content/content.js", true);
|
||||
let mm = window.getGroupMessageManager("browsers");
|
||||
mm.loadFrameScript("chrome://browser/content/content.js", true);
|
||||
|
||||
// initialize observers and listeners
|
||||
// and give C++ access to gBrowser
|
||||
|
@ -34,7 +34,7 @@
|
||||
<xul:hbox flex="1" class="browserSidebarContainer">
|
||||
<xul:vbox flex="1" class="browserContainer">
|
||||
<xul:stack flex="1" class="browserStack" anonid="browserStack">
|
||||
<xul:browser anonid="initialBrowser" type="content-primary" message="true"
|
||||
<xul:browser anonid="initialBrowser" type="content-primary" message="true" messagemanagergroup="browsers"
|
||||
xbl:inherits="tooltip=contenttooltip,contextmenu=contentcontextmenu,autocompletepopup,selectpopup"/>
|
||||
</xul:stack>
|
||||
</xul:vbox>
|
||||
@ -1529,6 +1529,7 @@
|
||||
"browser");
|
||||
b.setAttribute("type", "content-targetable");
|
||||
b.setAttribute("message", "true");
|
||||
b.setAttribute("messagemanagergroup", "browsers");
|
||||
b.setAttribute("contextmenu", this.getAttribute("contentcontextmenu"));
|
||||
b.setAttribute("tooltip", this.getAttribute("contenttooltip"));
|
||||
|
||||
|
@ -764,7 +764,7 @@ let SessionStoreInternal = {
|
||||
// internal data about the window.
|
||||
aWindow.__SSi = this._generateWindowID();
|
||||
|
||||
let mm = aWindow.messageManager;
|
||||
let mm = aWindow.getGroupMessageManager("browsers");
|
||||
MESSAGES.forEach(msg => mm.addMessageListener(msg, this));
|
||||
|
||||
// Load the frame script after registering listeners.
|
||||
@ -1093,7 +1093,7 @@ let SessionStoreInternal = {
|
||||
// Cache the window state until it is completely gone.
|
||||
DyingWindowCache.set(aWindow, winData);
|
||||
|
||||
let mm = aWindow.messageManager;
|
||||
let mm = aWindow.getGroupMessageManager("browsers");
|
||||
MESSAGES.forEach(msg => mm.removeMessageListener(msg, this));
|
||||
|
||||
delete aWindow.__SSi;
|
||||
|
@ -76,7 +76,8 @@ add_task(function () {
|
||||
|
||||
// Create a new window to attach our frame script to.
|
||||
let win = yield promiseNewWindowLoaded();
|
||||
win.messageManager.loadFrameScript(FRAME_SCRIPT, true);
|
||||
let mm = win.getGroupMessageManager("browsers");
|
||||
mm.loadFrameScript(FRAME_SCRIPT, true);
|
||||
|
||||
// Create a new tab in the new window that will load the frame script.
|
||||
let tab = win.gBrowser.addTab("about:mozilla");
|
||||
|
@ -174,7 +174,7 @@ let UI = {
|
||||
});
|
||||
|
||||
// ___ setup DOMWillOpenModalDialog message handler
|
||||
let mm = gWindow.messageManager;
|
||||
let mm = gWindow.getGroupMessageManager("browsers");
|
||||
let callback = this._onDOMWillOpenModalDialog.bind(this);
|
||||
mm.addMessageListener("Panorama:DOMWillOpenModalDialog", callback);
|
||||
|
||||
@ -235,7 +235,7 @@ let UI = {
|
||||
|
||||
// ___ load frame script
|
||||
let frameScript = "chrome://browser/content/tabview-content.js";
|
||||
gWindow.messageManager.loadFrameScript(frameScript, true);
|
||||
mm.loadFrameScript(frameScript, true);
|
||||
|
||||
// ___ Done
|
||||
this._frameInitialized = true;
|
||||
|
@ -866,5 +866,7 @@ bin/libfreebl_32int64_3.so
|
||||
|
||||
|
||||
#ifdef MOZ_ASAN
|
||||
#ifdef CLANG_CXX
|
||||
@BINPATH@/llvm-symbolizer
|
||||
#endif
|
||||
#endif
|
||||
|
@ -320,9 +320,9 @@ HiddenBrowser.prototype = {
|
||||
// Swap docShells.
|
||||
tabbrowser.swapNewTabWithBrowser(aTab, this._browser);
|
||||
|
||||
// Load all default frame scripts attached to the target window.
|
||||
// Load all delayed frame scripts attached to the "browers" message manager.
|
||||
let mm = aTab.linkedBrowser.messageManager;
|
||||
let scripts = win.messageManager.getDelayedFrameScripts();
|
||||
let scripts = win.getGroupMessageManager("browsers").getDelayedFrameScripts();
|
||||
Array.forEach(scripts, ([script, runGlobal]) => mm.loadFrameScript(script, true, runGlobal));
|
||||
|
||||
// Remove the browser, it will be recreated by a timer.
|
||||
|
@ -64,7 +64,7 @@ case "$target" in
|
||||
|
||||
kernel_name=`uname -s | tr "[[:upper:]]" "[[:lower:]]"`
|
||||
|
||||
for version in $android_gnu_compiler_version 4.7 4.6 4.4.3 ; do
|
||||
for version in $android_gnu_compiler_version 4.8 4.7 4.6 4.4.3; do
|
||||
case "$target_cpu" in
|
||||
arm)
|
||||
target_name=arm-linux-androideabi-$version
|
||||
|
@ -39,6 +39,8 @@ interface nsIPrincipal;
|
||||
* - "frame message managers" which correspond to frame elements
|
||||
* - "window message managers" which correspond to top-level chrome
|
||||
* windows
|
||||
* - "group message managers" which correspond to named message
|
||||
* managers with a specific window MM as the parent
|
||||
* - the "global message manager", on the parent side. See below.
|
||||
*
|
||||
* The DOM-realm message managers can communicate in the ways shown by
|
||||
@ -54,6 +56,16 @@ interface nsIPrincipal;
|
||||
* | +-->frame MMp1_1<------------>frame MMc1_1
|
||||
* | |
|
||||
* | +-->frame MMp1_2<------------>frame MMc1_2
|
||||
* | |
|
||||
* | +-->group MMgr1
|
||||
* | | |
|
||||
* | | +-->frame MMp2_1<------->frame MMc2_1
|
||||
* | | |
|
||||
* | | +-->frame MMp2_2<------->frame MMc2_2
|
||||
* | |
|
||||
* | +-->group MMgr2
|
||||
* | | ...
|
||||
* | |
|
||||
* | ...
|
||||
* |
|
||||
* +-->window MMw2
|
||||
@ -64,17 +76,23 @@ interface nsIPrincipal;
|
||||
* message managers in the hierarchy above MMp1_1, in this diagram
|
||||
* MMw1 and MMg, will also notify their message listeners when the
|
||||
* message arrives.
|
||||
*
|
||||
* A message sent from MMc2_1 will be sent to MMp2_1 and also notify
|
||||
* all message managers in the hierarchy above that, including the
|
||||
* group message manager MMgr1.
|
||||
|
||||
* For example: a message broadcast through the global MMg on the
|
||||
* parent side would be broadcast to MMw1, which would transitively
|
||||
* broadcast it to MMp1_1, MM1p_2". The message would next be
|
||||
* broadcast to MMw2, and so on down the hierarchy.
|
||||
* broadcast it to MMp1_1, MM1p_2. The message would next be
|
||||
* broadcast to MMgr1, which would broadcast it to MMp2_1 and MMp2_2.
|
||||
* After that it would broadcast to MMgr2 and then to MMw2, and so
|
||||
* on down the hierarchy.
|
||||
*
|
||||
* ***** PERFORMANCE AND SECURITY WARNING *****
|
||||
* Messages broadcast through the global MM and window MMs can result
|
||||
* in messages being dispatched across many OS processes, and to many
|
||||
* processes with different permissions. Great care should be taken
|
||||
* when broadcasting.
|
||||
* Messages broadcast through the global MM and window or group MMs
|
||||
* can result in messages being dispatched across many OS processes,
|
||||
* and to many processes with different permissions. Great care
|
||||
* should be taken when broadcasting.
|
||||
*
|
||||
* Interfaces
|
||||
* ----------
|
||||
|
@ -143,6 +143,8 @@ already_AddRefed<nsIDocument>
|
||||
DOMParser::ParseFromBuffer(const Uint8Array& aBuf, uint32_t aBufLen,
|
||||
SupportedType aType, ErrorResult& rv)
|
||||
{
|
||||
aBuf.ComputeLengthAndData();
|
||||
|
||||
if (aBufLen > aBuf.Length()) {
|
||||
rv.Throw(NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY);
|
||||
return nullptr;
|
||||
|
@ -1212,7 +1212,10 @@ WebSocket::Send(const ArrayBuffer& aData,
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||
|
||||
MOZ_ASSERT(sizeof(*aData.Data()) == 1);
|
||||
aData.ComputeLengthAndData();
|
||||
|
||||
static_assert(sizeof(*aData.Data()) == 1, "byte-sized data required");
|
||||
|
||||
uint32_t len = aData.Length();
|
||||
char* data = reinterpret_cast<char*>(aData.Data());
|
||||
|
||||
@ -1226,7 +1229,10 @@ WebSocket::Send(const ArrayBufferView& aData,
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||
|
||||
MOZ_ASSERT(sizeof(*aData.Data()) == 1);
|
||||
aData.ComputeLengthAndData();
|
||||
|
||||
static_assert(sizeof(*aData.Data()) == 1, "byte-sized data required");
|
||||
|
||||
uint32_t len = aData.Length();
|
||||
char* data = reinterpret_cast<char*>(aData.Data());
|
||||
|
||||
|
@ -303,7 +303,10 @@ nsDOMDataChannel::Send(const ArrayBuffer& aData, ErrorResult& aRv)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||
|
||||
MOZ_ASSERT(sizeof(*aData.Data()) == 1);
|
||||
aData.ComputeLengthAndData();
|
||||
|
||||
static_assert(sizeof(*aData.Data()) == 1, "byte-sized data required");
|
||||
|
||||
uint32_t len = aData.Length();
|
||||
char* data = reinterpret_cast<char*>(aData.Data());
|
||||
|
||||
@ -316,7 +319,10 @@ nsDOMDataChannel::Send(const ArrayBufferView& aData, ErrorResult& aRv)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||
|
||||
MOZ_ASSERT(sizeof(*aData.Data()) == 1);
|
||||
aData.ComputeLengthAndData();
|
||||
|
||||
static_assert(sizeof(*aData.Data()) == 1, "byte-sized data required");
|
||||
|
||||
uint32_t len = aData.Length();
|
||||
char* data = reinterpret_cast<char*>(aData.Data());
|
||||
|
||||
|
@ -2529,6 +2529,7 @@ GetRequestBody(nsIVariant* aBody, nsIInputStream** aResult, uint64_t* aContentLe
|
||||
JS::Rooted<JSObject*> obj(cx, realVal.toObjectOrNull());
|
||||
if (JS_IsArrayBufferObject(obj)) {
|
||||
ArrayBuffer buf(obj);
|
||||
buf.ComputeLengthAndData();
|
||||
return GetRequestBody(buf.Data(), buf.Length(), aResult,
|
||||
aContentLength, aContentType, aCharset);
|
||||
}
|
||||
@ -2572,14 +2573,16 @@ nsXMLHttpRequest::GetRequestBody(nsIVariant* aVariant,
|
||||
switch (body.GetType()) {
|
||||
case nsXMLHttpRequest::RequestBody::ArrayBuffer:
|
||||
{
|
||||
return ::GetRequestBody(value.mArrayBuffer->Data(),
|
||||
value.mArrayBuffer->Length(), aResult,
|
||||
const ArrayBuffer* buffer = value.mArrayBuffer;
|
||||
buffer->ComputeLengthAndData();
|
||||
return ::GetRequestBody(buffer->Data(), buffer->Length(), aResult,
|
||||
aContentLength, aContentType, aCharset);
|
||||
}
|
||||
case nsXMLHttpRequest::RequestBody::ArrayBufferView:
|
||||
{
|
||||
return ::GetRequestBody(value.mArrayBufferView->Data(),
|
||||
value.mArrayBufferView->Length(), aResult,
|
||||
const ArrayBufferView* view = value.mArrayBufferView;
|
||||
view->ComputeLengthAndData();
|
||||
return ::GetRequestBody(view->Data(), view->Length(), aResult,
|
||||
aContentLength, aContentType, aCharset);
|
||||
}
|
||||
case nsXMLHttpRequest::RequestBody::Blob:
|
||||
@ -3583,15 +3586,11 @@ nsXMLHttpRequest::OnProgress(nsIRequest *aRequest, nsISupports *aContext, uint64
|
||||
// So, try to remove the headers, if possible.
|
||||
bool lengthComputable = (aProgressMax != UINT64_MAX);
|
||||
if (upload) {
|
||||
uint64_t loaded = aProgress;
|
||||
uint64_t total = aProgressMax;
|
||||
mUploadTransferred = aProgress;
|
||||
if (lengthComputable) {
|
||||
uint64_t headerSize = aProgressMax - mUploadTotal;
|
||||
loaded -= headerSize;
|
||||
total -= headerSize;
|
||||
mUploadTransferred = aProgressMax - mUploadTotal;
|
||||
}
|
||||
mUploadLengthComputable = lengthComputable;
|
||||
mUploadTransferred = loaded;
|
||||
mProgressSinceLastProgressEvent = true;
|
||||
|
||||
MaybeDispatchProgressEvents(false);
|
||||
|
@ -4010,7 +4010,7 @@ CanvasRenderingContext2D::PutImageData(ImageData& imageData, double dx,
|
||||
|
||||
error = PutImageData_explicit(JS_DoubleToInt32(dx), JS_DoubleToInt32(dy),
|
||||
imageData.Width(), imageData.Height(),
|
||||
arr.Data(), arr.Length(), false, 0, 0, 0, 0);
|
||||
&arr, false, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void
|
||||
@ -4024,7 +4024,7 @@ CanvasRenderingContext2D::PutImageData(ImageData& imageData, double dx,
|
||||
|
||||
error = PutImageData_explicit(JS_DoubleToInt32(dx), JS_DoubleToInt32(dy),
|
||||
imageData.Width(), imageData.Height(),
|
||||
arr.Data(), arr.Length(), true,
|
||||
&arr, true,
|
||||
JS_DoubleToInt32(dirtyX),
|
||||
JS_DoubleToInt32(dirtyY),
|
||||
JS_DoubleToInt32(dirtyWidth),
|
||||
@ -4036,7 +4036,7 @@ CanvasRenderingContext2D::PutImageData(ImageData& imageData, double dx,
|
||||
|
||||
nsresult
|
||||
CanvasRenderingContext2D::PutImageData_explicit(int32_t x, int32_t y, uint32_t w, uint32_t h,
|
||||
unsigned char *aData, uint32_t aDataLen,
|
||||
dom::Uint8ClampedArray* aArray,
|
||||
bool hasDirtyRect, int32_t dirtyX, int32_t dirtyY,
|
||||
int32_t dirtyWidth, int32_t dirtyHeight)
|
||||
{
|
||||
@ -4089,8 +4089,12 @@ CanvasRenderingContext2D::PutImageData_explicit(int32_t x, int32_t y, uint32_t w
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
aArray->ComputeLengthAndData();
|
||||
|
||||
uint32_t dataLen = aArray->Length();
|
||||
|
||||
uint32_t len = w * h * 4;
|
||||
if (aDataLen != len) {
|
||||
if (dataLen != len) {
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
|
||||
@ -4101,7 +4105,7 @@ CanvasRenderingContext2D::PutImageData_explicit(int32_t x, int32_t y, uint32_t w
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
uint8_t *src = aData;
|
||||
uint8_t *src = aArray->Data();
|
||||
uint8_t *dst = imgsurf->Data();
|
||||
|
||||
for (uint32_t j = 0; j < h; j++) {
|
||||
|
@ -551,7 +551,7 @@ protected:
|
||||
JSObject** aRetval);
|
||||
|
||||
nsresult PutImageData_explicit(int32_t x, int32_t y, uint32_t w, uint32_t h,
|
||||
unsigned char *aData, uint32_t aDataLen,
|
||||
dom::Uint8ClampedArray* aArray,
|
||||
bool hasDirtyRect, int32_t dirtyX, int32_t dirtyY,
|
||||
int32_t dirtyWidth, int32_t dirtyHeight);
|
||||
|
||||
|
@ -70,6 +70,8 @@ ImageData::Constructor(const GlobalObject& aGlobal,
|
||||
const Optional<uint32_t>& aHeight,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
aData.ComputeLengthAndData();
|
||||
|
||||
uint32_t length = aData.Length();
|
||||
if (length == 0 || length % 4) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
|
@ -83,18 +83,21 @@ WebGLMemoryPressureObserver::Observe(nsISupports* aSubject,
|
||||
|
||||
if (!mContext->mCanLoseContextInForeground &&
|
||||
ProcessPriorityManager::CurrentProcessIsForeground())
|
||||
{
|
||||
wantToLoseContext = false;
|
||||
else if (!nsCRT::strcmp(aSomeData,
|
||||
MOZ_UTF16("heap-minimize")))
|
||||
} else if (!nsCRT::strcmp(aSomeData,
|
||||
MOZ_UTF16("heap-minimize")))
|
||||
{
|
||||
wantToLoseContext = mContext->mLoseContextOnHeapMinimize;
|
||||
}
|
||||
|
||||
if (wantToLoseContext)
|
||||
if (wantToLoseContext) {
|
||||
mContext->ForceLoseContext();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
WebGLContextOptions::WebGLContextOptions()
|
||||
: alpha(true), depth(true), stencil(false),
|
||||
premultipliedAlpha(true), antialias(true),
|
||||
@ -168,12 +171,12 @@ WebGLContext::WebGLContext()
|
||||
|
||||
WebGLMemoryTracker::AddWebGLContext(this);
|
||||
|
||||
mAllowRestore = true;
|
||||
mAllowContextRestore = true;
|
||||
mLastLossWasSimulated = false;
|
||||
mContextLossTimerRunning = false;
|
||||
mDrawSinceContextLossTimerSet = false;
|
||||
mRunContextLossTimerAgain = false;
|
||||
mContextRestorer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
mContextStatus = ContextNotLost;
|
||||
mContextLostErrorSet = false;
|
||||
mLoseContextOnHeapMinimize = false;
|
||||
mCanLoseContextInForeground = true;
|
||||
|
||||
@ -571,11 +574,8 @@ WebGLContext::SetDimensions(int32_t width, int32_t height)
|
||||
mResetLayer = true;
|
||||
mOptionsFrozen = true;
|
||||
|
||||
mHasRobustness = gl->HasRobustness();
|
||||
|
||||
// increment the generation number
|
||||
++mGeneration;
|
||||
|
||||
#if 0
|
||||
if (mGeneration > 0) {
|
||||
// XXX dispatch context lost event
|
||||
@ -1110,6 +1110,96 @@ WebGLContext::DummyFramebufferOperation(const char *info)
|
||||
ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckContextLost(GLContext* gl, bool* out_isGuilty)
|
||||
{
|
||||
MOZ_ASSERT(gl);
|
||||
MOZ_ASSERT(out_isGuilty);
|
||||
|
||||
bool isEGL = gl->GetContextType() == gl::GLContextType::EGL;
|
||||
|
||||
GLenum resetStatus = LOCAL_GL_NO_ERROR;
|
||||
if (gl->HasRobustness()) {
|
||||
gl->MakeCurrent();
|
||||
resetStatus = gl->fGetGraphicsResetStatus();
|
||||
} else if (isEGL) {
|
||||
// Simulate a ARB_robustness guilty context loss for when we
|
||||
// get an EGL_CONTEXT_LOST error. It may not actually be guilty,
|
||||
// but we can't make any distinction.
|
||||
if (!gl->MakeCurrent(true) && gl->IsContextLost()) {
|
||||
resetStatus = LOCAL_GL_UNKNOWN_CONTEXT_RESET_ARB;
|
||||
}
|
||||
}
|
||||
|
||||
if (resetStatus == LOCAL_GL_NO_ERROR) {
|
||||
*out_isGuilty = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Assume guilty unless we find otherwise!
|
||||
bool isGuilty = true;
|
||||
switch (resetStatus) {
|
||||
case LOCAL_GL_INNOCENT_CONTEXT_RESET_ARB:
|
||||
// Either nothing wrong, or not our fault.
|
||||
isGuilty = false;
|
||||
break;
|
||||
case LOCAL_GL_GUILTY_CONTEXT_RESET_ARB:
|
||||
NS_WARNING("WebGL content on the page definitely caused the graphics"
|
||||
" card to reset.");
|
||||
break;
|
||||
case LOCAL_GL_UNKNOWN_CONTEXT_RESET_ARB:
|
||||
NS_WARNING("WebGL content on the page might have caused the graphics"
|
||||
" card to reset");
|
||||
// If we can't tell, assume guilty.
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(false, "Unreachable.");
|
||||
// If we do get here, let's pretend to be guilty as an escape plan.
|
||||
break;
|
||||
}
|
||||
|
||||
if (isGuilty) {
|
||||
NS_WARNING("WebGL context on this page is considered guilty, and will"
|
||||
" not be restored.");
|
||||
}
|
||||
|
||||
*out_isGuilty = isGuilty;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::TryToRestoreContext()
|
||||
{
|
||||
if (NS_FAILED(SetDimensions(mWidth, mHeight)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
class UpdateContextLossStatusTask : public nsRunnable
|
||||
{
|
||||
WebGLContext* const mContext;
|
||||
|
||||
public:
|
||||
UpdateContextLossStatusTask(WebGLContext* context)
|
||||
: mContext(context)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
mContext->UpdateContextLossStatus();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
WebGLContext::EnqueueUpdateContextLossStatus()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> task = new UpdateContextLossStatusTask(this);
|
||||
NS_DispatchToCurrentThread(task);
|
||||
}
|
||||
|
||||
// We use this timer for many things. Here are the things that it is activated for:
|
||||
// 1) If a script is using the MOZ_WEBGL_lose_context extension.
|
||||
// 2) If we are using EGL and _NOT ANGLE_, we query periodically to see if the
|
||||
@ -1125,137 +1215,123 @@ WebGLContext::DummyFramebufferOperation(const char *info)
|
||||
// At a bare minimum, from context lost to context restores, it would take 3
|
||||
// full timer iterations: detection, webglcontextlost, webglcontextrestored.
|
||||
void
|
||||
WebGLContext::RobustnessTimerCallback(nsITimer* timer)
|
||||
WebGLContext::UpdateContextLossStatus()
|
||||
{
|
||||
TerminateContextLossTimer();
|
||||
|
||||
if (!mCanvasElement) {
|
||||
// the canvas is gone. That happens when the page was closed before we got
|
||||
// this timer event. In this case, there's nothing to do here, just don't crash.
|
||||
return;
|
||||
}
|
||||
if (mContextStatus == ContextNotLost) {
|
||||
// We don't know that we're lost, but we might be, so we need to
|
||||
// check. If we're guilty, don't allow restores, though.
|
||||
|
||||
bool isGuilty = true;
|
||||
bool isContextLost = CheckContextLost(gl, &isGuilty);
|
||||
|
||||
if (isContextLost) {
|
||||
if (isGuilty)
|
||||
mAllowContextRestore = false;
|
||||
|
||||
ForceLoseContext();
|
||||
}
|
||||
|
||||
// Fall through.
|
||||
}
|
||||
|
||||
// If the context has been lost and we're waiting for it to be restored, do
|
||||
// that now.
|
||||
if (mContextStatus == ContextLostAwaitingEvent) {
|
||||
bool defaultAction;
|
||||
// The context has been lost and we haven't yet triggered the
|
||||
// callback, so do that now.
|
||||
|
||||
bool useDefaultHandler;
|
||||
nsContentUtils::DispatchTrustedEvent(mCanvasElement->OwnerDoc(),
|
||||
static_cast<nsIDOMHTMLCanvasElement*>(mCanvasElement),
|
||||
NS_LITERAL_STRING("webglcontextlost"),
|
||||
true,
|
||||
true,
|
||||
&defaultAction);
|
||||
&useDefaultHandler);
|
||||
// We sent the callback, so we're just 'regular lost' now.
|
||||
mContextStatus = ContextLost;
|
||||
// If we're told to use the default handler, it means the script
|
||||
// didn't bother to handle the event. In this case, we shouldn't
|
||||
// auto-restore the context.
|
||||
if (useDefaultHandler)
|
||||
mAllowContextRestore = false;
|
||||
|
||||
// If the script didn't handle the event, we don't allow restores.
|
||||
if (defaultAction)
|
||||
mAllowRestore = false;
|
||||
// Fall through.
|
||||
}
|
||||
|
||||
// If the script handled the event and we are allowing restores, then
|
||||
// mark it to be restored. Otherwise, leave it as context lost
|
||||
// (unusable).
|
||||
if (!defaultAction && mAllowRestore) {
|
||||
ForceRestoreContext();
|
||||
// Restart the timer so that it will be restored on the next
|
||||
// callback.
|
||||
SetupContextLossTimer();
|
||||
} else {
|
||||
if (mContextStatus == ContextLost) {
|
||||
// Context is lost, and we've already sent the callback. We
|
||||
// should try to restore the context if we're both allowed to,
|
||||
// and supposed to.
|
||||
|
||||
// Are we allowed to restore the context?
|
||||
if (!mAllowContextRestore)
|
||||
return;
|
||||
|
||||
// If we're only simulated-lost, we shouldn't auto-restore, and
|
||||
// instead we should wait for restoreContext() to be called.
|
||||
if (mLastLossWasSimulated)
|
||||
return;
|
||||
|
||||
ForceRestoreContext();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mContextStatus == ContextLostAwaitingRestore) {
|
||||
// Context is lost, but we should try to restore it.
|
||||
|
||||
if (!mAllowContextRestore) {
|
||||
// We might decide this after thinking we'd be OK restoring
|
||||
// the context, so downgrade.
|
||||
mContextStatus = ContextLost;
|
||||
}
|
||||
} else if (mContextStatus == ContextLostAwaitingRestore) {
|
||||
// Try to restore the context. If it fails, try again later.
|
||||
if (NS_FAILED(SetDimensions(mWidth, mHeight))) {
|
||||
SetupContextLossTimer();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryToRestoreContext()) {
|
||||
// Failed to restore. Try again later.
|
||||
RunContextLossTimer();
|
||||
return;
|
||||
}
|
||||
|
||||
// Revival!
|
||||
mContextStatus = ContextNotLost;
|
||||
nsContentUtils::DispatchTrustedEvent(mCanvasElement->OwnerDoc(),
|
||||
static_cast<nsIDOMHTMLCanvasElement*>(mCanvasElement),
|
||||
NS_LITERAL_STRING("webglcontextrestored"),
|
||||
true,
|
||||
true);
|
||||
// Set all flags back to the state they were in before the context was
|
||||
// lost.
|
||||
mEmitContextLostErrorOnce = true;
|
||||
mAllowRestore = true;
|
||||
}
|
||||
|
||||
MaybeRestoreContext();
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::MaybeRestoreContext()
|
||||
{
|
||||
// Don't try to handle it if we already know it's busted.
|
||||
if (mContextStatus != ContextNotLost || gl == nullptr)
|
||||
return;
|
||||
|
||||
bool isEGL = gl->GetContextType() == gl::GLContextType::EGL,
|
||||
isANGLE = gl->IsANGLE();
|
||||
|
||||
GLContext::ContextResetARB resetStatus = GLContext::CONTEXT_NO_ERROR;
|
||||
if (mHasRobustness) {
|
||||
gl->MakeCurrent();
|
||||
resetStatus = (GLContext::ContextResetARB) gl->fGetGraphicsResetStatus();
|
||||
} else if (isEGL) {
|
||||
// Simulate a ARB_robustness guilty context loss for when we
|
||||
// get an EGL_CONTEXT_LOST error. It may not actually be guilty,
|
||||
// but we can't make any distinction, so we must assume the worst
|
||||
// case.
|
||||
if (!gl->MakeCurrent(true) && gl->IsContextLost()) {
|
||||
resetStatus = GLContext::CONTEXT_GUILTY_CONTEXT_RESET_ARB;
|
||||
}
|
||||
}
|
||||
|
||||
if (resetStatus != GLContext::CONTEXT_NO_ERROR) {
|
||||
// It's already lost, but clean up after it and signal to JS that it is
|
||||
// lost.
|
||||
ForceLoseContext();
|
||||
}
|
||||
|
||||
switch (resetStatus) {
|
||||
case GLContext::CONTEXT_NO_ERROR:
|
||||
// If there has been activity since the timer was set, it's possible
|
||||
// that we did or are going to miss something, so clear this flag and
|
||||
// run it again some time later.
|
||||
if (mDrawSinceContextLossTimerSet)
|
||||
SetupContextLossTimer();
|
||||
break;
|
||||
case GLContext::CONTEXT_GUILTY_CONTEXT_RESET_ARB:
|
||||
NS_WARNING("WebGL content on the page caused the graphics card to reset; not restoring the context");
|
||||
mAllowRestore = false;
|
||||
break;
|
||||
case GLContext::CONTEXT_INNOCENT_CONTEXT_RESET_ARB:
|
||||
break;
|
||||
case GLContext::CONTEXT_UNKNOWN_CONTEXT_RESET_ARB:
|
||||
NS_WARNING("WebGL content on the page might have caused the graphics card to reset");
|
||||
if (isEGL && isANGLE) {
|
||||
// If we're using ANGLE, we ONLY get back UNKNOWN context resets, including for guilty contexts.
|
||||
// This means that we can't restore it or risk restoring a guilty context. Should this ever change,
|
||||
// we can get rid of the whole IsANGLE() junk from GLContext.h since, as of writing, this is the
|
||||
// only use for it. See ANGLE issue 261.
|
||||
mAllowRestore = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::ForceLoseContext()
|
||||
{
|
||||
if (mContextStatus == ContextLostAwaitingEvent)
|
||||
return;
|
||||
|
||||
printf_stderr("WebGL(%p)::ForceLoseContext\n", this);
|
||||
MOZ_ASSERT(!IsContextLost());
|
||||
mContextStatus = ContextLostAwaitingEvent;
|
||||
// Queue up a task to restore the event.
|
||||
SetupContextLossTimer();
|
||||
mContextLostErrorSet = false;
|
||||
mLastLossWasSimulated = false;
|
||||
|
||||
// Burn it all!
|
||||
DestroyResourcesAndContext();
|
||||
|
||||
// Queue up a task, since we know the status changed.
|
||||
EnqueueUpdateContextLossStatus();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::ForceRestoreContext()
|
||||
{
|
||||
printf_stderr("WebGL(%p)::ForceRestoreContext\n", this);
|
||||
mContextStatus = ContextLostAwaitingRestore;
|
||||
mAllowContextRestore = true; // Hey, you did say 'force'.
|
||||
|
||||
// Queue up a task, since we know the status changed.
|
||||
EnqueueUpdateContextLossStatus();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -202,9 +202,6 @@ public:
|
||||
int32_t x, int32_t y, int32_t w, int32_t h)
|
||||
{ return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
bool LoseContext();
|
||||
bool RestoreContext();
|
||||
|
||||
void SynthesizeGLError(GLenum err);
|
||||
void SynthesizeGLError(GLenum err, const char *fmt, ...);
|
||||
|
||||
@ -261,11 +258,14 @@ public:
|
||||
|
||||
bool MinCapabilityMode() const { return mMinCapability; }
|
||||
|
||||
void RobustnessTimerCallback(nsITimer* timer);
|
||||
static void RobustnessTimerCallbackStatic(nsITimer* timer, void *thisPointer);
|
||||
void SetupContextLossTimer();
|
||||
void UpdateContextLossStatus();
|
||||
void EnqueueUpdateContextLossStatus();
|
||||
static void ContextLossCallbackStatic(nsITimer* timer, void* thisPointer);
|
||||
void RunContextLossTimer();
|
||||
void TerminateContextLossTimer();
|
||||
|
||||
bool TryToRestoreContext();
|
||||
|
||||
void AssertCachedBindings();
|
||||
void AssertCachedState();
|
||||
|
||||
@ -511,6 +511,7 @@ public:
|
||||
|
||||
void Uniform1iv(WebGLUniformLocation* location,
|
||||
const dom::Int32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform1iv_base(location, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform1iv(WebGLUniformLocation* location,
|
||||
@ -522,6 +523,7 @@ public:
|
||||
|
||||
void Uniform2iv(WebGLUniformLocation* location,
|
||||
const dom::Int32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform2iv_base(location, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform2iv(WebGLUniformLocation* location,
|
||||
@ -533,6 +535,7 @@ public:
|
||||
|
||||
void Uniform3iv(WebGLUniformLocation* location,
|
||||
const dom::Int32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform3iv_base(location, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform3iv(WebGLUniformLocation* location,
|
||||
@ -544,6 +547,7 @@ public:
|
||||
|
||||
void Uniform4iv(WebGLUniformLocation* location,
|
||||
const dom::Int32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform4iv_base(location, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform4iv(WebGLUniformLocation* location,
|
||||
@ -555,6 +559,7 @@ public:
|
||||
|
||||
void Uniform1fv(WebGLUniformLocation* location,
|
||||
const dom::Float32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform1fv_base(location, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform1fv(WebGLUniformLocation* location,
|
||||
@ -566,6 +571,7 @@ public:
|
||||
|
||||
void Uniform2fv(WebGLUniformLocation* location,
|
||||
const dom::Float32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform2fv_base(location, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform2fv(WebGLUniformLocation* location,
|
||||
@ -577,6 +583,7 @@ public:
|
||||
|
||||
void Uniform3fv(WebGLUniformLocation* location,
|
||||
const dom::Float32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform3fv_base(location, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform3fv(WebGLUniformLocation* location,
|
||||
@ -588,6 +595,7 @@ public:
|
||||
|
||||
void Uniform4fv(WebGLUniformLocation* location,
|
||||
const dom::Float32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform4fv_base(location, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform4fv(WebGLUniformLocation* location,
|
||||
@ -600,6 +608,7 @@ public:
|
||||
void UniformMatrix2fv(WebGLUniformLocation* location,
|
||||
WebGLboolean transpose,
|
||||
const dom::Float32Array &value) {
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix2fv_base(location, transpose, value.Length(), value.Data());
|
||||
}
|
||||
void UniformMatrix2fv(WebGLUniformLocation* location,
|
||||
@ -615,6 +624,7 @@ public:
|
||||
void UniformMatrix3fv(WebGLUniformLocation* location,
|
||||
WebGLboolean transpose,
|
||||
const dom::Float32Array &value) {
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix3fv_base(location, transpose, value.Length(), value.Data());
|
||||
}
|
||||
void UniformMatrix3fv(WebGLUniformLocation* location,
|
||||
@ -630,6 +640,7 @@ public:
|
||||
void UniformMatrix4fv(WebGLUniformLocation* location,
|
||||
WebGLboolean transpose,
|
||||
const dom::Float32Array &value) {
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix4fv_base(location, transpose, value.Length(), value.Data());
|
||||
}
|
||||
void UniformMatrix4fv(WebGLUniformLocation* location,
|
||||
@ -655,8 +666,12 @@ public:
|
||||
bool ValidateSamplerUniformSetter(const char* info,
|
||||
WebGLUniformLocation *location,
|
||||
GLint value);
|
||||
|
||||
void Viewport(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
// -----------------------------------------------------------------------------
|
||||
// WEBGL_lose_context
|
||||
public:
|
||||
void LoseContext();
|
||||
void RestoreContext();
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Asynchronous Queries (WebGLContextAsyncQueries.cpp)
|
||||
@ -753,6 +768,7 @@ public:
|
||||
GLfloat x2, GLfloat x3);
|
||||
|
||||
void VertexAttrib1fv(GLuint idx, const dom::Float32Array &arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
VertexAttrib1fv_base(idx, arr.Length(), arr.Data());
|
||||
}
|
||||
void VertexAttrib1fv(GLuint idx, const dom::Sequence<GLfloat>& arr) {
|
||||
@ -760,6 +776,7 @@ public:
|
||||
}
|
||||
|
||||
void VertexAttrib2fv(GLuint idx, const dom::Float32Array &arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
VertexAttrib2fv_base(idx, arr.Length(), arr.Data());
|
||||
}
|
||||
void VertexAttrib2fv(GLuint idx, const dom::Sequence<GLfloat>& arr) {
|
||||
@ -767,6 +784,7 @@ public:
|
||||
}
|
||||
|
||||
void VertexAttrib3fv(GLuint idx, const dom::Float32Array &arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
VertexAttrib3fv_base(idx, arr.Length(), arr.Data());
|
||||
}
|
||||
void VertexAttrib3fv(GLuint idx, const dom::Sequence<GLfloat>& arr) {
|
||||
@ -774,6 +792,7 @@ public:
|
||||
}
|
||||
|
||||
void VertexAttrib4fv(GLuint idx, const dom::Float32Array &arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
VertexAttrib4fv_base(idx, arr.Length(), arr.Data());
|
||||
}
|
||||
void VertexAttrib4fv(GLuint idx, const dom::Sequence<GLfloat>& arr) {
|
||||
@ -854,7 +873,6 @@ protected:
|
||||
bool mOptionsFrozen;
|
||||
bool mMinCapability;
|
||||
bool mDisableExtensions;
|
||||
bool mHasRobustness;
|
||||
bool mIsMesa;
|
||||
bool mLoseContextOnHeapMinimize;
|
||||
bool mCanLoseContextInForeground;
|
||||
@ -1101,7 +1119,6 @@ protected:
|
||||
GLenum type,
|
||||
const GLvoid *data);
|
||||
|
||||
void MaybeRestoreContext();
|
||||
void ForceLoseContext();
|
||||
void ForceRestoreContext();
|
||||
|
||||
@ -1163,7 +1180,7 @@ protected:
|
||||
|
||||
GLint mStencilRefFront, mStencilRefBack;
|
||||
GLuint mStencilValueMaskFront, mStencilValueMaskBack,
|
||||
mStencilWriteMaskFront, mStencilWriteMaskBack;
|
||||
mStencilWriteMaskFront, mStencilWriteMaskBack;
|
||||
realGLboolean mColorWriteMask[4];
|
||||
realGLboolean mDepthWriteMask;
|
||||
GLfloat mColorClearValue[4];
|
||||
@ -1177,9 +1194,10 @@ protected:
|
||||
bool mAlreadyWarnedAboutViewportLargerThanDest;
|
||||
|
||||
nsCOMPtr<nsITimer> mContextRestorer;
|
||||
bool mAllowRestore;
|
||||
bool mAllowContextRestore;
|
||||
bool mLastLossWasSimulated;
|
||||
bool mContextLossTimerRunning;
|
||||
bool mDrawSinceContextLossTimerSet;
|
||||
bool mRunContextLossTimerAgain;
|
||||
ContextStatus mContextStatus;
|
||||
bool mContextLostErrorSet;
|
||||
|
||||
|
@ -203,8 +203,10 @@ WebGLContext::BufferData(GLenum target,
|
||||
}
|
||||
|
||||
const ArrayBuffer& data = maybeData.Value();
|
||||
data.ComputeLengthAndData();
|
||||
|
||||
// careful: data.Length() could conceivably be any size_t, but GLsizeiptr is like intptr_t.
|
||||
// Careful: data.Length() could conceivably be any uint32_t, but GLsizeiptr
|
||||
// is like intptr_t.
|
||||
if (!CheckedInt<GLsizeiptr>(data.Length()).isValid())
|
||||
return ErrorOutOfMemory("bufferData: bad size");
|
||||
|
||||
@ -253,7 +255,10 @@ WebGLContext::BufferData(GLenum target, const ArrayBufferView& data,
|
||||
if (!boundBuffer)
|
||||
return ErrorInvalidOperation("bufferData: no buffer bound!");
|
||||
|
||||
// careful: data.Length() could conceivably be any size_t, but GLsizeiptr is like intptr_t.
|
||||
data.ComputeLengthAndData();
|
||||
|
||||
// Careful: data.Length() could conceivably be any uint32_t, but GLsizeiptr
|
||||
// is like intptr_t.
|
||||
if (!CheckedInt<GLsizeiptr>(data.Length()).isValid())
|
||||
return ErrorOutOfMemory("bufferData: bad size");
|
||||
|
||||
@ -290,8 +295,6 @@ WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
|
||||
return;
|
||||
}
|
||||
|
||||
const ArrayBuffer& data = maybeData.Value();
|
||||
|
||||
if (byteOffset < 0)
|
||||
return ErrorInvalidValue("bufferSubData: negative offset");
|
||||
|
||||
@ -300,6 +303,9 @@ WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
|
||||
if (!boundBuffer)
|
||||
return ErrorInvalidOperation("bufferData: no buffer bound!");
|
||||
|
||||
const ArrayBuffer& data = maybeData.Value();
|
||||
data.ComputeLengthAndData();
|
||||
|
||||
CheckedInt<WebGLsizeiptr> checked_neededByteLength = CheckedInt<WebGLsizeiptr>(byteOffset) + data.Length();
|
||||
if (!checked_neededByteLength.isValid())
|
||||
return ErrorInvalidValue("bufferSubData: integer overflow computing the needed byte length");
|
||||
@ -336,6 +342,8 @@ WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
|
||||
if (!boundBuffer)
|
||||
return ErrorInvalidOperation("bufferSubData: no buffer bound!");
|
||||
|
||||
data.ComputeLengthAndData();
|
||||
|
||||
CheckedInt<WebGLsizeiptr> checked_neededByteLength = CheckedInt<WebGLsizeiptr>(byteOffset) + data.Length();
|
||||
if (!checked_neededByteLength.isValid())
|
||||
return ErrorInvalidValue("bufferSubData: integer overflow computing the needed byte length");
|
||||
|
@ -128,7 +128,7 @@ WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei count)
|
||||
if (!DrawArrays_check(first, count, 1, "drawArrays"))
|
||||
return;
|
||||
|
||||
SetupContextLossTimer();
|
||||
RunContextLossTimer();
|
||||
gl->fDrawArrays(mode, first, count);
|
||||
|
||||
Draw_cleanup();
|
||||
@ -149,7 +149,7 @@ WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsiz
|
||||
if (!DrawInstanced_check("drawArraysInstanced"))
|
||||
return;
|
||||
|
||||
SetupContextLossTimer();
|
||||
RunContextLossTimer();
|
||||
gl->fDrawArraysInstanced(mode, first, count, primcount);
|
||||
|
||||
Draw_cleanup();
|
||||
@ -296,7 +296,7 @@ WebGLContext::DrawElements(GLenum mode, GLsizei count, GLenum type,
|
||||
return;
|
||||
}
|
||||
|
||||
SetupContextLossTimer();
|
||||
RunContextLossTimer();
|
||||
|
||||
if (gl->IsSupported(gl::GLFeature::draw_range_elements)) {
|
||||
gl->fDrawRangeElements(mode, 0, upperBound,
|
||||
@ -324,7 +324,7 @@ WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
|
||||
if (!DrawInstanced_check("drawElementsInstanced"))
|
||||
return;
|
||||
|
||||
SetupContextLossTimer();
|
||||
RunContextLossTimer();
|
||||
gl->fDrawElementsInstanced(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset), primcount);
|
||||
|
||||
Draw_cleanup();
|
||||
|
@ -2126,7 +2126,8 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
||||
if (!isReadTypeValid)
|
||||
return ErrorInvalidEnum("readPixels: Bad type", type);
|
||||
|
||||
int dataType = JS_GetArrayBufferViewType(pixels.Value().Obj());
|
||||
const ArrayBufferView& pixbuf = pixels.Value();
|
||||
int dataType = JS_GetArrayBufferViewType(pixbuf.Obj());
|
||||
|
||||
// Check the pixels param type
|
||||
if (dataType != requiredDataType)
|
||||
@ -2144,11 +2145,15 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
||||
if (!checked_neededByteLength.isValid())
|
||||
return ErrorInvalidOperation("readPixels: integer overflow computing the needed buffer size");
|
||||
|
||||
uint32_t dataByteLen = JS_GetTypedArrayByteLength(pixels.Value().Obj());
|
||||
// Compute length and data. Don't reenter after this point, lest the
|
||||
// precomputed go out of sync with the instant length/data.
|
||||
pixbuf.ComputeLengthAndData();
|
||||
|
||||
uint32_t dataByteLen = pixbuf.Length();
|
||||
if (checked_neededByteLength.value() > dataByteLen)
|
||||
return ErrorInvalidOperation("readPixels: buffer too small");
|
||||
|
||||
void* data = pixels.Value().Data();
|
||||
void* data = pixbuf.Data();
|
||||
if (!data) {
|
||||
ErrorOutOfMemory("readPixels: buffer storage is null. Did we run out of memory?");
|
||||
return rv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
@ -3261,6 +3266,8 @@ WebGLContext::CompressedTexImage2D(GLenum target, GLint level, GLenum internalfo
|
||||
return;
|
||||
}
|
||||
|
||||
view.ComputeLengthAndData();
|
||||
|
||||
uint32_t byteLength = view.Length();
|
||||
if (!ValidateCompTexImageDataSize(target, internalformat, width, height, byteLength, func)) {
|
||||
return;
|
||||
@ -3304,6 +3311,8 @@ WebGLContext::CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset,
|
||||
MOZ_ASSERT(tex);
|
||||
WebGLTexture::ImageInfo& levelInfo = tex->ImageInfoAt(target, level);
|
||||
|
||||
view.ComputeLengthAndData();
|
||||
|
||||
uint32_t byteLength = view.Length();
|
||||
if (!ValidateCompTexImageDataSize(target, format, width, height, byteLength, func))
|
||||
return;
|
||||
@ -3670,10 +3679,24 @@ WebGLContext::TexImage2D(GLenum target, GLint level,
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
void* data;
|
||||
uint32_t length;
|
||||
int jsArrayType;
|
||||
if (pixels.IsNull()) {
|
||||
data = nullptr;
|
||||
length = 0;
|
||||
jsArrayType = -1;
|
||||
} else {
|
||||
const ArrayBufferView& view = pixels.Value();
|
||||
view.ComputeLengthAndData();
|
||||
|
||||
data = view.Data();
|
||||
length = view.Length();
|
||||
jsArrayType = int(JS_GetArrayBufferViewType(view.Obj()));
|
||||
}
|
||||
|
||||
return TexImage2D_base(target, level, internalformat, width, height, 0, border, format, type,
|
||||
pixels.IsNull() ? 0 : pixels.Value().Data(),
|
||||
pixels.IsNull() ? 0 : pixels.Value().Length(),
|
||||
pixels.IsNull() ? -1 : (int)JS_GetArrayBufferViewType(pixels.Value().Obj()),
|
||||
data, length, jsArrayType,
|
||||
WebGLTexelFormat::Auto, false);
|
||||
}
|
||||
|
||||
@ -3691,6 +3714,8 @@ WebGLContext::TexImage2D(GLenum target, GLint level,
|
||||
}
|
||||
|
||||
Uint8ClampedArray arr(pixels->GetDataObject());
|
||||
arr.ComputeLengthAndData();
|
||||
|
||||
return TexImage2D_base(target, level, internalformat, pixels->Width(),
|
||||
pixels->Height(), 4*pixels->Width(), 0,
|
||||
format, type, arr.Data(), arr.Length(), -1,
|
||||
@ -3799,10 +3824,13 @@ WebGLContext::TexSubImage2D(GLenum target, GLint level,
|
||||
if (pixels.IsNull())
|
||||
return ErrorInvalidValue("texSubImage2D: pixels must not be null!");
|
||||
|
||||
const ArrayBufferView& view = pixels.Value();
|
||||
view.ComputeLengthAndData();
|
||||
|
||||
return TexSubImage2D_base(target, level, xoffset, yoffset,
|
||||
width, height, 0, format, type,
|
||||
pixels.Value().Data(), pixels.Value().Length(),
|
||||
JS_GetArrayBufferViewType(pixels.Value().Obj()),
|
||||
view.Data(), view.Length(),
|
||||
JS_GetArrayBufferViewType(view.Obj()),
|
||||
WebGLTexelFormat::Auto, false);
|
||||
}
|
||||
|
||||
@ -3819,6 +3847,8 @@ WebGLContext::TexSubImage2D(GLenum target, GLint level,
|
||||
return ErrorInvalidValue("texSubImage2D: pixels must not be null!");
|
||||
|
||||
Uint8ClampedArray arr(pixels->GetDataObject());
|
||||
arr.ComputeLengthAndData();
|
||||
|
||||
return TexSubImage2D_base(target, level, xoffset, yoffset,
|
||||
pixels->Width(), pixels->Height(),
|
||||
4*pixels->Width(), format, type,
|
||||
@ -3827,27 +3857,34 @@ WebGLContext::TexSubImage2D(GLenum target, GLint level,
|
||||
WebGLTexelFormat::RGBA8, false);
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
WebGLContext::LoseContext()
|
||||
{
|
||||
if (IsContextLost())
|
||||
return false;
|
||||
return ErrorInvalidOperation("loseContext: Context is already lost.");
|
||||
|
||||
ForceLoseContext();
|
||||
|
||||
return true;
|
||||
mLastLossWasSimulated = true;
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
WebGLContext::RestoreContext()
|
||||
{
|
||||
if (!IsContextLost() || !mAllowRestore) {
|
||||
return false;
|
||||
if (!IsContextLost())
|
||||
return ErrorInvalidOperation("restoreContext: Context is not lost.");
|
||||
|
||||
if (!mLastLossWasSimulated) {
|
||||
return ErrorInvalidOperation("restoreContext: Context loss was not simulated."
|
||||
" Cannot simulate restore.");
|
||||
}
|
||||
// If we're currently lost, and the last loss was simulated, then
|
||||
// we're currently only simulated-lost, allowing us to call
|
||||
// restoreContext().
|
||||
|
||||
if (!mAllowContextRestore)
|
||||
return ErrorInvalidOperation("restoreContext: Context cannot be restored.");
|
||||
|
||||
ForceRestoreContext();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -8,33 +8,45 @@
|
||||
using namespace mozilla;
|
||||
|
||||
/* static */ void
|
||||
WebGLContext::RobustnessTimerCallbackStatic(nsITimer* timer, void *thisPointer) {
|
||||
static_cast<WebGLContext*>(thisPointer)->RobustnessTimerCallback(timer);
|
||||
WebGLContext::ContextLossCallbackStatic(nsITimer* timer, void* thisPointer)
|
||||
{
|
||||
(void)timer;
|
||||
WebGLContext* context = static_cast<WebGLContext*>(thisPointer);
|
||||
|
||||
context->TerminateContextLossTimer();
|
||||
|
||||
context->UpdateContextLossStatus();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::SetupContextLossTimer() {
|
||||
WebGLContext::RunContextLossTimer()
|
||||
{
|
||||
// If the timer was already running, don't restart it here. Instead,
|
||||
// wait until the previous call is done, then fire it one more time.
|
||||
// This is an optimization to prevent unnecessary cross-communication
|
||||
// between threads.
|
||||
// This is an optimization to prevent unnecessary
|
||||
// cross-communication between threads.
|
||||
if (mContextLossTimerRunning) {
|
||||
mDrawSinceContextLossTimerSet = true;
|
||||
mRunContextLossTimerAgain = true;
|
||||
return;
|
||||
}
|
||||
|
||||
mContextRestorer->InitWithFuncCallback(RobustnessTimerCallbackStatic,
|
||||
static_cast<void*>(this),
|
||||
1000,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
mContextRestorer->InitWithFuncCallback(ContextLossCallbackStatic,
|
||||
static_cast<void*>(this),
|
||||
1000,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
mContextLossTimerRunning = true;
|
||||
mDrawSinceContextLossTimerSet = false;
|
||||
mRunContextLossTimerAgain = false;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::TerminateContextLossTimer() {
|
||||
if (mContextLossTimerRunning) {
|
||||
mContextRestorer->Cancel();
|
||||
mContextLossTimerRunning = false;
|
||||
WebGLContext::TerminateContextLossTimer()
|
||||
{
|
||||
if (!mContextLossTimerRunning)
|
||||
return;
|
||||
|
||||
mContextRestorer->Cancel();
|
||||
mContextLossTimerRunning = false;
|
||||
|
||||
if (mRunContextLossTimerAgain) {
|
||||
RunContextLossTimer();
|
||||
}
|
||||
}
|
||||
|
@ -21,15 +21,13 @@ WebGLExtensionLoseContext::~WebGLExtensionLoseContext()
|
||||
void
|
||||
WebGLExtensionLoseContext::LoseContext()
|
||||
{
|
||||
if (!mContext->LoseContext())
|
||||
mContext->mWebGLError = LOCAL_GL_INVALID_OPERATION;
|
||||
mContext->LoseContext();
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
WebGLExtensionLoseContext::RestoreContext()
|
||||
{
|
||||
if (!mContext->RestoreContext())
|
||||
mContext->mWebGLError = LOCAL_GL_INVALID_OPERATION;
|
||||
mContext->RestoreContext();
|
||||
}
|
||||
|
||||
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionLoseContext)
|
||||
|
@ -99,7 +99,7 @@ function testLosingAndRestoringContext()
|
||||
// restore the context after this event has exited.
|
||||
setTimeout(function() {
|
||||
shouldGenerateGLError(gl, gl.NO_ERROR, "extension.restoreContext()");
|
||||
// The context should still be lost. It will not get restored until the
|
||||
// The context should still be lost. It will not get restored until the
|
||||
// webglrestorecontext event is fired.
|
||||
shouldBeTrue("gl.isContextLost()");
|
||||
shouldBe("gl.getError()", "gl.NO_ERROR");
|
||||
|
@ -250,12 +250,16 @@ SourceBuffer::SetAppendWindowEnd(double aAppendWindowEnd, ErrorResult& aRv)
|
||||
void
|
||||
SourceBuffer::AppendBuffer(const ArrayBuffer& aData, ErrorResult& aRv)
|
||||
{
|
||||
aData.ComputeLengthAndData();
|
||||
|
||||
AppendData(aData.Data(), aData.Length(), aRv);
|
||||
}
|
||||
|
||||
void
|
||||
SourceBuffer::AppendBuffer(const ArrayBufferView& aData, ErrorResult& aRv)
|
||||
{
|
||||
aData.ComputeLengthAndData();
|
||||
|
||||
AppendData(aData.Data(), aData.Length(), aRv);
|
||||
}
|
||||
|
||||
|
@ -171,6 +171,8 @@ AnalyserNode::GetFloatFrequencyData(const Float32Array& aArray)
|
||||
return;
|
||||
}
|
||||
|
||||
aArray.ComputeLengthAndData();
|
||||
|
||||
float* buffer = aArray.Data();
|
||||
size_t length = std::min(size_t(aArray.Length()), mOutputBuffer.Length());
|
||||
|
||||
@ -189,6 +191,8 @@ AnalyserNode::GetByteFrequencyData(const Uint8Array& aArray)
|
||||
|
||||
const double rangeScaleFactor = 1.0 / (mMaxDecibels - mMinDecibels);
|
||||
|
||||
aArray.ComputeLengthAndData();
|
||||
|
||||
unsigned char* buffer = aArray.Data();
|
||||
size_t length = std::min(size_t(aArray.Length()), mOutputBuffer.Length());
|
||||
|
||||
@ -204,6 +208,8 @@ AnalyserNode::GetByteFrequencyData(const Uint8Array& aArray)
|
||||
void
|
||||
AnalyserNode::GetFloatTimeDomainData(const Float32Array& aArray)
|
||||
{
|
||||
aArray.ComputeLengthAndData();
|
||||
|
||||
float* buffer = aArray.Data();
|
||||
size_t length = std::min(size_t(aArray.Length()), mBuffer.Length());
|
||||
|
||||
@ -215,6 +221,8 @@ AnalyserNode::GetFloatTimeDomainData(const Float32Array& aArray)
|
||||
void
|
||||
AnalyserNode::GetByteTimeDomainData(const Uint8Array& aArray)
|
||||
{
|
||||
aArray.ComputeLengthAndData();
|
||||
|
||||
unsigned char* buffer = aArray.Data();
|
||||
size_t length = std::min(size_t(aArray.Length()), mBuffer.Length());
|
||||
|
||||
|
@ -130,6 +130,8 @@ void
|
||||
AudioBuffer::CopyFromChannel(const Float32Array& aDestination, uint32_t aChannelNumber,
|
||||
uint32_t aStartInChannel, ErrorResult& aRv)
|
||||
{
|
||||
aDestination.ComputeLengthAndData();
|
||||
|
||||
uint32_t length = aDestination.Length();
|
||||
CheckedInt<uint32_t> end = aStartInChannel;
|
||||
end += length;
|
||||
@ -156,6 +158,8 @@ AudioBuffer::CopyToChannel(JSContext* aJSContext, const Float32Array& aSource,
|
||||
uint32_t aChannelNumber, uint32_t aStartInChannel,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
aSource.ComputeLengthAndData();
|
||||
|
||||
uint32_t length = aSource.Length();
|
||||
CheckedInt<uint32_t> end = aStartInChannel;
|
||||
end += length;
|
||||
|
@ -400,6 +400,9 @@ AudioContext::CreatePeriodicWave(const Float32Array& aRealData,
|
||||
const Float32Array& aImagData,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
aRealData.ComputeLengthAndData();
|
||||
aImagData.ComputeLengthAndData();
|
||||
|
||||
if (aRealData.Length() != aImagData.Length() ||
|
||||
aRealData.Length() == 0 ||
|
||||
aRealData.Length() > 4096) {
|
||||
@ -434,6 +437,8 @@ AudioContext::DecodeAudioData(const ArrayBuffer& aBuffer,
|
||||
JSContext* cx = jsapi.cx();
|
||||
JSAutoCompartment ac(cx, aBuffer.Obj());
|
||||
|
||||
aBuffer.ComputeLengthAndData();
|
||||
|
||||
// Neuter the array buffer
|
||||
size_t length = aBuffer.Length();
|
||||
JS::RootedObject obj(cx, aBuffer.Obj());
|
||||
|
@ -55,6 +55,7 @@ public:
|
||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return;
|
||||
}
|
||||
aValues.ComputeLengthAndData();
|
||||
AudioParamTimeline::SetValueCurveAtTime(aValues.Data(), aValues.Length(),
|
||||
DOMTimeToStreamTime(aStartTime), aDuration, aRv);
|
||||
mCallback(mNode);
|
||||
|
@ -308,6 +308,10 @@ BiquadFilterNode::GetFrequencyResponse(const Float32Array& aFrequencyHz,
|
||||
const Float32Array& aMagResponse,
|
||||
const Float32Array& aPhaseResponse)
|
||||
{
|
||||
aFrequencyHz.ComputeLengthAndData();
|
||||
aMagResponse.ComputeLengthAndData();
|
||||
aPhaseResponse.ComputeLengthAndData();
|
||||
|
||||
uint32_t length = std::min(std::min(aFrequencyHz.Length(), aMagResponse.Length()),
|
||||
aPhaseResponse.Length());
|
||||
if (!length) {
|
||||
|
@ -313,10 +313,14 @@ WaveShaperNode::SetCurve(const Nullable<Float32Array>& aCurve)
|
||||
{
|
||||
nsTArray<float> curve;
|
||||
if (!aCurve.IsNull()) {
|
||||
mCurve = aCurve.Value().Obj();
|
||||
const Float32Array& floats = aCurve.Value();
|
||||
|
||||
curve.SetLength(aCurve.Value().Length());
|
||||
PodCopy(curve.Elements(), aCurve.Value().Data(), aCurve.Value().Length());
|
||||
mCurve = floats.Obj();
|
||||
|
||||
floats.ComputeLengthAndData();
|
||||
|
||||
curve.SetLength(floats.Length());
|
||||
PodCopy(curve.Elements(), floats.Data(), floats.Length());
|
||||
} else {
|
||||
mCurve = nullptr;
|
||||
}
|
||||
|
@ -27,6 +27,15 @@ GetUserMediaLog()
|
||||
}
|
||||
#endif
|
||||
|
||||
static PRLogModuleInfo*
|
||||
GetWebrtcTraceLog()
|
||||
{
|
||||
static PRLogModuleInfo *sLog;
|
||||
if (!sLog)
|
||||
sLog = PR_NewLogModule("webrtc_trace");
|
||||
return sLog;
|
||||
}
|
||||
|
||||
#include "MediaEngineWebRTC.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "nsIComponentRegistrar.h"
|
||||
@ -65,6 +74,14 @@ MediaEngineWebRTC::MediaEngineWebRTC(MediaEnginePrefs &aPrefs)
|
||||
gFarendObserver = new AudioOutputObserver();
|
||||
}
|
||||
|
||||
void
|
||||
MediaEngineWebRTC::Print(webrtc::TraceLevel level, const char* message, int length)
|
||||
{
|
||||
PRLogModuleInfo *log = GetWebrtcTraceLog();
|
||||
// XXX look at log level?
|
||||
PR_LOG(log, PR_LOG_DEBUG, ("%s", message));
|
||||
}
|
||||
|
||||
void
|
||||
MediaEngineWebRTC::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSource> >* aVSources)
|
||||
{
|
||||
@ -130,7 +147,7 @@ MediaEngineWebRTC::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSourc
|
||||
}
|
||||
}
|
||||
|
||||
PRLogModuleInfo *logs = GetWebRTCLogInfo();
|
||||
PRLogModuleInfo *logs = GetWebrtcTraceLog();
|
||||
if (!gWebrtcTraceLoggingOn && logs && logs->level > 0) {
|
||||
// no need to a critical section or lock here
|
||||
gWebrtcTraceLoggingOn = 1;
|
||||
@ -143,7 +160,11 @@ MediaEngineWebRTC::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSourc
|
||||
LOG(("%s Logging webrtc to %s level %d", __FUNCTION__, file, logs->level));
|
||||
|
||||
mVideoEngine->SetTraceFilter(logs->level);
|
||||
mVideoEngine->SetTraceFile(file);
|
||||
if (strcmp(file, "nspr") == 0) {
|
||||
mVideoEngine->SetTraceCallback(this);
|
||||
} else {
|
||||
mVideoEngine->SetTraceFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
ptrViEBase = webrtc::ViEBase::GetInterface(mVideoEngine);
|
||||
@ -263,7 +284,7 @@ MediaEngineWebRTC::EnumerateAudioDevices(nsTArray<nsRefPtr<MediaEngineAudioSourc
|
||||
}
|
||||
}
|
||||
|
||||
PRLogModuleInfo *logs = GetWebRTCLogInfo();
|
||||
PRLogModuleInfo *logs = GetWebrtcTraceLog();
|
||||
if (!gWebrtcTraceLoggingOn && logs && logs->level > 0) {
|
||||
// no need to a critical section or lock here
|
||||
gWebrtcTraceLoggingOn = 1;
|
||||
@ -276,7 +297,11 @@ MediaEngineWebRTC::EnumerateAudioDevices(nsTArray<nsRefPtr<MediaEngineAudioSourc
|
||||
LOG(("Logging webrtc to %s level %d", __FUNCTION__, file, logs->level));
|
||||
|
||||
mVoiceEngine->SetTraceFilter(logs->level);
|
||||
mVoiceEngine->SetTraceFile(file);
|
||||
if (strcmp(file, "nspr") == 0) {
|
||||
mVoiceEngine->SetTraceCallback(this);
|
||||
} else {
|
||||
mVoiceEngine->SetTraceFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
ptrVoEBase = webrtc::VoEBase::GetInterface(mVoiceEngine);
|
||||
@ -340,13 +365,16 @@ MediaEngineWebRTC::Shutdown()
|
||||
// This is likely paranoia
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
// Clear callbacks before we go away since the engines may outlive us
|
||||
if (mVideoEngine) {
|
||||
mVideoSources.Clear();
|
||||
mVideoEngine->SetTraceCallback(nullptr);
|
||||
webrtc::VideoEngine::Delete(mVideoEngine);
|
||||
}
|
||||
|
||||
if (mVoiceEngine) {
|
||||
mAudioSources.Clear();
|
||||
mVoiceEngine->SetTraceCallback(nullptr);
|
||||
webrtc::VoiceEngine::Delete(mVoiceEngine);
|
||||
}
|
||||
|
||||
|
@ -356,7 +356,8 @@ private:
|
||||
NullTransport *mNullTransport;
|
||||
};
|
||||
|
||||
class MediaEngineWebRTC : public MediaEngine
|
||||
class MediaEngineWebRTC : public MediaEngine,
|
||||
public webrtc::TraceCallback
|
||||
{
|
||||
public:
|
||||
MediaEngineWebRTC(MediaEnginePrefs &aPrefs);
|
||||
@ -368,6 +369,9 @@ public:
|
||||
virtual void EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSource> >*);
|
||||
virtual void EnumerateAudioDevices(nsTArray<nsRefPtr<MediaEngineAudioSource> >*);
|
||||
|
||||
// Webrtc trace callbacks for proxying to NSPR
|
||||
virtual void Print(webrtc::TraceLevel level, const char* message, int length);
|
||||
|
||||
private:
|
||||
~MediaEngineWebRTC() {
|
||||
Shutdown();
|
||||
|
@ -64,12 +64,6 @@ SVGAnimationElement::Init()
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
bool
|
||||
SVGAnimationElement::PassesConditionalProcessingTests()
|
||||
{
|
||||
return SVGTests::PassesConditionalProcessingTests();
|
||||
}
|
||||
|
||||
const nsAttrValue*
|
||||
SVGAnimationElement::GetAnimAttr(nsIAtom* aName) const
|
||||
{
|
||||
@ -313,6 +307,13 @@ SVGAnimationElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
SVGAnimationElementBase::AfterSetAttr(aNamespaceID, aName, aValue,
|
||||
aNotify);
|
||||
|
||||
if (SVGTests::IsConditionalProcessingAttribute(aName)) {
|
||||
bool isDisabled = !SVGTests::PassesConditionalProcessingTests();
|
||||
if (mTimedElement.SetIsDisabled(isDisabled)) {
|
||||
AnimationNeedsResample();
|
||||
}
|
||||
}
|
||||
|
||||
if (aNamespaceID != kNameSpaceID_XLink || aName != nsGkAtoms::href)
|
||||
return rv;
|
||||
|
||||
|
@ -58,7 +58,6 @@ public:
|
||||
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify) MOZ_OVERRIDE;
|
||||
|
||||
bool PassesConditionalProcessingTests();
|
||||
const nsAttrValue* GetAnimAttr(nsIAtom* aName) const;
|
||||
bool GetAnimAttr(nsIAtom* aAttName, nsAString& aResult) const;
|
||||
bool HasAnimAttr(nsIAtom* aAttName) const;
|
||||
|
@ -2716,14 +2716,11 @@ OffThreadScriptReceiverCallback(void *aToken, void *aCallbackData)
|
||||
|
||||
nsresult
|
||||
nsXULPrototypeScript::Compile(JS::SourceBufferHolder& aSrcBuf,
|
||||
nsIURI* aURI,
|
||||
uint32_t aLineNo,
|
||||
nsIURI* aURI, uint32_t aLineNo,
|
||||
nsIDocument* aDocument,
|
||||
nsXULPrototypeDocument* aProtoDoc,
|
||||
nsIOffThreadScriptReceiver *aOffThreadReceiver /* = nullptr */)
|
||||
{
|
||||
// We'll compile the script in the compilation scope.
|
||||
NS_ENSURE_STATE(aProtoDoc);
|
||||
NS_ENSURE_TRUE(xpc::GetCompilationScope(), NS_ERROR_UNEXPECTED);
|
||||
AutoSafeJSContext cx;
|
||||
JSAutoCompartment ac(cx, xpc::GetCompilationScope());
|
||||
@ -2770,12 +2767,11 @@ nsXULPrototypeScript::Compile(const char16_t* aText,
|
||||
nsIURI* aURI,
|
||||
uint32_t aLineNo,
|
||||
nsIDocument* aDocument,
|
||||
nsXULPrototypeDocument* aProtoDoc,
|
||||
nsIOffThreadScriptReceiver *aOffThreadReceiver /* = nullptr */)
|
||||
{
|
||||
JS::SourceBufferHolder srcBuf(aText, aTextLength,
|
||||
JS::SourceBufferHolder::NoOwnership);
|
||||
return Compile(srcBuf, aURI, aLineNo, aDocument, aProtoDoc, aOffThreadReceiver);
|
||||
return Compile(srcBuf, aURI, aLineNo, aDocument, aOffThreadReceiver);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -238,13 +238,11 @@ public:
|
||||
nsresult Compile(JS::SourceBufferHolder& aSrcBuf,
|
||||
nsIURI* aURI, uint32_t aLineNo,
|
||||
nsIDocument* aDocument,
|
||||
nsXULPrototypeDocument* aProtoDoc,
|
||||
nsIOffThreadScriptReceiver *aOffThreadReceiver = nullptr);
|
||||
|
||||
nsresult Compile(const char16_t* aText, int32_t aTextLength,
|
||||
nsIURI* aURI, uint32_t aLineNo,
|
||||
nsIDocument* aDocument,
|
||||
nsXULPrototypeDocument* aProtoDoc,
|
||||
nsIOffThreadScriptReceiver *aOffThreadReceiver = nullptr);
|
||||
|
||||
void UnlinkJSObjects();
|
||||
|
@ -3549,10 +3549,7 @@ XULDocument::OnStreamComplete(nsIStreamLoader* aLoader,
|
||||
mOffThreadCompileStringBuf = nullptr;
|
||||
mOffThreadCompileStringLength = 0;
|
||||
|
||||
rv = mCurrentScriptProto->Compile(srcBuf,
|
||||
uri, 1, this,
|
||||
mMasterPrototype,
|
||||
this);
|
||||
rv = mCurrentScriptProto->Compile(srcBuf, uri, 1, this, this);
|
||||
if (NS_SUCCEEDED(rv) && !mCurrentScriptProto->GetScriptObject()) {
|
||||
// We will be notified via OnOffThreadCompileComplete when the
|
||||
// compile finishes. Keep the contents of the compiled script
|
||||
|
@ -566,7 +566,7 @@ XULContentSinkImpl::HandleEndElement(const char16_t *aName)
|
||||
script->mOutOfLine = false;
|
||||
if (doc)
|
||||
script->Compile(mText, mTextLength, mDocumentURL,
|
||||
script->mLineNo, doc, mPrototype);
|
||||
script->mLineNo, doc);
|
||||
}
|
||||
|
||||
FlushText(false);
|
||||
|
@ -79,6 +79,7 @@ Crypto::GetRandomValues(JSContext* aCx, const ArrayBufferView& aArray,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aArray.ComputeLengthAndData();
|
||||
uint32_t dataLen = aArray.Length();
|
||||
if (dataLen == 0) {
|
||||
NS_WARNING("ArrayBufferView length is 0, cannot continue");
|
||||
|
@ -107,6 +107,7 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
static bool sDoNotTrackEnabled = false;
|
||||
static uint32_t sDoNotTrackValue = 1;
|
||||
static bool sVibratorEnabled = false;
|
||||
static uint32_t sMaxVibrateMS = 0;
|
||||
static uint32_t sMaxVibrateListLen = 0;
|
||||
@ -118,6 +119,9 @@ Navigator::Init()
|
||||
Preferences::AddBoolVarCache(&sDoNotTrackEnabled,
|
||||
"privacy.donottrackheader.enabled",
|
||||
false);
|
||||
Preferences::AddUintVarCache(&sDoNotTrackValue,
|
||||
"privacy.donottrackheader.value",
|
||||
1);
|
||||
Preferences::AddBoolVarCache(&sVibratorEnabled,
|
||||
"dom.vibrator.enabled", true);
|
||||
Preferences::AddUintVarCache(&sMaxVibrateMS,
|
||||
@ -621,7 +625,11 @@ NS_IMETHODIMP
|
||||
Navigator::GetDoNotTrack(nsAString &aResult)
|
||||
{
|
||||
if (sDoNotTrackEnabled) {
|
||||
aResult.AssignLiteral("yes");
|
||||
if (sDoNotTrackValue == 0) {
|
||||
aResult.AssignLiteral("0");
|
||||
} else {
|
||||
aResult.AssignLiteral("1");
|
||||
}
|
||||
} else {
|
||||
aResult.AssignLiteral("unspecified");
|
||||
}
|
||||
@ -784,19 +792,21 @@ Navigator::Vibrate(const nsTArray<uint32_t>& aPattern)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aPattern.Length() > sMaxVibrateListLen) {
|
||||
return false;
|
||||
nsTArray<uint32_t> pattern(aPattern);
|
||||
|
||||
if (pattern.Length() > sMaxVibrateListLen) {
|
||||
pattern.SetLength(sMaxVibrateMS);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < aPattern.Length(); ++i) {
|
||||
if (aPattern[i] > sMaxVibrateMS) {
|
||||
return false;
|
||||
for (size_t i = 0; i < pattern.Length(); ++i) {
|
||||
if (pattern[i] > sMaxVibrateMS) {
|
||||
pattern[i] = sMaxVibrateMS;
|
||||
}
|
||||
}
|
||||
|
||||
// The spec says we check sVibratorEnabled after we've done the sanity
|
||||
// checking on the pattern.
|
||||
if (aPattern.IsEmpty() || !sVibratorEnabled) {
|
||||
if (pattern.IsEmpty() || !sVibratorEnabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -814,7 +824,7 @@ Navigator::Vibrate(const nsTArray<uint32_t>& aPattern)
|
||||
}
|
||||
gVibrateWindowListener = new VibrateWindowListener(mWindow, doc);
|
||||
|
||||
hal::Vibrate(aPattern, mWindow);
|
||||
hal::Vibrate(pattern, mWindow);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1237,8 +1247,10 @@ Navigator::SendBeacon(const nsAString& aUrl,
|
||||
return false;
|
||||
}
|
||||
|
||||
rv = strStream->SetData(reinterpret_cast<char*>(aData.Value().GetAsArrayBufferView().Data()),
|
||||
aData.Value().GetAsArrayBufferView().Length());
|
||||
ArrayBufferView& view = aData.Value().GetAsArrayBufferView();
|
||||
view.ComputeLengthAndData();
|
||||
rv = strStream->SetData(reinterpret_cast<char*>(view.Data()),
|
||||
view.Length());
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
|
@ -60,6 +60,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=889335
|
||||
if (currentTestIdx >= tests.length) {
|
||||
tearDown();
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
tests[currentTestIdx]();
|
||||
|
@ -26,7 +26,7 @@ struct TypedArrayObjectStorage : AllTypedArraysBase {
|
||||
protected:
|
||||
JSObject* mObj;
|
||||
|
||||
TypedArrayObjectStorage()
|
||||
TypedArrayObjectStorage(JSObject *obj) : mObj(obj)
|
||||
{
|
||||
}
|
||||
|
||||
@ -55,32 +55,43 @@ private:
|
||||
* or array buffer object.
|
||||
*/
|
||||
template<typename T,
|
||||
JSObject* UnboxArray(JSObject*, uint32_t*, T**)>
|
||||
JSObject* UnwrapArray(JSObject*),
|
||||
void GetLengthAndData(JSObject*, uint32_t*, T**)>
|
||||
struct TypedArray_base : public TypedArrayObjectStorage {
|
||||
typedef T element_type;
|
||||
|
||||
TypedArray_base(JSObject* obj)
|
||||
: TypedArrayObjectStorage(obj),
|
||||
mData(nullptr),
|
||||
mLength(0),
|
||||
mComputed(false)
|
||||
{
|
||||
DoInit(obj);
|
||||
MOZ_ASSERT(obj != nullptr);
|
||||
}
|
||||
|
||||
TypedArray_base()
|
||||
: TypedArrayObjectStorage(nullptr),
|
||||
mData(nullptr),
|
||||
mLength(0),
|
||||
mComputed(false)
|
||||
{
|
||||
mObj = nullptr;
|
||||
}
|
||||
|
||||
explicit TypedArray_base(TypedArray_base&& aOther)
|
||||
: TypedArrayObjectStorage(Move(aOther)),
|
||||
mData(aOther.mData),
|
||||
mLength(aOther.mLength)
|
||||
mLength(aOther.mLength),
|
||||
mComputed(aOther.mComputed)
|
||||
{
|
||||
aOther.mData = nullptr;
|
||||
aOther.mLength = 0;
|
||||
aOther.mComputed = false;
|
||||
}
|
||||
|
||||
private:
|
||||
T* mData;
|
||||
uint32_t mLength;
|
||||
mutable T* mData;
|
||||
mutable uint32_t mLength;
|
||||
mutable bool mComputed;
|
||||
|
||||
public:
|
||||
inline bool Init(JSObject* obj)
|
||||
@ -95,12 +106,12 @@ public:
|
||||
}
|
||||
|
||||
inline T *Data() const {
|
||||
MOZ_ASSERT(inited());
|
||||
MOZ_ASSERT(mComputed);
|
||||
return mData;
|
||||
}
|
||||
|
||||
inline uint32_t Length() const {
|
||||
MOZ_ASSERT(inited());
|
||||
MOZ_ASSERT(mComputed);
|
||||
return mLength;
|
||||
}
|
||||
|
||||
@ -115,10 +126,26 @@ public:
|
||||
JS::MutableHandle<JSObject*>::fromMarkedLocation(&mObj));
|
||||
}
|
||||
|
||||
inline void ComputeLengthAndData() const
|
||||
{
|
||||
MOZ_ASSERT(inited());
|
||||
MOZ_ASSERT(!mComputed);
|
||||
GetLengthAndData(mObj, &mLength, &mData);
|
||||
mComputed = true;
|
||||
}
|
||||
|
||||
protected:
|
||||
inline void DoInit(JSObject* obj)
|
||||
{
|
||||
mObj = UnboxArray(obj, &mLength, &mData);
|
||||
mObj = UnwrapArray(obj);
|
||||
}
|
||||
|
||||
inline void ComputeData() const {
|
||||
MOZ_ASSERT(inited());
|
||||
if (!mComputed) {
|
||||
GetLengthAndData(mObj, &mLength, &mData);
|
||||
mComputed = true;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
@ -127,20 +154,25 @@ private:
|
||||
|
||||
|
||||
template<typename T,
|
||||
JSObject* UnwrapArray(JSObject*),
|
||||
T* GetData(JSObject*),
|
||||
JSObject* UnboxArray(JSObject*, uint32_t*, T**),
|
||||
void GetLengthAndData(JSObject*, uint32_t*, T**),
|
||||
JSObject* CreateNew(JSContext*, uint32_t)>
|
||||
struct TypedArray : public TypedArray_base<T,UnboxArray> {
|
||||
TypedArray(JSObject* obj) :
|
||||
TypedArray_base<T,UnboxArray>(obj)
|
||||
struct TypedArray : public TypedArray_base<T, UnwrapArray, GetLengthAndData> {
|
||||
private:
|
||||
typedef TypedArray_base<T, UnwrapArray, GetLengthAndData> Base;
|
||||
|
||||
public:
|
||||
TypedArray(JSObject* obj)
|
||||
: Base(obj)
|
||||
{}
|
||||
|
||||
TypedArray() :
|
||||
TypedArray_base<T,UnboxArray>()
|
||||
TypedArray()
|
||||
: Base()
|
||||
{}
|
||||
|
||||
explicit TypedArray(TypedArray&& aOther)
|
||||
: TypedArray_base<T,UnboxArray>(Move(aOther))
|
||||
: Base(Move(aOther))
|
||||
{
|
||||
}
|
||||
|
||||
@ -178,37 +210,37 @@ private:
|
||||
TypedArray(const TypedArray&) MOZ_DELETE;
|
||||
};
|
||||
|
||||
typedef TypedArray<int8_t, JS_GetInt8ArrayData, JS_GetObjectAsInt8Array,
|
||||
JS_NewInt8Array>
|
||||
typedef TypedArray<int8_t, js::UnwrapInt8Array, JS_GetInt8ArrayData,
|
||||
js::GetInt8ArrayLengthAndData, JS_NewInt8Array>
|
||||
Int8Array;
|
||||
typedef TypedArray<uint8_t, JS_GetUint8ArrayData,
|
||||
JS_GetObjectAsUint8Array, JS_NewUint8Array>
|
||||
typedef TypedArray<uint8_t, js::UnwrapUint8Array, JS_GetUint8ArrayData,
|
||||
js::GetUint8ArrayLengthAndData, JS_NewUint8Array>
|
||||
Uint8Array;
|
||||
typedef TypedArray<uint8_t, JS_GetUint8ClampedArrayData,
|
||||
JS_GetObjectAsUint8ClampedArray, JS_NewUint8ClampedArray>
|
||||
typedef TypedArray<uint8_t, js::UnwrapUint8ClampedArray, JS_GetUint8ClampedArrayData,
|
||||
js::GetUint8ClampedArrayLengthAndData, JS_NewUint8ClampedArray>
|
||||
Uint8ClampedArray;
|
||||
typedef TypedArray<int16_t, JS_GetInt16ArrayData,
|
||||
JS_GetObjectAsInt16Array, JS_NewInt16Array>
|
||||
typedef TypedArray<int16_t, js::UnwrapInt16Array, JS_GetInt16ArrayData,
|
||||
js::GetInt16ArrayLengthAndData, JS_NewInt16Array>
|
||||
Int16Array;
|
||||
typedef TypedArray<uint16_t, JS_GetUint16ArrayData,
|
||||
JS_GetObjectAsUint16Array, JS_NewUint16Array>
|
||||
typedef TypedArray<uint16_t, js::UnwrapUint16Array, JS_GetUint16ArrayData,
|
||||
js::GetUint16ArrayLengthAndData, JS_NewUint16Array>
|
||||
Uint16Array;
|
||||
typedef TypedArray<int32_t, JS_GetInt32ArrayData,
|
||||
JS_GetObjectAsInt32Array, JS_NewInt32Array>
|
||||
typedef TypedArray<int32_t, js::UnwrapInt32Array, JS_GetInt32ArrayData,
|
||||
js::GetInt32ArrayLengthAndData, JS_NewInt32Array>
|
||||
Int32Array;
|
||||
typedef TypedArray<uint32_t, JS_GetUint32ArrayData,
|
||||
JS_GetObjectAsUint32Array, JS_NewUint32Array>
|
||||
typedef TypedArray<uint32_t, js::UnwrapUint32Array, JS_GetUint32ArrayData,
|
||||
js::GetUint32ArrayLengthAndData, JS_NewUint32Array>
|
||||
Uint32Array;
|
||||
typedef TypedArray<float, JS_GetFloat32ArrayData,
|
||||
JS_GetObjectAsFloat32Array, JS_NewFloat32Array>
|
||||
typedef TypedArray<float, js::UnwrapFloat32Array, JS_GetFloat32ArrayData,
|
||||
js::GetFloat32ArrayLengthAndData, JS_NewFloat32Array>
|
||||
Float32Array;
|
||||
typedef TypedArray<double, JS_GetFloat64ArrayData,
|
||||
JS_GetObjectAsFloat64Array, JS_NewFloat64Array>
|
||||
typedef TypedArray<double, js::UnwrapFloat64Array, JS_GetFloat64ArrayData,
|
||||
js::GetFloat64ArrayLengthAndData, JS_NewFloat64Array>
|
||||
Float64Array;
|
||||
typedef TypedArray_base<uint8_t, JS_GetObjectAsArrayBufferView>
|
||||
typedef TypedArray_base<uint8_t, js::UnwrapArrayBufferView, js::GetArrayBufferViewLengthAndData>
|
||||
ArrayBufferView;
|
||||
typedef TypedArray<uint8_t, JS_GetArrayBufferData,
|
||||
JS_GetObjectAsArrayBuffer, JS_NewArrayBuffer>
|
||||
typedef TypedArray<uint8_t, js::UnwrapArrayBuffer, JS_GetArrayBufferData,
|
||||
js::GetArrayBufferLengthAndData, JS_NewArrayBuffer>
|
||||
ArrayBuffer;
|
||||
|
||||
// A class for converting an nsTArray to a TypedArray
|
||||
|
@ -26,12 +26,14 @@ CryptoBuffer::Assign(const SECItem* aItem)
|
||||
uint8_t*
|
||||
CryptoBuffer::Assign(const ArrayBuffer& aData)
|
||||
{
|
||||
aData.ComputeLengthAndData();
|
||||
return Assign(aData.Data(), aData.Length());
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
CryptoBuffer::Assign(const ArrayBufferView& aData)
|
||||
{
|
||||
aData.ComputeLengthAndData();
|
||||
return Assign(aData.Data(), aData.Length());
|
||||
}
|
||||
|
||||
|
@ -28,10 +28,12 @@ public:
|
||||
uint8_t* Assign(const OwningArrayBufferViewOrArrayBuffer& aData);
|
||||
|
||||
template<typename T,
|
||||
JSObject* UnboxArray(JSObject*, uint32_t*, T**)>
|
||||
uint8_t* Assign(const TypedArray_base<T, UnboxArray>& aData)
|
||||
JSObject* UnwrapArray(JSObject*),
|
||||
void GetLengthAndData(JSObject*, uint32_t*, T**)>
|
||||
uint8_t* Assign(const TypedArray_base<T, UnwrapArray, GetLengthAndData>& aArray)
|
||||
{
|
||||
return Assign(aData.Data(), aData.Length());
|
||||
aArray.ComputeLengthAndData();
|
||||
return Assign(aArray.Data(), aArray.Length());
|
||||
}
|
||||
|
||||
|
||||
|
@ -107,6 +107,7 @@ public:
|
||||
const TextDecodeOptions& aOptions,
|
||||
nsAString& aOutDecodedString,
|
||||
ErrorResult& aRv) {
|
||||
aView.ComputeLengthAndData();
|
||||
Decode(reinterpret_cast<char*>(aView.Data()), aView.Length(),
|
||||
aOptions.mStream, aOutDecodedString, aRv);
|
||||
}
|
||||
|
@ -756,6 +756,7 @@ already_AddRefed<nsIInputStream>
|
||||
LockedFile::GetInputStream(const ArrayBuffer& aValue, uint64_t* aInputLength,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
aValue.ComputeLengthAndData();
|
||||
const char* data = reinterpret_cast<const char*>(aValue.Data());
|
||||
uint32_t length = aValue.Length();
|
||||
|
||||
|
@ -112,9 +112,11 @@ Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions)
|
||||
str.Length());
|
||||
} else if (data.IsArrayBuffer()) {
|
||||
ArrayBuffer& buffer = data.GetAsArrayBuffer();
|
||||
buffer.ComputeLengthAndData();
|
||||
arrayData.AppendElements(buffer.Data(), buffer.Length());
|
||||
} else if (data.IsArrayBufferView()){
|
||||
ArrayBufferView& view = data.GetAsArrayBufferView();
|
||||
view.ComputeLengthAndData();
|
||||
arrayData.AppendElements(view.Data(), view.Length());
|
||||
} else {
|
||||
blobData = data.GetAsBlob();
|
||||
|
@ -3,7 +3,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const TIMEUPDATE_TIMEOUT_LENGTH = 10000;
|
||||
const ENDED_TIMEOUT_LENGTH = 10000;
|
||||
const ENDED_TIMEOUT_LENGTH = 30000;
|
||||
|
||||
/* Time we wait for the canplaythrough event to fire
|
||||
* Note: this needs to be at least 30s because the
|
||||
|
23
dom/smil/crashtests/1010681-1.svg
Normal file
23
dom/smil/crashtests/1010681-1.svg
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
class="reftest-wait">
|
||||
<script>
|
||||
<![CDATA[
|
||||
|
||||
function boom()
|
||||
{
|
||||
var animate =
|
||||
document.createElementNS("http://www.w3.org/2000/svg", "animate");
|
||||
animate.setAttribute("dur", "2s");
|
||||
document.documentElement.appendChild(animate);
|
||||
animate.targetElement;
|
||||
animate.requiredFeatures.insertItemBefore(0, 0);
|
||||
document.documentElement.setCurrentTime(4);
|
||||
document.documentElement.setCurrentTime(0);
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
|
||||
window.addEventListener("load", boom, false);
|
||||
|
||||
]]>
|
||||
</script></svg>
|
After Width: | Height: | Size: 608 B |
@ -51,3 +51,4 @@ load 697640-1.svg
|
||||
load 699325-1.svg
|
||||
load 709907-1.svg
|
||||
load 720103-1.svg
|
||||
load 1010681-1.svg
|
||||
|
@ -672,12 +672,10 @@ nsSMILAnimationController::SampleAnimation(AnimationElementPtrKey* aKey,
|
||||
NS_ENSURE_TRUE(aData, PL_DHASH_NEXT);
|
||||
|
||||
SVGAnimationElement* animElem = aKey->GetKey();
|
||||
if (animElem->PassesConditionalProcessingTests()) {
|
||||
SampleAnimationParams* params = static_cast<SampleAnimationParams*>(aData);
|
||||
SampleAnimationParams* params = static_cast<SampleAnimationParams*>(aData);
|
||||
|
||||
SampleTimedElement(animElem, params->mActiveContainers);
|
||||
AddAnimationToCompositorTable(animElem, params->mCompositorTable);
|
||||
}
|
||||
SampleTimedElement(animElem, params->mActiveContainers);
|
||||
AddAnimationToCompositorTable(animElem, params->mCompositorTable);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
@ -253,6 +253,7 @@ nsSMILTimedElement::nsSMILTimedElement()
|
||||
mSeekState(SEEK_NOT_SEEKING),
|
||||
mDeferIntervalUpdates(false),
|
||||
mDoDeferredUpdate(false),
|
||||
mIsDisabled(false),
|
||||
mDeleteCount(0),
|
||||
mUpdateIntervalRecursionDepth(0)
|
||||
{
|
||||
@ -521,6 +522,9 @@ nsSMILTimedElement::SetTimeClient(nsSMILAnimationFunction* aClient)
|
||||
void
|
||||
nsSMILTimedElement::SampleAt(nsSMILTime aContainerTime)
|
||||
{
|
||||
if (mIsDisabled)
|
||||
return;
|
||||
|
||||
// Milestones are cleared before a sample
|
||||
mPrevRegisteredMilestone = sMaxMilestone;
|
||||
|
||||
@ -530,6 +534,9 @@ nsSMILTimedElement::SampleAt(nsSMILTime aContainerTime)
|
||||
void
|
||||
nsSMILTimedElement::SampleEndAt(nsSMILTime aContainerTime)
|
||||
{
|
||||
if (mIsDisabled)
|
||||
return;
|
||||
|
||||
// Milestones are cleared before a sample
|
||||
mPrevRegisteredMilestone = sMaxMilestone;
|
||||
|
||||
@ -797,36 +804,38 @@ nsSMILTimedElement::Rewind()
|
||||
mSeekState == SEEK_BACKWARD_FROM_ACTIVE,
|
||||
"Rewind in the middle of a forwards seek?");
|
||||
|
||||
// Putting us in the startup state will ensure we skip doing any interval
|
||||
// updates
|
||||
mElementState = STATE_STARTUP;
|
||||
ClearIntervals();
|
||||
ClearTimingState(RemoveNonDynamic);
|
||||
RebuildTimingState(RemoveNonDynamic);
|
||||
|
||||
UnsetBeginSpec(RemoveNonDynamic);
|
||||
UnsetEndSpec(RemoveNonDynamic);
|
||||
|
||||
if (mClient) {
|
||||
mClient->Inactivate(false);
|
||||
}
|
||||
|
||||
if (mAnimationElement->HasAnimAttr(nsGkAtoms::begin)) {
|
||||
nsAutoString attValue;
|
||||
mAnimationElement->GetAnimAttr(nsGkAtoms::begin, attValue);
|
||||
SetBeginSpec(attValue, mAnimationElement, RemoveNonDynamic);
|
||||
}
|
||||
|
||||
if (mAnimationElement->HasAnimAttr(nsGkAtoms::end)) {
|
||||
nsAutoString attValue;
|
||||
mAnimationElement->GetAnimAttr(nsGkAtoms::end, attValue);
|
||||
SetEndSpec(attValue, mAnimationElement, RemoveNonDynamic);
|
||||
}
|
||||
|
||||
mPrevRegisteredMilestone = sMaxMilestone;
|
||||
RegisterMilestone();
|
||||
NS_ABORT_IF_FALSE(!mCurrentInterval,
|
||||
"Current interval is set at end of rewind");
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
bool
|
||||
RemoveAll(nsSMILInstanceTime* aInstanceTime)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsSMILTimedElement::SetIsDisabled(bool aIsDisabled)
|
||||
{
|
||||
if (mIsDisabled == aIsDisabled)
|
||||
return false;
|
||||
|
||||
if (aIsDisabled) {
|
||||
mIsDisabled = true;
|
||||
ClearTimingState(RemoveAll);
|
||||
} else {
|
||||
RebuildTimingState(RemoveAll);
|
||||
mIsDisabled = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
bool
|
||||
@ -1438,6 +1447,45 @@ nsSMILTimedElement::Reset()
|
||||
RemoveInstanceTimes(mEndInstances, resetEnd);
|
||||
}
|
||||
|
||||
void
|
||||
nsSMILTimedElement::ClearTimingState(RemovalTestFunction aRemove)
|
||||
{
|
||||
mElementState = STATE_STARTUP;
|
||||
ClearIntervals();
|
||||
|
||||
UnsetBeginSpec(aRemove);
|
||||
UnsetEndSpec(aRemove);
|
||||
|
||||
if (mClient) {
|
||||
mClient->Inactivate(false);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsSMILTimedElement::RebuildTimingState(RemovalTestFunction aRemove)
|
||||
{
|
||||
MOZ_ASSERT(mAnimationElement,
|
||||
"Attempting to enable a timed element not attached to an "
|
||||
"animation element");
|
||||
MOZ_ASSERT(mElementState == STATE_STARTUP,
|
||||
"Rebuilding timing state from non-startup state");
|
||||
|
||||
if (mAnimationElement->HasAnimAttr(nsGkAtoms::begin)) {
|
||||
nsAutoString attValue;
|
||||
mAnimationElement->GetAnimAttr(nsGkAtoms::begin, attValue);
|
||||
SetBeginSpec(attValue, mAnimationElement, aRemove);
|
||||
}
|
||||
|
||||
if (mAnimationElement->HasAnimAttr(nsGkAtoms::end)) {
|
||||
nsAutoString attValue;
|
||||
mAnimationElement->GetAnimAttr(nsGkAtoms::end, attValue);
|
||||
SetEndSpec(attValue, mAnimationElement, aRemove);
|
||||
}
|
||||
|
||||
mPrevRegisteredMilestone = sMaxMilestone;
|
||||
RegisterMilestone();
|
||||
}
|
||||
|
||||
void
|
||||
nsSMILTimedElement::DoPostSeek()
|
||||
{
|
||||
|
@ -239,6 +239,18 @@ public:
|
||||
*/
|
||||
void Rewind();
|
||||
|
||||
/**
|
||||
* Marks this element as disabled or not. If the element is disabled, it
|
||||
* will ignore any future samples and discard any accumulated timing state.
|
||||
*
|
||||
* This is used by SVG to "turn off" timed elements when the associated
|
||||
* animation element has failing conditional processing tests.
|
||||
*
|
||||
* Returns true if the disabled state of the timed element was changed
|
||||
* as a result of this call (i.e. it was not a redundant call).
|
||||
*/
|
||||
bool SetIsDisabled(bool aIsDisabled);
|
||||
|
||||
/**
|
||||
* Attempts to set an attribute on this timed element.
|
||||
*
|
||||
@ -423,6 +435,28 @@ protected:
|
||||
*/
|
||||
void Reset();
|
||||
|
||||
/**
|
||||
* Clears all accumulated timing state except for those instance times for
|
||||
* which aRemove does not return true.
|
||||
*
|
||||
* Unlike the Reset method which only clears instance times, this clears the
|
||||
* element's state, intervals (including current interval), and tells the
|
||||
* client animation function to stop applying a result. In effect, it returns
|
||||
* the element to its initial state but preserves any instance times excluded
|
||||
* by the passed-in function.
|
||||
*/
|
||||
void ClearTimingState(RemovalTestFunction aRemove);
|
||||
|
||||
/**
|
||||
* Recreates timing state by re-applying begin/end attributes specified on
|
||||
* the associated animation element.
|
||||
*
|
||||
* Note that this does not completely restore the information cleared by
|
||||
* ClearTimingState since it leaves the element in the startup state.
|
||||
* The element state will be updated on the next sample.
|
||||
*/
|
||||
void RebuildTimingState(RemovalTestFunction aRemove);
|
||||
|
||||
/**
|
||||
* Completes a seek operation by sending appropriate events and, in the case
|
||||
* of a backwards seek, updating the state of timing information that was
|
||||
@ -616,6 +650,7 @@ protected:
|
||||
bool mDeferIntervalUpdates;
|
||||
bool mDoDeferredUpdate; // Set if an update to the current interval was
|
||||
// requested while mDeferIntervalUpdates was set
|
||||
bool mIsDisabled;
|
||||
|
||||
// Stack-based helper class to call UpdateCurrentInterval when it is destroyed
|
||||
class AutoIntervalUpdater;
|
||||
|
@ -24,6 +24,7 @@ support-files =
|
||||
[test_smilCSSInvalidValues.xhtml]
|
||||
[test_smilCSSPaced.xhtml]
|
||||
[test_smilChangeAfterFrozen.xhtml]
|
||||
[test_smilConditionalProcessing.html]
|
||||
[test_smilContainerBinding.xhtml]
|
||||
[test_smilCrossContainer.xhtml]
|
||||
[test_smilDynamicDelayedBeginElement.xhtml]
|
||||
|
82
dom/smil/test/test_smilConditionalProcessing.html
Normal file
82
dom/smil/test/test_smilConditionalProcessing.html
Normal file
@ -0,0 +1,82 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test conditional processing tests applied to animations</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<svg id="svg" width="120px" height="120px"
|
||||
onload="this.pauseAnimations()">
|
||||
<circle r="50" fill="blue" id="circle">
|
||||
<set attributeName="cy" to="100" begin="0s" dur="100s" id="a"/>
|
||||
<set attributeName="cx" to="100" begin="a.end" dur="100s" id="b"/>
|
||||
</circle>
|
||||
</svg>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
var svg = document.getElementById("svg"),
|
||||
a = document.getElementById("a"),
|
||||
b = document.getElementById("b"),
|
||||
circle = document.getElementById("circle");
|
||||
|
||||
// Check initial state
|
||||
svg.setCurrentTime(50);
|
||||
is(a.getStartTime(), 0, "a has resolved start time at start");
|
||||
is(circle.cy.animVal.value, 100, "a is in effect at start");
|
||||
is(b.getStartTime(), 100, "b has resolved start time at start");
|
||||
|
||||
// Add a failing conditional processing test
|
||||
a.setAttribute("requiredFeatures",
|
||||
"http://www.w3.org/TR/SVGX/feature#SharksWithLasers");
|
||||
ok(hasUnresolvedStartTime(a),
|
||||
"a has unresolved start time with failing conditional processing test");
|
||||
is(circle.cy.animVal.value, 0,
|
||||
"a is not in effect with failing conditional processing test");
|
||||
ok(hasUnresolvedStartTime(b),
|
||||
"b has unresolved start time with failing conditional processing test on a");
|
||||
|
||||
// Remove failing conditional processing test
|
||||
a.removeAttribute("requiredFeatures");
|
||||
is(a.getStartTime(), 0, "a has resolved start time after removing test");
|
||||
is(circle.cy.animVal.value, 100, "a is in effect after removing test");
|
||||
is(b.getStartTime(), 100, "b has resolved start time after removing test on a");
|
||||
|
||||
// Add another failing conditional processing test
|
||||
// According to the spec, if a null string or empty string value is set for
|
||||
// the 'requiredFeatures' attribute, the attribute returns "false".
|
||||
a.setAttribute("requiredFeatures", "");
|
||||
|
||||
// Fast forward until |a| would have finished
|
||||
var endEventsReceived = 0;
|
||||
a.addEventListener("endEvent", function() { endEventsReceived++; });
|
||||
svg.setCurrentTime(150);
|
||||
is(endEventsReceived, 0,
|
||||
"a does not dispatch end events with failing condition processing test");
|
||||
is(circle.cx.animVal.value, 0,
|
||||
"b is not in effect with failing conditional processing test on a");
|
||||
|
||||
// Make test pass
|
||||
a.setAttribute("requiredFeatures",
|
||||
"http://www.w3.org/TR/SVG11/feature#Animation");
|
||||
is(circle.cx.animVal.value, 100,
|
||||
"b is in effect with passing conditional processing test on a");
|
||||
|
||||
function hasUnresolvedStartTime(anim) {
|
||||
// getStartTime throws INVALID_STATE_ERR when there is no current interval
|
||||
try {
|
||||
anim.getStartTime();
|
||||
return false;
|
||||
} catch(e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -21,7 +21,6 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || toolkit == 'android' #Bug
|
||||
[test_bug628069_1.html]
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
|
||||
[test_bug628069_2.html]
|
||||
[test_bug629535.html]
|
||||
[test_bug631440.html]
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
|
||||
[test_bug653364.html]
|
||||
@ -33,6 +32,7 @@ skip-if = buildapp == 'b2g' # b2g(clipboard undefined) b2g-debug(clipboard undef
|
||||
[test_domWindowUtils.html]
|
||||
[test_domWindowUtils_scrollXY.html]
|
||||
[test_domWindowUtils_scrollbarSize.html]
|
||||
[test_donottrack.html]
|
||||
[test_focus_legend_noparent.html]
|
||||
[test_focusrings.xul]
|
||||
skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT
|
||||
|
@ -1,46 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=629535
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 629535</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=629535">Mozilla Bug 629535</a>
|
||||
|
||||
<script type="application/javascript">
|
||||
|
||||
const dntPref = 'privacy.donottrackheader.enabled';
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
is(SpecialPowers.getBoolPref(dntPref), false,
|
||||
'DNT should be disabled by default');
|
||||
is(navigator.doNotTrack, 'unspecified',
|
||||
'navigator.doNotTrack should initially be "unspecified".');
|
||||
|
||||
SpecialPowers.pushPrefEnv({"clear": [[dntPref]]}, test1);
|
||||
|
||||
function test1() {
|
||||
is(navigator.doNotTrack, "unspecified", 'after clearing pref');
|
||||
SpecialPowers.pushPrefEnv({"set": [[dntPref, true]]}, test2);
|
||||
}
|
||||
|
||||
function test2() {
|
||||
is(navigator.doNotTrack, "yes", 'after setting pref to true');
|
||||
SpecialPowers.pushPrefEnv({"set": [[dntPref, false]]}, test3);
|
||||
}
|
||||
|
||||
function test3() {
|
||||
is(navigator.doNotTrack, "unspecified", 'after setting pref to false');
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
103
dom/tests/mochitest/general/test_donottrack.html
Normal file
103
dom/tests/mochitest/general/test_donottrack.html
Normal file
@ -0,0 +1,103 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=629535
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 629535</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=629535">Mozilla Bug 629535</a>
|
||||
|
||||
<script type="application/javascript">
|
||||
|
||||
const dntPref = 'privacy.donottrackheader.enabled';
|
||||
const dntValuePref = 'privacy.donottrackheader.value';
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var currentTestIdx = -1;
|
||||
var tests = [];
|
||||
function nextTest() {
|
||||
currentTestIdx++;
|
||||
if (currentTestIdx >= tests.length) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
tests[currentTestIdx]();
|
||||
}
|
||||
|
||||
tests.push(function testDefaultValues() {
|
||||
// The default pref values depend on the OS it seems.
|
||||
var isAndroid = !!navigator.userAgent.contains("Android");
|
||||
var isB2G = !isAndroid && /Mobile|Tablet/.test(navigator.userAgent);
|
||||
|
||||
is(SpecialPowers.getBoolPref(dntPref), false,
|
||||
'DNT should be disabled by default');
|
||||
is(navigator.doNotTrack, 'unspecified',
|
||||
'navigator.doNotTrack should initially be "unspecified".');
|
||||
is(SpecialPowers.getIntPref(dntValuePref), isB2G ? -1 : 1,
|
||||
'DNT value should be "1" by default');
|
||||
|
||||
nextTest();
|
||||
});
|
||||
|
||||
tests.push(function clearedEnabled() {
|
||||
SpecialPowers.pushPrefEnv({"clear": [[dntPref]]}, function() {
|
||||
is(navigator.doNotTrack, "unspecified", 'after clearing pref');
|
||||
nextTest();
|
||||
});
|
||||
});
|
||||
|
||||
tests.push(function setEnabled() {
|
||||
SpecialPowers.pushPrefEnv({"set": [[dntPref, true]]}, function() {
|
||||
is(navigator.doNotTrack, "1", 'after setting pref to true');
|
||||
nextTest();
|
||||
});
|
||||
});
|
||||
|
||||
tests.push(function clearedValue() {
|
||||
SpecialPowers.pushPrefEnv({"clear": [[dntValuePref]]}, function() {
|
||||
is(navigator.doNotTrack, "1", 'after clearing value pref');
|
||||
nextTest();
|
||||
});
|
||||
});
|
||||
|
||||
tests.push(function setValue0() {
|
||||
SpecialPowers.pushPrefEnv({"set": [[dntValuePref, 0]]}, function() {
|
||||
is(navigator.doNotTrack, "0", 'after setting value pref');
|
||||
nextTest();
|
||||
});
|
||||
});
|
||||
|
||||
tests.push(function setValue42() {
|
||||
SpecialPowers.pushPrefEnv({"set": [[dntValuePref, 42]]}, function() {
|
||||
is(navigator.doNotTrack, "1", 'after setting value pref');
|
||||
nextTest();
|
||||
});
|
||||
});
|
||||
|
||||
tests.push(function clearValueAgain() {
|
||||
SpecialPowers.pushPrefEnv({"clear": [[dntValuePref]]}, function() {
|
||||
is(navigator.doNotTrack, "1", 'after clearing value pref');
|
||||
nextTest();
|
||||
});
|
||||
});
|
||||
|
||||
tests.push(function setDisabled() {
|
||||
SpecialPowers.pushPrefEnv({"set": [[dntPref, false]]}, function() {
|
||||
is(navigator.doNotTrack, "unspecified", 'after setting pref to false');
|
||||
nextTest();
|
||||
});
|
||||
});
|
||||
|
||||
nextTest();
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -23,29 +23,36 @@ function expectSuccess(param) {
|
||||
is(result, true, 'vibrate(' + param + ') must succeed.');
|
||||
}
|
||||
|
||||
function testFailures() {
|
||||
function tests() {
|
||||
// Some edge cases that the bindings should handle for us.
|
||||
expectSuccess(null);
|
||||
expectSuccess(undefined);
|
||||
expectFailure(-1);
|
||||
// -1 will be converted to the highest unsigned long then clamped.
|
||||
expectSuccess(-1);
|
||||
expectSuccess('a');
|
||||
expectFailure([100, -1]);
|
||||
// -1 will be converted to the highest unsigned long then clamped.
|
||||
expectSuccess([100, -1]);
|
||||
expectSuccess([100, 'a']);
|
||||
|
||||
var maxVibrateMs = SpecialPowers.getIntPref('dom.vibrator.max_vibrate_ms');
|
||||
var maxVibrateListLen = SpecialPowers.getIntPref('dom.vibrator.max_vibrate_list_len');
|
||||
|
||||
// Make sure that these preferences are respected.
|
||||
expectFailure(maxVibrateMs + 1);
|
||||
expectFailure([maxVibrateMs + 1]);
|
||||
// If we pass a vibration pattern with a value higher than max_vibrate_ms or a
|
||||
// pattern longer than max_vibrate_list_len, the call should succeed but the
|
||||
// pattern should be modified to match the restrictions.
|
||||
|
||||
// Values will be clamped to dom.vibrator.max_vibrate_ms.
|
||||
expectSuccess(maxVibrateMs + 1);
|
||||
expectSuccess([maxVibrateMs + 1]);
|
||||
|
||||
var arr = [];
|
||||
for (var i = 0; i < maxVibrateListLen + 1; i++) {
|
||||
arr[i] = 0;
|
||||
}
|
||||
expectFailure(arr);
|
||||
}
|
||||
// The array will be truncated to have a length equal to dom.vibrator.max_vibrate_list_len.
|
||||
expectSuccess(arr);
|
||||
|
||||
|
||||
function testSuccesses() {
|
||||
expectSuccess(0);
|
||||
expectSuccess([]);
|
||||
expectSuccess('1000');
|
||||
@ -68,15 +75,13 @@ var origVibratorEnabled = SpecialPowers.getBoolPref('dom.vibrator.enabled');
|
||||
// Test with the vibrator pref enabled.
|
||||
try {
|
||||
SpecialPowers.setBoolPref('dom.vibrator.enabled', true);
|
||||
testFailures();
|
||||
testSuccesses();
|
||||
tests();
|
||||
|
||||
// Everything should be the same when the vibrator is disabled -- in
|
||||
// particular, a disabled vibrator shouldn't eat failures we'd otherwise
|
||||
// observe.
|
||||
SpecialPowers.setBoolPref('dom.vibrator.enabled', false);
|
||||
testFailures();
|
||||
testSuccesses();
|
||||
tests();
|
||||
}
|
||||
finally {
|
||||
SpecialPowers.setBoolPref('dom.vibrator.enabled', origVibratorEnabled);
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -73,6 +73,13 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
Matrix &PostTranslate(Float aX, Float aY)
|
||||
{
|
||||
_31 += aX;
|
||||
_32 += aY;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Matrix &Rotate(Float aAngle)
|
||||
{
|
||||
return *this = Matrix::Rotation(aAngle) * *this;
|
||||
|
@ -2699,19 +2699,6 @@ public:
|
||||
|
||||
GLint GetMaxTextureImageSize() { return mMaxTextureImageSize; }
|
||||
|
||||
public:
|
||||
/**
|
||||
* Context reset constants.
|
||||
* These are used to determine who is guilty when a context reset
|
||||
* happens.
|
||||
*/
|
||||
enum ContextResetARB {
|
||||
CONTEXT_NO_ERROR = 0,
|
||||
CONTEXT_GUILTY_CONTEXT_RESET_ARB = 0x8253,
|
||||
CONTEXT_INNOCENT_CONTEXT_RESET_ARB = 0x8254,
|
||||
CONTEXT_UNKNOWN_CONTEXT_RESET_ARB = 0x8255
|
||||
};
|
||||
|
||||
public:
|
||||
std::map<GLuint, SharedSurface_GL*> mFBOMapping;
|
||||
|
||||
|
@ -238,7 +238,15 @@ public:
|
||||
* If this method is not used, or we pass in nullptr, we target the compositor's
|
||||
* usual swap chain and render to the screen.
|
||||
*/
|
||||
virtual void SetTargetContext(gfx::DrawTarget* aTarget) = 0;
|
||||
void SetTargetContext(gfx::DrawTarget* aTarget, const nsIntRect& aRect)
|
||||
{
|
||||
mTarget = aTarget;
|
||||
mTargetBounds = aRect;
|
||||
}
|
||||
void ClearTargetContext()
|
||||
{
|
||||
mTarget = nullptr;
|
||||
}
|
||||
|
||||
typedef uint32_t MakeCurrentFlags;
|
||||
static const MakeCurrentFlags ForceMakeCurrent = 0x1;
|
||||
@ -522,6 +530,9 @@ protected:
|
||||
|
||||
virtual gfx::IntSize GetWidgetSize() const = 0;
|
||||
|
||||
RefPtr<gfx::DrawTarget> mTarget;
|
||||
nsIntRect mTargetBounds;
|
||||
|
||||
private:
|
||||
static LayersBackend sBackend;
|
||||
|
||||
|
@ -59,12 +59,14 @@ AddTransformedRegion(nsIntRegion& aDest, const nsIntRegion& aSource, const gfx3D
|
||||
while ((r = iter.Next())) {
|
||||
aDest.Or(aDest, TransformRect(*r, aTransform));
|
||||
}
|
||||
aDest.SimplifyOutward(20);
|
||||
}
|
||||
|
||||
static void
|
||||
AddRegion(nsIntRegion& aDest, const nsIntRegion& aSource)
|
||||
{
|
||||
aDest.Or(aDest, aSource);
|
||||
aDest.SimplifyOutward(20);
|
||||
}
|
||||
|
||||
static nsIntRegion
|
||||
|
@ -291,7 +291,7 @@ BasicCompositor::DrawQuad(const gfx::Rect& aRect,
|
||||
transformBounds.MoveTo(0, 0);
|
||||
}
|
||||
|
||||
newTransform.Translate(-offset.x, -offset.y);
|
||||
newTransform.PostTranslate(-offset.x, -offset.y);
|
||||
buffer->SetTransform(newTransform);
|
||||
|
||||
RefPtr<SourceSurface> sourceMask;
|
||||
@ -412,7 +412,7 @@ BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion,
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCopyTarget) {
|
||||
if (mTarget) {
|
||||
// If we have a copy target, then we don't have a widget-provided mDrawTarget (currently). Create a dummy
|
||||
// placeholder so that CreateRenderTarget() works.
|
||||
mDrawTarget = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(1,1), SurfaceFormat::B8G8R8A8);
|
||||
@ -424,7 +424,7 @@ BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion,
|
||||
}
|
||||
|
||||
// Setup an intermediate render target to buffer all compositing. We will
|
||||
// copy this into mDrawTarget (the widget), and/or mCopyTarget in EndFrame()
|
||||
// copy this into mDrawTarget (the widget), and/or mTarget in EndFrame()
|
||||
RefPtr<CompositingRenderTarget> target = CreateRenderTarget(mInvalidRect, INIT_MODE_CLEAR);
|
||||
SetRenderTarget(target);
|
||||
|
||||
@ -471,7 +471,9 @@ BasicCompositor::EndFrame()
|
||||
// Note: Most platforms require us to buffer drawing to the widget surface.
|
||||
// That's why we don't draw to mDrawTarget directly.
|
||||
RefPtr<SourceSurface> source = mRenderTarget->mDrawTarget->Snapshot();
|
||||
RefPtr<DrawTarget> dest(mCopyTarget ? mCopyTarget : mDrawTarget);
|
||||
RefPtr<DrawTarget> dest(mTarget ? mTarget : mDrawTarget);
|
||||
|
||||
nsIntPoint offset = mTarget ? mTargetBounds.TopLeft() : nsIntPoint();
|
||||
|
||||
// The source DrawTarget is clipped to the invalidation region, so we have
|
||||
// to copy the individual rectangles in the region or else we'll draw blank
|
||||
@ -480,9 +482,9 @@ BasicCompositor::EndFrame()
|
||||
for (const nsIntRect *r = iter.Next(); r; r = iter.Next()) {
|
||||
dest->CopySurface(source,
|
||||
IntRect(r->x - mInvalidRect.x, r->y - mInvalidRect.y, r->width, r->height),
|
||||
IntPoint(r->x, r->y));
|
||||
IntPoint(r->x - offset.x, r->y - offset.y));
|
||||
}
|
||||
if (!mCopyTarget) {
|
||||
if (!mTarget) {
|
||||
mWidget->EndRemoteDrawing();
|
||||
}
|
||||
|
||||
|
@ -103,10 +103,6 @@ public:
|
||||
virtual bool CanUseCanvasLayerForSize(const gfx::IntSize &aSize) MOZ_OVERRIDE { return true; }
|
||||
virtual int32_t GetMaxTextureSize() const MOZ_OVERRIDE { return INT32_MAX; }
|
||||
virtual void SetDestinationSurfaceSize(const gfx::IntSize& aSize) MOZ_OVERRIDE { }
|
||||
virtual void SetTargetContext(gfx::DrawTarget* aTarget) MOZ_OVERRIDE
|
||||
{
|
||||
mCopyTarget = aTarget;
|
||||
}
|
||||
|
||||
virtual void SetScreenRenderOffset(const ScreenPoint& aOffset) MOZ_OVERRIDE {
|
||||
}
|
||||
@ -138,9 +134,6 @@ private:
|
||||
RefPtr<gfx::DrawTarget> mDrawTarget;
|
||||
// The current render target for drawing
|
||||
RefPtr<BasicCompositingRenderTarget> mRenderTarget;
|
||||
// An optional destination target to copy the results
|
||||
// to after drawing is completed.
|
||||
RefPtr<gfx::DrawTarget> mCopyTarget;
|
||||
|
||||
gfx::IntRect mInvalidRect;
|
||||
nsIntRegion mInvalidRegion;
|
||||
|
@ -117,7 +117,7 @@ FillRectWithMask(DrawTarget* aDT,
|
||||
|
||||
Matrix transform = oldTransform * inverseMask;
|
||||
if (aSurfaceTransform) {
|
||||
transform = transform * (*aSurfaceTransform);
|
||||
transform = (*aSurfaceTransform) * transform;
|
||||
}
|
||||
|
||||
SurfacePattern source(aSurface, aExtendMode, transform, aFilter);
|
||||
|
@ -53,6 +53,7 @@ public:
|
||||
NS_ASSERTION(BasicManager()->InConstruction(),
|
||||
"Can only set properties in construction phase");
|
||||
mInvalidRegion.Or(mInvalidRegion, aRegion);
|
||||
mInvalidRegion.SimplifyOutward(20);
|
||||
mValidRegion.Sub(mValidRegion, mInvalidRegion);
|
||||
}
|
||||
|
||||
|
@ -337,6 +337,14 @@ ClientLayerManager::RunOverfillCallback(const uint32_t aOverfill)
|
||||
mOverfillCallbacks.Clear();
|
||||
}
|
||||
|
||||
static nsIntRect
|
||||
ToOutsideIntRect(const gfxRect &aRect)
|
||||
{
|
||||
gfxRect r = aRect;
|
||||
r.RoundOut();
|
||||
return nsIntRect(r.X(), r.Y(), r.Width(), r.Height());
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::MakeSnapshotIfRequired()
|
||||
{
|
||||
@ -345,27 +353,22 @@ ClientLayerManager::MakeSnapshotIfRequired()
|
||||
}
|
||||
if (mWidget) {
|
||||
if (CompositorChild* remoteRenderer = GetRemoteRenderer()) {
|
||||
nsIntRect bounds;
|
||||
mWidget->GetBounds(bounds);
|
||||
IntSize widgetSize = bounds.Size().ToIntSize();
|
||||
SurfaceDescriptor inSnapshot, snapshot;
|
||||
if (mForwarder->AllocSurfaceDescriptor(widgetSize,
|
||||
nsIntRect bounds = ToOutsideIntRect(mShadowTarget->GetClipExtents());
|
||||
SurfaceDescriptor inSnapshot;
|
||||
if (!bounds.IsEmpty() &&
|
||||
mForwarder->AllocSurfaceDescriptor(bounds.Size().ToIntSize(),
|
||||
gfxContentType::COLOR_ALPHA,
|
||||
&inSnapshot) &&
|
||||
// The compositor will usually reuse |snapshot| and return
|
||||
// it through |outSnapshot|, but if it doesn't, it's
|
||||
// responsible for freeing |snapshot|.
|
||||
remoteRenderer->SendMakeSnapshot(inSnapshot, &snapshot)) {
|
||||
RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(snapshot);
|
||||
remoteRenderer->SendMakeSnapshot(inSnapshot, bounds)) {
|
||||
RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(inSnapshot);
|
||||
DrawTarget* dt = mShadowTarget->GetDrawTarget();
|
||||
Rect widgetRect(Point(0, 0), Size(widgetSize.width, widgetSize.height));
|
||||
dt->DrawSurface(surf, widgetRect, widgetRect,
|
||||
Rect dstRect(bounds.x, bounds.y, bounds.width, bounds.height);
|
||||
Rect srcRect(0, 0, bounds.width, bounds.height);
|
||||
dt->DrawSurface(surf, dstRect, srcRect,
|
||||
DrawSurfaceOptions(),
|
||||
DrawOptions(1.0f, CompositionOp::OP_OVER));
|
||||
}
|
||||
if (IsSurfaceDescriptorValid(snapshot)) {
|
||||
mForwarder->DestroySharedSurface(&snapshot);
|
||||
}
|
||||
mForwarder->DestroySharedSurface(&inSnapshot);
|
||||
}
|
||||
}
|
||||
mShadowTarget = nullptr;
|
||||
|
@ -60,6 +60,7 @@ public:
|
||||
NS_ASSERTION(ClientManager()->InConstruction(),
|
||||
"Can only set properties in construction phase");
|
||||
mInvalidRegion.Or(mInvalidRegion, aRegion);
|
||||
mInvalidRegion.SimplifyOutward(20);
|
||||
mValidRegion.Sub(mValidRegion, mInvalidRegion);
|
||||
}
|
||||
|
||||
|
@ -430,29 +430,36 @@ SampleAnimations(Layer* aLayer, TimeStamp aPoint)
|
||||
continue;
|
||||
}
|
||||
|
||||
double numIterations = animation.numIterations() != -1 ?
|
||||
animation.numIterations() : NS_IEEEPositiveInfinity();
|
||||
double positionInIteration =
|
||||
ElementAnimations::GetPositionInIteration(elapsedDuration,
|
||||
animation.duration(),
|
||||
numIterations,
|
||||
animation.direction());
|
||||
AnimationTiming timing;
|
||||
timing.mIterationDuration = animation.duration();
|
||||
timing.mIterationCount = animation.iterationCount();
|
||||
timing.mDirection = animation.direction();
|
||||
// Animations typically only run on the compositor during their active
|
||||
// interval but if we end up sampling them outside that range (for
|
||||
// example, while they are waiting to be removed) we currently just
|
||||
// assume that we should fill.
|
||||
timing.mFillMode = NS_STYLE_ANIMATION_FILL_MODE_BOTH;
|
||||
|
||||
NS_ABORT_IF_FALSE(0.0 <= positionInIteration &&
|
||||
positionInIteration <= 1.0,
|
||||
"position should be in [0-1]");
|
||||
ComputedTiming computedTiming =
|
||||
ElementAnimation::GetComputedTimingAt(elapsedDuration, timing);
|
||||
|
||||
NS_ABORT_IF_FALSE(0.0 <= computedTiming.mTimeFraction &&
|
||||
computedTiming.mTimeFraction <= 1.0,
|
||||
"time fraction should be in [0-1]");
|
||||
|
||||
int segmentIndex = 0;
|
||||
AnimationSegment* segment = animation.segments().Elements();
|
||||
while (segment->endPortion() < positionInIteration) {
|
||||
while (segment->endPortion() < computedTiming.mTimeFraction) {
|
||||
++segment;
|
||||
++segmentIndex;
|
||||
}
|
||||
|
||||
double positionInSegment = (positionInIteration - segment->startPortion()) /
|
||||
(segment->endPortion() - segment->startPortion());
|
||||
double positionInSegment =
|
||||
(computedTiming.mTimeFraction - segment->startPortion()) /
|
||||
(segment->endPortion() - segment->startPortion());
|
||||
|
||||
double portion = animData.mFunctions[segmentIndex]->GetValue(positionInSegment);
|
||||
double portion =
|
||||
animData.mFunctions[segmentIndex]->GetValue(positionInSegment);
|
||||
|
||||
// interpolate the property
|
||||
Animatable interpolatedValue;
|
||||
|
@ -161,7 +161,7 @@ LayerManagerComposite::BeginTransaction()
|
||||
}
|
||||
|
||||
void
|
||||
LayerManagerComposite::BeginTransactionWithDrawTarget(DrawTarget* aTarget)
|
||||
LayerManagerComposite::BeginTransactionWithDrawTarget(DrawTarget* aTarget, const nsIntRect& aRect)
|
||||
{
|
||||
mInTransaction = true;
|
||||
|
||||
@ -180,8 +180,9 @@ LayerManagerComposite::BeginTransactionWithDrawTarget(DrawTarget* aTarget)
|
||||
}
|
||||
|
||||
mIsCompositorReady = true;
|
||||
mCompositor->SetTargetContext(aTarget);
|
||||
mCompositor->SetTargetContext(aTarget, aRect);
|
||||
mTarget = aTarget;
|
||||
mTargetBounds = aRect;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -223,12 +224,13 @@ LayerManagerComposite::EndTransaction(DrawThebesLayerCallback aCallback,
|
||||
}
|
||||
|
||||
if (mRoot && mClonedLayerTreeProperties) {
|
||||
MOZ_ASSERT(!mTarget);
|
||||
nsIntRegion invalid =
|
||||
mClonedLayerTreeProperties->ComputeDifferences(mRoot, nullptr, &mGeometryChanged);
|
||||
mClonedLayerTreeProperties = nullptr;
|
||||
|
||||
mInvalidRegion.Or(mInvalidRegion, invalid);
|
||||
} else {
|
||||
} else if (!mTarget) {
|
||||
mInvalidRegion.Or(mInvalidRegion, mRenderBounds);
|
||||
}
|
||||
|
||||
@ -247,7 +249,7 @@ LayerManagerComposite::EndTransaction(DrawThebesLayerCallback aCallback,
|
||||
mGeometryChanged = false;
|
||||
}
|
||||
|
||||
mCompositor->SetTargetContext(nullptr);
|
||||
mCompositor->ClearTargetContext();
|
||||
mTarget = nullptr;
|
||||
|
||||
#ifdef MOZ_LAYERS_HAVE_LOG
|
||||
@ -405,6 +407,15 @@ LayerManagerComposite::Render()
|
||||
}
|
||||
}
|
||||
|
||||
nsIntRegion invalid;
|
||||
if (mTarget) {
|
||||
invalid = mTargetBounds;
|
||||
} else {
|
||||
invalid = mInvalidRegion;
|
||||
// Reset the invalid region now that we've begun compositing.
|
||||
mInvalidRegion.SetEmpty();
|
||||
}
|
||||
|
||||
nsIntRect clipRect;
|
||||
Rect bounds(mRenderBounds.x, mRenderBounds.y, mRenderBounds.width, mRenderBounds.height);
|
||||
Rect actualBounds;
|
||||
@ -415,16 +426,13 @@ LayerManagerComposite::Render()
|
||||
clipRect = *mRoot->GetClipRect();
|
||||
WorldTransformRect(clipRect);
|
||||
Rect rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
|
||||
mCompositor->BeginFrame(mInvalidRegion, &rect, mWorldMatrix, bounds, nullptr, &actualBounds);
|
||||
mCompositor->BeginFrame(invalid, &rect, mWorldMatrix, bounds, nullptr, &actualBounds);
|
||||
} else {
|
||||
gfx::Rect rect;
|
||||
mCompositor->BeginFrame(mInvalidRegion, nullptr, mWorldMatrix, bounds, &rect, &actualBounds);
|
||||
mCompositor->BeginFrame(invalid, nullptr, mWorldMatrix, bounds, &rect, &actualBounds);
|
||||
clipRect = nsIntRect(rect.x, rect.y, rect.width, rect.height);
|
||||
}
|
||||
|
||||
// Reset the invalid region now that we've begun compositing.
|
||||
mInvalidRegion.SetEmpty();
|
||||
|
||||
if (actualBounds.IsEmpty()) {
|
||||
mCompositor->GetWidget()->PostRender(this);
|
||||
return;
|
||||
|
@ -111,7 +111,7 @@ public:
|
||||
{
|
||||
MOZ_CRASH("Use BeginTransactionWithDrawTarget");
|
||||
}
|
||||
void BeginTransactionWithDrawTarget(gfx::DrawTarget* aTarget);
|
||||
void BeginTransactionWithDrawTarget(gfx::DrawTarget* aTarget, const nsIntRect& aRect);
|
||||
|
||||
virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) MOZ_OVERRIDE;
|
||||
virtual void EndTransaction(DrawThebesLayerCallback aCallback,
|
||||
@ -271,6 +271,7 @@ private:
|
||||
* Context target, nullptr when drawing directly to our swap chain.
|
||||
*/
|
||||
RefPtr<gfx::DrawTarget> mTarget;
|
||||
nsIntRect mTargetBounds;
|
||||
|
||||
gfx::Matrix mWorldMatrix;
|
||||
nsIntRegion mInvalidRegion;
|
||||
|
@ -47,7 +47,7 @@ void
|
||||
ThebesLayerD3D10::InvalidateRegion(const nsIntRegion &aRegion)
|
||||
{
|
||||
mInvalidRegion.Or(mInvalidRegion, aRegion);
|
||||
mInvalidRegion.SimplifyOutward(10);
|
||||
mInvalidRegion.SimplifyOutward(20);
|
||||
mValidRegion.Sub(mValidRegion, mInvalidRegion);
|
||||
}
|
||||
|
||||
|
@ -1019,7 +1019,7 @@ CompositorD3D11::PaintToTarget()
|
||||
SurfaceFormat::B8G8R8A8);
|
||||
mTarget->CopySurface(sourceSurface,
|
||||
IntRect(0, 0, bbDesc.Width, bbDesc.Height),
|
||||
IntPoint());
|
||||
IntPoint(-mTargetBounds.x, -mTargetBounds.y));
|
||||
mTarget->Flush();
|
||||
mContext->Unmap(readTexture, 0);
|
||||
}
|
||||
|
@ -55,11 +55,6 @@ public:
|
||||
virtual bool CanUseCanvasLayerForSize(const gfx::IntSize& aSize) MOZ_OVERRIDE;
|
||||
virtual int32_t GetMaxTextureSize() const MOZ_FINAL;
|
||||
|
||||
virtual void SetTargetContext(gfx::DrawTarget* aTarget) MOZ_OVERRIDE
|
||||
{
|
||||
mTarget = aTarget;
|
||||
}
|
||||
|
||||
virtual void MakeCurrent(MakeCurrentFlags aFlags = 0) MOZ_OVERRIDE {}
|
||||
|
||||
virtual TemporaryRef<CompositingRenderTarget>
|
||||
@ -168,8 +163,6 @@ private:
|
||||
|
||||
DeviceAttachmentsD3D11* mAttachments;
|
||||
|
||||
RefPtr<gfx::DrawTarget> mTarget;
|
||||
|
||||
nsIWidget* mWidget;
|
||||
|
||||
nsIntSize mSize;
|
||||
|
@ -743,7 +743,7 @@ CompositorD3D9::PaintToTarget()
|
||||
SurfaceFormat::B8G8R8A8);
|
||||
mTarget->CopySurface(sourceSurface,
|
||||
IntRect(0, 0, desc.Width, desc.Height),
|
||||
IntPoint());
|
||||
IntPoint(-mTargetBounds.x, -mTargetBounds.y));
|
||||
mTarget->Flush();
|
||||
destSurf->UnlockRect();
|
||||
}
|
||||
|
@ -32,11 +32,6 @@ public:
|
||||
virtual bool CanUseCanvasLayerForSize(const gfx::IntSize &aSize) MOZ_OVERRIDE;
|
||||
virtual int32_t GetMaxTextureSize() const MOZ_FINAL;
|
||||
|
||||
virtual void SetTargetContext(gfx::DrawTarget *aTarget) MOZ_OVERRIDE
|
||||
{
|
||||
mTarget = aTarget;
|
||||
}
|
||||
|
||||
virtual void MakeCurrent(MakeCurrentFlags aFlags = 0) MOZ_OVERRIDE {}
|
||||
|
||||
virtual TemporaryRef<CompositingRenderTarget>
|
||||
@ -168,11 +163,6 @@ private:
|
||||
/* Widget associated with this layer manager */
|
||||
nsIWidget *mWidget;
|
||||
|
||||
/*
|
||||
* Context target, nullptr when drawing directly to our swap chain.
|
||||
*/
|
||||
RefPtr<gfx::DrawTarget> mTarget;
|
||||
|
||||
RefPtr<CompositingRenderTargetD3D9> mDefaultRT;
|
||||
RefPtr<CompositingRenderTargetD3D9> mCurrentRT;
|
||||
|
||||
|
@ -50,6 +50,7 @@ void
|
||||
ThebesLayerD3D9::InvalidateRegion(const nsIntRegion &aRegion)
|
||||
{
|
||||
mInvalidRegion.Or(mInvalidRegion, aRegion);
|
||||
mInvalidRegion.SimplifyOutward(20);
|
||||
mValidRegion.Sub(mValidRegion, mInvalidRegion);
|
||||
}
|
||||
|
||||
|
@ -328,11 +328,10 @@ CompositorParent::RecvResume()
|
||||
|
||||
bool
|
||||
CompositorParent::RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
|
||||
SurfaceDescriptor* aOutSnapshot)
|
||||
const nsIntRect& aRect)
|
||||
{
|
||||
RefPtr<DrawTarget> target = GetDrawTargetForDescriptor(aInSnapshot, gfx::BackendType::CAIRO);
|
||||
ForceComposeToTarget(target);
|
||||
*aOutSnapshot = aInSnapshot;
|
||||
ForceComposeToTarget(target, &aRect);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -609,7 +608,7 @@ CompositorParent::Composite()
|
||||
}
|
||||
|
||||
void
|
||||
CompositorParent::CompositeToTarget(DrawTarget* aTarget)
|
||||
CompositorParent::CompositeToTarget(DrawTarget* aTarget, const nsIntRect* aRect)
|
||||
{
|
||||
profiler_tracing("Paint", "Composite", TRACING_INTERVAL_START);
|
||||
PROFILER_LABEL("CompositorParent", "Composite");
|
||||
@ -639,7 +638,7 @@ CompositorParent::CompositeToTarget(DrawTarget* aTarget)
|
||||
AutoResolveRefLayers resolve(mCompositionManager);
|
||||
|
||||
if (aTarget) {
|
||||
mLayerManager->BeginTransactionWithDrawTarget(aTarget);
|
||||
mLayerManager->BeginTransactionWithDrawTarget(aTarget, *aRect);
|
||||
} else {
|
||||
mLayerManager->BeginTransaction();
|
||||
}
|
||||
@ -720,13 +719,13 @@ CompositorParent::DidComposite()
|
||||
}
|
||||
|
||||
void
|
||||
CompositorParent::ForceComposeToTarget(DrawTarget* aTarget)
|
||||
CompositorParent::ForceComposeToTarget(DrawTarget* aTarget, const nsIntRect* aRect)
|
||||
{
|
||||
PROFILER_LABEL("CompositorParent", "ForceComposeToTarget");
|
||||
AutoRestore<bool> override(mOverrideComposeReadiness);
|
||||
mOverrideComposeReadiness = true;
|
||||
|
||||
CompositeToTarget(aTarget);
|
||||
CompositeToTarget(aTarget, aRect);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1136,7 +1135,7 @@ public:
|
||||
virtual bool RecvResume() MOZ_OVERRIDE { return true; }
|
||||
virtual bool RecvNotifyChildCreated(const uint64_t& child) MOZ_OVERRIDE;
|
||||
virtual bool RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
|
||||
SurfaceDescriptor* aOutSnapshot)
|
||||
const nsIntRect& aRect)
|
||||
{ return true; }
|
||||
virtual bool RecvFlushRendering() MOZ_OVERRIDE { return true; }
|
||||
virtual bool RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) { return true; }
|
||||
|
@ -86,7 +86,7 @@ public:
|
||||
virtual bool RecvResume() MOZ_OVERRIDE;
|
||||
virtual bool RecvNotifyChildCreated(const uint64_t& child) MOZ_OVERRIDE;
|
||||
virtual bool RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
|
||||
SurfaceDescriptor* aOutSnapshot) MOZ_OVERRIDE;
|
||||
const nsIntRect& aRect) MOZ_OVERRIDE;
|
||||
virtual bool RecvFlushRendering() MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) MOZ_OVERRIDE;
|
||||
@ -254,8 +254,8 @@ private:
|
||||
virtual bool DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) MOZ_OVERRIDE;
|
||||
virtual void ScheduleTask(CancelableTask*, int);
|
||||
void Composite();
|
||||
void CompositeToTarget(gfx::DrawTarget* aTarget);
|
||||
void ForceComposeToTarget(gfx::DrawTarget* aTarget);
|
||||
void CompositeToTarget(gfx::DrawTarget* aTarget, const nsIntRect* aRect = nullptr);
|
||||
void ForceComposeToTarget(gfx::DrawTarget* aTarget, const nsIntRect* aRect = nullptr);
|
||||
|
||||
void SetEGLSurfaceSize(int width, int height);
|
||||
|
||||
|
@ -178,8 +178,10 @@ struct Animation {
|
||||
// startTime, the direction, the duration, and the current time.
|
||||
// The segments must uniquely cover the portion from 0.0 to 1.0
|
||||
AnimationSegment[] segments;
|
||||
// How many times to repeat the animation. -1 means "forever".
|
||||
float numIterations;
|
||||
// Number of times to repeat the animation, including positive infinity.
|
||||
// Values <= 0 mean the animation will not play (although events are still
|
||||
// dispatched on the main thread).
|
||||
float iterationCount;
|
||||
// This uses the NS_STYLE_ANIMATION_DIRECTION_* constants.
|
||||
int32_t direction;
|
||||
nsCSSProperty property;
|
||||
|
@ -72,8 +72,7 @@ parent:
|
||||
//
|
||||
// NB: this message will result in animations, transforms, effects,
|
||||
// and so forth being interpolated. That's what we want to happen.
|
||||
sync MakeSnapshot(SurfaceDescriptor inSnapshot)
|
||||
returns (SurfaceDescriptor outSnapshot);
|
||||
sync MakeSnapshot(SurfaceDescriptor inSnapshot, nsIntRect dirtyRect);
|
||||
|
||||
// Make sure any pending composites are started immediately and
|
||||
// block until they are completed.
|
||||
|
@ -1250,7 +1250,7 @@ CompositorOGL::EndFrame()
|
||||
mWidget->GetBounds(rect);
|
||||
}
|
||||
RefPtr<DrawTarget> target = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(rect.width, rect.height), SurfaceFormat::B8G8R8A8);
|
||||
CopyToTarget(target, mCurrentRenderTarget->GetTransform());
|
||||
CopyToTarget(target, nsIntPoint(), mCurrentRenderTarget->GetTransform());
|
||||
|
||||
WriteSnapshotToDumpFile(this, target);
|
||||
}
|
||||
@ -1261,7 +1261,7 @@ CompositorOGL::EndFrame()
|
||||
LayerScope::EndFrame(mGLContext);
|
||||
|
||||
if (mTarget) {
|
||||
CopyToTarget(mTarget, mCurrentRenderTarget->GetTransform());
|
||||
CopyToTarget(mTarget, mTargetBounds.TopLeft(), mCurrentRenderTarget->GetTransform());
|
||||
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
||||
mCurrentRenderTarget = nullptr;
|
||||
return;
|
||||
@ -1360,7 +1360,7 @@ CompositorOGL::EndFrameForExternalComposition(const gfx::Matrix& aTransform)
|
||||
// This lets us reftest and screenshot content rendered externally
|
||||
if (mTarget) {
|
||||
MakeCurrent();
|
||||
CopyToTarget(mTarget, aTransform);
|
||||
CopyToTarget(mTarget, mTargetBounds.TopLeft(), aTransform);
|
||||
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
if (mTexturePool) {
|
||||
@ -1388,7 +1388,7 @@ CompositorOGL::SetDestinationSurfaceSize(const gfx::IntSize& aSize)
|
||||
}
|
||||
|
||||
void
|
||||
CompositorOGL::CopyToTarget(DrawTarget *aTarget, const gfx::Matrix& aTransform)
|
||||
CompositorOGL::CopyToTarget(DrawTarget* aTarget, const nsIntPoint& aTopLeft, const gfx::Matrix& aTransform)
|
||||
{
|
||||
IntRect rect;
|
||||
if (mUseExternalSurfaceSize) {
|
||||
@ -1423,6 +1423,8 @@ CompositorOGL::CopyToTarget(DrawTarget *aTarget, const gfx::Matrix& aTransform)
|
||||
glToCairoTransform.Scale(1.0, -1.0);
|
||||
glToCairoTransform.Translate(0.0, -height);
|
||||
|
||||
glToCairoTransform.PostTranslate(-aTopLeft.x, -aTopLeft.y);
|
||||
|
||||
Matrix oldMatrix = aTarget->GetTransform();
|
||||
aTarget->SetTransform(glToCairoTransform);
|
||||
Rect floatRect = Rect(rect.x, rect.y, rect.width, rect.height);
|
||||
|
@ -235,11 +235,6 @@ public:
|
||||
|
||||
virtual void MakeCurrent(MakeCurrentFlags aFlags = 0) MOZ_OVERRIDE;
|
||||
|
||||
virtual void SetTargetContext(gfx::DrawTarget* aTarget) MOZ_OVERRIDE
|
||||
{
|
||||
mTarget = aTarget;
|
||||
}
|
||||
|
||||
virtual void PrepareViewport(const gfx::IntSize& aSize,
|
||||
const gfx::Matrix& aWorldTransform) MOZ_OVERRIDE;
|
||||
|
||||
@ -279,11 +274,6 @@ private:
|
||||
return gfx::ToIntSize(mWidgetSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Context target, nullptr when drawing directly to our swap chain.
|
||||
*/
|
||||
RefPtr<gfx::DrawTarget> mTarget;
|
||||
|
||||
/** Widget associated with this compositor */
|
||||
nsIWidget *mWidget;
|
||||
nsIntSize mWidgetSize;
|
||||
@ -382,7 +372,7 @@ private:
|
||||
* Copies the content of our backbuffer to the set transaction target.
|
||||
* Does not restore the target FBO, so only call from EndFrame.
|
||||
*/
|
||||
void CopyToTarget(gfx::DrawTarget* aTarget, const gfx::Matrix& aWorldMatrix);
|
||||
void CopyToTarget(gfx::DrawTarget* aTarget, const nsIntPoint& aTopLeft, const gfx::Matrix& aWorldMatrix);
|
||||
|
||||
/**
|
||||
* Implements the flipping of the y-axis to convert from layers/compositor
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "gfxTypes.h"
|
||||
#include "mozilla/Scoped.h"
|
||||
#include "nscore.h"
|
||||
#include "nsSize.h"
|
||||
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
#include "nsStringFwd.h"
|
||||
@ -22,7 +23,6 @@ struct nsIntPoint;
|
||||
struct nsIntRect;
|
||||
struct gfxRect;
|
||||
struct gfxPoint;
|
||||
struct nsIntSize;
|
||||
|
||||
template <typename T>
|
||||
struct already_AddRefed;
|
||||
@ -274,11 +274,18 @@ protected:
|
||||
*/
|
||||
class gfxUnknownSurface : public gfxASurface {
|
||||
public:
|
||||
gfxUnknownSurface(cairo_surface_t *surf) {
|
||||
gfxUnknownSurface(cairo_surface_t *surf)
|
||||
: mSize(-1, -1)
|
||||
{
|
||||
Init(surf, true);
|
||||
}
|
||||
|
||||
virtual ~gfxUnknownSurface() { }
|
||||
virtual const nsIntSize GetSize() const { return mSize; }
|
||||
void SetSize(const nsIntSize& aSize) { mSize = aSize; }
|
||||
|
||||
private:
|
||||
nsIntSize mSize;
|
||||
};
|
||||
|
||||
#endif /* GFX_ASURFACE_H */
|
||||
|
@ -149,6 +149,11 @@ gfxWindowsSurface::CreateSimilarSurface(gfxContentType aContent,
|
||||
}
|
||||
|
||||
nsRefPtr<gfxASurface> result = Wrap(surface);
|
||||
if (mForPrinting) {
|
||||
MOZ_ASSERT(result->GetType() == gfxSurfaceType::Recording);
|
||||
gfxUnknownSurface *unknown = static_cast<gfxUnknownSurface*>(result.get());
|
||||
unknown->SetSize(aSize);
|
||||
}
|
||||
cairo_surface_destroy(surface);
|
||||
return result.forget();
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ static bool GetX4Lane(JSContext *cx, unsigned argc, Value *vp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!typedObj.owner().isNeutered());
|
||||
Elem *data = reinterpret_cast<Elem *>(typedObj.typedMem());
|
||||
Type32x4::setReturn(args, data[lane]);
|
||||
return true;
|
||||
@ -100,6 +101,7 @@ static bool SignMask(JSContext *cx, unsigned argc, Value *vp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!typedObj.owner().isNeutered());
|
||||
Elem *data = reinterpret_cast<Elem *>(typedObj.typedMem());
|
||||
int32_t mx = data[0] < 0.0 ? 1 : 0;
|
||||
int32_t my = data[1] < 0.0 ? 1 : 0;
|
||||
@ -274,6 +276,7 @@ X4TypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(!result->owner().isNeutered());
|
||||
switch (descr->type()) {
|
||||
#define STORE_LANES(_constant, _type, _name) \
|
||||
case _constant: \
|
||||
@ -406,7 +409,9 @@ template<typename Elem>
|
||||
static Elem
|
||||
TypedObjectMemory(HandleValue v)
|
||||
{
|
||||
return reinterpret_cast<Elem>(v.toObject().as<TypedObject>().typedMem());
|
||||
TypedObject &obj = v.toObject().as<TypedObject>();
|
||||
MOZ_ASSERT(!obj.owner().isNeutered());
|
||||
return reinterpret_cast<Elem>(obj.typedMem());
|
||||
}
|
||||
|
||||
template<typename V>
|
||||
@ -421,6 +426,7 @@ js::Create(JSContext *cx, typename V::Elem *data)
|
||||
if (!result)
|
||||
return nullptr;
|
||||
|
||||
MOZ_ASSERT(!result->owner().isNeutered());
|
||||
Elem *resultMem = reinterpret_cast<Elem *>(result->typedMem());
|
||||
memcpy(resultMem, data, sizeof(Elem) * V::lanes);
|
||||
return result;
|
||||
|
@ -2480,7 +2480,7 @@ TypedObject::constructUnsized(JSContext *cx, unsigned int argc, Value *vp)
|
||||
Rooted<ArrayBufferObject*> buffer(cx);
|
||||
buffer = &args[0].toObject().as<ArrayBufferObject>();
|
||||
|
||||
if (callee->opaque() || buffer->isNeutered()) {
|
||||
if (callee->opaque()) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage,
|
||||
nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
|
||||
return false;
|
||||
@ -2533,6 +2533,12 @@ TypedObject::constructUnsized(JSContext *cx, unsigned int argc, Value *vp)
|
||||
length = maximumLength;
|
||||
}
|
||||
|
||||
if (buffer->isNeutered()) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage,
|
||||
nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
|
||||
return false;
|
||||
}
|
||||
|
||||
Rooted<TypedObject*> obj(cx);
|
||||
obj = TypedObject::createUnattached(cx, callee, length);
|
||||
if (!obj)
|
||||
|
@ -58,8 +58,9 @@
|
||||
function TypedObjectGet(descr, typedObj, offset) {
|
||||
assert(IsObject(descr) && ObjectIsTypeDescr(descr),
|
||||
"get() called with bad type descr");
|
||||
assert(TypedObjectIsAttached(typedObj),
|
||||
"get() called with unattached typedObj");
|
||||
|
||||
if (!TypedObjectIsAttached(typedObj))
|
||||
ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED);
|
||||
|
||||
switch (DESCR_KIND(descr)) {
|
||||
case JS_TYPEREPR_SCALAR_KIND:
|
||||
@ -186,7 +187,8 @@ function TypedObjectGetX4(descr, typedObj, offset) {
|
||||
// it to `descr` as needed. This is the most general entry point
|
||||
// and works for any type.
|
||||
function TypedObjectSet(descr, typedObj, offset, fromValue) {
|
||||
assert(TypedObjectIsAttached(typedObj), "set() called with unattached typedObj");
|
||||
if (!TypedObjectIsAttached(typedObj))
|
||||
ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED);
|
||||
|
||||
// Fast path: `fromValue` is a typed object with same type
|
||||
// representation as the destination. In that case, we can just do a
|
||||
|
@ -327,24 +327,25 @@ ValidateConstant(JSContext *cx, AsmJSModule::Global &global, HandleValue globalV
|
||||
static bool
|
||||
LinkModuleToHeap(JSContext *cx, AsmJSModule &module, Handle<ArrayBufferObject*> heap)
|
||||
{
|
||||
if (!IsValidAsmJSHeapLength(heap->byteLength())) {
|
||||
uint32_t heapLength = heap->byteLength();
|
||||
if (!IsValidAsmJSHeapLength(heapLength)) {
|
||||
ScopedJSFreePtr<char> msg(
|
||||
JS_smprintf("ArrayBuffer byteLength 0x%x is not a valid heap length. The next "
|
||||
"valid length is 0x%x",
|
||||
heap->byteLength(),
|
||||
RoundUpToNextValidAsmJSHeapLength(heap->byteLength())));
|
||||
heapLength,
|
||||
RoundUpToNextValidAsmJSHeapLength(heapLength)));
|
||||
return LinkFail(cx, msg.get());
|
||||
}
|
||||
|
||||
// This check is sufficient without considering the size of the loaded datum because heap
|
||||
// loads and stores start on an aligned boundary and the heap byteLength has larger alignment.
|
||||
JS_ASSERT((module.minHeapLength() - 1) <= INT32_MAX);
|
||||
if (heap->byteLength() < module.minHeapLength()) {
|
||||
if (heapLength < module.minHeapLength()) {
|
||||
ScopedJSFreePtr<char> msg(
|
||||
JS_smprintf("ArrayBuffer byteLength of 0x%x is less than 0x%x (which is the"
|
||||
"largest constant heap access offset rounded up to the next valid "
|
||||
"heap size).",
|
||||
heap->byteLength(),
|
||||
heapLength,
|
||||
module.minHeapLength()));
|
||||
return LinkFail(cx, msg.get());
|
||||
}
|
||||
@ -460,15 +461,6 @@ CallAsmJS(JSContext *cx, unsigned argc, Value *vp)
|
||||
// the arguments.
|
||||
const AsmJSModule::ExportedFunction &func = FunctionToExportedFunction(callee, module);
|
||||
|
||||
// An asm.js module is specialized to its heap's base address and length
|
||||
// which is normally immutable except for the neuter operation that occurs
|
||||
// when an ArrayBuffer is transfered. Throw an internal error if we try to
|
||||
// run with a neutered heap.
|
||||
if (module.maybeHeapBufferObject() && module.maybeHeapBufferObject()->isNeutered()) {
|
||||
js_ReportOverRecursed(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
// The calling convention for an external call into asm.js is to pass an
|
||||
// array of 8-byte values where each value contains either a coerced int32
|
||||
// (in the low word) or double value, with the coercions specified by the
|
||||
@ -500,6 +492,15 @@ CallAsmJS(JSContext *cx, unsigned argc, Value *vp)
|
||||
}
|
||||
}
|
||||
|
||||
// An asm.js module is specialized to its heap's base address and length
|
||||
// which is normally immutable except for the neuter operation that occurs
|
||||
// when an ArrayBuffer is transfered. Throw an internal error if we're
|
||||
// about to run with a neutered heap.
|
||||
if (module.maybeHeapBufferObject() && module.maybeHeapBufferObject()->isNeutered()) {
|
||||
js_ReportOverRecursed(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
// Push an AsmJSActivation to describe the asm.js frames we're about to
|
||||
// push when running this module. Additionally, push a JitActivation so
|
||||
|
@ -35,6 +35,7 @@ using namespace js::jit;
|
||||
|
||||
using mozilla::DebugOnly;
|
||||
using mozilla::Maybe;
|
||||
using mozilla::SafeCast;
|
||||
|
||||
class jit::BaselineFrameInspector
|
||||
{
|
||||
@ -7080,9 +7081,13 @@ IonBuilder::getElemTryTypedStatic(bool *emitted, MDefinition *obj, MDefinition *
|
||||
return true;
|
||||
|
||||
TypedArrayObject *tarr = &tarrObj->as<TypedArrayObject>();
|
||||
ArrayBufferView::ViewType viewType = (ArrayBufferView::ViewType) tarr->type();
|
||||
|
||||
types::TypeObjectKey *tarrType = types::TypeObjectKey::get(tarr);
|
||||
if (tarrType->unknownProperties())
|
||||
return true;
|
||||
|
||||
// LoadTypedArrayElementStatic currently treats uint32 arrays as int32.
|
||||
ArrayBufferView::ViewType viewType = (ArrayBufferView::ViewType) tarr->type();
|
||||
if (viewType == ArrayBufferView::TYPE_UINT32)
|
||||
return true;
|
||||
|
||||
@ -7091,6 +7096,7 @@ IonBuilder::getElemTryTypedStatic(bool *emitted, MDefinition *obj, MDefinition *
|
||||
return true;
|
||||
|
||||
// Emit LoadTypedArrayElementStatic.
|
||||
tarrType->watchStateChangeForTypedArrayData(constraints());
|
||||
|
||||
obj->setImplicitlyUsedUnchecked();
|
||||
index->setImplicitlyUsedUnchecked();
|
||||
@ -7433,21 +7439,14 @@ IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
|
||||
return pushTypeBarrier(load, types, barrier);
|
||||
}
|
||||
|
||||
MInstruction *
|
||||
IonBuilder::getTypedArrayLength(MDefinition *obj)
|
||||
void
|
||||
IonBuilder::addTypedArrayLengthAndData(MDefinition *obj,
|
||||
BoundsChecking checking,
|
||||
MDefinition **index,
|
||||
MInstruction **length, MInstruction **elements)
|
||||
{
|
||||
if (obj->isConstant() && obj->toConstant()->value().isObject()) {
|
||||
TypedArrayObject *tarr = &obj->toConstant()->value().toObject().as<TypedArrayObject>();
|
||||
int32_t length = (int32_t) tarr->length();
|
||||
obj->setImplicitlyUsedUnchecked();
|
||||
return MConstant::New(alloc(), Int32Value(length));
|
||||
}
|
||||
return MTypedArrayLength::New(alloc(), obj);
|
||||
}
|
||||
MOZ_ASSERT((index != nullptr) == (elements != nullptr));
|
||||
|
||||
MInstruction *
|
||||
IonBuilder::getTypedArrayElements(MDefinition *obj)
|
||||
{
|
||||
if (obj->isConstant() && obj->toConstant()->value().isObject()) {
|
||||
TypedArrayObject *tarr = &obj->toConstant()->value().toObject().as<TypedArrayObject>();
|
||||
void *data = tarr->viewData();
|
||||
@ -7463,14 +7462,36 @@ IonBuilder::getTypedArrayElements(MDefinition *obj)
|
||||
// (ArrayBufferObject::changeContents).
|
||||
types::TypeObjectKey *tarrType = types::TypeObjectKey::get(tarr);
|
||||
if (!tarrType->unknownProperties()) {
|
||||
tarrType->watchStateChangeForTypedArrayBuffer(constraints());
|
||||
tarrType->watchStateChangeForTypedArrayData(constraints());
|
||||
|
||||
obj->setImplicitlyUsedUnchecked();
|
||||
return MConstantElements::New(alloc(), data);
|
||||
|
||||
int32_t len = SafeCast<int32_t>(tarr->length());
|
||||
*length = MConstant::New(alloc(), Int32Value(len));
|
||||
current->add(*length);
|
||||
|
||||
if (index) {
|
||||
if (checking == DoBoundsCheck)
|
||||
*index = addBoundsCheck(*index, *length);
|
||||
|
||||
*elements = MConstantElements::New(alloc(), data);
|
||||
current->add(*elements);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return MTypedArrayElements::New(alloc(), obj);
|
||||
|
||||
*length = MTypedArrayLength::New(alloc(), obj);
|
||||
current->add(*length);
|
||||
|
||||
if (index) {
|
||||
if (checking == DoBoundsCheck)
|
||||
*index = addBoundsCheck(*index, *length);
|
||||
|
||||
*elements = MTypedArrayElements::New(alloc(), obj);
|
||||
current->add(*elements);
|
||||
}
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
@ -7562,16 +7583,10 @@ IonBuilder::jsop_getelem_typed(MDefinition *obj, MDefinition *index,
|
||||
// uint32 reads that may produce either doubles or integers.
|
||||
MIRType knownType = MIRTypeForTypedArrayRead(arrayType, allowDouble);
|
||||
|
||||
// Get the length.
|
||||
MInstruction *length = getTypedArrayLength(obj);
|
||||
current->add(length);
|
||||
|
||||
// Bounds check.
|
||||
index = addBoundsCheck(index, length);
|
||||
|
||||
// Get the elements vector.
|
||||
MInstruction *elements = getTypedArrayElements(obj);
|
||||
current->add(elements);
|
||||
// Get length, bounds-check, then get elements, and add all instructions.
|
||||
MInstruction *length;
|
||||
MInstruction *elements;
|
||||
addTypedArrayLengthAndData(obj, DoBoundsCheck, &index, &length, &elements);
|
||||
|
||||
// Load the element.
|
||||
MLoadTypedArrayElement *load = MLoadTypedArrayElement::New(alloc(), elements, index, arrayType);
|
||||
@ -7770,13 +7785,18 @@ IonBuilder::setElemTryTypedStatic(bool *emitted, MDefinition *object,
|
||||
return true;
|
||||
#endif
|
||||
|
||||
ArrayBufferView::ViewType viewType = (ArrayBufferView::ViewType) tarr->type();
|
||||
types::TypeObjectKey *tarrType = types::TypeObjectKey::get(tarr);
|
||||
if (tarrType->unknownProperties())
|
||||
return true;
|
||||
|
||||
ArrayBufferView::ViewType viewType = (ArrayBufferView::ViewType) tarr->type();
|
||||
MDefinition *ptr = convertShiftToMaskForStaticTypedArray(index, viewType);
|
||||
if (!ptr)
|
||||
return true;
|
||||
|
||||
// Emit StoreTypedArrayElementStatic.
|
||||
tarrType->watchStateChangeForTypedArrayData(constraints());
|
||||
|
||||
object->setImplicitlyUsedUnchecked();
|
||||
index->setImplicitlyUsedUnchecked();
|
||||
|
||||
@ -8044,18 +8064,13 @@ IonBuilder::jsop_setelem_typed(ScalarTypeDescr::Type arrayType,
|
||||
current->add(idInt32);
|
||||
id = idInt32;
|
||||
|
||||
// Get the length.
|
||||
MInstruction *length = getTypedArrayLength(obj);
|
||||
current->add(length);
|
||||
|
||||
if (!expectOOB && safety == SetElem_Normal) {
|
||||
// Bounds check.
|
||||
id = addBoundsCheck(id, length);
|
||||
}
|
||||
|
||||
// Get the elements vector.
|
||||
MInstruction *elements = getTypedArrayElements(obj);
|
||||
current->add(elements);
|
||||
// Get length, bounds-check, then get elements, and add all instructions.
|
||||
MInstruction *length;
|
||||
MInstruction *elements;
|
||||
BoundsChecking checking = (!expectOOB && safety == SetElem_Normal)
|
||||
? DoBoundsCheck
|
||||
: SkipBoundsCheck;
|
||||
addTypedArrayLengthAndData(obj, checking, &id, &length, &elements);
|
||||
|
||||
// Clamp value to [0, 255] for Uint8ClampedArray.
|
||||
MDefinition *toWrite = value;
|
||||
@ -8156,8 +8171,7 @@ IonBuilder::jsop_length_fastPath()
|
||||
|
||||
if (objTypes && objTypes->getTypedArrayType() != ScalarTypeDescr::TYPE_MAX) {
|
||||
current->pop();
|
||||
MInstruction *length = getTypedArrayLength(obj);
|
||||
current->add(length);
|
||||
MInstruction *length = addTypedArrayLength(obj);
|
||||
current->push(length);
|
||||
return true;
|
||||
}
|
||||
|
@ -542,9 +542,27 @@ class IonBuilder : public MIRGenerator
|
||||
TypeDescrSet elemTypeReprs,
|
||||
int32_t elemSize);
|
||||
|
||||
// Typed array helpers.
|
||||
MInstruction *getTypedArrayLength(MDefinition *obj);
|
||||
MInstruction *getTypedArrayElements(MDefinition *obj);
|
||||
enum BoundsChecking { DoBoundsCheck, SkipBoundsCheck };
|
||||
|
||||
// Add instructions to compute a typed array's length and data. Also
|
||||
// optionally convert |*index| into a bounds-checked definition, if
|
||||
// requested.
|
||||
//
|
||||
// If you only need the array's length, use addTypedArrayLength below.
|
||||
void addTypedArrayLengthAndData(MDefinition *obj,
|
||||
BoundsChecking checking,
|
||||
MDefinition **index,
|
||||
MInstruction **length, MInstruction **elements);
|
||||
|
||||
// Add an instruction to compute a typed array's length to the current
|
||||
// block. If you also need the typed array's data, use the above method
|
||||
// instead.
|
||||
MInstruction *addTypedArrayLength(MDefinition *obj) {
|
||||
MInstruction *length;
|
||||
addTypedArrayLengthAndData(obj, SkipBoundsCheck, nullptr, &length, nullptr);
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
MDefinition *getCallee();
|
||||
|
||||
@ -717,6 +735,7 @@ class IonBuilder : public MIRGenerator
|
||||
InliningStatus inlineIsCallable(CallInfo &callInfo);
|
||||
InliningStatus inlineHaveSameClass(CallInfo &callInfo);
|
||||
InliningStatus inlineToObject(CallInfo &callInfo);
|
||||
InliningStatus inlineToInteger(CallInfo &callInfo);
|
||||
InliningStatus inlineDump(CallInfo &callInfo);
|
||||
InliningStatus inlineHasClass(CallInfo &callInfo, const Class *clasp) {
|
||||
return inlineHasClasses(callInfo, clasp, nullptr);
|
||||
|
@ -163,6 +163,8 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSFunction *target)
|
||||
return inlineHaveSameClass(callInfo);
|
||||
if (native == intrinsic_ToObject)
|
||||
return inlineToObject(callInfo);
|
||||
if (native == intrinsic_ToInteger)
|
||||
return inlineToInteger(callInfo);
|
||||
|
||||
// TypedObject intrinsics.
|
||||
if (native == intrinsic_ObjectIsTypedObject)
|
||||
@ -1894,6 +1896,24 @@ IonBuilder::inlineToObject(CallInfo &callInfo)
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineToInteger(CallInfo &callInfo)
|
||||
{
|
||||
if (callInfo.argc() != 1 || callInfo.constructing())
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
// Only fast-path if we know the input is in integer in the int32 range.
|
||||
if (getInlineReturnType() != MIRType_Int32)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
|
||||
MToInt32 *toInt32 = MToInt32::New(alloc(), callInfo.getArg(0));
|
||||
current->add(toInt32);
|
||||
current->push(toInt32);
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineBailout(CallInfo &callInfo)
|
||||
{
|
||||
|
@ -248,18 +248,22 @@ class AliasSet {
|
||||
FrameArgument = 1 << 6, // An argument kept on the stack frame
|
||||
AsmJSGlobalVar = 1 << 7, // An asm.js global var
|
||||
AsmJSHeap = 1 << 8, // An asm.js heap load
|
||||
Last = AsmJSHeap,
|
||||
TypedArrayLength = 1 << 9,// A typed array's length
|
||||
Last = TypedArrayLength,
|
||||
Any = Last | (Last - 1),
|
||||
|
||||
NumCategories = 9,
|
||||
NumCategories = 10,
|
||||
|
||||
// Indicates load or store.
|
||||
Store_ = 1 << 31
|
||||
};
|
||||
|
||||
static_assert((1 << NumCategories) - 1 == Any,
|
||||
"NumCategories must include all flags present in Any");
|
||||
|
||||
explicit AliasSet(uint32_t flags)
|
||||
: flags_(flags)
|
||||
{
|
||||
JS_STATIC_ASSERT((1 << NumCategories) - 1 == Any);
|
||||
}
|
||||
|
||||
public:
|
||||
@ -5890,9 +5894,7 @@ class MTypedArrayLength
|
||||
return congruentIfOperandsEqual(ins);
|
||||
}
|
||||
AliasSet getAliasSet() const {
|
||||
// The typed array |length| property is immutable, so there is no
|
||||
// implicit dependency.
|
||||
return AliasSet::None();
|
||||
return AliasSet::Load(AliasSet::TypedArrayLength);
|
||||
}
|
||||
|
||||
void computeRange(TempAllocator &alloc);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user