зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to m-c. a=merge
This commit is contained in:
Коммит
e8c3b4d1bb
|
@ -1289,7 +1289,7 @@ nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
|
|||
} else if (role.EqualsLiteral("xul:progressmeter")) {
|
||||
accessible = new XULProgressMeterAccessible(aContent, aDoc);
|
||||
|
||||
} else if (role.EqualsLiteral("xulstatusbar")) {
|
||||
} else if (role.EqualsLiteral("xul:statusbar")) {
|
||||
accessible = new XULStatusBarAccessible(aContent, aDoc);
|
||||
|
||||
} else if (role.EqualsLiteral("xul:scale")) {
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
"statusbarpanel shouldn't be accessible.");
|
||||
testRole("statusbarpanel-iconic", ROLE_PUSHBUTTON);
|
||||
testRole("statusbarpanel-iconic-text", ROLE_PUSHBUTTON);
|
||||
testRole("statusbar", ROLE_STATUSBAR);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
@ -49,6 +50,7 @@
|
|||
<statusbarpanel id="statusbarpanel"></statusbarpanel>
|
||||
<statusbarpanel id="statusbarpanel-iconic" class="statusbarpanel-iconic"></statusbarpanel>
|
||||
<statusbarpanel id="statusbarpanel-iconic-text" class="statusbarpanel-iconic-text"></statusbarpanel>
|
||||
<statusbar id="statusbar"></statusbar>
|
||||
|
||||
</hbox>
|
||||
</window>
|
||||
|
|
|
@ -217,7 +217,6 @@ class Automation(object):
|
|||
universal_newlines=False,
|
||||
startupinfo=None,
|
||||
creationflags=0):
|
||||
args = automationutils.wrapCommand(args)
|
||||
_log.info("INFO | automation.py | Launching: %s", subprocess.list2cmdline(args))
|
||||
subprocess.Popen.__init__(self, args, bufsize, executable,
|
||||
stdin, stdout, stderr,
|
||||
|
|
|
@ -26,7 +26,6 @@ __all__ = [
|
|||
"getDebuggerInfo",
|
||||
"DEBUGGER_INFO",
|
||||
"replaceBackSlashes",
|
||||
"wrapCommand",
|
||||
'KeyValueParseError',
|
||||
'parseKeyValue',
|
||||
'systemMemory',
|
||||
|
@ -402,19 +401,6 @@ def processLeakLog(leakLogFile, leakThreshold = 0):
|
|||
def replaceBackSlashes(input):
|
||||
return input.replace('\\', '/')
|
||||
|
||||
def wrapCommand(cmd):
|
||||
"""
|
||||
If running on OS X 10.5 or older, wrap |cmd| so that it will
|
||||
be executed as an i386 binary, in case it's a 32-bit/64-bit universal
|
||||
binary.
|
||||
"""
|
||||
if platform.system() == "Darwin" and \
|
||||
hasattr(platform, 'mac_ver') and \
|
||||
platform.mac_ver()[0][:4] < '10.6':
|
||||
return ["arch", "-arch", "i386"] + cmd
|
||||
# otherwise just execute the command normally
|
||||
return cmd
|
||||
|
||||
class KeyValueParseError(Exception):
|
||||
"""error when parsing strings of serialized key-values"""
|
||||
def __init__(self, msg, errors=()):
|
||||
|
|
|
@ -540,8 +540,8 @@ double
|
|||
AudioContext::CurrentTime() const
|
||||
{
|
||||
MediaStream* stream = Destination()->Stream();
|
||||
return stream->StreamTimeToSeconds(stream->GetCurrentTime()) +
|
||||
ExtraCurrentTime();
|
||||
return StreamTimeToDOMTime(stream->
|
||||
StreamTimeToSeconds(stream->GetCurrentTime()));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -233,6 +233,11 @@ public:
|
|||
return aTime - ExtraCurrentTime();
|
||||
}
|
||||
|
||||
double StreamTimeToDOMTime(double aTime) const
|
||||
{
|
||||
return aTime + ExtraCurrentTime();
|
||||
}
|
||||
|
||||
IMPL_EVENT_HANDLER(mozinterruptbegin)
|
||||
IMPL_EVENT_HANDLER(mozinterruptend)
|
||||
|
||||
|
|
|
@ -358,7 +358,6 @@ private:
|
|||
// Add the delay caused by the main thread
|
||||
playbackTick += mSharedBuffers->DelaySoFar();
|
||||
// Compute the playback time in the coordinate system of the destination
|
||||
// FIXME: bug 970773
|
||||
double playbackTime =
|
||||
mSource->DestinationTimeFromTicks(mDestination, playbackTick);
|
||||
|
||||
|
@ -383,22 +382,13 @@ private:
|
|||
|
||||
NS_IMETHODIMP Run()
|
||||
{
|
||||
// If it's not safe to run scripts right now, schedule this to run later
|
||||
if (!nsContentUtils::IsSafeToRunScript()) {
|
||||
nsContentUtils::AddScriptRunner(this);
|
||||
nsRefPtr<ScriptProcessorNode> node = static_cast<ScriptProcessorNode*>
|
||||
(mStream->Engine()->NodeMainThread());
|
||||
if (!node) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<ScriptProcessorNode> node;
|
||||
{
|
||||
// No need to keep holding the lock for the whole duration of this
|
||||
// function, since we're holding a strong reference to it, so if
|
||||
// we can obtain the reference, we will hold the node alive in
|
||||
// this function.
|
||||
MutexAutoLock lock(mStream->Engine()->NodeMutex());
|
||||
node = static_cast<ScriptProcessorNode*>(mStream->Engine()->Node());
|
||||
}
|
||||
if (!node || !node->Context()) {
|
||||
AudioContext* context = node->Context();
|
||||
if (!context) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -413,9 +403,9 @@ private:
|
|||
if (!mNullInput) {
|
||||
ErrorResult rv;
|
||||
inputBuffer =
|
||||
AudioBuffer::Create(node->Context(), mInputChannels.Length(),
|
||||
AudioBuffer::Create(context, mInputChannels.Length(),
|
||||
node->BufferSize(),
|
||||
node->Context()->SampleRate(), cx, rv);
|
||||
context->SampleRate(), cx, rv);
|
||||
if (rv.Failed()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -433,7 +423,7 @@ private:
|
|||
nsRefPtr<AudioProcessingEvent> event = new AudioProcessingEvent(node, nullptr, nullptr);
|
||||
event->InitEvent(inputBuffer,
|
||||
mInputChannels.Length(),
|
||||
mPlaybackTime);
|
||||
context->StreamTimeToDOMTime(mPlaybackTime));
|
||||
node->DispatchTrustedEvent(event);
|
||||
|
||||
// Steal the output buffers if they have been set.
|
||||
|
|
|
@ -117,6 +117,7 @@ skip-if = (toolkit == 'gonk' && !debug)
|
|||
[test_periodicWave.html]
|
||||
[test_scriptProcessorNode.html]
|
||||
[test_scriptProcessorNodeChannelCount.html]
|
||||
[test_scriptProcessorNode_playbackTime1.html]
|
||||
[test_scriptProcessorNodeZeroInputOutput.html]
|
||||
[test_scriptProcessorNodeNotConnected.html]
|
||||
[test_singleSourceDest.html]
|
||||
|
|
|
@ -64,8 +64,10 @@ addLoadEvent(function() {
|
|||
sourceSP.connect(sp);
|
||||
sp.connect(context.destination);
|
||||
var lastPlaybackTime = 0;
|
||||
sp.onaudioprocess = function(e) {
|
||||
isnot(buffer, null, "The audioprocess handler for sourceSP must be run at this point");
|
||||
|
||||
var emptyBuffer = context.createBuffer(1, 2048, context.sampleRate);
|
||||
|
||||
function checkAudioProcessingEvent(e) {
|
||||
is(e.target, sp, "Correct event target");
|
||||
ok(e.playbackTime > lastPlaybackTime, "playbackTime correctly set");
|
||||
lastPlaybackTime = e.playbackTime;
|
||||
|
@ -76,24 +78,21 @@ addLoadEvent(function() {
|
|||
is(e.outputBuffer.length, 2048, "Correct length for the output buffer");
|
||||
is(e.outputBuffer.sampleRate, context.sampleRate, "Correct sample rate for the output buffer");
|
||||
|
||||
// Because of the initial latency added by the second script processor node,
|
||||
// we will never see any generated audio frames in the first callback.
|
||||
var emptyBuffer = context.createBuffer(1, 2048, context.sampleRate);
|
||||
compareChannels(e.inputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
|
||||
compareChannels(e.inputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
|
||||
compareChannels(e.outputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
|
||||
compareChannels(e.outputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
|
||||
}
|
||||
|
||||
sp.onaudioprocess = function(e) {
|
||||
isnot(buffer, null, "The audioprocess handler for sourceSP must be run at this point");
|
||||
checkAudioProcessingEvent(e);
|
||||
|
||||
// Because of the initial latency added by the second script processor node,
|
||||
// we will never see any generated audio frames in the first callback.
|
||||
compareChannels(e.inputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
|
||||
compareChannels(e.inputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
|
||||
|
||||
sp.onaudioprocess = function(e) {
|
||||
is(e.target, sp, "Correct event target");
|
||||
ok(e.playbackTime > lastPlaybackTime, "playbackTime correctly set");
|
||||
lastPlaybackTime = e.playbackTime;
|
||||
is(e.inputBuffer.numberOfChannels, 2, "Correct number of channels for the input buffer");
|
||||
is(e.inputBuffer.length, 2048, "Correct length for the input buffer");
|
||||
is(e.inputBuffer.sampleRate, context.sampleRate, "Correct sample rate for the input buffer");
|
||||
is(e.outputBuffer.numberOfChannels, 2, "Correct number of channels for the output buffer");
|
||||
is(e.outputBuffer.length, 2048, "Correct length for the output buffer");
|
||||
is(e.outputBuffer.sampleRate, context.sampleRate, "Correct sample rate for the output buffer");
|
||||
checkAudioProcessingEvent(e);
|
||||
|
||||
var firstNonZero = findFirstNonZeroSample(e.inputBuffer);
|
||||
ok(firstNonZero <= 2048, "First non-zero sample within range");
|
||||
|
@ -102,8 +101,6 @@ addLoadEvent(function() {
|
|||
compareChannels(e.inputBuffer.getChannelData(1), emptyBuffer.getChannelData(0), firstNonZero);
|
||||
compareChannels(e.inputBuffer.getChannelData(0), buffer.getChannelData(0), 2048 - firstNonZero, firstNonZero, 0);
|
||||
compareChannels(e.inputBuffer.getChannelData(1), buffer.getChannelData(1), 2048 - firstNonZero, firstNonZero, 0);
|
||||
compareChannels(e.outputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
|
||||
compareChannels(e.outputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
|
||||
|
||||
if (firstNonZero == 0) {
|
||||
// If we did not experience any delays, the test is done!
|
||||
|
@ -113,22 +110,12 @@ addLoadEvent(function() {
|
|||
} else if (firstNonZero != 2048) {
|
||||
// In case we just saw a zero buffer this time, wait one more round
|
||||
sp.onaudioprocess = function(e) {
|
||||
is(e.target, sp, "Correct event target");
|
||||
ok(e.playbackTime > lastPlaybackTime, "playbackTime correctly set");
|
||||
lastPlaybackTime = e.playbackTime;
|
||||
is(e.inputBuffer.numberOfChannels, 2, "Correct number of channels for the input buffer");
|
||||
is(e.inputBuffer.length, 2048, "Correct length for the input buffer");
|
||||
is(e.inputBuffer.sampleRate, context.sampleRate, "Correct sample rate for the input buffer");
|
||||
is(e.outputBuffer.numberOfChannels, 2, "Correct number of channels for the output buffer");
|
||||
is(e.outputBuffer.length, 2048, "Correct length for the output buffer");
|
||||
is(e.outputBuffer.sampleRate, context.sampleRate, "Correct sample rate for the output buffer");
|
||||
checkAudioProcessingEvent(e);
|
||||
|
||||
compareChannels(e.inputBuffer.getChannelData(0), buffer.getChannelData(0), firstNonZero, 0, 2048 - firstNonZero);
|
||||
compareChannels(e.inputBuffer.getChannelData(1), buffer.getChannelData(1), firstNonZero, 0, 2048 - firstNonZero);
|
||||
compareChannels(e.inputBuffer.getChannelData(0), emptyBuffer.getChannelData(0), undefined, firstNonZero);
|
||||
compareChannels(e.inputBuffer.getChannelData(1), emptyBuffer.getChannelData(0), undefined, firstNonZero);
|
||||
compareChannels(e.outputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
|
||||
compareChannels(e.outputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
|
||||
|
||||
sp.onaudioprocess = null;
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test ScriptProcessorNode playbackTime for bug 970773</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(
|
||||
function() {
|
||||
const delay = 0.1;
|
||||
var context = new AudioContext();
|
||||
SimpleTest.executeSoon( // to ensure that AudioContext has started
|
||||
function() {
|
||||
setTimeout( // wait for |delay|
|
||||
function() {
|
||||
var sp = context.createScriptProcessor(256);
|
||||
sp.connect(context.destination);
|
||||
sp.onaudioprocess =
|
||||
function(e) {
|
||||
var minimum =
|
||||
(delay + e.inputBuffer.length/context.sampleRate) *
|
||||
(1.0 - 1.0/Math.pow(2.0,52.0)); // double precision
|
||||
ok(e.playbackTime >= minimum,
|
||||
"playbackTime " + e.playbackTime +
|
||||
" beyond expected minimum " + minimum);
|
||||
sp.onaudioprocess = null;
|
||||
SimpleTest.finish();
|
||||
};
|
||||
}, 1000 * delay);
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -71,12 +71,13 @@ class ScriptSettingsStackEntry {
|
|||
friend class ScriptSettingsStack;
|
||||
|
||||
public:
|
||||
ScriptSettingsStackEntry(nsIGlobalObject *aGlobal, bool aCandidate);
|
||||
~ScriptSettingsStackEntry();
|
||||
|
||||
bool NoJSAPI() { return !mGlobalObject; }
|
||||
|
||||
protected:
|
||||
ScriptSettingsStackEntry(nsIGlobalObject *aGlobal, bool aCandidate);
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> mGlobalObject;
|
||||
bool mIsCandidateEntryPoint;
|
||||
|
||||
|
|
|
@ -4,15 +4,6 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DIRS += [
|
||||
'ucvja',
|
||||
'ucvcn',
|
||||
'ucvlatin',
|
||||
'ucvtw',
|
||||
'ucvko',
|
||||
'ucvibm',
|
||||
]
|
||||
|
||||
TEST_DIRS += ['tests']
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
|
@ -31,6 +22,13 @@ EXPORTS += [
|
|||
'nsUConvCID.h',
|
||||
'nsUCSupport.h',
|
||||
'uconvutil.h',
|
||||
'ucvcn/nsUCvCnCID.h',
|
||||
'ucvibm/nsUCvIBMCID.h',
|
||||
'ucvja/nsUCVJA2CID.h',
|
||||
'ucvja/nsUCVJACID.h',
|
||||
'ucvko/nsUCvKOCID.h',
|
||||
'ucvlatin/nsUCvLatinCID.h',
|
||||
'ucvtw/nsUCvTWCID.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORTS += [
|
||||
'nsUCvCnCID.h',
|
||||
]
|
|
@ -1,9 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORTS += [
|
||||
'nsUCvIBMCID.h',
|
||||
]
|
|
@ -1,10 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORTS += [
|
||||
'nsUCVJA2CID.h',
|
||||
'nsUCVJACID.h',
|
||||
]
|
|
@ -1,9 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORTS += [
|
||||
'nsUCvKOCID.h',
|
||||
]
|
|
@ -1,9 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORTS += [
|
||||
'nsUCvLatinCID.h',
|
||||
]
|
|
@ -1,9 +0,0 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORTS += [
|
||||
'nsUCvTWCID.h',
|
||||
]
|
|
@ -0,0 +1,256 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// Interfaces by which the embedding can interact with the Debugger API.
|
||||
|
||||
#ifndef js_DebugAPI_h
|
||||
#define js_DebugAPI_h
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Move.h"
|
||||
|
||||
#include "jspubtd.h"
|
||||
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
namespace js {
|
||||
class Debugger;
|
||||
}
|
||||
|
||||
namespace JS {
|
||||
namespace dbg {
|
||||
|
||||
// Helping embedding code build objects for Debugger
|
||||
// -------------------------------------------------
|
||||
//
|
||||
// Some Debugger API features lean on the embedding application to construct
|
||||
// their result values. For example, Debugger.Frame.prototype.scriptEntryReason
|
||||
// calls hooks provided by the embedding to construct values explaining why it
|
||||
// invoked JavaScript; if F is a frame called from a mouse click event handler,
|
||||
// F.scriptEntryReason would return an object of the form:
|
||||
//
|
||||
// { eventType: "mousedown", event: <object> }
|
||||
//
|
||||
// where <object> is a Debugger.Object whose referent is the event being
|
||||
// dispatched.
|
||||
//
|
||||
// However, Debugger implements a trust boundary. Debuggee code may be
|
||||
// considered untrusted; debugger code needs to be protected from debuggee
|
||||
// getters, setters, proxies, Object.watch watchpoints, and any other feature
|
||||
// that might accidentally cause debugger code to set the debuggee running. The
|
||||
// Debugger API tries to make it easy to write safe debugger code by only
|
||||
// offering access to debuggee objects via Debugger.Object instances, which
|
||||
// ensure that only those operations whose explicit purpose is to invoke
|
||||
// debuggee code do so. But this protective membrane is only helpful if we
|
||||
// interpose Debugger.Object instances in all the necessary spots.
|
||||
//
|
||||
// SpiderMonkey's compartment system also implements a trust boundary. The
|
||||
// debuggee and debugger are always in different compartments. Inter-compartment
|
||||
// work requires carefully tracking which compartment each JSObject or JS::Value
|
||||
// belongs to, and ensuring that is is correctly wrapped for each operation.
|
||||
//
|
||||
// It seems precarious to expect the embedding's hooks to implement these trust
|
||||
// boundaries. Instead, the JS::dbg::Builder API segregates the code which
|
||||
// constructs trusted objects from that which deals with untrusted objects.
|
||||
// Trusted objects have an entirely different C++ type, so code that improperly
|
||||
// mixes trusted and untrusted objects is caught at compile time.
|
||||
//
|
||||
// In the structure shown above, there are two trusted objects, and one
|
||||
// untrusted object:
|
||||
//
|
||||
// - The overall object, with the 'eventType' and 'event' properties, is a
|
||||
// trusted object. We're going to return it to D.F.p.scriptEntryReason's
|
||||
// caller, which will handle it directly.
|
||||
//
|
||||
// - The Debugger.Object instance appearing as the value of the 'event' property
|
||||
// is a trusted object. It belongs to the same Debugger instance as the
|
||||
// Debugger.Frame instance whose scriptEntryReason accessor was called, and
|
||||
// presents a safe reflection-oriented API for inspecting its referent, which
|
||||
// is:
|
||||
//
|
||||
// - The actual event object, an untrusted object, and the referent of the
|
||||
// Debugger.Object above. (Content can do things like replacing accessors on
|
||||
// Event.prototype.)
|
||||
//
|
||||
// Using JS::dbg::Builder, all objects and values the embedding deals with
|
||||
// directly are considered untrusted, and are assumed to be debuggee values. The
|
||||
// only way to construct trusted objects is to use Builder's own methods, which
|
||||
// return a separate Object type. The only way to set a property on a trusted
|
||||
// object is through that Object type. The actual trusted object is never
|
||||
// exposed to the embedding.
|
||||
//
|
||||
// So, for example, the embedding might use code like the following to construct
|
||||
// the object shown above, given a Builder passed to it by Debugger:
|
||||
//
|
||||
// bool
|
||||
// MyScriptEntryReason::explain(JSContext *cx,
|
||||
// Builder &builder,
|
||||
// Builder::Object &result)
|
||||
// {
|
||||
// JSObject *eventObject = ... obtain debuggee event object somehow ...;
|
||||
// if (!eventObject)
|
||||
// return false;
|
||||
// result = builder.newObject(cx);
|
||||
// return result &&
|
||||
// result.defineProperty(cx, "eventType", SafelyFetchType(eventObject)) &&
|
||||
// result.defineProperty(cx, "event", eventObject);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// Object::defineProperty also accepts an Object as the value to store on the
|
||||
// property. By its type, we know that the value is trusted, so we set it
|
||||
// directly as the property's value, without interposing a Debugger.Object
|
||||
// wrapper. This allows the embedding to builted nested structures of trusted
|
||||
// objects.
|
||||
//
|
||||
// The Builder and Builder::Object methods take care of doing whatever
|
||||
// compartment switching and wrapping are necessary to construct the trusted
|
||||
// values in the Debugger's compartment.
|
||||
//
|
||||
// The Object type is self-rooting. Construction, assignment, and destruction
|
||||
// all properly root the referent object.
|
||||
|
||||
class BuilderOrigin;
|
||||
|
||||
class Builder {
|
||||
// The Debugger instance whose client we are building a value for. We build
|
||||
// objects in this object's compartment.
|
||||
PersistentRootedObject debuggerObject;
|
||||
|
||||
// debuggerObject's Debugger structure, for convenience.
|
||||
js::Debugger *debugger;
|
||||
|
||||
// Check that |thing| is in the same compartment as our debuggerObject. Used
|
||||
// for assertions when constructing BuiltThings. We can overload this as we
|
||||
// add more instantiations of BuiltThing.
|
||||
#if DEBUG
|
||||
void assertBuilt(JSObject *obj);
|
||||
#else
|
||||
void assertBuilt(JSObject *obj) { }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// A reference to a trusted object or value. At the moment, we only use it
|
||||
// with JSObject *.
|
||||
template<typename T>
|
||||
class BuiltThing {
|
||||
friend class BuilderOrigin;
|
||||
|
||||
void nonNull() {}
|
||||
|
||||
protected:
|
||||
// The Builder to which this trusted thing belongs.
|
||||
Builder &owner;
|
||||
|
||||
// A rooted reference to our value.
|
||||
PersistentRooted<T> value;
|
||||
|
||||
BuiltThing(JSContext *cx, Builder &owner_, T value_ = js::GCMethods<T>::initial())
|
||||
: owner(owner_), value(cx, value_)
|
||||
{
|
||||
owner.assertBuilt(value_);
|
||||
}
|
||||
|
||||
// Forward some things from our owner, for convenience.
|
||||
js::Debugger *debugger() const { return owner.debugger; }
|
||||
JSObject *debuggerObject() const { return owner.debuggerObject; }
|
||||
|
||||
public:
|
||||
BuiltThing(const BuiltThing &rhs) : owner(rhs.owner), value(rhs.value) { }
|
||||
BuiltThing &operator=(const BuiltThing &rhs) {
|
||||
MOZ_ASSERT(&owner == &rhs.owner);
|
||||
owner.assertBuilt(rhs.value);
|
||||
value = rhs.value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
typedef void (BuiltThing::* ConvertibleToBool)();
|
||||
operator ConvertibleToBool() const {
|
||||
// If we ever instantiate BuiltThink<Value>, this might not suffice.
|
||||
return value ? &BuiltThing::nonNull : 0;
|
||||
}
|
||||
|
||||
private:
|
||||
BuiltThing() MOZ_DELETE;
|
||||
};
|
||||
|
||||
public:
|
||||
// A reference to a trusted object, possibly null. Instances of Object are
|
||||
// always properly rooted. They can be copied and assigned, as if they were
|
||||
// pointers.
|
||||
class Object: private BuiltThing<JSObject *> {
|
||||
friend class Builder; // for construction
|
||||
friend class BuilderOrigin; // for unwrapping
|
||||
|
||||
typedef BuiltThing<JSObject *> Base;
|
||||
|
||||
// This is private, because only Builders can create Objects that
|
||||
// actually point to something (hence the 'friend' declaration).
|
||||
Object(JSContext *cx, Builder &owner_, HandleObject obj) : Base(cx, owner_, obj.get()) { }
|
||||
|
||||
bool definePropertyToTrusted(JSContext *cx, const char *name,
|
||||
JS::MutableHandleValue value);
|
||||
|
||||
public:
|
||||
Object(JSContext *cx, Builder &owner_) : Base(cx, owner_, nullptr) { }
|
||||
Object(const Object &rhs) : Base(rhs) { }
|
||||
|
||||
// Our automatically-generated assignment operator can see our base
|
||||
// class's assignment operator, so we don't need to write one out here.
|
||||
|
||||
// Set the property named |name| on this object to |value|.
|
||||
//
|
||||
// If |value| is a string or primitive, re-wrap it for the debugger's
|
||||
// compartment.
|
||||
//
|
||||
// If |value| is an object, assume it is a debuggee object and make a
|
||||
// Debugger.Object instance referring to it. Set that as the propery's
|
||||
// value.
|
||||
//
|
||||
// If |value| is another trusted object, store it directly as the
|
||||
// property's value.
|
||||
//
|
||||
// On error, report the problem on cx and return false.
|
||||
bool defineProperty(JSContext *cx, const char *name, JS::HandleValue value);
|
||||
bool defineProperty(JSContext *cx, const char *name, JS::HandleObject value);
|
||||
bool defineProperty(JSContext *cx, const char *name, Object &value);
|
||||
|
||||
using Base::ConvertibleToBool;
|
||||
using Base::operator ConvertibleToBool;
|
||||
};
|
||||
|
||||
// Build an empty object for direct use by debugger code, owned by this
|
||||
// Builder. If an error occurs, report it on cx and return a false Object.
|
||||
Object newObject(JSContext *cx);
|
||||
|
||||
protected:
|
||||
Builder(JSContext *cx, js::Debugger *debugger);
|
||||
};
|
||||
|
||||
// Debugger itself instantiates this subclass of Builder, which can unwrap
|
||||
// BuiltThings that belong to it.
|
||||
class BuilderOrigin : public Builder {
|
||||
template<typename T>
|
||||
T unwrapAny(const BuiltThing<T> &thing) {
|
||||
MOZ_ASSERT(&thing.owner == this);
|
||||
return thing.value.get();
|
||||
}
|
||||
|
||||
public:
|
||||
BuilderOrigin(JSContext *cx, js::Debugger *debugger_)
|
||||
: Builder(cx, debugger_)
|
||||
{ }
|
||||
|
||||
JSObject *unwrap(Object &object) { return unwrapAny(object); }
|
||||
};
|
||||
|
||||
} // namespace dbg
|
||||
} // namespace JS
|
||||
|
||||
|
||||
#endif /* js_DebugAPI_h */
|
|
@ -198,7 +198,10 @@ class Base {
|
|||
// edges. The EdgeRange should be freed with 'js_delete'. (You could use
|
||||
// ScopedDJSeletePtr<EdgeRange> to manage it.) On OOM, report an exception
|
||||
// on |cx| and return nullptr.
|
||||
virtual EdgeRange *edges(JSContext *cx) const = 0;
|
||||
//
|
||||
// If wantNames is true, compute names for edges. Doing so can be expensive
|
||||
// in time and memory.
|
||||
virtual EdgeRange *edges(JSContext *cx, bool wantNames) const = 0;
|
||||
|
||||
// Return the Zone to which this node's referent belongs, or nullptr if the
|
||||
// referent is not of a type allocated in SpiderMonkey Zones.
|
||||
|
@ -333,9 +336,11 @@ class Node {
|
|||
|
||||
const jschar *typeName() const { return base()->typeName(); }
|
||||
size_t size() const { return base()->size(); }
|
||||
EdgeRange *edges(JSContext *cx) const { return base()->edges(cx); }
|
||||
JS::Zone *zone() const { return base()->zone(); }
|
||||
JSCompartment *compartment() const { return base()->compartment(); }
|
||||
EdgeRange *edges(JSContext *cx, bool wantNames = true) const {
|
||||
return base()->edges(cx, wantNames);
|
||||
}
|
||||
|
||||
// A hash policy for ubi::Nodes.
|
||||
// This simply uses the stock PointerHasher on the ubi::Node's pointer.
|
||||
|
@ -365,7 +370,8 @@ class Edge {
|
|||
virtual ~Edge() { }
|
||||
|
||||
public:
|
||||
// This edge's name.
|
||||
// This edge's name. This may be nullptr, if Node::edges was called with
|
||||
// false as the wantNames parameter.
|
||||
//
|
||||
// The storage is owned by this Edge, and will be freed when this Edge is
|
||||
// destructed.
|
||||
|
@ -428,7 +434,7 @@ template<typename Referent>
|
|||
class TracerConcrete : public Base {
|
||||
const jschar *typeName() const MOZ_OVERRIDE { return concreteTypeName; }
|
||||
size_t size() const MOZ_OVERRIDE { return 0; } // not implemented yet; bug 1011300
|
||||
EdgeRange *edges(JSContext *) const MOZ_OVERRIDE;
|
||||
EdgeRange *edges(JSContext *, bool wantNames) const MOZ_OVERRIDE;
|
||||
JS::Zone *zone() const MOZ_OVERRIDE { return get().zone(); }
|
||||
JSCompartment *compartment() const MOZ_OVERRIDE { return nullptr; }
|
||||
|
||||
|
@ -472,7 +478,7 @@ template<>
|
|||
class Concrete<void> : public Base {
|
||||
const jschar *typeName() const MOZ_OVERRIDE;
|
||||
size_t size() const MOZ_OVERRIDE;
|
||||
EdgeRange *edges(JSContext *cx) const MOZ_OVERRIDE;
|
||||
EdgeRange *edges(JSContext *cx, bool wantNames) const MOZ_OVERRIDE;
|
||||
JS::Zone *zone() const MOZ_OVERRIDE;
|
||||
JSCompartment *compartment() const MOZ_OVERRIDE;
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ struct BreadthFirst {
|
|||
// We do nothing with noGC, other than require it to exist, with a lifetime
|
||||
// that encloses our own.
|
||||
BreadthFirst(JSContext *cx, Handler &handler, const JS::AutoCheckCannotGC &noGC)
|
||||
: cx(cx), visited(cx), handler(handler), pending(cx),
|
||||
: wantNames(true), cx(cx), visited(cx), handler(handler), pending(cx),
|
||||
traversalBegun(false), stopRequested(false), abandonRequested(false)
|
||||
{ }
|
||||
|
||||
|
@ -95,6 +95,10 @@ struct BreadthFirst {
|
|||
// as many starting points as you like. Return false on OOM.
|
||||
bool addStart(Node node) { return pending.append(node); }
|
||||
|
||||
// True if the handler wants us to compute edge names; doing so can be
|
||||
// expensive in time and memory. True by default.
|
||||
bool wantNames;
|
||||
|
||||
// Traverse the graph in breadth-first order, starting at the given
|
||||
// start nodes, applying |handler::operator()| for each edge traversed
|
||||
// as described above.
|
||||
|
@ -113,7 +117,7 @@ struct BreadthFirst {
|
|||
pending.popFront();
|
||||
|
||||
// Get a range containing all origin's outgoing edges.
|
||||
js::ScopedJSDeletePtr<EdgeRange> range(origin.edges(cx));
|
||||
js::ScopedJSDeletePtr<EdgeRange> range(origin.edges(cx, wantNames));
|
||||
if (!range)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -123,9 +123,6 @@ ValidateGlobalVariable(JSContext *cx, const AsmJSModule &module, AsmJSModule::Gl
|
|||
if (!GetDataProperty(cx, importVal, field, &v))
|
||||
return false;
|
||||
|
||||
if (!v.isPrimitive())
|
||||
return LinkFail(cx, "Imported values must be primitives");
|
||||
|
||||
switch (global.varInitCoercion()) {
|
||||
case AsmJS_ToInt32:
|
||||
if (!ToInt32(cx, v, (int32_t *)datum))
|
||||
|
@ -184,7 +181,6 @@ ValidateMathBuiltinFunction(JSContext *cx, AsmJSModule::Global &global, HandleVa
|
|||
RootedValue v(cx);
|
||||
if (!GetDataProperty(cx, globalVal, cx->names().Math, &v))
|
||||
return false;
|
||||
|
||||
RootedPropertyName field(cx, global.mathName());
|
||||
if (!GetDataProperty(cx, v, field, &v))
|
||||
return false;
|
||||
|
@ -230,7 +226,6 @@ ValidateConstant(JSContext *cx, AsmJSModule::Global &global, HandleValue globalV
|
|||
|
||||
if (!GetDataProperty(cx, v, field, &v))
|
||||
return false;
|
||||
|
||||
if (!v.isNumber())
|
||||
return LinkFail(cx, "math / global constant value needs to be a number");
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
load(libdir + "asm.js");
|
||||
load(libdir + "asserts.js");
|
||||
|
||||
assertAsmTypeFail(USE_ASM + "var i; function f(){} return f");
|
||||
assertAsmTypeFail(USE_ASM + "const i; function f(){} return f");
|
||||
|
@ -118,14 +117,6 @@ assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "const i=+imp.i; function
|
|||
assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "var i=+imp.i; function f() { return +i } return f")(this, {i:1.4})), 1.4);
|
||||
assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "const i=+imp.i; function f() { return +i } return f")(this, {i:1.4})), 1.4);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "var g=0; function f() { var i=42; while (1) { break; } g = i; return g|0 } return f"))(), 42);
|
||||
assertAsmLinkFail(asmCompile('glob','foreign', USE_ASM + 'var i = +foreign.x; function f() {} return f'), null, {x:{valueOf:function() { return 42 }}});
|
||||
assertAsmLinkFail(asmCompile('glob','foreign', USE_ASM + 'var i = foreign.x|0; function f() {} return f'), null, {x:{valueOf:function() { return 42 }}});
|
||||
assertEq(asmLink(asmCompile('glob','foreign', USE_ASM + 'var i = foreign.x|0; function f() { return i|0} return f'), null, {x:"blah"})(), 0);
|
||||
assertEq(asmLink(asmCompile('glob','foreign', USE_ASM + 'var i = +foreign.x; function f() { return +i} return f'), null, {x:"blah"})(), NaN);
|
||||
assertEq(asmLink(asmCompile('glob','foreign', USE_ASM + 'var tof = glob.Math.fround; var i = tof(foreign.x); function f() { return +i} return f'), this, {x:"blah"})(), NaN);
|
||||
assertThrowsInstanceOf(() => asmCompile('glob','foreign',USE_ASM + 'var i = foreign.x|0; function f() { return i|0} return f')(null, {x:Symbol("blah")}), TypeError);
|
||||
assertThrowsInstanceOf(() => asmCompile('glob','foreign',USE_ASM + 'var i = +foreign.x; function f() { return +i} return f')(null, {x:Symbol("blah")}), TypeError);
|
||||
assertThrowsInstanceOf(() => asmCompile('glob','foreign',USE_ASM + 'var tof = glob.Math.fround; var i = tof(foreign.x); function f() { return +i} return f')(this, {x:Symbol("blah")}), TypeError);
|
||||
|
||||
var f1 = asmCompile('global', 'foreign', 'heap', USE_ASM + 'var i32 = new global.Int32Array(heap); function g() { return i32[4]|0 } return g');
|
||||
var global = this;
|
||||
|
|
|
@ -686,12 +686,27 @@ class MDefinition : public MNode
|
|||
|
||||
public:
|
||||
// Opcode testing and casts.
|
||||
template<typename MIRType> bool is() const {
|
||||
return op() == MIRType::classOpcode;
|
||||
}
|
||||
template<typename MIRType> MIRType *to() {
|
||||
JS_ASSERT(is<MIRType>());
|
||||
return static_cast<MIRType *>(this);
|
||||
}
|
||||
template<typename MIRType> const MIRType *to() const {
|
||||
JS_ASSERT(is<MIRType>());
|
||||
return static_cast<const MIRType *>(this);
|
||||
}
|
||||
# define OPCODE_CASTS(opcode) \
|
||||
bool is##opcode() const { \
|
||||
return op() == Op_##opcode; \
|
||||
return is<M##opcode>(); \
|
||||
} \
|
||||
inline M##opcode *to##opcode(); \
|
||||
inline const M##opcode *to##opcode() const;
|
||||
M##opcode *to##opcode() { \
|
||||
return to<M##opcode>(); \
|
||||
} \
|
||||
const M##opcode *to##opcode() const { \
|
||||
return to<M##opcode>(); \
|
||||
}
|
||||
MIR_OPCODE_LIST(OPCODE_CASTS)
|
||||
# undef OPCODE_CASTS
|
||||
|
||||
|
@ -832,8 +847,9 @@ class MInstruction
|
|||
};
|
||||
|
||||
#define INSTRUCTION_HEADER(opcode) \
|
||||
static const Opcode classOpcode = MDefinition::Op_##opcode; \
|
||||
Opcode op() const { \
|
||||
return MDefinition::Op_##opcode; \
|
||||
return classOpcode; \
|
||||
} \
|
||||
const char *opName() const { \
|
||||
return #opcode; \
|
||||
|
@ -6632,7 +6648,8 @@ class MTypedArrayElements
|
|||
|
||||
// Checks whether a typed object is neutered.
|
||||
class MNeuterCheck
|
||||
: public MUnaryInstruction
|
||||
: public MUnaryInstruction,
|
||||
public SingleObjectPolicy
|
||||
{
|
||||
private:
|
||||
explicit MNeuterCheck(MDefinition *object)
|
||||
|
@ -6663,6 +6680,10 @@ class MNeuterCheck
|
|||
AliasSet getAliasSet() const {
|
||||
return AliasSet::Load(AliasSet::ObjectFields);
|
||||
}
|
||||
|
||||
TypePolicy *typePolicy() {
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
// Load a binary data object's "elements", which is just its opaque
|
||||
|
@ -11247,6 +11268,8 @@ class MAsmJSCall MOZ_FINAL : public MVariadicInstruction
|
|||
}
|
||||
};
|
||||
|
||||
#undef INSTRUCTION_HEADER
|
||||
|
||||
void MUse::init(MDefinition *producer, MNode *consumer)
|
||||
{
|
||||
MOZ_ASSERT(!consumer_, "Initializing MUse that already has a consumer");
|
||||
|
@ -11284,22 +11307,7 @@ void MUse::discardProducer()
|
|||
producer_ = nullptr;
|
||||
}
|
||||
|
||||
#undef INSTRUCTION_HEADER
|
||||
|
||||
// Implement opcode casts now that the compiler can see the inheritance.
|
||||
#define OPCODE_CASTS(opcode) \
|
||||
M##opcode *MDefinition::to##opcode() \
|
||||
{ \
|
||||
JS_ASSERT(is##opcode()); \
|
||||
return static_cast<M##opcode *>(this); \
|
||||
} \
|
||||
const M##opcode *MDefinition::to##opcode() const \
|
||||
{ \
|
||||
JS_ASSERT(is##opcode()); \
|
||||
return static_cast<const M##opcode *>(this); \
|
||||
}
|
||||
MIR_OPCODE_LIST(OPCODE_CASTS)
|
||||
#undef OPCODE_CASTS
|
||||
// Implement cast functions now that the compiler can see the inheritance.
|
||||
|
||||
MDefinition *MNode::toDefinition()
|
||||
{
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "js/CharacterEncoding.h"
|
||||
#include "js/Class.h"
|
||||
#include "js/Date.h"
|
||||
#include "js/DebugAPI.h"
|
||||
#include "js/GCAPI.h"
|
||||
#include "js/HashTable.h"
|
||||
#include "js/HeapAPI.h"
|
||||
|
|
|
@ -71,6 +71,7 @@ EXPORTS.js += [
|
|||
'../public/CharacterEncoding.h',
|
||||
'../public/Class.h',
|
||||
'../public/Date.h',
|
||||
'../public/DebugAPI.h',
|
||||
'../public/GCAPI.h',
|
||||
'../public/HashTable.h',
|
||||
'../public/HeapAPI.h',
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "frontend/BytecodeCompiler.h"
|
||||
#include "gc/Marking.h"
|
||||
#include "jit/BaselineJIT.h"
|
||||
#include "js/DebugAPI.h"
|
||||
#include "js/GCAPI.h"
|
||||
#include "js/Vector.h"
|
||||
#include "vm/ArgumentsObject.h"
|
||||
|
@ -35,6 +36,7 @@
|
|||
|
||||
using namespace js;
|
||||
|
||||
using JS::dbg::Builder;
|
||||
using js::frontend::IsIdentifier;
|
||||
using mozilla::ArrayLength;
|
||||
using mozilla::Maybe;
|
||||
|
@ -6276,6 +6278,81 @@ static const JSFunctionSpec DebuggerEnv_methods[] = {
|
|||
};
|
||||
|
||||
|
||||
|
||||
/*** JS::dbg::Builder ****************************************************************************/
|
||||
|
||||
Builder::Builder(JSContext *cx, js::Debugger *debugger)
|
||||
: debuggerObject(cx, debugger->toJSObject().get()),
|
||||
debugger(debugger)
|
||||
{ }
|
||||
|
||||
|
||||
#if DEBUG
|
||||
void
|
||||
Builder::assertBuilt(JSObject *obj)
|
||||
{
|
||||
// We can't use assertSameCompartment here, because that is always keyed to
|
||||
// some JSContext's current compartment, whereas BuiltThings can be
|
||||
// constructed and assigned to without respect to any particular context;
|
||||
// the only constraint is that they should be in their debugger's compartment.
|
||||
MOZ_ASSERT_IF(obj, debuggerObject->compartment() == obj->compartment());
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
Builder::Object::definePropertyToTrusted(JSContext *cx, const char *name,
|
||||
JS::MutableHandleValue trusted)
|
||||
{
|
||||
// We should have checked for false Objects before calling this.
|
||||
MOZ_ASSERT(value);
|
||||
|
||||
JSAtom *atom = Atomize(cx, name, strlen(name));
|
||||
if (!atom)
|
||||
return false;
|
||||
RootedId id(cx, AtomToId(atom));
|
||||
|
||||
return JSObject::defineGeneric(cx, value, id, trusted);
|
||||
}
|
||||
|
||||
bool
|
||||
Builder::Object::defineProperty(JSContext *cx, const char *name, JS::HandleValue propval_)
|
||||
{
|
||||
AutoCompartment ac(cx, debuggerObject());
|
||||
|
||||
RootedValue propval(cx, propval_);
|
||||
if (!debugger()->wrapDebuggeeValue(cx, &propval))
|
||||
return false;
|
||||
|
||||
return definePropertyToTrusted(cx, name, &propval);
|
||||
}
|
||||
|
||||
bool
|
||||
Builder::Object::defineProperty(JSContext *cx, const char *name, JS::HandleObject propval_)
|
||||
{
|
||||
RootedValue propval(cx, ObjectOrNullValue(propval_));
|
||||
return defineProperty(cx, name, propval);
|
||||
}
|
||||
|
||||
bool
|
||||
Builder::Object::defineProperty(JSContext *cx, const char *name, Builder::Object &propval_)
|
||||
{
|
||||
AutoCompartment ac(cx, debuggerObject());
|
||||
|
||||
RootedValue propval(cx, ObjectOrNullValue(propval_.value));
|
||||
return definePropertyToTrusted(cx, name, &propval);
|
||||
}
|
||||
|
||||
Builder::Object
|
||||
Builder::newObject(JSContext *cx)
|
||||
{
|
||||
AutoCompartment ac(cx, debuggerObject);
|
||||
|
||||
RootedObject obj(cx, NewBuiltinClassInstance(cx, &JSObject::class_));
|
||||
|
||||
// If the allocation failed, this will return a false Object, as the spec promises.
|
||||
return Object(cx, *this, obj);
|
||||
}
|
||||
|
||||
|
||||
/*** Glue ****************************************************************************************/
|
||||
|
||||
|
|
|
@ -643,6 +643,7 @@ DebuggerMemory::takeCensus(JSContext *cx, unsigned argc, Value *vp)
|
|||
dbg::DefaultCensusTraversal traversal(cx, handler, noGC);
|
||||
if (!traversal.init())
|
||||
return false;
|
||||
traversal.wantNames = false;
|
||||
|
||||
// Walk the debuggee compartments, using it to set the starting points
|
||||
// (the debuggee globals) for the traversal, and to populate
|
||||
|
|
|
@ -28,11 +28,11 @@ using JS::ubi::Node;
|
|||
using JS::ubi::TracerConcrete;
|
||||
|
||||
// All operations on null ubi::Nodes crash.
|
||||
const jschar *Concrete<void>::typeName() const { MOZ_CRASH("null ubi::Node"); }
|
||||
size_t Concrete<void>::size() const { MOZ_CRASH("null ubi::Node"); }
|
||||
EdgeRange *Concrete<void>::edges(JSContext *) const { MOZ_CRASH("null ubi::Node"); }
|
||||
JS::Zone *Concrete<void>::zone() const { MOZ_CRASH("null ubi::Node"); }
|
||||
JSCompartment *Concrete<void>::compartment() const { MOZ_CRASH("null ubi::Node"); }
|
||||
const jschar *Concrete<void>::typeName() const { MOZ_CRASH("null ubi::Node"); }
|
||||
size_t Concrete<void>::size() const { MOZ_CRASH("null ubi::Node"); }
|
||||
EdgeRange *Concrete<void>::edges(JSContext *, bool) const { MOZ_CRASH("null ubi::Node"); }
|
||||
JS::Zone *Concrete<void>::zone() const { MOZ_CRASH("null ubi::Node"); }
|
||||
JSCompartment *Concrete<void>::compartment() const { MOZ_CRASH("null ubi::Node"); }
|
||||
|
||||
Node::Node(JSGCTraceKind kind, void *ptr)
|
||||
{
|
||||
|
@ -132,6 +132,9 @@ class SimpleEdgeVectorTracer : public JSTracer {
|
|||
// The vector to which we add SimpleEdges.
|
||||
SimpleEdgeVector *vec;
|
||||
|
||||
// True if we should populate the edge's names.
|
||||
bool wantNames;
|
||||
|
||||
static void staticCallback(JSTracer *trc, void **thingp, JSGCTraceKind kind) {
|
||||
static_cast<SimpleEdgeVectorTracer *>(trc)->callback(thingp, kind);
|
||||
}
|
||||
|
@ -140,22 +143,25 @@ class SimpleEdgeVectorTracer : public JSTracer {
|
|||
if (!okay)
|
||||
return;
|
||||
|
||||
// Ask the tracer to compute an edge name for us.
|
||||
char buffer[1024];
|
||||
const char *name = getTracingEdgeName(buffer, sizeof(buffer));
|
||||
jschar *jsname = nullptr;
|
||||
if (wantNames) {
|
||||
// Ask the tracer to compute an edge name for us.
|
||||
char buffer[1024];
|
||||
const char *name = getTracingEdgeName(buffer, sizeof(buffer));
|
||||
|
||||
// Convert the name to jschars.
|
||||
jschar *jsname = js_pod_malloc<jschar>(strlen(name) + 1);
|
||||
if (!jsname) {
|
||||
okay = false;
|
||||
return;
|
||||
// Convert the name to jschars.
|
||||
jsname = js_pod_malloc<jschar>(strlen(name) + 1);
|
||||
if (!jsname) {
|
||||
okay = false;
|
||||
return;
|
||||
}
|
||||
|
||||
size_t i;
|
||||
for (i = 0; name[i]; i++)
|
||||
jsname[i] = name[i];
|
||||
jsname[i] = '\0';
|
||||
}
|
||||
|
||||
size_t i;
|
||||
for (i = 0; name[i]; i++)
|
||||
jsname[i] = name[i];
|
||||
jsname[i] = '\0';
|
||||
|
||||
// The simplest code is correct! The temporary SimpleEdge takes
|
||||
// ownership of name; if the append succeeds, the vector element
|
||||
// then takes ownership; if the append fails, then the temporary
|
||||
|
@ -170,9 +176,12 @@ class SimpleEdgeVectorTracer : public JSTracer {
|
|||
// True if no errors (OOM, say) have yet occurred.
|
||||
bool okay;
|
||||
|
||||
SimpleEdgeVectorTracer(JSContext *cx, SimpleEdgeVector *vec)
|
||||
: JSTracer(JS_GetRuntime(cx), staticCallback), vec(vec), okay(true) {
|
||||
}
|
||||
SimpleEdgeVectorTracer(JSContext *cx, SimpleEdgeVector *vec, bool wantNames)
|
||||
: JSTracer(JS_GetRuntime(cx), staticCallback),
|
||||
vec(vec),
|
||||
wantNames(wantNames),
|
||||
okay(true)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
|
@ -189,8 +198,8 @@ class SimpleEdgeRange : public EdgeRange {
|
|||
public:
|
||||
explicit SimpleEdgeRange(JSContext *cx) : edges(cx), i(0) { }
|
||||
|
||||
bool init(JSContext *cx, void *thing, JSGCTraceKind kind) {
|
||||
SimpleEdgeVectorTracer tracer(cx, &edges);
|
||||
bool init(JSContext *cx, void *thing, JSGCTraceKind kind, bool wantNames = true) {
|
||||
SimpleEdgeVectorTracer tracer(cx, &edges, wantNames);
|
||||
JS_TraceChildren(&tracer, thing, kind);
|
||||
settle();
|
||||
return tracer.okay;
|
||||
|
@ -202,12 +211,12 @@ class SimpleEdgeRange : public EdgeRange {
|
|||
|
||||
template<typename Referent>
|
||||
EdgeRange *
|
||||
TracerConcrete<Referent>::edges(JSContext *cx) const {
|
||||
TracerConcrete<Referent>::edges(JSContext *cx, bool wantNames) const {
|
||||
js::ScopedJSDeletePtr<SimpleEdgeRange> r(js_new<SimpleEdgeRange>(cx));
|
||||
if (!r)
|
||||
return nullptr;
|
||||
|
||||
if (!r->init(cx, ptr, ::js::gc::MapTypeToTraceKind<Referent>::kind))
|
||||
if (!r->init(cx, ptr, ::js::gc::MapTypeToTraceKind<Referent>::kind, wantNames))
|
||||
return nullptr;
|
||||
|
||||
return r.forget();
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CSS Filters: Drop Shadow Default Color</title>
|
||||
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
|
||||
<style type="text/css">
|
||||
#target {
|
||||
filter: url(#drop-shadow);
|
||||
background-color: #00f;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>You should see a blue square with a green drop shadow.</p>
|
||||
<div id="target"></div>
|
||||
<svg width="0" height="0">
|
||||
<filter id="drop-shadow" x="-50" y="-50" width="200" height="200" filterUnits="userSpaceOnUse">
|
||||
<feDropShadow dx="10" dy="10" stdDeviation="3" flood-color="#0f0" color-interpolation-filters="sRGB"/>
|
||||
</filter>
|
||||
</svg>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,31 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CSS Filters: Drop Shadow Default Color</title>
|
||||
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
|
||||
<link rel="help" href="http://www.w3.org/TR/filter-effects-1/#funcdef-drop-shadow">
|
||||
<link rel="help" href="http://www.w3.org/TR/css3-background/#the-box-shadow">
|
||||
<link rel="match" href="drop-shadow-default-color-ref.html">
|
||||
<meta name="assert"
|
||||
content="If the color is unspecified in a CSS drop-shadow filter
|
||||
function, it should default to the value of the CSS color
|
||||
property.">
|
||||
<style type="text/css">
|
||||
#target {
|
||||
filter: drop-shadow(10px 10px 3px);
|
||||
color: #0f0;
|
||||
background-color: #00f;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>You should see a blue square with a green drop shadow.</p>
|
||||
<div id="target"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,31 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CSS Filters: Negative Drop Shadow Offset</title>
|
||||
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
|
||||
<style type="text/css">
|
||||
#target {
|
||||
filter: url(#drop-shadow);
|
||||
background-color: #00f;
|
||||
position: relative;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>You should see a blue square with a green drop shadow in its top left corner.</p>
|
||||
<div id="target"></div>
|
||||
<svg width="0" height="0">
|
||||
<filter id="drop-shadow" x="-50" y="-50" width="200" height="200" filterUnits="userSpaceOnUse">
|
||||
<feDropShadow dx="-10" dy="-10" stdDeviation="3" flood-color="#0f0" color-interpolation-filters="sRGB"/>
|
||||
</filter>
|
||||
</svg>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,32 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CSS Filters: Negative Drop Shadow Offset</title>
|
||||
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
|
||||
<link rel="help" href="http://www.w3.org/TR/filter-effects-1/#funcdef-drop-shadow">
|
||||
<link rel="match" href="drop-shadow-negative-offset-ref.html">
|
||||
<meta name="assert"
|
||||
content="Given negative shadow offsets, the CSS drop-shadow filter
|
||||
function should add a drop shadow extending from the top left
|
||||
corner of an HTML element.">
|
||||
<style type="text/css">
|
||||
#target {
|
||||
filter: drop-shadow(-10px -10px 3px #0f0);
|
||||
background-color: #00f;
|
||||
position: relative;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>You should see a blue square with a green drop shadow in its top left corner.</p>
|
||||
<div id="target"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,28 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CSS Filters: Drop Shadow on HTML Element</title>
|
||||
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
|
||||
<style type="text/css">
|
||||
#target {
|
||||
filter: url(#drop-shadow);
|
||||
background-color: #00f;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>You should see a blue square with a green drop shadow.</p>
|
||||
<div id="target"></div>
|
||||
<svg width="0" height="0">
|
||||
<filter id="drop-shadow" x="-50" y="-50" width="200" height="200" filterUnits="userSpaceOnUse">
|
||||
<feDropShadow dx="10" dy="10" stdDeviation="3" flood-color="#0f0" color-interpolation-filters="sRGB"/>
|
||||
</filter>
|
||||
</svg>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,28 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CSS Filters: Drop Shadow on HTML Element</title>
|
||||
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
|
||||
<link rel="help" href="http://www.w3.org/TR/filter-effects-1/#funcdef-drop-shadow">
|
||||
<link rel="match" href="drop-shadow-ref.html">
|
||||
<meta name="assert"
|
||||
content="The CSS drop-shadow filter function should add a drop shadow to
|
||||
an HTML element.">
|
||||
<style type="text/css">
|
||||
#target {
|
||||
filter: drop-shadow(10px 10px 3px #0f0);
|
||||
background-color: #00f;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>You should see a blue square with a green drop shadow.</p>
|
||||
<div id="target"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -7,3 +7,6 @@ default-preferences pref(layout.css.filters.enabled,true)
|
|||
== blur.svg blur-ref.svg
|
||||
== blur-zero-radius.html blur-zero-radius-ref.html
|
||||
== blur-zoomed-page.html blur-zoomed-page-ref.html
|
||||
== drop-shadow.html drop-shadow-ref.html
|
||||
== drop-shadow-default-color.html drop-shadow-default-color-ref.html
|
||||
== drop-shadow-negative-offset.html drop-shadow-negative-offset-ref.html
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
fuzzy(110,1802) == additive-1.svg additive-1-ref.svg # bug 981344
|
||||
== animate-width-1.svg lime.svg
|
||||
fuzzy-if(cocoaWidget,1,32) fuzzy-if(winWidget,1,1) == paced-1.svg paced-1-ref.svg # bug 981640
|
||||
fuzzy-if(cocoaWidget,1,32) fuzzy-if(winWidget,15,4) == paced-1.svg paced-1-ref.svg # bug 981640
|
||||
== rotate-angle-1.svg rotate-angle-ref.svg
|
||||
== rotate-angle-2.svg rotate-angle-ref.svg
|
||||
== rotate-angle-3.svg rotate-angle-ref.svg
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// Keep others in (case-insensitive) order:
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxUtils.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsStyleStruct.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
|
@ -16,9 +17,11 @@ using namespace mozilla;
|
|||
using namespace mozilla::gfx;
|
||||
|
||||
nsCSSFilterInstance::nsCSSFilterInstance(const nsStyleFilter& aFilter,
|
||||
nsIFrame *aTargetFrame,
|
||||
const nsIntRect& aTargetBBoxInFilterSpace,
|
||||
const gfxMatrix& aFrameSpaceInCSSPxToFilterSpaceTransform)
|
||||
: mFilter(aFilter)
|
||||
, mTargetFrame(aTargetFrame)
|
||||
, mTargetBBoxInFilterSpace(aTargetBBoxInFilterSpace)
|
||||
, mFrameSpaceInCSSPxToFilterSpaceTransform(aFrameSpaceInCSSPxToFilterSpaceTransform)
|
||||
{
|
||||
|
@ -38,6 +41,9 @@ nsCSSFilterInstance::BuildPrimitives(nsTArray<FilterPrimitiveDescription>& aPrim
|
|||
case NS_STYLE_FILTER_BRIGHTNESS:
|
||||
case NS_STYLE_FILTER_CONTRAST:
|
||||
case NS_STYLE_FILTER_DROP_SHADOW:
|
||||
descr = CreatePrimitiveDescription(PrimitiveType::DropShadow, aPrimitiveDescrs);
|
||||
result = SetAttributesForDropShadow(descr);
|
||||
break;
|
||||
case NS_STYLE_FILTER_GRAYSCALE:
|
||||
case NS_STYLE_FILTER_HUE_ROTATE:
|
||||
case NS_STYLE_FILTER_INVERT:
|
||||
|
@ -78,17 +84,49 @@ nsCSSFilterInstance::CreatePrimitiveDescription(PrimitiveType aType,
|
|||
nsresult
|
||||
nsCSSFilterInstance::SetAttributesForBlur(FilterPrimitiveDescription& aDescr)
|
||||
{
|
||||
// Get the radius from the style.
|
||||
nsStyleCoord radiusStyleCoord = mFilter.GetFilterParameter();
|
||||
if (radiusStyleCoord.GetUnit() != eStyleUnit_Coord) {
|
||||
const nsStyleCoord& radiusInFrameSpace = mFilter.GetFilterParameter();
|
||||
if (radiusInFrameSpace.GetUnit() != eStyleUnit_Coord) {
|
||||
NS_NOTREACHED("unexpected unit");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Get the radius in frame space.
|
||||
nscoord radiusInFrameSpace = radiusStyleCoord.GetCoordValue();
|
||||
Size radiusInFilterSpace = BlurRadiusToFilterSpace(radiusInFrameSpace.GetCoordValue());
|
||||
aDescr.Attributes().Set(eGaussianBlurStdDeviation, radiusInFilterSpace);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCSSFilterInstance::SetAttributesForDropShadow(FilterPrimitiveDescription& aDescr)
|
||||
{
|
||||
nsCSSShadowArray* shadows = mFilter.GetDropShadow();
|
||||
if (!shadows || shadows->Length() != 1) {
|
||||
NS_NOTREACHED("Exactly one drop shadow should have been parsed.");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCSSShadowItem* shadow = shadows->ShadowAt(0);
|
||||
|
||||
// Set drop shadow blur radius.
|
||||
Size radiusInFilterSpace = BlurRadiusToFilterSpace(shadow->mRadius);
|
||||
aDescr.Attributes().Set(eDropShadowStdDeviation, radiusInFilterSpace);
|
||||
|
||||
// Set offset.
|
||||
IntPoint offsetInFilterSpace = OffsetToFilterSpace(shadow->mXOffset, shadow->mYOffset);
|
||||
aDescr.Attributes().Set(eDropShadowOffset, offsetInFilterSpace);
|
||||
|
||||
// Set color. If unspecified, use the CSS color property.
|
||||
nscolor shadowColor = shadow->mHasColor ?
|
||||
shadow->mColor : mTargetFrame->StyleColor()->mColor;
|
||||
aDescr.Attributes().Set(eDropShadowColor, ToAttributeColor(shadowColor));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Size
|
||||
nsCSSFilterInstance::BlurRadiusToFilterSpace(nscoord aRadiusInFrameSpace)
|
||||
{
|
||||
float radiusInFrameSpaceInCSSPx =
|
||||
nsPresContext::AppUnitsToFloatCSSPixels(radiusInFrameSpace);
|
||||
nsPresContext::AppUnitsToFloatCSSPixels(aRadiusInFrameSpace);
|
||||
|
||||
// Convert the radius to filter space.
|
||||
gfxSize radiusInFilterSpace(radiusInFrameSpaceInCSSPx,
|
||||
|
@ -101,15 +139,40 @@ nsCSSFilterInstance::SetAttributesForBlur(FilterPrimitiveDescription& aDescr)
|
|||
// Check the radius limits.
|
||||
if (radiusInFilterSpace.width < 0 || radiusInFilterSpace.height < 0) {
|
||||
NS_NOTREACHED("we shouldn't have parsed a negative radius in the style");
|
||||
return NS_ERROR_FAILURE;
|
||||
return Size();
|
||||
}
|
||||
gfxFloat maxStdDeviation = (gfxFloat)kMaxStdDeviation;
|
||||
radiusInFilterSpace.width = std::min(radiusInFilterSpace.width, maxStdDeviation);
|
||||
radiusInFilterSpace.height = std::min(radiusInFilterSpace.height, maxStdDeviation);
|
||||
|
||||
// Set the radius parameter.
|
||||
aDescr.Attributes().Set(eGaussianBlurStdDeviation, ToSize(radiusInFilterSpace));
|
||||
return NS_OK;
|
||||
return ToSize(radiusInFilterSpace);
|
||||
}
|
||||
|
||||
IntPoint
|
||||
nsCSSFilterInstance::OffsetToFilterSpace(nscoord aXOffsetInFrameSpace,
|
||||
nscoord aYOffsetInFrameSpace)
|
||||
{
|
||||
gfxPoint offsetInFilterSpace(nsPresContext::AppUnitsToFloatCSSPixels(aXOffsetInFrameSpace),
|
||||
nsPresContext::AppUnitsToFloatCSSPixels(aYOffsetInFrameSpace));
|
||||
|
||||
// Convert the radius to filter space.
|
||||
gfxSize frameSpaceInCSSPxToFilterSpaceScale =
|
||||
mFrameSpaceInCSSPxToFilterSpaceTransform.ScaleFactors(true);
|
||||
offsetInFilterSpace.x *= frameSpaceInCSSPxToFilterSpaceScale.width;
|
||||
offsetInFilterSpace.y *= frameSpaceInCSSPxToFilterSpaceScale.height;
|
||||
|
||||
return IntPoint(int32_t(offsetInFilterSpace.x), int32_t(offsetInFilterSpace.y));
|
||||
}
|
||||
|
||||
Color
|
||||
nsCSSFilterInstance::ToAttributeColor(nscolor aColor)
|
||||
{
|
||||
return Color(
|
||||
NS_GET_R(aColor) / 255.0,
|
||||
NS_GET_G(aColor) / 255.0,
|
||||
NS_GET_B(aColor) / 255.0,
|
||||
NS_GET_A(aColor) / 255.0
|
||||
);
|
||||
}
|
||||
|
||||
int32_t
|
||||
|
|
|
@ -9,7 +9,11 @@
|
|||
#include "FilterSupport.h"
|
||||
#include "gfxMatrix.h"
|
||||
#include "gfxRect.h"
|
||||
#include "mozilla/gfx/Point.h"
|
||||
#include "mozilla/gfx/Types.h"
|
||||
#include "nsColor.h"
|
||||
|
||||
class nsIFrame;
|
||||
struct nsStyleFilter;
|
||||
template<class T> class nsTArray;
|
||||
|
||||
|
@ -20,8 +24,11 @@ template<class T> class nsTArray;
|
|||
*/
|
||||
class nsCSSFilterInstance
|
||||
{
|
||||
typedef mozilla::gfx::Color Color;
|
||||
typedef mozilla::gfx::FilterPrimitiveDescription FilterPrimitiveDescription;
|
||||
typedef mozilla::gfx::IntPoint IntPoint;
|
||||
typedef mozilla::gfx::PrimitiveType PrimitiveType;
|
||||
typedef mozilla::gfx::Size Size;
|
||||
|
||||
public:
|
||||
/**
|
||||
|
@ -34,6 +41,7 @@ public:
|
|||
* the filtered element's frame space in CSS pixels to filter space.
|
||||
*/
|
||||
nsCSSFilterInstance(const nsStyleFilter& aFilter,
|
||||
nsIFrame *aTargetFrame,
|
||||
const nsIntRect& mTargetBBoxInFilterSpace,
|
||||
const gfxMatrix& aFrameSpaceInCSSPxToFilterSpaceTransform);
|
||||
|
||||
|
@ -55,6 +63,7 @@ private:
|
|||
* Sets aDescr's attributes using the style info in mFilter.
|
||||
*/
|
||||
nsresult SetAttributesForBlur(FilterPrimitiveDescription& aDescr);
|
||||
nsresult SetAttributesForDropShadow(FilterPrimitiveDescription& aDescr);
|
||||
|
||||
/**
|
||||
* Returns the index of the last result in the aPrimitiveDescrs, which we'll
|
||||
|
@ -71,11 +80,34 @@ private:
|
|||
void SetBounds(FilterPrimitiveDescription& aDescr,
|
||||
const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs);
|
||||
|
||||
/**
|
||||
* Converts an nscolor to a Color, suitable for use as a
|
||||
* FilterPrimitiveDescription attribute.
|
||||
*/
|
||||
Color ToAttributeColor(nscolor aColor);
|
||||
|
||||
/**
|
||||
* Converts a blur radius in frame space to filter space.
|
||||
*/
|
||||
Size BlurRadiusToFilterSpace(nscoord aRadiusInFrameSpace);
|
||||
|
||||
/**
|
||||
* Converts a point defined by a pair of nscoord x, y coordinates from frame
|
||||
* space to filter space.
|
||||
*/
|
||||
IntPoint OffsetToFilterSpace(nscoord aXOffsetInFrameSpace,
|
||||
nscoord aYOffsetInFrameSpace);
|
||||
|
||||
/**
|
||||
* The CSS filter originally from the style system.
|
||||
*/
|
||||
const nsStyleFilter& mFilter;
|
||||
|
||||
/**
|
||||
* The frame for the element that is currently being filtered.
|
||||
*/
|
||||
nsIFrame* mTargetFrame;
|
||||
|
||||
/**
|
||||
* The bounding box of the element being filtered, in filter space. Used for
|
||||
* input bounds if this CSS filter is the first in the filter chain.
|
||||
|
|
|
@ -260,7 +260,8 @@ nsFilterInstance::BuildPrimitivesForFilter(const nsStyleFilter& aFilter)
|
|||
}
|
||||
|
||||
// Build primitives for a CSS filter.
|
||||
nsCSSFilterInstance cssFilterInstance(aFilter, mTargetBBoxInFilterSpace,
|
||||
nsCSSFilterInstance cssFilterInstance(aFilter, mTargetFrame,
|
||||
mTargetBBoxInFilterSpace,
|
||||
mFrameSpaceInCSSPxToFilterSpaceTransform);
|
||||
return cssFilterInstance.BuildPrimitives(mPrimitiveDescriptions);
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ nr_stun_encode_htonl(UINT4 data, int buflen, UCHAR *buf, int *offset)
|
|||
int
|
||||
nr_stun_encode_htonll(UINT8 data, int buflen, UCHAR *buf, int *offset)
|
||||
{
|
||||
UINT8 d = htonll(data);
|
||||
UINT8 d = nr_htonll(data);
|
||||
|
||||
if (*offset + sizeof(d) > buflen) {
|
||||
r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
|
||||
|
@ -193,7 +193,7 @@ nr_stun_decode_htonll(UCHAR *buf, int buflen, int *offset, UINT8 *data)
|
|||
|
||||
memcpy(&d, &buf[*offset], sizeof(d));
|
||||
*offset += sizeof(d);
|
||||
*data = htonll(d);
|
||||
*data = nr_htonll(d);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ static char *RCSSTRING __UNUSED__ ="$Id: byteorder.c,v 1.2 2007/06/26 22:37:55 a
|
|||
BYTE((n),(y))=tmp
|
||||
|
||||
UINT8
|
||||
htonll(UINT8 hostlonglong)
|
||||
nr_htonll(UINT8 hostlonglong)
|
||||
{
|
||||
UINT8 netlonglong = hostlonglong;
|
||||
UCHAR tmp;
|
||||
|
@ -69,8 +69,8 @@ htonll(UINT8 hostlonglong)
|
|||
}
|
||||
|
||||
UINT8
|
||||
ntohll(UINT8 netlonglong)
|
||||
nr_ntohll(UINT8 netlonglong)
|
||||
{
|
||||
return htonll(netlonglong);
|
||||
return nr_htonll(netlonglong);
|
||||
}
|
||||
|
||||
|
|
|
@ -39,9 +39,9 @@
|
|||
#ifndef _byteorder_h
|
||||
#define _byteorder_h
|
||||
|
||||
UINT8 htonll(UINT8 hostlonglong);
|
||||
UINT8 nr_htonll(UINT8 hostlonglong);
|
||||
|
||||
UINT8 ntohll(UINT8 netlonglong);
|
||||
UINT8 nr_ntohll(UINT8 netlonglong);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -592,7 +592,9 @@ static const uint32_t EnabledCiphers[] = {
|
|||
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
|
||||
};
|
||||
|
||||
// Disalbe all NSS suites modes without PFS or with old and rusty ciphersuites.
|
||||
// Don't remove suites; TODO(mt@mozilla.com) restore; bug 1052610
|
||||
#if 0
|
||||
// Disable all NSS suites modes without PFS or with old and rusty ciphersuites.
|
||||
// Anything outside this list is governed by the usual combination of policy
|
||||
// and user preferences.
|
||||
static const uint32_t DisabledCiphers[] = {
|
||||
|
@ -647,6 +649,7 @@ static const uint32_t DisabledCiphers[] = {
|
|||
TLS_RSA_WITH_NULL_SHA256,
|
||||
TLS_RSA_WITH_NULL_MD5,
|
||||
};
|
||||
#endif // bug 1052610
|
||||
|
||||
bool TransportLayerDtls::SetupCipherSuites(PRFileDesc* ssl_fd) const {
|
||||
SECStatus rv;
|
||||
|
|
|
@ -458,8 +458,8 @@ pref("apz.zoom_animation_duration_ms", 250);
|
|||
pref("apz.subframe.enabled", true);
|
||||
pref("apz.fling_repaint_interval", 16);
|
||||
pref("apz.pan_repaint_interval", 16);
|
||||
pref("apz.apz.x_skate_size_multiplier", "2.5");
|
||||
pref("apz.apz.y_skate_size_multiplier", "3.5");
|
||||
pref("apz.x_skate_size_multiplier", "2.5");
|
||||
pref("apz.y_skate_size_multiplier", "3.5");
|
||||
#else
|
||||
pref("apz.subframe.enabled", false);
|
||||
pref("apz.fling_repaint_interval", 75);
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace mozilla {
|
|||
#if defined(ANDROID)
|
||||
#define LOG_ERROR(args...) __android_log_print(ANDROID_LOG_ERROR, "Sandbox", ## args)
|
||||
#else
|
||||
#define LOG_ERROR(fmt, args...) fprintf(stderr, "Sandbox: " fmt, ## args)
|
||||
#define LOG_ERROR(fmt, args...) fprintf(stderr, "Sandbox: " fmt "\n", ## args)
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_GMP_SANDBOX
|
||||
|
|
|
@ -54,13 +54,6 @@ class GeckoRuntimeRunner(BaseRunner):
|
|||
# Bug 775416 - Ensure that binary options are passed in first
|
||||
command[1:1] = self.cmdargs
|
||||
|
||||
# If running on OS X 10.5 or older, wrap |cmd| so that it will
|
||||
# be executed as an i386 binary, in case it's a 32-bit/64-bit universal
|
||||
# binary.
|
||||
if mozinfo.isMac and hasattr(platform, 'mac_ver') and \
|
||||
platform.mac_ver()[0][:4] < '10.6':
|
||||
command = ["arch", "-arch", "i386"] + command
|
||||
|
||||
if hasattr(self.app_ctx, 'wrap_command'):
|
||||
command = self.app_ctx.wrap_command(command)
|
||||
return command
|
||||
|
|
|
@ -11,6 +11,13 @@
|
|||
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
#ifndef MOZ_CALLSTACK_DISABLED
|
||||
#include "CodeAddressService.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsStackWalk.h"
|
||||
#include "nsTHashtable.h"
|
||||
#endif
|
||||
|
||||
#include "mozilla/CondVar.h"
|
||||
#include "mozilla/DeadlockDetector.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
|
@ -41,6 +48,31 @@ unsigned BlockingResourceBase::sResourceAcqnChainFrontTPI = (unsigned)-1;
|
|||
BlockingResourceBase::DDT* BlockingResourceBase::sDeadlockDetector;
|
||||
|
||||
|
||||
void
|
||||
BlockingResourceBase::StackWalkCallback(void* aPc, void* aSp, void* aClosure)
|
||||
{
|
||||
#ifndef MOZ_CALLSTACK_DISABLED
|
||||
AcquisitionState* state = (AcquisitionState*)aClosure;
|
||||
state->AppendElement(aPc);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
BlockingResourceBase::GetStackTrace(AcquisitionState& aState)
|
||||
{
|
||||
#ifndef MOZ_CALLSTACK_DISABLED
|
||||
// Skip this function and the calling function.
|
||||
const uint32_t kSkipFrames = 2;
|
||||
|
||||
aState.Clear();
|
||||
|
||||
// NB: Ignore the return value, there's nothing useful we can do if this
|
||||
// this fails.
|
||||
NS_StackWalk(StackWalkCallback, kSkipFrames,
|
||||
24, &aState, 0, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* PrintCycle
|
||||
* Append to |aOut| detailed information about the circular
|
||||
|
@ -85,6 +117,70 @@ PrintCycle(const BlockingResourceBase::DDT::ResourceAcquisitionArray* aCycle, ns
|
|||
return maybeImminent;
|
||||
}
|
||||
|
||||
#ifndef MOZ_CALLSTACK_DISABLED
|
||||
class CodeAddressServiceWriter MOZ_FINAL
|
||||
{
|
||||
public:
|
||||
explicit CodeAddressServiceWriter(nsACString& aOut) : mOut(aOut) {}
|
||||
|
||||
void Write(const char* aFmt, ...) const
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, aFmt);
|
||||
|
||||
const size_t kMaxLength = 4096;
|
||||
char buffer[kMaxLength];
|
||||
|
||||
vsnprintf(buffer, kMaxLength, aFmt, ap);
|
||||
mOut += buffer;
|
||||
fprintf(stderr, "%s", buffer);
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
private:
|
||||
nsACString& mOut;
|
||||
};
|
||||
|
||||
struct CodeAddressServiceLock MOZ_FINAL
|
||||
{
|
||||
static void Unlock() { }
|
||||
static void Lock() { }
|
||||
static bool IsLocked() { return true; }
|
||||
};
|
||||
|
||||
struct CodeAddressServiceStringAlloc MOZ_FINAL
|
||||
{
|
||||
static char* copy(const char* aString) { return ::strdup(aString); }
|
||||
static void free(char* aString) { ::free(aString); }
|
||||
};
|
||||
|
||||
class CodeAddressServiceStringTable MOZ_FINAL
|
||||
{
|
||||
public:
|
||||
CodeAddressServiceStringTable() : mSet(32) {}
|
||||
|
||||
const char* Intern(const char* aString)
|
||||
{
|
||||
nsCharPtrHashKey* e = mSet.PutEntry(aString);
|
||||
return e->GetKey();
|
||||
}
|
||||
|
||||
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
return mSet.SizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef nsTHashtable<nsCharPtrHashKey> StringSet;
|
||||
StringSet mSet;
|
||||
};
|
||||
|
||||
typedef CodeAddressService<CodeAddressServiceStringTable,
|
||||
CodeAddressServiceStringAlloc,
|
||||
CodeAddressServiceWriter,
|
||||
CodeAddressServiceLock> WalkTheStackCodeAddressService;
|
||||
#endif
|
||||
|
||||
bool
|
||||
BlockingResourceBase::Print(nsACString& aOut) const
|
||||
|
@ -95,15 +191,28 @@ BlockingResourceBase::Print(nsACString& aOut) const
|
|||
aOut += " : ";
|
||||
aOut += mName;
|
||||
|
||||
if (mAcquired) {
|
||||
bool acquired = IsAcquired();
|
||||
|
||||
if (acquired) {
|
||||
fputs(" (currently acquired)\n", stderr);
|
||||
aOut += " (currently acquired)\n";
|
||||
}
|
||||
|
||||
fputs(" calling context\n", stderr);
|
||||
#ifdef MOZ_CALLSTACK_DISABLED
|
||||
fputs(" [stack trace unavailable]\n", stderr);
|
||||
#else
|
||||
const AcquisitionState& state = acquired ? mAcquired : mFirstSeen;
|
||||
|
||||
return mAcquired;
|
||||
WalkTheStackCodeAddressService addressService;
|
||||
CodeAddressServiceWriter writer(aOut);
|
||||
for (uint32_t i = 0; i < state.Length(); i++) {
|
||||
addressService.WriteLocation(writer, state[i]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return acquired;
|
||||
}
|
||||
|
||||
|
||||
|
@ -112,7 +221,11 @@ BlockingResourceBase::BlockingResourceBase(
|
|||
BlockingResourceBase::BlockingResourceType aType)
|
||||
: mName(aName)
|
||||
, mType(aType)
|
||||
#ifdef MOZ_CALLSTACK_DISABLED
|
||||
, mAcquired(false)
|
||||
#else
|
||||
, mAcquired()
|
||||
#endif
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mName, "Name must be nonnull");
|
||||
// PR_CallOnce guaranatees that InitStatics is called in a
|
||||
|
@ -182,6 +295,11 @@ BlockingResourceBase::CheckAcquire()
|
|||
return;
|
||||
}
|
||||
|
||||
#ifndef MOZ_CALLSTACK_DISABLED
|
||||
// Update the current stack before printing.
|
||||
GetStackTrace(mAcquired);
|
||||
#endif
|
||||
|
||||
fputs("###!!! ERROR: Potential deadlock detected:\n", stderr);
|
||||
nsAutoCString out("Potential deadlock detected:\n");
|
||||
bool maybeImminent = PrintCycle(cycle, out);
|
||||
|
@ -211,11 +329,20 @@ BlockingResourceBase::Acquire()
|
|||
"FIXME bug 456272: annots. to allow Acquire()ing condvars");
|
||||
return;
|
||||
}
|
||||
NS_ASSERTION(!mAcquired,
|
||||
NS_ASSERTION(!IsAcquired(),
|
||||
"reacquiring already acquired resource");
|
||||
|
||||
ResourceChainAppend(ResourceChainFront());
|
||||
|
||||
#ifdef MOZ_CALLSTACK_DISABLED
|
||||
mAcquired = true;
|
||||
#else
|
||||
// Take a stack snapshot.
|
||||
GetStackTrace(mAcquired);
|
||||
if (mFirstSeen.IsEmpty()) {
|
||||
mFirstSeen = mAcquired;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -229,7 +356,7 @@ BlockingResourceBase::Release()
|
|||
}
|
||||
|
||||
BlockingResourceBase* chainFront = ResourceChainFront();
|
||||
NS_ASSERTION(chainFront && mAcquired,
|
||||
NS_ASSERTION(chainFront && IsAcquired(),
|
||||
"Release()ing something that hasn't been Acquire()ed");
|
||||
|
||||
if (chainFront == this) {
|
||||
|
@ -255,7 +382,7 @@ BlockingResourceBase::Release()
|
|||
}
|
||||
}
|
||||
|
||||
mAcquired = false;
|
||||
ClearAcquisitionState();
|
||||
}
|
||||
|
||||
|
||||
|
@ -340,10 +467,10 @@ ReentrantMonitor::Wait(PRIntervalTime aInterval)
|
|||
|
||||
// save monitor state and reset it to empty
|
||||
int32_t savedEntryCount = mEntryCount;
|
||||
bool savedAcquisitionState = GetAcquisitionState();
|
||||
AcquisitionState savedAcquisitionState = GetAcquisitionState();
|
||||
BlockingResourceBase* savedChainPrev = mChainPrev;
|
||||
mEntryCount = 0;
|
||||
SetAcquisitionState(false);
|
||||
ClearAcquisitionState();
|
||||
mChainPrev = 0;
|
||||
|
||||
nsresult rv;
|
||||
|
@ -377,9 +504,9 @@ CondVar::Wait(PRIntervalTime aInterval)
|
|||
AssertCurrentThreadOwnsMutex();
|
||||
|
||||
// save mutex state and reset to empty
|
||||
bool savedAcquisitionState = mLock->GetAcquisitionState();
|
||||
AcquisitionState savedAcquisitionState = mLock->GetAcquisitionState();
|
||||
BlockingResourceBase* savedChainPrev = mLock->mChainPrev;
|
||||
mLock->SetAcquisitionState(false);
|
||||
mLock->ClearAcquisitionState();
|
||||
mLock->mChainPrev = 0;
|
||||
|
||||
// give up mutex until we're back from Wait()
|
||||
|
|
|
@ -16,9 +16,18 @@
|
|||
#include "nsISupportsImpl.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
// NB: Comment this out to enable callstack tracking.
|
||||
#define MOZ_CALLSTACK_DISABLED
|
||||
|
||||
#include "prinit.h"
|
||||
|
||||
#include "nsStringGlue.h"
|
||||
|
||||
#ifndef MOZ_CALLSTACK_DISABLED
|
||||
#include "nsTArray.h"
|
||||
#endif
|
||||
|
||||
#include "nsXPCOM.h"
|
||||
#endif
|
||||
|
||||
|
@ -88,6 +97,12 @@ public:
|
|||
typedef DeadlockDetector<BlockingResourceBase> DDT;
|
||||
|
||||
protected:
|
||||
#ifdef MOZ_CALLSTACK_DISABLED
|
||||
typedef bool AcquisitionState;
|
||||
#else
|
||||
typedef nsAutoTArray<void*, 24> AcquisitionState;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* BlockingResourceBase
|
||||
* Initialize this blocking resource. Also hooks the resource into
|
||||
|
@ -184,7 +199,7 @@ protected:
|
|||
*
|
||||
* *NOT* thread safe. Requires ownership of underlying resource.
|
||||
*/
|
||||
bool GetAcquisitionState()
|
||||
AcquisitionState GetAcquisitionState()
|
||||
{
|
||||
return mAcquired;
|
||||
}
|
||||
|
@ -195,11 +210,41 @@ protected:
|
|||
*
|
||||
* *NOT* thread safe. Requires ownership of underlying resource.
|
||||
*/
|
||||
void SetAcquisitionState(bool aAcquisitionState)
|
||||
void SetAcquisitionState(const AcquisitionState& aAcquisitionState)
|
||||
{
|
||||
mAcquired = aAcquisitionState;
|
||||
}
|
||||
|
||||
/**
|
||||
* ClearAcquisitionState
|
||||
* Indicate this resource is not acquired.
|
||||
*
|
||||
* *NOT* thread safe. Requires ownership of underlying resource.
|
||||
*/
|
||||
void ClearAcquisitionState()
|
||||
{
|
||||
#ifdef MOZ_CALLSTACK_DISABLED
|
||||
mAcquired = false;
|
||||
#else
|
||||
mAcquired.Clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* IsAcquired
|
||||
* Indicates if this resource is acquired.
|
||||
*
|
||||
* *NOT* thread safe. Requires ownership of underlying resource.
|
||||
*/
|
||||
bool IsAcquired() const
|
||||
{
|
||||
#ifdef MOZ_CALLSTACK_DISABLED
|
||||
return mAcquired;
|
||||
#else
|
||||
return !mAcquired.IsEmpty();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* mChainPrev
|
||||
* A series of resource acquisitions creates a chain of orders. This
|
||||
|
@ -227,7 +272,15 @@ private:
|
|||
* mAcquired
|
||||
* Indicates if this resource is currently acquired.
|
||||
*/
|
||||
bool mAcquired;
|
||||
AcquisitionState mAcquired;
|
||||
|
||||
#ifndef MOZ_CALLSTACK_DISABLED
|
||||
/**
|
||||
* mFirstSeen
|
||||
* Inidicates where this resource was first acquired.
|
||||
*/
|
||||
AcquisitionState mFirstSeen;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* sCallOnce
|
||||
|
@ -266,6 +319,9 @@ private:
|
|||
*/
|
||||
static void Shutdown();
|
||||
|
||||
static void StackWalkCallback(void* aPc, void* aSp, void* aClosure);
|
||||
static void GetStackTrace(AcquisitionState& aState);
|
||||
|
||||
# ifdef MOZILLA_INTERNAL_API
|
||||
// so it can call BlockingResourceBase::Shutdown()
|
||||
friend void LogTerm();
|
||||
|
|
|
@ -605,7 +605,10 @@ ThreadStackHelper::FillStackBuffer()
|
|||
}
|
||||
#endif
|
||||
const char* const label = entry->label();
|
||||
if (mStackToFill->IsSameAsEntry(prevLabel, label)) {
|
||||
if (mStackToFill->IsSameAsEntry(prevLabel, label) ||
|
||||
!strcmp(label, "js::RunScript")) {
|
||||
// Avoid duplicate labels to save space in the stack.
|
||||
// Avoid js::RunScript labels because we save actual JS frames above.
|
||||
continue;
|
||||
}
|
||||
mStackToFill->infallibleAppend(label);
|
||||
|
|
Загрузка…
Ссылка в новой задаче