This commit is contained in:
Ryan VanderMeulen 2013-04-15 12:12:34 -04:00
Родитель d2a0208792 d602676c91
Коммит 84b40fcc6a
84 изменённых файлов: 1932 добавлений и 1378 удалений

Просмотреть файл

@ -4219,7 +4219,6 @@ MOZ_OMX_PLUGIN=
MOZ_VP8=
MOZ_VP8_ERROR_CONCEALMENT=
MOZ_VP8_ENCODER=
MOZ_WEBVTT=1
MOZ_WEBSPEECH=1
VPX_AS=
VPX_ASFLAGS=
@ -5701,10 +5700,6 @@ if test -n "$MOZ_OPUS"; then
AC_DEFINE(MOZ_OPUS)
fi
if test -n "$MOZ_WEBVTT"; then
AC_DEFINE(MOZ_WEBVTT)
fi
dnl ========================================================
dnl = Check alsa availability on Linux if using sydneyaudio
dnl ========================================================
@ -8909,7 +8904,6 @@ AC_SUBST(MOZ_VORBIS)
AC_SUBST(MOZ_TREMOR)
AC_SUBST(MOZ_OPUS)
AC_SUBST(MOZ_WEBM)
AC_SUBST(MOZ_WEBVTT)
AC_SUBST(MOZ_DASH)
AC_SUBST(MOZ_WMF)
AC_SUBST(MOZ_MEDIA_PLUGINS)

Просмотреть файл

@ -177,6 +177,18 @@ AudioNodeStream::EnsureTrack()
return track;
}
bool
AudioNodeStream::AllInputsFinished() const
{
uint32_t inputCount = mInputs.Length();
for (uint32_t i = 0; i < inputCount; ++i) {
if (!mInputs[i]->GetSource()->IsFinishedOnGraphThread()) {
return false;
}
}
return !!inputCount;
}
AudioChunk*
AudioNodeStream::ObtainInputBlock(AudioChunk* aTmpChunk)
{

Просмотреть файл

@ -74,6 +74,7 @@ public:
double aStreamTime);
virtual void ProduceOutput(GraphTime aFrom, GraphTime aTo);
TrackTicks GetCurrentPosition();
bool AllInputsFinished() const;
// Any thread
AudioNodeEngine* Engine() { return mEngine; }

Просмотреть файл

@ -413,12 +413,11 @@ AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* aContext)
: AudioNode(aContext)
, mLoopStart(0.0)
, mLoopEnd(0.0)
, mLoop(false)
, mStartCalled(false)
, mPlaybackRate(new AudioParam(this, SendPlaybackRateToStream, 1.0f))
, mPannerNode(nullptr)
, mLoop(false)
, mStartCalled(false)
{
SetProduceOwnOutput(true);
mStream = aContext->Graph()->CreateAudioNodeStream(
new AudioBufferSourceNodeEngine(aContext->Destination()),
MediaStreamGraph::INTERNAL_STREAM);
@ -503,6 +502,9 @@ AudioBufferSourceNode::Start(JSContext* aCx, double aWhen, double aOffset,
ns->SetInt32Parameter(AudioBufferSourceNodeEngine::DURATION,
NS_lround(endOffset*rate) - offsetTicks);
ns->SetInt32Parameter(AudioBufferSourceNodeEngine::SAMPLE_RATE, rate);
MOZ_ASSERT(!mPlayingRef, "We can only accept a successful start() call once");
mPlayingRef.Take(this);
}
void
@ -528,7 +530,9 @@ void
AudioBufferSourceNode::NotifyMainThreadStateChanged()
{
if (mStream->IsFinished()) {
SetProduceOwnOutput(false);
// Drop the playing reference
// Warning: The below line might delete this.
mPlayingRef.Drop(this);
}
}

Просмотреть файл

@ -50,16 +50,6 @@ public:
mPannerNode = aPannerNode;
}
void JSBindingFinalized()
{
// If the JS binding goes away on a node which never received a start()
// call, then it can no longer produce output.
if (!mStartCalled) {
SetProduceOwnOutput(false);
}
AudioNode::JSBindingFinalized();
}
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioBufferSourceNode, AudioNode)
@ -126,13 +116,14 @@ public:
private:
static void SendPlaybackRateToStream(AudioNode* aNode);
nsRefPtr<AudioBuffer> mBuffer;
double mLoopStart;
double mLoopEnd;
bool mLoop;
bool mStartCalled;
nsRefPtr<AudioBuffer> mBuffer;
nsRefPtr<AudioParam> mPlaybackRate;
PannerNode* mPannerNode;
SelfReference<AudioBufferSourceNode> mPlayingRef; // a reference to self while playing
bool mLoop;
bool mStartCalled;
};
}

Просмотреть файл

@ -6,7 +6,6 @@
#include "AudioContext.h"
#include "nsContentUtils.h"
#include "nsIDOMWindow.h"
#include "nsPIDOMWindow.h"
#include "mozilla/ErrorResult.h"
#include "MediaStreamGraph.h"
@ -33,7 +32,7 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AudioContext, Release)
static uint8_t gWebAudioOutputKey;
AudioContext::AudioContext(nsIDOMWindow* aWindow)
AudioContext::AudioContext(nsPIDOMWindow* aWindow)
: mWindow(aWindow)
, mDestination(new AudioDestinationNode(this, MediaStreamGraph::GetInstance()))
{
@ -233,13 +232,19 @@ AudioContext::CurrentTime() const
void
AudioContext::Suspend()
{
DestinationStream()->ChangeExplicitBlockerCount(1);
MediaStream* ds = DestinationStream();
if (ds) {
ds->ChangeExplicitBlockerCount(1);
}
}
void
AudioContext::Resume()
{
DestinationStream()->ChangeExplicitBlockerCount(-1);
MediaStream* ds = DestinationStream();
if (ds) {
ds->ChangeExplicitBlockerCount(-1);
}
}
}

Просмотреть файл

@ -19,7 +19,6 @@
#include "MediaBufferDecoder.h"
#include "StreamBuffer.h"
#include "MediaStreamGraph.h"
#include "nsIDOMWindow.h"
// X11 has a #define for CurrentTime. Unbelievable :-(.
// See content/media/DOMMediaStream.h for more fun!
@ -29,7 +28,7 @@
struct JSContext;
class JSObject;
class nsIDOMWindow;
class nsPIDOMWindow;
namespace mozilla {
@ -53,14 +52,14 @@ class PannerNode;
class AudioContext MOZ_FINAL : public nsWrapperCache,
public EnableWebAudioCheck
{
explicit AudioContext(nsIDOMWindow* aParentWindow);
explicit AudioContext(nsPIDOMWindow* aParentWindow);
~AudioContext();
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AudioContext)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(AudioContext)
nsIDOMWindow* GetParentObject() const
nsPIDOMWindow* GetParentObject() const
{
return mWindow;
}
@ -148,7 +147,7 @@ private:
friend struct ::mozilla::WebAudioDecodeJob;
private:
nsCOMPtr<nsIDOMWindow> mWindow;
nsCOMPtr<nsPIDOMWindow> mWindow;
nsRefPtr<AudioDestinationNode> mDestination;
nsRefPtr<AudioListener> mListener;
MediaBufferDecoder mDecoder;

Просмотреть файл

@ -9,31 +9,17 @@
#include "AudioNodeEngine.h"
#include "AudioNodeStream.h"
#include "MediaStreamGraph.h"
#include "nsContentUtils.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(AudioDestinationNode, AudioNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(AudioDestinationNode, AudioNode)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(AudioDestinationNode)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AudioDestinationNode)
NS_INTERFACE_MAP_END_INHERITING(AudioNode)
NS_IMPL_CYCLE_COLLECTING_ADDREF(AudioDestinationNode)
NS_IMPL_CYCLE_COLLECTING_RELEASE(AudioDestinationNode)
NS_IMPL_ISUPPORTS_INHERITED0(AudioDestinationNode, AudioNode)
AudioDestinationNode::AudioDestinationNode(AudioContext* aContext, MediaStreamGraph* aGraph)
: AudioNode(aContext)
{
mStream = aGraph->CreateAudioNodeStream(new AudioNodeEngine(),
MediaStreamGraph::EXTERNAL_STREAM);
SetIsDOMBinding();
}
JSObject*

Просмотреть файл

@ -14,19 +14,12 @@ namespace dom {
class AudioContext;
/**
* Need to have an nsWrapperCache on AudioDestinationNodes since
* AudioContext.destination returns them.
*/
class AudioDestinationNode : public AudioNode,
public nsWrapperCache
class AudioDestinationNode : public AudioNode
{
public:
AudioDestinationNode(AudioContext* aContext, MediaStreamGraph* aGraph);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(AudioDestinationNode,
AudioNode)
virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope) MOZ_OVERRIDE;
@ -35,12 +28,6 @@ public:
return 0;
}
void JSBindingFinalized()
{
// Don't do anything special for destination nodes, as they will always
// remain accessible through the AudioContext.
}
};
}

Просмотреть файл

@ -13,44 +13,32 @@
namespace mozilla {
namespace dom {
inline void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
AudioNode::InputNode& aField,
const char* aName,
unsigned aFlags)
{
CycleCollectionNoteChild(aCallback, aField.mInputNode.get(), aName, aFlags);
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(AudioNode, nsDOMEventTargetHelper)
tmp->DisconnectFromGraph();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOutputNodes)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(AudioNode, nsDOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutputNodes)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
inline void
ImplCycleCollectionUnlink(nsCycleCollectionTraversalCallback& aCallback,
AudioNode::InputNode& aField,
const char* aName,
unsigned aFlags)
{
aField.mInputNode = nullptr;
}
NS_IMPL_CYCLE_COLLECTION_3(AudioNode, mContext, mInputNodes, mOutputNodes)
NS_IMPL_CYCLE_COLLECTING_ADDREF(AudioNode)
NS_IMPL_CYCLE_COLLECTING_RELEASE(AudioNode)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AudioNode)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF_INHERITED(AudioNode, nsDOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(AudioNode, nsDOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AudioNode)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
AudioNode::AudioNode(AudioContext* aContext)
: mContext(aContext)
, mJSBindingFinalized(false)
, mCanProduceOwnOutput(false)
, mOutputEnded(false)
{
MOZ_ASSERT(aContext);
nsDOMEventTargetHelper::BindToOwner(aContext->GetParentObject());
SetIsDOMBinding();
}
AudioNode::~AudioNode()
{
DestroyMediaStream();
DisconnectFromGraph();
MOZ_ASSERT(mInputNodes.IsEmpty());
MOZ_ASSERT(mOutputNodes.IsEmpty());
}
@ -81,21 +69,8 @@ FindIndexOfNodeWithPorts(const nsTArray<AudioNode::InputNode>& aInputNodes, cons
}
void
AudioNode::UpdateOutputEnded()
AudioNode::DisconnectFromGraph()
{
if (mOutputEnded) {
// Already ended, so nothing to do.
return;
}
if (mCanProduceOwnOutput ||
!mInputNodes.IsEmpty() ||
(!mJSBindingFinalized && NumberOfInputs() > 0)) {
// This node could still produce output in the future.
return;
}
mOutputEnded = true;
// Addref this temporarily so the refcount bumping below doesn't destroy us
// prematurely
nsRefPtr<AudioNode> kungFuDeathGrip = this;
@ -106,9 +81,8 @@ AudioNode::UpdateOutputEnded()
// Disconnect inputs. We don't need them anymore.
while (!mInputNodes.IsEmpty()) {
uint32_t i = mInputNodes.Length() - 1;
nsRefPtr<AudioNode> input = mInputNodes[i].mInputNode.forget();
nsRefPtr<AudioNode> input = mInputNodes[i].mInputNode;
mInputNodes.RemoveElementAt(i);
NS_ASSERTION(mOutputNodes.Contains(this), "input/output inconsistency");
input->mOutputNodes.RemoveElement(this);
}
@ -117,12 +91,9 @@ AudioNode::UpdateOutputEnded()
nsRefPtr<AudioNode> output = mOutputNodes[i].forget();
mOutputNodes.RemoveElementAt(i);
uint32_t inputIndex = FindIndexOfNode(output->mInputNodes, this);
NS_ASSERTION(inputIndex != nsTArray<AudioNode::InputNode>::NoIndex, "input/output inconsistency");
// It doesn't matter which one we remove, since we're going to remove all
// entries for this node anyway.
output->mInputNodes.RemoveElementAt(inputIndex);
output->UpdateOutputEnded();
}
DestroyMediaStream();
@ -143,11 +114,6 @@ AudioNode::Connect(AudioNode& aDestination, uint32_t aOutput,
return;
}
if (IsOutputEnded() || aDestination.IsOutputEnded()) {
// No need to connect since we're not going to produce anything other
// than silence.
return;
}
if (FindIndexOfNodeWithPorts(aDestination.mInputNodes, this, aInput, aOutput) !=
nsTArray<AudioNode::InputNode>::NoIndex) {
// connection already exists.
@ -157,9 +123,6 @@ AudioNode::Connect(AudioNode& aDestination, uint32_t aOutput,
// The MediaStreamGraph will handle cycle detection. We don't need to do it
// here.
// Addref this temporarily so the refcount bumping below doesn't destroy us
nsRefPtr<AudioNode> kungFuDeathGrip = this;
mOutputNodes.AppendElement(&aDestination);
InputNode* input = aDestination.mInputNodes.AppendElement();
input->mInputNode = this;
@ -219,10 +182,6 @@ AudioNode::Disconnect(uint32_t aOutput, ErrorResult& aRv)
return;
}
// Disconnect everything connected to this output. First find the
// corresponding inputs and remove them.
nsAutoTArray<nsRefPtr<AudioNode>,4> outputsToUpdate;
for (int32_t i = mOutputNodes.Length() - 1; i >= 0; --i) {
AudioNode* dest = mOutputNodes[i];
for (int32_t j = dest->mInputNodes.Length() - 1; j >= 0; --j) {
@ -232,17 +191,12 @@ AudioNode::Disconnect(uint32_t aOutput, ErrorResult& aRv)
// Remove one instance of 'dest' from mOutputNodes. There could be
// others, and it's not correct to remove them all since some of them
// could be for different output ports.
*outputsToUpdate.AppendElement() = mOutputNodes[i].forget();
mOutputNodes.RemoveElementAt(i);
break;
}
}
}
for (uint32_t i = 0; i < outputsToUpdate.Length(); ++i) {
outputsToUpdate[i]->UpdateOutputEnded();
}
// This disconnection may have disconnected a panner and a source.
Context()->UpdatePannerSource();
}

Просмотреть файл

@ -7,6 +7,7 @@
#ifndef AudioNode_h_
#define AudioNode_h_
#include "nsDOMEventTargetHelper.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/Attributes.h"
#include "EnableWebAudioCheck.h"
@ -26,6 +27,36 @@ namespace dom {
struct ThreeDPoint;
template<class T>
class SelfReference {
public:
SelfReference() : mHeld(false) {}
~SelfReference()
{
NS_ASSERTION(!mHeld, "Forgot to drop the self reference?");
}
void Take(T* t)
{
if (!mHeld) {
mHeld = true;
t->AddRef();
}
}
void Drop(T* t)
{
if (mHeld) {
mHeld = false;
t->Release();
}
}
operator bool() const { return mHeld; }
private:
bool mHeld;
};
/**
* The DOM object representing a Web Audio AudioNode.
*
@ -38,14 +69,8 @@ struct ThreeDPoint;
* in the future. If it isn't, then we break its connections to its inputs
* and outputs, allowing nodes to be immediately disconnected. This
* disconnection is done internally, invisible to DOM users.
*
* We say that a node cannot produce output in the future if it has no inputs
* that can, and it is not producing output itself without any inputs, and
* either it can never have any inputs or it has no JS wrapper. (If it has a
* JS wrapper and can accept inputs, then a new input could be added in
* the future.)
*/
class AudioNode : public nsISupports,
class AudioNode : public nsDOMEventTargetHelper,
public EnableWebAudioCheck
{
public:
@ -71,14 +96,8 @@ public:
}
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(AudioNode)
void JSBindingFinalized()
{
NS_ASSERTION(!mJSBindingFinalized, "JS binding already finalized");
mJSBindingFinalized = true;
UpdateOutputEnded();
}
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioNode,
nsDOMEventTargetHelper)
virtual AudioBufferSourceNode* AsAudioBufferSourceNode() {
return nullptr;
@ -105,10 +124,6 @@ public:
virtual uint32_t NumberOfInputs() const { return 1; }
virtual uint32_t NumberOfOutputs() const { return 1; }
// This could possibly delete 'this'.
void UpdateOutputEnded();
bool IsOutputEnded() const { return mOutputEnded; }
struct InputNode {
~InputNode()
{
@ -117,9 +132,8 @@ public:
}
}
// Strong reference.
// May be null if the source node has gone away.
nsRefPtr<AudioNode> mInputNode;
// Weak reference.
AudioNode* mInputNode;
nsRefPtr<MediaInputPort> mStreamPort;
// The index of the input port this node feeds into.
uint32_t mInputPort;
@ -129,21 +143,15 @@ public:
MediaStream* Stream() { return mStream; }
// Set this to true when the node can produce its own output even if there
// are no inputs.
void SetProduceOwnOutput(bool aCanProduceOwnOutput)
{
mCanProduceOwnOutput = aCanProduceOwnOutput;
if (!aCanProduceOwnOutput) {
UpdateOutputEnded();
}
}
const nsTArray<InputNode>& InputNodes() const
{
return mInputNodes;
}
private:
// This could possibly delete 'this'.
void DisconnectFromGraph();
protected:
static void Callback(AudioNode* aNode) { /* not implemented */ }
@ -171,15 +179,6 @@ private:
// exact matching entry, since mOutputNodes doesn't include the port
// identifiers and the same node could be connected on multiple ports.
nsTArray<nsRefPtr<AudioNode> > mOutputNodes;
// True if the JS binding has been finalized (so script no longer has
// a reference to this node).
bool mJSBindingFinalized;
// True if this node can produce its own output even when all inputs
// have ended their output.
bool mCanProduceOwnOutput;
// True if this node can never produce anything except silence in the future.
// Updated by UpdateOutputEnded().
bool mOutputEnded;
};
}

Просмотреть файл

@ -24,15 +24,42 @@ NS_IMPL_ADDREF_INHERITED(DelayNode, AudioNode)
NS_IMPL_RELEASE_INHERITED(DelayNode, AudioNode)
class DelayNodeEngine : public AudioNodeEngine
{
class PlayingRefChanged : public nsRunnable
{
public:
explicit DelayNodeEngine(AudioDestinationNode* aDestination)
enum ChangeType { ADDREF, RELEASE };
PlayingRefChanged(DelayNode& aNode, ChangeType aChange)
: mNode(aNode)
, mChange(aChange)
{
}
NS_IMETHOD Run()
{
if (mChange == ADDREF) {
mNode.mPlayingRef.Take(&mNode);
} else if (mChange == RELEASE) {
mNode.mPlayingRef.Drop(&mNode);
}
return NS_OK;
}
private:
DelayNode& mNode;
ChangeType mChange;
};
public:
DelayNodeEngine(AudioDestinationNode* aDestination, DelayNode& aDelay)
: mSource(nullptr)
, mDestination(static_cast<AudioNodeStream*> (aDestination->Stream()))
, mDelayNode(aDelay)
// Keep the default value in sync with the default value in DelayNode::DelayNode.
, mDelay(0.f)
, mMaxDelay(0.)
, mWriteIndex(0)
, mLeftOverData(INT32_MIN)
, mCurrentDelayTime(0.)
{
}
@ -98,7 +125,30 @@ public:
MOZ_ASSERT(mSource == aStream, "Invalid source stream");
const bool firstTime = !!!mBuffer.Length();
const uint32_t numChannels = aInput.mChannelData.Length();
const uint32_t numChannels = aInput.IsNull() ?
mBuffer.Length() :
aInput.mChannelData.Length();
bool playedBackAllLeftOvers = false;
if (!mBuffer.IsEmpty() &&
mLeftOverData == INT32_MIN &&
aStream->AllInputsFinished()) {
mLeftOverData = static_cast<int32_t>(mCurrentDelayTime * IdealAudioRate());
nsRefPtr<PlayingRefChanged> refchanged =
new PlayingRefChanged(mDelayNode, PlayingRefChanged::ADDREF);
NS_DispatchToMainThread(refchanged);
} else if (mLeftOverData != INT32_MIN) {
mLeftOverData -= WEBAUDIO_BLOCK_SIZE;
if (mLeftOverData <= 0) {
mLeftOverData = INT32_MIN;
playedBackAllLeftOvers = true;
nsRefPtr<PlayingRefChanged> refchanged =
new PlayingRefChanged(mDelayNode, PlayingRefChanged::RELEASE);
NS_DispatchToMainThread(refchanged);
}
}
if (!EnsureBuffer(numChannels)) {
aOutput->SetNull(0);
@ -134,7 +184,7 @@ public:
float* buffer = mBuffer[channel].Elements();
const uint32_t bufferLength = mBuffer[channel].Length();
const float* input = static_cast<const float*>(aInput.mChannelData[channel]);
const float* input = static_cast<const float*>(aInput.mChannelData.SafeElementAt(channel));
float* output = static_cast<float*>(const_cast<void*>(aOutput->mChannelData[channel]));
for (uint32_t i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
@ -146,7 +196,9 @@ public:
}
// Write the input sample to the correct location in our buffer
if (input) {
buffer[writeIndex] = input[i];
}
// Now, determine the correct read position. We adjust the read position to be
// from currentDelayTime seconds in the past. We also interpolate the two input
@ -183,10 +235,16 @@ public:
mWriteIndex = writeIndex;
}
}
if (playedBackAllLeftOvers) {
// Delete our buffered data once we no longer need it
mBuffer.Clear();
}
}
AudioNodeStream* mSource;
AudioNodeStream* mDestination;
DelayNode& mDelayNode;
AudioParamTimeline mDelay;
// Maximum delay time in seconds
double mMaxDelay;
@ -195,6 +253,9 @@ public:
// Write index for the buffer, to write the frames to the correct index of the buffer
// given the current delay.
uint32_t mWriteIndex;
// How much data we have in our buffer which needs to be flushed out when our inputs
// finish.
int32_t mLeftOverData;
// Current delay time, in seconds
double mCurrentDelayTime;
};
@ -203,7 +264,7 @@ DelayNode::DelayNode(AudioContext* aContext, double aMaxDelay)
: AudioNode(aContext)
, mDelay(new AudioParam(this, SendDelayToStream, 0.0f))
{
DelayNodeEngine* engine = new DelayNodeEngine(aContext->Destination());
DelayNodeEngine* engine = new DelayNodeEngine(aContext->Destination(), *this);
mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM);
engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get()));
AudioNodeStream* ns = static_cast<AudioNodeStream*>(mStream.get());

Просмотреть файл

@ -37,9 +37,11 @@ public:
private:
static void SendDelayToStream(AudioNode* aNode);
friend class DelayNodeEngine;
private:
nsRefPtr<AudioParam> mDelay;
SelfReference<DelayNode> mPlayingRef;
};
}

Просмотреть файл

@ -180,7 +180,9 @@ PannerNode::PannerNode(AudioContext* aContext)
PannerNode::~PannerNode()
{
if (Context()) {
Context()->UnregisterPannerNode(this);
}
DestroyMediaStream();
}

Просмотреть файл

@ -25,6 +25,7 @@ addLoadEvent(function() {
is(destination.context, context, "Destination node has proper context");
is(destination.numberOfInputs, 1, "Destination node has 1 inputs");
is(destination.numberOfOutputs, 0, "Destination node has 0 outputs");
ok(destination instanceof EventTarget, "AudioNodes must be EventTargets");
testWith(context, buffer, destination, function(source) {
source.start(0);

Просмотреть файл

@ -1,141 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DOMSVGAnimatedTransformList.h"
#include "DOMSVGTransformList.h"
#include "SVGAnimatedTransformList.h"
#include "nsSVGAttrTearoffTable.h"
#include "mozilla/dom/SVGAnimatedTransformListBinding.h"
#include "nsContentUtils.h"
namespace mozilla {
static
nsSVGAttrTearoffTable<SVGAnimatedTransformList,DOMSVGAnimatedTransformList>
sSVGAnimatedTransformListTearoffTable;
NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(DOMSVGAnimatedTransformList, mElement)
NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGAnimatedTransformList)
NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGAnimatedTransformList)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGAnimatedTransformList)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
JSObject*
DOMSVGAnimatedTransformList::WrapObject(JSContext* aCx, JSObject* aScope)
{
return mozilla::dom::SVGAnimatedTransformListBinding::Wrap(aCx, aScope, this);
}
//----------------------------------------------------------------------
already_AddRefed<DOMSVGTransformList>
DOMSVGAnimatedTransformList::BaseVal()
{
if (!mBaseVal) {
mBaseVal = new DOMSVGTransformList(this, InternalAList().GetBaseValue());
}
nsRefPtr<DOMSVGTransformList> baseVal = mBaseVal;
return baseVal.forget();
}
already_AddRefed<DOMSVGTransformList>
DOMSVGAnimatedTransformList::AnimVal()
{
if (!mAnimVal) {
mAnimVal = new DOMSVGTransformList(this, InternalAList().GetAnimValue());
}
nsRefPtr<DOMSVGTransformList> animVal = mAnimVal;
return animVal.forget();
}
/* static */ already_AddRefed<DOMSVGAnimatedTransformList>
DOMSVGAnimatedTransformList::GetDOMWrapper(SVGAnimatedTransformList *aList,
nsSVGElement *aElement)
{
nsRefPtr<DOMSVGAnimatedTransformList> wrapper =
sSVGAnimatedTransformListTearoffTable.GetTearoff(aList);
if (!wrapper) {
wrapper = new DOMSVGAnimatedTransformList(aElement);
sSVGAnimatedTransformListTearoffTable.AddTearoff(aList, wrapper);
}
return wrapper.forget();
}
/* static */ DOMSVGAnimatedTransformList*
DOMSVGAnimatedTransformList::GetDOMWrapperIfExists(
SVGAnimatedTransformList *aList)
{
return sSVGAnimatedTransformListTearoffTable.GetTearoff(aList);
}
DOMSVGAnimatedTransformList::~DOMSVGAnimatedTransformList()
{
// Script no longer has any references to us, to our base/animVal objects, or
// to any of their list items.
sSVGAnimatedTransformListTearoffTable.RemoveTearoff(&InternalAList());
}
void
DOMSVGAnimatedTransformList::InternalBaseValListWillChangeLengthTo(
uint32_t aNewLength)
{
// When the number of items in our internal counterpart's baseVal changes,
// we MUST keep our baseVal in sync. If we don't, script will either see a
// list that is too short and be unable to access indexes that should be
// valid, or else, MUCH WORSE, script will see a list that is too long and be
// able to access "items" at indexes that are out of bounds (read/write to
// bad memory)!!
nsRefPtr<DOMSVGAnimatedTransformList> kungFuDeathGrip;
if (mBaseVal) {
if (aNewLength < mBaseVal->LengthNoFlush()) {
// InternalListLengthWillChange might clear last reference to |this|.
// Retain a temporary reference to keep from dying before returning.
kungFuDeathGrip = this;
}
mBaseVal->InternalListLengthWillChange(aNewLength);
}
// If our attribute is not animating, then our animVal mirrors our baseVal
// and we must sync its length too. (If our attribute is animating, then the
// SMIL engine takes care of calling InternalAnimValListWillChangeLengthTo()
// if necessary.)
if (!IsAnimating()) {
InternalAnimValListWillChangeLengthTo(aNewLength);
}
}
void
DOMSVGAnimatedTransformList::InternalAnimValListWillChangeLengthTo(
uint32_t aNewLength)
{
if (mAnimVal) {
mAnimVal->InternalListLengthWillChange(aNewLength);
}
}
bool
DOMSVGAnimatedTransformList::IsAnimating() const
{
return InternalAList().IsAnimating();
}
SVGAnimatedTransformList&
DOMSVGAnimatedTransformList::InternalAList()
{
return *mElement->GetAnimatedTransformList();
}
const SVGAnimatedTransformList&
DOMSVGAnimatedTransformList::InternalAList() const
{
return *mElement->GetAnimatedTransformList();
}
} // namespace mozilla

Просмотреть файл

@ -1,130 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MOZILLA_DOMSVGANIMATEDTRANSFORMLIST_H__
#define MOZILLA_DOMSVGANIMATEDTRANSFORMLIST_H__
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsSVGElement.h"
#include "nsWrapperCache.h"
#include "mozilla/Attributes.h"
namespace mozilla {
class DOMSVGTransformList;
class SVGAnimatedTransformList;
/**
* Class DOMSVGAnimatedTransformList
*
* This class is used to create the DOM tearoff objects that wrap internal
* SVGAnimatedTransformList objects.
*
* See the architecture comment in DOMSVGAnimatedLengthList.h (that's
* LENGTH list). The comment for that class largly applies to this one too
* and will go a long way to helping you understand the architecture here.
*
* This class is strongly intertwined with DOMSVGTransformList and
* DOMSVGTransform.
* Our DOMSVGTransformList base and anim vals are friends and take care of
* nulling out our pointers to them when they die (making our pointers to them
* true weak refs).
*/
class DOMSVGAnimatedTransformList MOZ_FINAL : public nsISupports,
public nsWrapperCache
{
friend class DOMSVGTransformList;
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMSVGAnimatedTransformList)
/**
* Factory method to create and return a DOMSVGAnimatedTransformList wrapper
* for a given internal SVGAnimatedTransformList object. The factory takes
* care of caching the object that it returns so that the same object can be
* returned for the given SVGAnimatedTransformList each time it is requested.
* The cached object is only removed from the cache when it is destroyed due
* to there being no more references to it or to any of its descendant
* objects. If that happens, any subsequent call requesting the DOM wrapper
* for the SVGAnimatedTransformList will naturally result in a new
* DOMSVGAnimatedTransformList being returned.
*/
static already_AddRefed<DOMSVGAnimatedTransformList>
GetDOMWrapper(SVGAnimatedTransformList *aList, nsSVGElement *aElement);
/**
* This method returns the DOMSVGAnimatedTransformList wrapper for an internal
* SVGAnimatedTransformList object if it currently has a wrapper. If it does
* not, then nullptr is returned.
*/
static DOMSVGAnimatedTransformList*
GetDOMWrapperIfExists(SVGAnimatedTransformList *aList);
/**
* Called by internal code to notify us when we need to sync the length of
* our baseVal DOM list with its internal list. This is called just prior to
* the length of the internal baseVal list being changed so that any DOM list
* items that need to be removed from the DOM list can first get their values
* from their internal counterpart.
*
* The only time this method could fail is on OOM when trying to increase the
* length of the DOM list. If that happens then this method simply clears the
* list and returns. Callers just proceed as normal, and we simply accept
* that the DOM list will be empty (until successfully set to a new value).
*/
void InternalBaseValListWillChangeLengthTo(uint32_t aNewLength);
void InternalAnimValListWillChangeLengthTo(uint32_t aNewLength);
/**
* Returns true if our attribute is animating (in which case our animVal is
* not simply a mirror of our baseVal).
*/
bool IsAnimating() const;
// WebIDL
nsSVGElement* GetParentObject() const { return mElement; }
virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope) MOZ_OVERRIDE;
// These aren't weak refs because mBaseVal and mAnimVal are weak
already_AddRefed<DOMSVGTransformList> BaseVal();
already_AddRefed<DOMSVGTransformList> AnimVal();
private:
/**
* Only our static GetDOMWrapper() factory method may create objects of our
* type.
*/
explicit DOMSVGAnimatedTransformList(nsSVGElement *aElement)
: mBaseVal(nullptr)
, mAnimVal(nullptr)
, mElement(aElement)
{
SetIsDOMBinding();
}
~DOMSVGAnimatedTransformList();
/// Get a reference to this DOM wrapper object's internal counterpart.
SVGAnimatedTransformList& InternalAList();
const SVGAnimatedTransformList& InternalAList() const;
// Weak refs to our DOMSVGTransformList baseVal/animVal objects. These objects
// are friends and take care of clearing these pointers when they die, making
// these true weak references.
DOMSVGTransformList *mBaseVal;
DOMSVGTransformList *mAnimVal;
// Strong ref to our element to keep it alive. We hold this not only for
// ourself, but also for our base/animVal and all of their items.
nsRefPtr<nsSVGElement> mElement;
};
} // namespace mozilla
#endif // MOZILLA_DOMSVGANIMATEDTRANSFORMLIST_H__

Просмотреть файл

@ -6,7 +6,7 @@
#include "DOMSVGTransformList.h"
#include "mozilla/dom/SVGTransform.h"
#include "mozilla/dom/SVGMatrix.h"
#include "SVGAnimatedTransformList.h"
#include "nsSVGAnimatedTransformList.h"
#include "nsSVGElement.h"
#include "nsContentUtils.h"
#include "mozilla/dom/SVGTransformListBinding.h"
@ -36,7 +36,7 @@ namespace mozilla {
using namespace dom;
// We could use NS_IMPL_CYCLE_COLLECTION_1, except that in Unlink() we need to
// clear our DOMSVGAnimatedTransformList's weak ref to us to be safe. (The other
// clear our SVGAnimatedTransformList's weak ref to us to be safe. (The other
// option would be to not unlink and rely on the breaking of the other edges in
// the cycle, as NS_SVG_VAL_IMPL_CYCLE_COLLECTION does.)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGTransformList)
@ -116,7 +116,7 @@ DOMSVGTransformList::InternalListLengthWillChange(uint32_t aNewLength)
SVGTransformList&
DOMSVGTransformList::InternalList() const
{
SVGAnimatedTransformList *alist = Element()->GetAnimatedTransformList();
nsSVGAnimatedTransformList *alist = Element()->GetAnimatedTransformList();
return IsAnimValList() && alist->mAnimVal ?
*alist->mAnimVal :
alist->mBaseVal;

Просмотреть файл

@ -7,7 +7,7 @@
#ifndef MOZILLA_DOMSVGTRANSFORMLIST_H__
#define MOZILLA_DOMSVGTRANSFORMLIST_H__
#include "DOMSVGAnimatedTransformList.h"
#include "mozilla/dom/SVGAnimatedTransformList.h"
#include "nsAutoPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsDebug.h"
@ -31,7 +31,7 @@ class SVGTransform;
* This class is used to create the DOM tearoff objects that wrap internal
* SVGTransformList objects.
*
* See the architecture comment in DOMSVGAnimatedTransformList.h.
* See the architecture comment in SVGAnimatedTransformList.h.
*/
class DOMSVGTransformList MOZ_FINAL : public nsISupports,
public nsWrapperCache
@ -42,7 +42,7 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMSVGTransformList)
DOMSVGTransformList(DOMSVGAnimatedTransformList *aAList,
DOMSVGTransformList(dom::SVGAnimatedTransformList *aAList,
const SVGTransformList &aInternalList)
: mAList(aAList)
{
@ -160,7 +160,7 @@ private:
// of clearing our pointer to them when they die.
FallibleTArray<dom::SVGTransform*> mItems;
nsRefPtr<DOMSVGAnimatedTransformList> mAList;
nsRefPtr<dom::SVGAnimatedTransformList> mAList;
};
} // namespace mozilla

Просмотреть файл

@ -17,7 +17,6 @@ FAIL_ON_WARNINGS = 1
CPPSRCS = \
DOMSVGAnimatedLengthList.cpp \
DOMSVGAnimatedNumberList.cpp \
DOMSVGAnimatedTransformList.cpp \
DOMSVGLength.cpp \
DOMSVGLengthList.cpp \
DOMSVGNumber.cpp \
@ -31,6 +30,7 @@ CPPSRCS = \
nsDOMSVGZoomEvent.cpp \
nsISVGPoint.cpp \
nsSVGAngle.cpp \
nsSVGAnimatedTransformList.cpp \
nsSVGBoolean.cpp \
nsSVGClass.cpp \
nsSVGDataParser.cpp \
@ -172,12 +172,14 @@ EXPORTS = \
EXPORTS_NAMESPACES = mozilla/dom
EXPORTS_mozilla/dom = \
nsSVGAnimatedTransformList.h \
SVGAElement.h \
SVGAltGlyphElement.h \
SVGAngle.h \
SVGAnimatedAngle.h \
SVGAnimatedBoolean.h \
SVGAnimatedLength.h \
SVGAnimatedTransformList.h \
SVGAnimateElement.h \
SVGAnimateTransformElement.h \
SVGAnimateMotionElement.h \

Просмотреть файл

@ -3,318 +3,136 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SVGAnimatedTransformList.h"
#include "DOMSVGAnimatedTransformList.h"
#include "mozilla/dom/SVGAnimationElement.h"
#include "nsSMILValue.h"
#include "prdtoa.h"
#include "SVGContentUtils.h"
#include "nsSVGTransform.h"
#include "SVGTransformListSMILType.h"
#include "mozilla/dom/SVGAnimatedTransformList.h"
#include "DOMSVGTransformList.h"
#include "nsSVGAnimatedTransformList.h"
#include "nsSVGAttrTearoffTable.h"
#include "mozilla/dom/SVGAnimatedTransformListBinding.h"
#include "nsContentUtils.h"
namespace mozilla {
namespace dom {
nsresult
SVGAnimatedTransformList::SetBaseValueString(const nsAString& aValue)
static
nsSVGAttrTearoffTable<nsSVGAnimatedTransformList, SVGAnimatedTransformList>
sSVGAnimatedTransformListTearoffTable;
NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(SVGAnimatedTransformList, mElement)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(SVGAnimatedTransformList, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(SVGAnimatedTransformList, Release)
JSObject*
SVGAnimatedTransformList::WrapObject(JSContext* aCx, JSObject* aScope)
{
SVGTransformList newBaseValue;
nsresult rv = newBaseValue.SetValueFromString(aValue);
if (NS_FAILED(rv)) {
return rv;
return SVGAnimatedTransformListBinding::Wrap(aCx, aScope, this);
}
DOMSVGAnimatedTransformList *domWrapper =
DOMSVGAnimatedTransformList::GetDOMWrapperIfExists(this);
if (domWrapper) {
// We must send this notification *before* changing mBaseVal! If the length
// of our baseVal is being reduced, our baseVal's DOM wrapper list may have
// to remove DOM items from itself, and any removed DOM items need to copy
// their internal counterpart values *before* we change them.
//
domWrapper->InternalBaseValListWillChangeLengthTo(newBaseValue.Length());
}
// We don't need to call DidChange* here - we're only called by
// nsSVGElement::ParseAttribute under Element::SetAttr,
// which takes care of notifying.
rv = mBaseVal.CopyFrom(newBaseValue);
if (NS_FAILED(rv) && domWrapper) {
// Attempting to increase mBaseVal's length failed - reduce domWrapper
// back to the same length:
domWrapper->InternalBaseValListWillChangeLengthTo(mBaseVal.Length());
} else {
mIsAttrSet = true;
}
return rv;
}
void
SVGAnimatedTransformList::ClearBaseValue()
//----------------------------------------------------------------------
already_AddRefed<DOMSVGTransformList>
SVGAnimatedTransformList::BaseVal()
{
DOMSVGAnimatedTransformList *domWrapper =
DOMSVGAnimatedTransformList::GetDOMWrapperIfExists(this);
if (domWrapper) {
// We must send this notification *before* changing mBaseVal! (See above.)
domWrapper->InternalBaseValListWillChangeLengthTo(0);
if (!mBaseVal) {
mBaseVal = new DOMSVGTransformList(this, InternalAList().GetBaseValue());
}
mBaseVal.Clear();
mIsAttrSet = false;
// Caller notifies
nsRefPtr<DOMSVGTransformList> baseVal = mBaseVal;
return baseVal.forget();
}
nsresult
SVGAnimatedTransformList::SetAnimValue(const SVGTransformList& aValue,
already_AddRefed<DOMSVGTransformList>
SVGAnimatedTransformList::AnimVal()
{
if (!mAnimVal) {
mAnimVal = new DOMSVGTransformList(this, InternalAList().GetAnimValue());
}
nsRefPtr<DOMSVGTransformList> animVal = mAnimVal;
return animVal.forget();
}
/* static */ already_AddRefed<SVGAnimatedTransformList>
SVGAnimatedTransformList::GetDOMWrapper(nsSVGAnimatedTransformList *aList,
nsSVGElement *aElement)
{
DOMSVGAnimatedTransformList *domWrapper =
DOMSVGAnimatedTransformList::GetDOMWrapperIfExists(this);
if (domWrapper) {
// A new animation may totally change the number of items in the animVal
// list, replacing what was essentially a mirror of the baseVal list, or
// else replacing and overriding an existing animation. When this happens
// we must try and keep our animVal's DOM wrapper in sync (see the comment
// in DOMSVGAnimatedTransformList::InternalBaseValListWillChangeLengthTo).
//
// It's not possible for us to reliably distinguish between calls to this
// method that are setting a new sample for an existing animation, and
// calls that are setting the first sample of an animation that will
// override an existing animation. Happily it's cheap to just blindly
// notify our animVal's DOM wrapper of its internal counterpart's new value
// each time this method is called, so that's what we do.
//
// Note that we must send this notification *before* setting or changing
// mAnimVal! (See the comment in SetBaseValueString above.)
//
domWrapper->InternalAnimValListWillChangeLengthTo(aValue.Length());
nsRefPtr<SVGAnimatedTransformList> wrapper =
sSVGAnimatedTransformListTearoffTable.GetTearoff(aList);
if (!wrapper) {
wrapper = new SVGAnimatedTransformList(aElement);
sSVGAnimatedTransformListTearoffTable.AddTearoff(aList, wrapper);
}
if (!mAnimVal) {
mAnimVal = new SVGTransformList();
return wrapper.forget();
}
nsresult rv = mAnimVal->CopyFrom(aValue);
if (NS_FAILED(rv)) {
// OOM. We clear the animation, and, importantly, ClearAnimValue() ensures
// that mAnimVal and its DOM wrapper (if any) will have the same length!
ClearAnimValue(aElement);
return rv;
/* static */ SVGAnimatedTransformList*
SVGAnimatedTransformList::GetDOMWrapperIfExists(
nsSVGAnimatedTransformList *aList)
{
return sSVGAnimatedTransformListTearoffTable.GetTearoff(aList);
}
aElement->DidAnimateTransformList();
return NS_OK;
SVGAnimatedTransformList::~SVGAnimatedTransformList()
{
// Script no longer has any references to us, to our base/animVal objects, or
// to any of their list items.
sSVGAnimatedTransformListTearoffTable.RemoveTearoff(&InternalAList());
}
void
SVGAnimatedTransformList::ClearAnimValue(nsSVGElement *aElement)
SVGAnimatedTransformList::InternalBaseValListWillChangeLengthTo(
uint32_t aNewLength)
{
DOMSVGAnimatedTransformList *domWrapper =
DOMSVGAnimatedTransformList::GetDOMWrapperIfExists(this);
if (domWrapper) {
// When all animation ends, animVal simply mirrors baseVal, which may have
// a different number of items to the last active animated value. We must
// keep the length of our animVal's DOM wrapper list in sync, and again we
// must do that before touching mAnimVal. See comments above.
//
domWrapper->InternalAnimValListWillChangeLengthTo(mBaseVal.Length());
// When the number of items in our internal counterpart's baseVal changes,
// we MUST keep our baseVal in sync. If we don't, script will either see a
// list that is too short and be unable to access indexes that should be
// valid, or else, MUCH WORSE, script will see a list that is too long and be
// able to access "items" at indexes that are out of bounds (read/write to
// bad memory)!!
nsRefPtr<SVGAnimatedTransformList> kungFuDeathGrip;
if (mBaseVal) {
if (aNewLength < mBaseVal->LengthNoFlush()) {
// InternalListLengthWillChange might clear last reference to |this|.
// Retain a temporary reference to keep from dying before returning.
kungFuDeathGrip = this;
}
mBaseVal->InternalListLengthWillChange(aNewLength);
}
// If our attribute is not animating, then our animVal mirrors our baseVal
// and we must sync its length too. (If our attribute is animating, then the
// SMIL engine takes care of calling InternalAnimValListWillChangeLengthTo()
// if necessary.)
if (!IsAnimating()) {
InternalAnimValListWillChangeLengthTo(aNewLength);
}
}
void
SVGAnimatedTransformList::InternalAnimValListWillChangeLengthTo(
uint32_t aNewLength)
{
if (mAnimVal) {
mAnimVal->InternalListLengthWillChange(aNewLength);
}
mAnimVal = nullptr;
aElement->DidAnimateTransformList();
}
bool
SVGAnimatedTransformList::IsExplicitlySet() const
SVGAnimatedTransformList::IsAnimating() const
{
// Like other methods of this name, we need to know when a transform value has
// been explicitly set.
//
// There are three ways an animated list can become set:
// 1) Markup -- we set mIsAttrSet to true on any successful call to
// SetBaseValueString and clear it on ClearBaseValue (as called by
// nsSVGElement::UnsetAttr or a failed nsSVGElement::ParseAttribute)
// 2) DOM call -- simply fetching the baseVal doesn't mean the transform value
// has been set. It is set if that baseVal has one or more transforms in
// the list.
// 3) Animation -- which will cause the mAnimVal member to be allocated
return mIsAttrSet || !mBaseVal.IsEmpty() || mAnimVal;
return InternalAList().IsAnimating();
}
nsISMILAttr*
SVGAnimatedTransformList::ToSMILAttr(nsSVGElement* aSVGElement)
nsSVGAnimatedTransformList&
SVGAnimatedTransformList::InternalAList()
{
return new SMILAnimatedTransformList(this, aSVGElement);
return *mElement->GetAnimatedTransformList();
}
nsresult
SVGAnimatedTransformList::SMILAnimatedTransformList::ValueFromString(
const nsAString& aStr,
const dom::SVGAnimationElement* aSrcElement,
nsSMILValue& aValue,
bool& aPreventCachingOfSandwich) const
const nsSVGAnimatedTransformList&
SVGAnimatedTransformList::InternalAList() const
{
NS_ENSURE_TRUE(aSrcElement, NS_ERROR_FAILURE);
NS_ABORT_IF_FALSE(aValue.IsNull(),
"aValue should have been cleared before calling ValueFromString");
const nsAttrValue* typeAttr = aSrcElement->GetAnimAttr(nsGkAtoms::type);
const nsIAtom* transformType = nsGkAtoms::translate; // default val
if (typeAttr) {
if (typeAttr->Type() != nsAttrValue::eAtom) {
// Recognized values of |type| are parsed as an atom -- so if we have
// something other than an atom, then we know already our |type| is
// invalid.
return NS_ERROR_FAILURE;
}
transformType = typeAttr->GetAtomValue();
}
ParseValue(aStr, transformType, aValue);
aPreventCachingOfSandwich = false;
return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK;
}
void
SVGAnimatedTransformList::SMILAnimatedTransformList::ParseValue(
const nsAString& aSpec,
const nsIAtom* aTransformType,
nsSMILValue& aResult)
{
NS_ABORT_IF_FALSE(aResult.IsNull(), "Unexpected type for SMIL value");
// nsSVGSMILTransform constructor should be expecting array with 3 params
PR_STATIC_ASSERT(SVGTransformSMILData::NUM_SIMPLE_PARAMS == 3);
float params[3] = { 0.f };
int32_t numParsed = ParseParameterList(aSpec, params, 3);
uint16_t transformType;
if (aTransformType == nsGkAtoms::translate) {
// tx [ty=0]
if (numParsed != 1 && numParsed != 2)
return;
transformType = SVG_TRANSFORM_TRANSLATE;
} else if (aTransformType == nsGkAtoms::scale) {
// sx [sy=sx]
if (numParsed != 1 && numParsed != 2)
return;
if (numParsed == 1) {
params[1] = params[0];
}
transformType = SVG_TRANSFORM_SCALE;
} else if (aTransformType == nsGkAtoms::rotate) {
// r [cx=0 cy=0]
if (numParsed != 1 && numParsed != 3)
return;
transformType = SVG_TRANSFORM_ROTATE;
} else if (aTransformType == nsGkAtoms::skewX) {
// x-angle
if (numParsed != 1)
return;
transformType = SVG_TRANSFORM_SKEWX;
} else if (aTransformType == nsGkAtoms::skewY) {
// y-angle
if (numParsed != 1)
return;
transformType = SVG_TRANSFORM_SKEWY;
} else {
return;
}
nsSMILValue val(&SVGTransformListSMILType::sSingleton);
SVGTransformSMILData transform(transformType, params);
if (NS_FAILED(SVGTransformListSMILType::AppendTransform(transform, val))) {
return; // OOM
}
// Success! Populate our outparam with parsed value.
aResult.Swap(val);
}
namespace
{
inline void
SkipWsp(nsACString::const_iterator& aIter,
const nsACString::const_iterator& aIterEnd)
{
while (aIter != aIterEnd && IsSVGWhitespace(*aIter))
++aIter;
}
} // end anonymous namespace block
int32_t
SVGAnimatedTransformList::SMILAnimatedTransformList::ParseParameterList(
const nsAString& aSpec,
float* aVars,
int32_t aNVars)
{
NS_ConvertUTF16toUTF8 spec(aSpec);
nsACString::const_iterator start, end;
spec.BeginReading(start);
spec.EndReading(end);
SkipWsp(start, end);
int numArgsFound = 0;
while (start != end) {
char const *arg = start.get();
char *argend;
float f = float(PR_strtod(arg, &argend));
if (arg == argend || argend > end.get() || !NS_finite(f))
return -1;
if (numArgsFound < aNVars) {
aVars[numArgsFound] = f;
}
start.advance(argend - arg);
numArgsFound++;
SkipWsp(start, end);
if (*start == ',') {
++start;
SkipWsp(start, end);
}
}
return numArgsFound;
}
nsSMILValue
SVGAnimatedTransformList::SMILAnimatedTransformList::GetBaseValue() const
{
// To benefit from Return Value Optimization and avoid copy constructor calls
// due to our use of return-by-value, we must return the exact same object
// from ALL return points. This function must only return THIS variable:
nsSMILValue val(&SVGTransformListSMILType::sSingleton);
if (!SVGTransformListSMILType::AppendTransforms(mVal->mBaseVal, val)) {
val = nsSMILValue();
}
return val;
}
nsresult
SVGAnimatedTransformList::SMILAnimatedTransformList::SetAnimValue(
const nsSMILValue& aNewAnimValue)
{
NS_ABORT_IF_FALSE(
aNewAnimValue.mType == &SVGTransformListSMILType::sSingleton,
"Unexpected type to assign animated value");
SVGTransformList animVal;
if (!SVGTransformListSMILType::GetTransforms(aNewAnimValue,
animVal.mItems)) {
return NS_ERROR_FAILURE;
}
return mVal->SetAnimValue(animVal, mElement);
}
void
SVGAnimatedTransformList::SMILAnimatedTransformList::ClearAnimValue()
{
if (mVal->mAnimVal) {
mVal->ClearAnimValue(mElement);
}
return *mElement->GetAnimatedTransformList();
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -4,138 +4,129 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MOZILLA_SVGANIMATEDTRANSFORMLIST_H__
#define MOZILLA_SVGANIMATEDTRANSFORMLIST_H__
#ifndef mozilla_dom_SVGAnimatedTransformList_h
#define mozilla_dom_SVGAnimatedTransformList_h
#include "nsAutoPtr.h"
#include "nsISMILAttr.h"
#include "SVGTransformList.h"
class nsIAtom;
class nsSMILValue;
class nsSVGElement;
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsSVGElement.h"
#include "nsWrapperCache.h"
#include "mozilla/Attributes.h"
namespace mozilla {
class DOMSVGTransformList;
class nsSVGAnimatedTransformList;
namespace dom {
class SVGAnimationElement;
class SVGTransform;
}
/**
* Class SVGAnimatedTransformList
*
* This class is very different to the SVG DOM interface of the same name found
* in the SVG specification. This is a lightweight internal class - see
* DOMSVGAnimatedTransformList for the heavier DOM class that wraps instances of
* this class and implements the SVG specification's SVGAnimatedTransformList
* DOM interface.
* This class is used to create the DOM tearoff objects that wrap internal
* nsSVGAnimatedTransformList objects.
*
* Except where noted otherwise, this class' methods take care of keeping the
* appropriate DOM wrappers in sync (see the comment in
* DOMSVGAnimatedTransformList::InternalBaseValListWillChangeTo) so that their
* consumers don't need to concern themselves with that.
* See the architecture comment in DOMSVGAnimatedLengthList.h (that's
* LENGTH list). The comment for that class largly applies to this one too
* and will go a long way to helping you understand the architecture here.
*
* This class is strongly intertwined with DOMSVGTransformList and
* DOMSVGTransform.
* Our DOMSVGTransformList base and anim vals are friends and take care of
* nulling out our pointers to them when they die (making our pointers to them
* true weak refs).
*/
class SVGAnimatedTransformList
class SVGAnimatedTransformList MOZ_FINAL : public nsWrapperCache
{
// friends so that they can get write access to mBaseVal
friend class dom::SVGTransform;
friend class DOMSVGTransformList;
friend class mozilla::DOMSVGTransformList;
public:
SVGAnimatedTransformList() : mIsAttrSet(false) { }
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(SVGAnimatedTransformList)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(SVGAnimatedTransformList)
/**
* Because it's so important that mBaseVal and its DOMSVGTransformList wrapper
* (if any) be kept in sync (see the comment in
* DOMSVGAnimatedTransformList::InternalBaseValListWillChangeTo), this method
* returns a const reference. Only our friend classes may get mutable
* references to mBaseVal.
* Factory method to create and return a SVGAnimatedTransformList wrapper
* for a given internal nsSVGAnimatedTransformList object. The factory takes
* care of caching the object that it returns so that the same object can be
* returned for the given nsSVGAnimatedTransformList each time it is requested.
* The cached object is only removed from the cache when it is destroyed due
* to there being no more references to it or to any of its descendant
* objects. If that happens, any subsequent call requesting the DOM wrapper
* for the nsSVGAnimatedTransformList will naturally result in a new
* SVGAnimatedTransformList being returned.
*/
const SVGTransformList& GetBaseValue() const {
return mBaseVal;
}
nsresult SetBaseValueString(const nsAString& aValue);
void ClearBaseValue();
const SVGTransformList& GetAnimValue() const {
return mAnimVal ? *mAnimVal : mBaseVal;
}
nsresult SetAnimValue(const SVGTransformList& aNewAnimValue,
nsSVGElement *aElement);
void ClearAnimValue(nsSVGElement *aElement);
static already_AddRefed<SVGAnimatedTransformList>
GetDOMWrapper(nsSVGAnimatedTransformList *aList, nsSVGElement *aElement);
/**
* Returns true if the corresponding transform attribute is set (or animated)
* to a valid value. Unlike HasTransform it will return true for an empty
* transform.
* This method returns the SVGAnimatedTransformList wrapper for an internal
* nsSVGAnimatedTransformList object if it currently has a wrapper. If it does
* not, then nullptr is returned.
*/
bool IsExplicitlySet() const;
static SVGAnimatedTransformList*
GetDOMWrapperIfExists(nsSVGAnimatedTransformList *aList);
/**
* Returns true if the corresponding transform attribute is set (or animated)
* to a valid value, such that we have at least one transform in our list.
* Returns false otherwise (e.g. if the transform attribute is missing or empty
* or invalid).
* Called by internal code to notify us when we need to sync the length of
* our baseVal DOM list with its internal list. This is called just prior to
* the length of the internal baseVal list being changed so that any DOM list
* items that need to be removed from the DOM list can first get their values
* from their internal counterpart.
*
* The only time this method could fail is on OOM when trying to increase the
* length of the DOM list. If that happens then this method simply clears the
* list and returns. Callers just proceed as normal, and we simply accept
* that the DOM list will be empty (until successfully set to a new value).
*/
bool HasTransform() const
{ return (mAnimVal && !mAnimVal->IsEmpty()) || !mBaseVal.IsEmpty(); }
void InternalBaseValListWillChangeLengthTo(uint32_t aNewLength);
void InternalAnimValListWillChangeLengthTo(uint32_t aNewLength);
bool IsAnimating() const {
return !!mAnimVal;
}
/**
* Returns true if our attribute is animating (in which case our animVal is
* not simply a mirror of our baseVal).
*/
bool IsAnimating() const;
/// Callers own the returned nsISMILAttr
nsISMILAttr* ToSMILAttr(nsSVGElement* aSVGElement);
// WebIDL
nsSVGElement* GetParentObject() const { return mElement; }
virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope) MOZ_OVERRIDE;
// These aren't weak refs because mBaseVal and mAnimVal are weak
already_AddRefed<DOMSVGTransformList> BaseVal();
already_AddRefed<DOMSVGTransformList> AnimVal();
private:
// mAnimVal is a pointer to allow us to determine if we're being animated or
// not. Making it a non-pointer member and using mAnimVal.IsEmpty() to check
// if we're animating is not an option, since that would break animation *to*
// the empty string (<set to="">).
SVGTransformList mBaseVal;
nsAutoPtr<SVGTransformList> mAnimVal;
bool mIsAttrSet;
struct SMILAnimatedTransformList : public nsISMILAttr
/**
* Only our static GetDOMWrapper() factory method may create objects of our
* type.
*/
explicit SVGAnimatedTransformList(nsSVGElement *aElement)
: mBaseVal(nullptr)
, mAnimVal(nullptr)
, mElement(aElement)
{
public:
SMILAnimatedTransformList(SVGAnimatedTransformList* aVal,
nsSVGElement* aSVGElement)
: mVal(aVal)
, mElement(aSVGElement)
{}
SetIsDOMBinding();
}
// nsISMILAttr methods
virtual nsresult ValueFromString(const nsAString& aStr,
const dom::SVGAnimationElement* aSrcElement,
nsSMILValue& aValue,
bool& aPreventCachingOfSandwich) const;
virtual nsSMILValue GetBaseValue() const;
virtual void ClearAnimValue();
virtual nsresult SetAnimValue(const nsSMILValue& aValue);
~SVGAnimatedTransformList();
protected:
static void ParseValue(const nsAString& aSpec,
const nsIAtom* aTransformType,
nsSMILValue& aResult);
static int32_t ParseParameterList(const nsAString& aSpec, float* aVars,
int32_t aNVars);
/// Get a reference to this DOM wrapper object's internal counterpart.
nsSVGAnimatedTransformList& InternalAList();
const nsSVGAnimatedTransformList& InternalAList() const;
// These will stay alive because a nsISMILAttr only lives as long
// as the Compositing step, and DOM elements don't get a chance to
// die during that.
SVGAnimatedTransformList* mVal;
nsSVGElement* mElement;
};
// Weak refs to our DOMSVGTransformList baseVal/animVal objects. These objects
// are friends and take care of clearing these pointers when they die, making
// these true weak references.
DOMSVGTransformList *mBaseVal;
DOMSVGTransformList *mAnimVal;
// Strong ref to our element to keep it alive. We hold this not only for
// ourself, but also for our base/animVal and all of their items.
nsRefPtr<nsSVGElement> mElement;
};
} // namespace dom
} // namespace mozilla
#endif // MOZILLA_SVGANIMATEDTRANSFORMLIST_H__
#endif // mozilla_dom_SVGAnimatedTransformList_h

Просмотреть файл

@ -6,7 +6,7 @@
#include "SVGFragmentIdentifier.h"
#include "mozilla/dom/SVGSVGElement.h"
#include "mozilla/dom/SVGViewElement.h"
#include "SVGAnimatedTransformList.h"
#include "nsSVGAnimatedTransformList.h"
using namespace mozilla;
@ -156,7 +156,7 @@ SVGFragmentIdentifier::ProcessSVGViewSpec(const nsAString &aViewSpec,
}
preserveAspectRatioFound = true;
} else if (IsMatchingParameter(token, NS_LITERAL_STRING("transform"))) {
SVGAnimatedTransformList transforms;
nsSVGAnimatedTransformList transforms;
if (transformFound ||
NS_FAILED(transforms.SetBaseValueString(params))) {
return false;

Просмотреть файл

@ -5,7 +5,7 @@
#include "mozilla/dom/SVGGradientElement.h"
#include "DOMSVGAnimatedTransformList.h"
#include "mozilla/dom/SVGAnimatedTransformList.h"
#include "mozilla/dom/SVGRadialGradientElementBinding.h"
#include "mozilla/dom/SVGLinearGradientElementBinding.h"
#include "mozilla/Util.h"
@ -78,12 +78,12 @@ SVGGradientElement::GradientUnits()
}
/* readonly attribute SVGAnimatedTransformList gradientTransform; */
already_AddRefed<DOMSVGAnimatedTransformList>
already_AddRefed<SVGAnimatedTransformList>
SVGGradientElement::GradientTransform()
{
// We're creating a DOM wrapper, so we must tell GetAnimatedTransformList
// to allocate the SVGAnimatedTransformList if it hasn't already done so:
return DOMSVGAnimatedTransformList::GetDOMWrapper(
return SVGAnimatedTransformList::GetDOMWrapper(
GetAnimatedTransformList(DO_ALLOCATE), this);
}
@ -172,11 +172,11 @@ SVGLinearGradientElement::Y2()
//----------------------------------------------------------------------
// nsSVGElement methods
SVGAnimatedTransformList*
nsSVGAnimatedTransformList*
SVGGradientElement::GetAnimatedTransformList(uint32_t aFlags)
{
if (!mGradientTransform && (aFlags & DO_ALLOCATE)) {
mGradientTransform = new SVGAnimatedTransformList();
mGradientTransform = new nsSVGAnimatedTransformList();
}
return mGradientTransform;
}

Просмотреть файл

@ -6,11 +6,11 @@
#ifndef __NS_SVGGRADIENTELEMENT_H__
#define __NS_SVGGRADIENTELEMENT_H__
#include "nsSVGAnimatedTransformList.h"
#include "nsSVGElement.h"
#include "nsSVGLength2.h"
#include "nsSVGEnum.h"
#include "nsSVGString.h"
#include "SVGAnimatedTransformList.h"
static const unsigned short SVG_SPREADMETHOD_UNKNOWN = 0;
static const unsigned short SVG_SPREADMETHOD_PAD = 1;
@ -29,11 +29,10 @@ NS_NewSVGRadialGradientElement(nsIContent** aResult,
already_AddRefed<nsINodeInfo> aNodeInfo);
namespace mozilla {
class DOMSVGAnimatedTransformList;
namespace dom {
class SVGAnimatedTransformList;
//--------------------- Gradients------------------------
typedef nsSVGElement SVGGradientElementBase;
@ -53,7 +52,7 @@ public:
// nsIContent
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const;
virtual SVGAnimatedTransformList*
virtual nsSVGAnimatedTransformList*
GetAnimatedTransformList(uint32_t aFlags = 0);
virtual nsIAtom* GetTransformListAttrName() const {
return nsGkAtoms::gradientTransform;
@ -61,7 +60,7 @@ public:
// WebIDL
already_AddRefed<nsIDOMSVGAnimatedEnumeration> GradientUnits();
already_AddRefed<DOMSVGAnimatedTransformList> GradientTransform();
already_AddRefed<SVGAnimatedTransformList> GradientTransform();
already_AddRefed<nsIDOMSVGAnimatedEnumeration> SpreadMethod();
already_AddRefed<nsIDOMSVGAnimatedString> Href();
@ -79,7 +78,7 @@ protected:
static StringInfo sStringInfo[1];
// SVGGradientElement values
nsAutoPtr<SVGAnimatedTransformList> mGradientTransform;
nsAutoPtr<nsSVGAnimatedTransformList> mGradientTransform;
};
//---------------------Linear Gradients------------------------

Просмотреть файл

@ -5,9 +5,9 @@
#include "mozilla/Util.h"
#include "DOMSVGAnimatedTransformList.h"
#include "nsCOMPtr.h"
#include "nsGkAtoms.h"
#include "mozilla/dom/SVGAnimatedTransformList.h"
#include "mozilla/dom/SVGPatternElement.h"
#include "mozilla/dom/SVGPatternElementBinding.h"
@ -94,12 +94,12 @@ SVGPatternElement::PatternContentUnits()
return mEnumAttributes[PATTERNCONTENTUNITS].ToDOMAnimatedEnum(this);
}
already_AddRefed<DOMSVGAnimatedTransformList>
already_AddRefed<SVGAnimatedTransformList>
SVGPatternElement::PatternTransform()
{
// We're creating a DOM wrapper, so we must tell GetAnimatedTransformList
// to allocate the SVGAnimatedTransformList if it hasn't already done so:
return DOMSVGAnimatedTransformList::GetDOMWrapper(
return SVGAnimatedTransformList::GetDOMWrapper(
GetAnimatedTransformList(DO_ALLOCATE), this);
}
@ -157,11 +157,11 @@ SVGPatternElement::IsAttributeMapped(const nsIAtom* name) const
//----------------------------------------------------------------------
// nsSVGElement methods
SVGAnimatedTransformList*
nsSVGAnimatedTransformList*
SVGPatternElement::GetAnimatedTransformList(uint32_t aFlags)
{
if (!mPatternTransform && (aFlags & DO_ALLOCATE)) {
mPatternTransform = new SVGAnimatedTransformList();
mPatternTransform = new nsSVGAnimatedTransformList();
}
return mPatternTransform;
}

Просмотреть файл

@ -12,7 +12,7 @@
#include "nsSVGElement.h"
#include "nsSVGViewBox.h"
#include "SVGAnimatedPreserveAspectRatio.h"
#include "SVGAnimatedTransformList.h"
#include "nsSVGAnimatedTransformList.h"
class nsSVGPatternFrame;
@ -20,9 +20,8 @@ nsresult NS_NewSVGPatternElement(nsIContent **aResult,
already_AddRefed<nsINodeInfo> aNodeInfo);
namespace mozilla {
class DOMSVGAnimatedTransformList;
namespace dom {
class SVGAnimatedTransformList;
typedef nsSVGElement SVGPatternElementBase;
@ -47,7 +46,7 @@ public:
// nsSVGSVGElement methods:
virtual bool HasValidDimensions() const;
virtual mozilla::SVGAnimatedTransformList*
virtual mozilla::nsSVGAnimatedTransformList*
GetAnimatedTransformList(uint32_t aFlags = 0);
virtual nsIAtom* GetTransformListAttrName() const {
return nsGkAtoms::patternTransform;
@ -58,7 +57,7 @@ public:
already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
already_AddRefed<nsIDOMSVGAnimatedEnumeration> PatternUnits();
already_AddRefed<nsIDOMSVGAnimatedEnumeration> PatternContentUnits();
already_AddRefed<DOMSVGAnimatedTransformList> PatternTransform();
already_AddRefed<SVGAnimatedTransformList> PatternTransform();
already_AddRefed<SVGAnimatedLength> X();
already_AddRefed<SVGAnimatedLength> Y();
already_AddRefed<SVGAnimatedLength> Width();
@ -81,7 +80,7 @@ protected:
nsSVGEnum mEnumAttributes[2];
static EnumInfo sEnumInfo[2];
nsAutoPtr<mozilla::SVGAnimatedTransformList> mPatternTransform;
nsAutoPtr<mozilla::nsSVGAnimatedTransformList> mPatternTransform;
enum { HREF };
nsSVGString mStringAttributes[1];

Просмотреть файл

@ -6,10 +6,10 @@
#include "mozilla/dom/SVGTransform.h"
#include "mozilla/dom/SVGMatrix.h"
#include "SVGAnimatedTransformList.h"
#include "nsError.h"
#include "nsContentUtils.h"
#include "nsAttrValueInlines.h"
#include "nsSVGAnimatedTransformList.h"
#include "nsSVGAttrTearoffTable.h"
#include "mozilla/dom/SVGTransformBinding.h"
@ -283,7 +283,7 @@ SVGTransform::RemovingFromList()
nsSVGTransform&
SVGTransform::InternalItem()
{
SVGAnimatedTransformList *alist = Element()->GetAnimatedTransformList();
nsSVGAnimatedTransformList *alist = Element()->GetAnimatedTransformList();
return mIsAnimValItem && alist->mAnimVal ?
(*alist->mAnimVal)[mListIndex] :
alist->mBaseVal[mListIndex];
@ -299,7 +299,7 @@ SVGTransform::InternalItem() const
bool
SVGTransform::IndexIsValid()
{
SVGAnimatedTransformList *alist = Element()->GetAnimatedTransformList();
nsSVGAnimatedTransformList *alist = Element()->GetAnimatedTransformList();
return (mIsAnimValItem &&
mListIndex < alist->GetAnimValue().Length()) ||
(!mIsAnimValItem &&

Просмотреть файл

@ -29,7 +29,7 @@ class SVGTransform;
*/
class SVGTransformList
{
friend class SVGAnimatedTransformList;
friend class nsSVGAnimatedTransformList;
friend class DOMSVGTransformList;
friend class dom::SVGTransform;

Просмотреть файл

@ -3,10 +3,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/SVGAnimatedTransformList.h"
#include "mozilla/dom/SVGTransformableElement.h"
#include "mozilla/dom/SVGMatrix.h"
#include "mozilla/dom/SVGSVGElement.h"
#include "DOMSVGAnimatedTransformList.h"
#include "nsContentUtils.h"
#include "nsIDOMMutationEvent.h"
#include "nsIFrame.h"
@ -18,12 +18,12 @@
namespace mozilla {
namespace dom {
already_AddRefed<DOMSVGAnimatedTransformList>
already_AddRefed<SVGAnimatedTransformList>
SVGTransformableElement::Transform()
{
// We're creating a DOM wrapper, so we must tell GetAnimatedTransformList
// to allocate the SVGAnimatedTransformList if it hasn't already done so:
return DOMSVGAnimatedTransformList::GetDOMWrapper(
return SVGAnimatedTransformList::GetDOMWrapper(
GetAnimatedTransformList(DO_ALLOCATE), this).get();
}
@ -136,11 +136,11 @@ SVGTransformableElement::SetAnimateMotionTransform(const gfxMatrix* aMatrix)
DidAnimateTransformList();
}
SVGAnimatedTransformList*
nsSVGAnimatedTransformList*
SVGTransformableElement::GetAnimatedTransformList(uint32_t aFlags)
{
if (!mTransforms && (aFlags & DO_ALLOCATE)) {
mTransforms = new SVGAnimatedTransformList();
mTransforms = new nsSVGAnimatedTransformList();
}
return mTransforms;
}

Просмотреть файл

@ -6,15 +6,14 @@
#ifndef SVGTransformableElement_h
#define SVGTransformableElement_h
#include "nsSVGAnimatedTransformList.h"
#include "nsSVGElement.h"
#include "gfxMatrix.h"
#include "SVGAnimatedTransformList.h"
namespace mozilla {
class DOMSVGAnimatedTransformList;
namespace dom {
class SVGAnimatedTransformList;
class SVGGraphicsElement;
class SVGMatrix;
class SVGIRect;
@ -29,7 +28,7 @@ public:
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE = 0;
// WebIDL
already_AddRefed<DOMSVGAnimatedTransformList> Transform();
already_AddRefed<SVGAnimatedTransformList> Transform();
nsSVGElement* GetNearestViewportElement();
nsSVGElement* GetFarthestViewportElement();
already_AddRefed<SVGIRect> GetBBox(ErrorResult& rv);
@ -53,7 +52,7 @@ public:
virtual const gfxMatrix* GetAnimateMotionTransform() const;
virtual void SetAnimateMotionTransform(const gfxMatrix* aMatrix);
virtual SVGAnimatedTransformList*
virtual nsSVGAnimatedTransformList*
GetAnimatedTransformList(uint32_t aFlags = 0);
virtual nsIAtom* GetTransformListAttrName() const {
return nsGkAtoms::transform;
@ -64,7 +63,7 @@ public:
protected:
// nsSVGElement overrides
nsAutoPtr<SVGAnimatedTransformList> mTransforms;
nsAutoPtr<nsSVGAnimatedTransformList> mTransforms;
// XXX maybe move this to property table, to save space on un-animated elems?
nsAutoPtr<gfxMatrix> mAnimateMotionTransform;

Просмотреть файл

@ -0,0 +1,321 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsSVGAnimatedTransformList.h"
#include "mozilla/dom/SVGAnimatedTransformList.h"
#include "mozilla/dom/SVGAnimationElement.h"
#include "nsSMILValue.h"
#include "prdtoa.h"
#include "SVGContentUtils.h"
#include "nsSVGTransform.h"
#include "SVGTransformListSMILType.h"
namespace mozilla {
using namespace dom;
nsresult
nsSVGAnimatedTransformList::SetBaseValueString(const nsAString& aValue)
{
SVGTransformList newBaseValue;
nsresult rv = newBaseValue.SetValueFromString(aValue);
if (NS_FAILED(rv)) {
return rv;
}
SVGAnimatedTransformList *domWrapper =
SVGAnimatedTransformList::GetDOMWrapperIfExists(this);
if (domWrapper) {
// We must send this notification *before* changing mBaseVal! If the length
// of our baseVal is being reduced, our baseVal's DOM wrapper list may have
// to remove DOM items from itself, and any removed DOM items need to copy
// their internal counterpart values *before* we change them.
//
domWrapper->InternalBaseValListWillChangeLengthTo(newBaseValue.Length());
}
// We don't need to call DidChange* here - we're only called by
// nsSVGElement::ParseAttribute under Element::SetAttr,
// which takes care of notifying.
rv = mBaseVal.CopyFrom(newBaseValue);
if (NS_FAILED(rv) && domWrapper) {
// Attempting to increase mBaseVal's length failed - reduce domWrapper
// back to the same length:
domWrapper->InternalBaseValListWillChangeLengthTo(mBaseVal.Length());
} else {
mIsAttrSet = true;
}
return rv;
}
void
nsSVGAnimatedTransformList::ClearBaseValue()
{
SVGAnimatedTransformList *domWrapper =
SVGAnimatedTransformList::GetDOMWrapperIfExists(this);
if (domWrapper) {
// We must send this notification *before* changing mBaseVal! (See above.)
domWrapper->InternalBaseValListWillChangeLengthTo(0);
}
mBaseVal.Clear();
mIsAttrSet = false;
// Caller notifies
}
nsresult
nsSVGAnimatedTransformList::SetAnimValue(const SVGTransformList& aValue,
nsSVGElement *aElement)
{
SVGAnimatedTransformList *domWrapper =
SVGAnimatedTransformList::GetDOMWrapperIfExists(this);
if (domWrapper) {
// A new animation may totally change the number of items in the animVal
// list, replacing what was essentially a mirror of the baseVal list, or
// else replacing and overriding an existing animation. When this happens
// we must try and keep our animVal's DOM wrapper in sync (see the comment
// in SVGAnimatedTransformList::InternalBaseValListWillChangeLengthTo).
//
// It's not possible for us to reliably distinguish between calls to this
// method that are setting a new sample for an existing animation, and
// calls that are setting the first sample of an animation that will
// override an existing animation. Happily it's cheap to just blindly
// notify our animVal's DOM wrapper of its internal counterpart's new value
// each time this method is called, so that's what we do.
//
// Note that we must send this notification *before* setting or changing
// mAnimVal! (See the comment in SetBaseValueString above.)
//
domWrapper->InternalAnimValListWillChangeLengthTo(aValue.Length());
}
if (!mAnimVal) {
mAnimVal = new SVGTransformList();
}
nsresult rv = mAnimVal->CopyFrom(aValue);
if (NS_FAILED(rv)) {
// OOM. We clear the animation, and, importantly, ClearAnimValue() ensures
// that mAnimVal and its DOM wrapper (if any) will have the same length!
ClearAnimValue(aElement);
return rv;
}
aElement->DidAnimateTransformList();
return NS_OK;
}
void
nsSVGAnimatedTransformList::ClearAnimValue(nsSVGElement *aElement)
{
SVGAnimatedTransformList *domWrapper =
SVGAnimatedTransformList::GetDOMWrapperIfExists(this);
if (domWrapper) {
// When all animation ends, animVal simply mirrors baseVal, which may have
// a different number of items to the last active animated value. We must
// keep the length of our animVal's DOM wrapper list in sync, and again we
// must do that before touching mAnimVal. See comments above.
//
domWrapper->InternalAnimValListWillChangeLengthTo(mBaseVal.Length());
}
mAnimVal = nullptr;
aElement->DidAnimateTransformList();
}
bool
nsSVGAnimatedTransformList::IsExplicitlySet() const
{
// Like other methods of this name, we need to know when a transform value has
// been explicitly set.
//
// There are three ways an animated list can become set:
// 1) Markup -- we set mIsAttrSet to true on any successful call to
// SetBaseValueString and clear it on ClearBaseValue (as called by
// nsSVGElement::UnsetAttr or a failed nsSVGElement::ParseAttribute)
// 2) DOM call -- simply fetching the baseVal doesn't mean the transform value
// has been set. It is set if that baseVal has one or more transforms in
// the list.
// 3) Animation -- which will cause the mAnimVal member to be allocated
return mIsAttrSet || !mBaseVal.IsEmpty() || mAnimVal;
}
nsISMILAttr*
nsSVGAnimatedTransformList::ToSMILAttr(nsSVGElement* aSVGElement)
{
return new SMILAnimatedTransformList(this, aSVGElement);
}
nsresult
nsSVGAnimatedTransformList::SMILAnimatedTransformList::ValueFromString(
const nsAString& aStr,
const dom::SVGAnimationElement* aSrcElement,
nsSMILValue& aValue,
bool& aPreventCachingOfSandwich) const
{
NS_ENSURE_TRUE(aSrcElement, NS_ERROR_FAILURE);
NS_ABORT_IF_FALSE(aValue.IsNull(),
"aValue should have been cleared before calling ValueFromString");
const nsAttrValue* typeAttr = aSrcElement->GetAnimAttr(nsGkAtoms::type);
const nsIAtom* transformType = nsGkAtoms::translate; // default val
if (typeAttr) {
if (typeAttr->Type() != nsAttrValue::eAtom) {
// Recognized values of |type| are parsed as an atom -- so if we have
// something other than an atom, then we know already our |type| is
// invalid.
return NS_ERROR_FAILURE;
}
transformType = typeAttr->GetAtomValue();
}
ParseValue(aStr, transformType, aValue);
aPreventCachingOfSandwich = false;
return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK;
}
void
nsSVGAnimatedTransformList::SMILAnimatedTransformList::ParseValue(
const nsAString& aSpec,
const nsIAtom* aTransformType,
nsSMILValue& aResult)
{
NS_ABORT_IF_FALSE(aResult.IsNull(), "Unexpected type for SMIL value");
// nsSVGSMILTransform constructor should be expecting array with 3 params
PR_STATIC_ASSERT(SVGTransformSMILData::NUM_SIMPLE_PARAMS == 3);
float params[3] = { 0.f };
int32_t numParsed = ParseParameterList(aSpec, params, 3);
uint16_t transformType;
if (aTransformType == nsGkAtoms::translate) {
// tx [ty=0]
if (numParsed != 1 && numParsed != 2)
return;
transformType = SVG_TRANSFORM_TRANSLATE;
} else if (aTransformType == nsGkAtoms::scale) {
// sx [sy=sx]
if (numParsed != 1 && numParsed != 2)
return;
if (numParsed == 1) {
params[1] = params[0];
}
transformType = SVG_TRANSFORM_SCALE;
} else if (aTransformType == nsGkAtoms::rotate) {
// r [cx=0 cy=0]
if (numParsed != 1 && numParsed != 3)
return;
transformType = SVG_TRANSFORM_ROTATE;
} else if (aTransformType == nsGkAtoms::skewX) {
// x-angle
if (numParsed != 1)
return;
transformType = SVG_TRANSFORM_SKEWX;
} else if (aTransformType == nsGkAtoms::skewY) {
// y-angle
if (numParsed != 1)
return;
transformType = SVG_TRANSFORM_SKEWY;
} else {
return;
}
nsSMILValue val(&SVGTransformListSMILType::sSingleton);
SVGTransformSMILData transform(transformType, params);
if (NS_FAILED(SVGTransformListSMILType::AppendTransform(transform, val))) {
return; // OOM
}
// Success! Populate our outparam with parsed value.
aResult.Swap(val);
}
namespace
{
inline void
SkipWsp(nsACString::const_iterator& aIter,
const nsACString::const_iterator& aIterEnd)
{
while (aIter != aIterEnd && IsSVGWhitespace(*aIter))
++aIter;
}
} // end anonymous namespace block
int32_t
nsSVGAnimatedTransformList::SMILAnimatedTransformList::ParseParameterList(
const nsAString& aSpec,
float* aVars,
int32_t aNVars)
{
NS_ConvertUTF16toUTF8 spec(aSpec);
nsACString::const_iterator start, end;
spec.BeginReading(start);
spec.EndReading(end);
SkipWsp(start, end);
int numArgsFound = 0;
while (start != end) {
char const *arg = start.get();
char *argend;
float f = float(PR_strtod(arg, &argend));
if (arg == argend || argend > end.get() || !NS_finite(f))
return -1;
if (numArgsFound < aNVars) {
aVars[numArgsFound] = f;
}
start.advance(argend - arg);
numArgsFound++;
SkipWsp(start, end);
if (*start == ',') {
++start;
SkipWsp(start, end);
}
}
return numArgsFound;
}
nsSMILValue
nsSVGAnimatedTransformList::SMILAnimatedTransformList::GetBaseValue() const
{
// To benefit from Return Value Optimization and avoid copy constructor calls
// due to our use of return-by-value, we must return the exact same object
// from ALL return points. This function must only return THIS variable:
nsSMILValue val(&SVGTransformListSMILType::sSingleton);
if (!SVGTransformListSMILType::AppendTransforms(mVal->mBaseVal, val)) {
val = nsSMILValue();
}
return val;
}
nsresult
nsSVGAnimatedTransformList::SMILAnimatedTransformList::SetAnimValue(
const nsSMILValue& aNewAnimValue)
{
NS_ABORT_IF_FALSE(
aNewAnimValue.mType == &SVGTransformListSMILType::sSingleton,
"Unexpected type to assign animated value");
SVGTransformList animVal;
if (!SVGTransformListSMILType::GetTransforms(aNewAnimValue,
animVal.mItems)) {
return NS_ERROR_FAILURE;
}
return mVal->SetAnimValue(animVal, mElement);
}
void
nsSVGAnimatedTransformList::SMILAnimatedTransformList::ClearAnimValue()
{
if (mVal->mAnimVal) {
mVal->ClearAnimValue(mElement);
}
}
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,141 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MOZILLA_SVGANIMATEDTRANSFORMLIST_H__
#define MOZILLA_SVGANIMATEDTRANSFORMLIST_H__
#include "nsAutoPtr.h"
#include "nsISMILAttr.h"
#include "SVGTransformList.h"
class nsIAtom;
class nsSMILValue;
class nsSVGElement;
namespace mozilla {
namespace dom {
class SVGAnimationElement;
class SVGTransform;
}
/**
* Class nsSVGAnimatedTransformList
*
* This class is very different to the SVG DOM interface of the same name found
* in the SVG specification. This is a lightweight internal class - see
* SVGAnimatedTransformList for the heavier DOM class that wraps instances of
* this class and implements the SVG specification's SVGAnimatedTransformList
* DOM interface.
*
* Except where noted otherwise, this class' methods take care of keeping the
* appropriate DOM wrappers in sync (see the comment in
* SVGAnimatedTransformList::InternalBaseValListWillChangeTo) so that their
* consumers don't need to concern themselves with that.
*/
class nsSVGAnimatedTransformList
{
// friends so that they can get write access to mBaseVal
friend class dom::SVGTransform;
friend class DOMSVGTransformList;
public:
nsSVGAnimatedTransformList() : mIsAttrSet(false) { }
/**
* Because it's so important that mBaseVal and its DOMSVGTransformList wrapper
* (if any) be kept in sync (see the comment in
* SVGAnimatedTransformList::InternalBaseValListWillChangeTo), this method
* returns a const reference. Only our friend classes may get mutable
* references to mBaseVal.
*/
const SVGTransformList& GetBaseValue() const {
return mBaseVal;
}
nsresult SetBaseValueString(const nsAString& aValue);
void ClearBaseValue();
const SVGTransformList& GetAnimValue() const {
return mAnimVal ? *mAnimVal : mBaseVal;
}
nsresult SetAnimValue(const SVGTransformList& aNewAnimValue,
nsSVGElement *aElement);
void ClearAnimValue(nsSVGElement *aElement);
/**
* Returns true if the corresponding transform attribute is set (or animated)
* to a valid value. Unlike HasTransform it will return true for an empty
* transform.
*/
bool IsExplicitlySet() const;
/**
* Returns true if the corresponding transform attribute is set (or animated)
* to a valid value, such that we have at least one transform in our list.
* Returns false otherwise (e.g. if the transform attribute is missing or empty
* or invalid).
*/
bool HasTransform() const
{ return (mAnimVal && !mAnimVal->IsEmpty()) || !mBaseVal.IsEmpty(); }
bool IsAnimating() const {
return !!mAnimVal;
}
/// Callers own the returned nsISMILAttr
nsISMILAttr* ToSMILAttr(nsSVGElement* aSVGElement);
private:
// mAnimVal is a pointer to allow us to determine if we're being animated or
// not. Making it a non-pointer member and using mAnimVal.IsEmpty() to check
// if we're animating is not an option, since that would break animation *to*
// the empty string (<set to="">).
SVGTransformList mBaseVal;
nsAutoPtr<SVGTransformList> mAnimVal;
bool mIsAttrSet;
struct SMILAnimatedTransformList : public nsISMILAttr
{
public:
SMILAnimatedTransformList(nsSVGAnimatedTransformList* aVal,
nsSVGElement* aSVGElement)
: mVal(aVal)
, mElement(aSVGElement)
{}
// nsISMILAttr methods
virtual nsresult ValueFromString(const nsAString& aStr,
const dom::SVGAnimationElement* aSrcElement,
nsSMILValue& aValue,
bool& aPreventCachingOfSandwich) const;
virtual nsSMILValue GetBaseValue() const;
virtual void ClearAnimValue();
virtual nsresult SetAnimValue(const nsSMILValue& aValue);
protected:
static void ParseValue(const nsAString& aSpec,
const nsIAtom* aTransformType,
nsSMILValue& aResult);
static int32_t ParseParameterList(const nsAString& aSpec, float* aVars,
int32_t aNVars);
// These will stay alive because a nsISMILAttr only lives as long
// as the Compositing step, and DOM elements don't get a chance to
// die during that.
nsSVGAnimatedTransformList* mVal;
nsSVGElement* mElement;
};
};
} // namespace mozilla
#endif // MOZILLA_SVGANIMATEDTRANSFORMLIST_H__

Просмотреть файл

@ -24,6 +24,7 @@
#include "nsCSSProps.h"
#include "nsCSSParser.h"
#include "nsEventListenerManager.h"
#include "nsSVGAnimatedTransformList.h"
#include "nsSVGLength2.h"
#include "nsSVGNumber2.h"
#include "nsSVGNumberPair.h"
@ -38,7 +39,6 @@
#include "SVGAnimatedLengthList.h"
#include "SVGAnimatedPointList.h"
#include "SVGAnimatedPathSegList.h"
#include "SVGAnimatedTransformList.h"
#include "SVGContentUtils.h"
#include "nsIFrame.h"
#include <stdarg.h>
@ -601,8 +601,8 @@ nsSVGElement::ParseAttribute(int32_t aNamespaceID,
// Check for SVGAnimatedTransformList attribute
} else if (GetTransformListAttrName() == aAttribute) {
// The transform attribute is being set, so we must ensure that the
// SVGAnimatedTransformList is/has been allocated:
SVGAnimatedTransformList *transformList =
// nsSVGAnimatedTransformList is/has been allocated:
nsSVGAnimatedTransformList *transformList =
GetAnimatedTransformList(DO_ALLOCATE);
rv = transformList->SetBaseValueString(aValue);
if (NS_FAILED(rv)) {
@ -820,7 +820,7 @@ nsSVGElement::UnsetAttrInternal(int32_t aNamespaceID, nsIAtom* aName,
// Check if this is a transform list attribute going away
if (GetTransformListAttrName() == aName) {
SVGAnimatedTransformList *transformList = GetAnimatedTransformList();
nsSVGAnimatedTransformList *transformList = GetAnimatedTransformList();
if (transformList) {
MaybeSerializeAttrBeforeRemoval(aName, aNotify);
transformList->ClearBaseValue();

Просмотреть файл

@ -52,7 +52,7 @@ class SVGUserUnitList;
class SVGAnimatedPointList;
class SVGAnimatedPathSegList;
class SVGAnimatedPreserveAspectRatio;
class SVGAnimatedTransformList;
class nsSVGAnimatedTransformList;
class SVGStringList;
class DOMSVGStringList;
}
@ -83,7 +83,7 @@ public:
typedef mozilla::SVGAnimatedPointList SVGAnimatedPointList;
typedef mozilla::SVGAnimatedPathSegList SVGAnimatedPathSegList;
typedef mozilla::SVGAnimatedPreserveAspectRatio SVGAnimatedPreserveAspectRatio;
typedef mozilla::SVGAnimatedTransformList SVGAnimatedTransformList;
typedef mozilla::nsSVGAnimatedTransformList nsSVGAnimatedTransformList;
typedef mozilla::SVGStringList SVGStringList;
// nsISupports
@ -264,18 +264,18 @@ public:
return nullptr;
}
/**
* Get the SVGAnimatedTransformList for this element.
* Get the nsSVGAnimatedTransformList for this element.
*
* Despite the fact that animated transform lists are used for a variety of
* attributes, no SVG element uses more than one.
*
* It's relatively uncommon for elements to have their transform attribute
* set, so to save memory the SVGAnimatedTransformList is not allocated until
* set, so to save memory the nsSVGAnimatedTransformList is not allocated until
* the attribute is set/animated or its DOM wrapper is created. Callers that
* require the SVGAnimatedTransformList to be allocated and for this method
* require the nsSVGAnimatedTransformList to be allocated and for this method
* to return non-null must pass the DO_ALLOCATE flag.
*/
virtual SVGAnimatedTransformList* GetAnimatedTransformList(
virtual nsSVGAnimatedTransformList* GetAnimatedTransformList(
uint32_t aFlags = 0) {
return nullptr;
}

Просмотреть файл

@ -82,10 +82,6 @@ DOMInterfaces = {
'nativeType': 'mozilla::dom::Activity',
},
'AnalyserNode': {
'wrapperCache': False
},
'AnimationEvent': {
'nativeType': 'nsDOMAnimationEvent',
},
@ -112,7 +108,6 @@ DOMInterfaces = {
'AudioBufferSourceNode': {
'implicitJSContext': [ 'start', 'noteOn', 'noteGrainOn' ],
'resultNotAddRefed': [ 'playbackRate' ],
'wrapperCache': False
},
'AudioListener' : {
@ -133,7 +128,6 @@ DOMInterfaces = {
'BiquadFilterNode': {
'resultNotAddRefed': [ 'frequency', 'q', 'gain' ],
'wrapperCache': False
},
'Blob': [
@ -229,7 +223,6 @@ DOMInterfaces = {
'DelayNode': [
{
'resultNotAddRefed': [ 'delayTime' ],
'wrapperCache': False
}],
'DesktopNotificationCenter': {
@ -292,7 +285,6 @@ DOMInterfaces = {
'binaryNames': {
'release': 'getRelease'
},
'wrapperCache': False
},
'Element': {
@ -378,7 +370,6 @@ DOMInterfaces = {
'GainNode': {
'resultNotAddRefed': [ 'gain' ],
'wrapperCache': False
},
'Gamepad': {
@ -656,7 +647,6 @@ DOMInterfaces = {
'PannerNode': [
{
'resultNotAddRefed': [ 'coneGain', 'distanceGain' ],
'wrapperCache': False
}],
'Performance': {
@ -740,8 +730,7 @@ DOMInterfaces = {
},
'SVGAnimatedTransformList': {
'nativeType': 'mozilla::DOMSVGAnimatedTransformList',
'headerFile': 'DOMSVGAnimatedTransformList.h'
'nativeOwnership': 'refcounted',
},
'SVGAnimationElement': {

Просмотреть файл

@ -11,7 +11,7 @@
*/
[PrefControlled]
interface AudioNode {
interface AudioNode : EventTarget {
[Throws]
void connect(AudioNode destination, optional unsigned long output = 0, optional unsigned long input = 0);

Просмотреть файл

@ -15,6 +15,10 @@ interface DummyInterface {
USSDReceivedEventDict ussdReceivedEvent();
InspectorRGBTriple rgbTriple();
Function getFunction();
void funcSocketsDict(optional SocketsDict arg);
void funcHttpConnDict(optional HttpConnDict arg);
void funcWebSocketDict(optional WebSocketDict arg);
void funcDNSCacheDict(optional DNSCacheDict arg);
};
interface DummyInterfaceWorkers {

Просмотреть файл

@ -0,0 +1,45 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
dictionary SocketsDict {
sequence<DOMString> host;
sequence<unsigned long> port;
sequence<boolean> active;
sequence<unsigned long> tcp;
sequence<double> socksent;
sequence<double> sockreceived;
double sent = 0;
double received = 0;
};
dictionary HttpConnInfoDict {
sequence<unsigned long> rtt;
sequence<unsigned long> ttl;
};
dictionary HttpConnDict {
sequence<DOMString> host;
sequence<unsigned long> port;
sequence<HttpConnInfoDict> active;
sequence<HttpConnInfoDict> idle;
sequence<boolean> spdy;
sequence<boolean> ssl;
};
dictionary WebSocketDict {
sequence<DOMString> hostport;
sequence<unsigned long> msgsent;
sequence<unsigned long> msgreceived;
sequence<double> sentsize;
sequence<double> receivedsize;
sequence<boolean> encrypted;
};
dictionary DNSCacheDict {
sequence<DOMString> hostname;
sequence<sequence<DOMString>> hostaddr;
sequence<DOMString> family;
sequence<double> expiration;
};

Просмотреть файл

@ -158,6 +158,7 @@ webidl_files = \
MozActivity.webidl \
MutationEvent.webidl \
MutationObserver.webidl \
NetDashboard.webidl \
Node.webidl \
NodeFilter.webidl \
NodeIterator.webidl \

Просмотреть файл

@ -2731,9 +2731,14 @@ WifiWorker.prototype = {
return;
}
this._reloadConfiguredNetworks((function(ok) {
// Give it a chance to remove the network even if reload is failed.
if (!ok) {
debug("Warning !!! Failed to reload the configured networks");
}
let ssid = network.ssid;
let networkKey = getNetworkKey(network);
if (!(networkKey in this.configuredNetworks)) {
this._sendMessage(message, false, "Trying to forget an unknown network", msg);
return;
@ -2756,6 +2761,7 @@ WifiWorker.prototype = {
});
});
});
}).bind(this));
},
wps: function(msg) {

Просмотреть файл

@ -859,6 +859,9 @@ public:
* will be mirrored here. This allows for asynchronous animation of the
* margins by reconciling the difference between this value and a value that
* is updated more frequently.
* If the left or top margins are negative, it means that the elements this
* layer represents are auto-positioned, and so fixed position margins should
* not have an effect on the corresponding axis.
*/
void SetFixedPositionMargins(const gfx::Margin& aMargins)
{

Просмотреть файл

@ -104,8 +104,8 @@ ContentClientRemote::EndPaint()
}
}
TemporaryRef<DrawTarget>
ContentClientRemote::CreateDTBuffer(ContentType aType,
void
ContentClientRemote::BuildTextureClient(ContentType aType,
const nsIntRect& aRect,
uint32_t aFlags)
{
@ -127,6 +127,14 @@ ContentClientRemote::CreateDTBuffer(ContentType aType,
MOZ_ASSERT(IsSurfaceDescriptorValid(*mTextureClient->GetDescriptor()));
CreateFrontBufferAndNotify(aRect);
}
TemporaryRef<DrawTarget>
ContentClientRemote::CreateDTBuffer(ContentType aType,
const nsIntRect& aRect,
uint32_t aFlags)
{
BuildTextureClient(aType, aRect, aFlags);
RefPtr<DrawTarget> ret = mTextureClient->LockDrawTarget();
return ret.forget();
@ -137,24 +145,7 @@ ContentClientRemote::CreateBuffer(ContentType aType,
const nsIntRect& aRect,
uint32_t aFlags)
{
NS_ABORT_IF_FALSE(!mIsNewBuffer,
"Bad! Did we create a buffer twice without painting?");
mIsNewBuffer = true;
if (mTextureClient) {
mOldTextures.AppendElement(mTextureClient);
DestroyBuffers();
}
mTextureInfo.mTextureFlags = aFlags | HostRelease;
mTextureClient = CreateTextureClient(TEXTURE_CONTENT);
mContentType = aType;
mSize = gfx::IntSize(aRect.width, aRect.height);
mTextureClient->EnsureAllocated(mSize, mContentType);
MOZ_ASSERT(IsSurfaceDescriptorValid(*mTextureClient->GetDescriptor()));
CreateFrontBufferAndNotify(aRect);
BuildTextureClient(aType, aRect, aFlags);
nsRefPtr<gfxASurface> ret = mTextureClient->LockSurface();
return ret.forget();

Просмотреть файл

@ -215,6 +215,11 @@ protected:
const nsIntRegion& aVisibleRegion,
bool aDidSelfCopy);
// create and configure mTextureClient
void BuildTextureClient(ContentType aType,
const nsIntRect& aRect,
uint32_t aFlags);
// Create the front buffer for the ContentClient/Host pair if necessary
// and notify the compositor that we have created the buffer(s).
virtual void CreateFrontBufferAndNotify(const nsIntRect& aBufferRect) = 0;

Просмотреть файл

@ -642,18 +642,25 @@ CompositorParent::TransformFixedLayers(Layer* aLayer,
// aFixedLayerMargins are the margins we expect to be at at the current
// time, obtained via SyncViewportInfo, and fixedMargins are the margins
// that were used during layout.
// If top/left of fixedMargins are negative, that indicates that this layer
// represents auto-positioned elements, and should not be affected by
// fixed margins at all.
const gfx::Margin& fixedMargins = aLayer->GetFixedPositionMargins();
if (fixedMargins.left >= 0) {
if (anchor.x > 0) {
translation.x -= aFixedLayerMargins.right - fixedMargins.right;
} else {
translation.x += aFixedLayerMargins.left - fixedMargins.left;
}
}
if (fixedMargins.top >= 0) {
if (anchor.y > 0) {
translation.y -= aFixedLayerMargins.bottom - fixedMargins.bottom;
} else {
translation.y += aFixedLayerMargins.top - fixedMargins.top;
}
}
// The transform already takes the resolution scale into account. Since we
// will apply the resolution scale again when computing the effective

Просмотреть файл

@ -0,0 +1,7 @@
<!DOCTYPE html>
<html style="transform-style: preserve-3d;"><head>
<meta http-equiv="content-type" content="text/html; charset=windows-1252"></head><body>
<iframe></iframe>
</body></html>

Просмотреть файл

@ -0,0 +1,7 @@
<!DOCTYPE html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"><meta charset="UTF-8">
</head><body>
<div style="display: table-caption"><iframe></iframe></div>
</body></html>

Просмотреть файл

@ -391,3 +391,5 @@ load 770381-1.html
load 795646.html
load 813372-1.html
load 836990-1.html
pref(layers.force-active,true) load 859526-1.html
pref(layers.force-active,true) load 859630-1.html

Просмотреть файл

@ -91,6 +91,7 @@
#include "nsStyleStructInlines.h"
#include "nsAnimationManager.h"
#include "nsTransitionManager.h"
#include "nsSVGIntegrationUtils.h"
#include <algorithm>
#ifdef MOZ_XUL
@ -7752,6 +7753,11 @@ DoApplyRenderingChangeToTree(nsIFrame* aFrame,
// opacity updates in many cases.
needInvalidatingPaint = true;
aFrame->MarkLayersActive(nsChangeHint_UpdateOpacityLayer);
if (nsSVGIntegrationUtils::UsingEffectsForFrame(aFrame)) {
// SVG effects paints the opacity without using
// nsDisplayOpacity. We need to invalidate manually.
aFrame->InvalidateFrameSubtree();
}
}
if ((aChange & nsChangeHint_UpdateTransformLayer) &&
aFrame->IsTransformed()) {

Просмотреть файл

@ -1395,10 +1395,16 @@ static void Sort(nsDisplayList* aList, int32_t aCount, nsDisplayList::SortLEQ aC
}
}
static nsIContent* FindContentInDocument(nsIContent* aContent, nsIDocument* aDoc) {
nsIContent* c = aContent;
static nsIContent* FindContentInDocument(nsDisplayItem* aItem, nsIDocument* aDoc) {
nsIFrame* frame = aItem->GetUnderlyingFrame();
nsIContent* c = frame->GetContent();
for (;;) {
nsIDocument* d = c->OwnerDoc();
nsIDocument* d;
if (c) {
d = c->OwnerDoc();
} else {
d = frame->PresContext()->Document();
}
if (d == aDoc) {
return c;
}
@ -1422,10 +1428,8 @@ static bool IsContentLEQ(nsDisplayItem* aItem1, nsDisplayItem* aItem2,
// mixed into the same list. Ensure that we're looking at content
// in commonAncestor's document.
nsIDocument* commonAncestorDoc = commonAncestor->OwnerDoc();
nsIContent* content1 = FindContentInDocument(aItem1->GetUnderlyingFrame()->GetContent(),
commonAncestorDoc);
nsIContent* content2 = FindContentInDocument(aItem2->GetUnderlyingFrame()->GetContent(),
commonAncestorDoc);
nsIContent* content1 = FindContentInDocument(aItem1, commonAncestorDoc);
nsIContent* content2 = FindContentInDocument(aItem2, commonAncestorDoc);
if (!content1 || !content2) {
NS_ERROR("Document trees are mixed up!");
// Something weird going on
@ -2957,6 +2961,19 @@ nsDisplayFixedPosition::BuildLayer(nsDisplayListBuilder* aBuilder,
aContainerParameters.mYScale,
NSAppUnitsToFloatPixels(fixedMargins.left, factor) *
aContainerParameters.mXScale);
// If the frame is auto-positioned on either axis, set the top/left layer
// margins to -1, to indicate to the compositor that this layer is
// unaffected by fixed margins.
if (position->mOffset.GetLeftUnit() == eStyleUnit_Auto &&
position->mOffset.GetRightUnit() == eStyleUnit_Auto) {
fixedLayerMargins.left = -1;
}
if (position->mOffset.GetTopUnit() == eStyleUnit_Auto &&
position->mOffset.GetBottomUnit() == eStyleUnit_Auto) {
fixedLayerMargins.top = -1;
}
layer->SetFixedPositionMargins(fixedLayerMargins);
return layer.forget();

Просмотреть файл

@ -409,6 +409,11 @@ nsRangeFrame::GetValueAtEventPoint(nsGUIEvent* aEvent)
nsPoint point =
nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, absPoint, this);
if (point == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)) {
// We don't want to change the current value for this error state.
return GetValue();
}
nsRect rangeContentRect = GetContentRectRelativeToSelf();
nsSize thumbSize;
@ -729,7 +734,8 @@ nsRangeFrame::ShouldUseNativeStyle() const
{
return (StyleDisplay()->mAppearance == NS_THEME_RANGE) &&
!PresContext()->HasAuthorSpecifiedRules(const_cast<nsRangeFrame*>(this),
STYLES_DISABLING_NATIVE_THEMING) &&
(NS_AUTHOR_SPECIFIED_BORDER |
NS_AUTHOR_SPECIFIED_BACKGROUND)) &&
!PresContext()->HasAuthorSpecifiedRules(mTrackDiv->GetPrimaryFrame(),
STYLES_DISABLING_NATIVE_THEMING) &&
!PresContext()->HasAuthorSpecifiedRules(mProgressDiv->GetPrimaryFrame(),

Просмотреть файл

@ -18,6 +18,7 @@
#include "nsPresContext.h"
#include "nsFrameManager.h"
#include "nsCSSFrameConstructor.h"
#include "nsIDocumentInlines.h"
#ifdef DEBUG
#include "nsBlockFrame.h"
@ -115,8 +116,7 @@ nsAbsoluteContainingBlock::Reflow(nsContainerFrame* aDelegatingFrame,
nsPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aReflowStatus,
nscoord aContainingBlockWidth,
nscoord aContainingBlockHeight,
const nsRect& aContainingBlock,
bool aConstrainHeight,
bool aCBWidthChanged,
bool aCBHeightChanged,
@ -135,7 +135,7 @@ nsAbsoluteContainingBlock::Reflow(nsContainerFrame* aDelegatingFrame,
// Reflow the frame
nsReflowStatus kidStatus = NS_FRAME_COMPLETE;
ReflowAbsoluteFrame(aDelegatingFrame, aPresContext, aReflowState,
aContainingBlockWidth, aContainingBlockHeight,
aContainingBlock,
aConstrainHeight, kidFrame, kidStatus,
aOverflowAreas);
nsIFrame* nextFrame = kidFrame->GetNextInFlow();
@ -350,8 +350,7 @@ nsresult
nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegatingFrame,
nsPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nscoord aContainingBlockWidth,
nscoord aContainingBlockHeight,
const nsRect& aContainingBlock,
bool aConstrainHeight,
nsIFrame* aKidFrame,
nsReflowStatus& aStatus,
@ -379,21 +378,7 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
AutoNoisyIndenter indent(nsBlockFrame::gNoisy);
#endif // DEBUG
nsresult rv;
// Get the border values
nsMargin border = aReflowState.mStyleBorder->GetComputedBorder();
// Respect fixed position margins.
if (aDelegatingFrame->GetAbsoluteListID() == nsIFrame::kFixedList) {
const nsMargin& fixedMargins = aPresContext->PresShell()->
GetContentDocumentFixedPositionMargins();
border += fixedMargins;
aContainingBlockWidth -= fixedMargins.left + fixedMargins.right;
aContainingBlockHeight -= fixedMargins.top + fixedMargins.bottom;
}
nscoord availWidth = aContainingBlockWidth;
nscoord availWidth = aContainingBlock.width;
if (availWidth == -1) {
NS_ASSERTION(aReflowState.ComputedWidth() != NS_UNCONSTRAINEDSIZE,
"Must have a useful width _somewhere_");
@ -404,12 +389,15 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
nsHTMLReflowMetrics kidDesiredSize;
nsHTMLReflowState kidReflowState(aPresContext, aReflowState, aKidFrame,
nsSize(availWidth, NS_UNCONSTRAINEDSIZE),
aContainingBlockWidth,
aContainingBlockHeight);
aContainingBlock.width,
aContainingBlock.height);
// Send the WillReflow() notification and position the frame
aKidFrame->WillReflow(aPresContext);
// Get the border values
const nsMargin& border = aReflowState.mStyleBorder->GetComputedBorder();
bool constrainHeight = (aReflowState.availableHeight != NS_UNCONSTRAINEDSIZE)
&& aConstrainHeight
// Don't split if told not to (e.g. for fixed frames)
@ -427,12 +415,15 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
}
// Do the reflow
rv = aKidFrame->Reflow(aPresContext, kidDesiredSize, kidReflowState, aStatus);
nsresult rv = aKidFrame->Reflow(aPresContext, kidDesiredSize, kidReflowState, aStatus);
// If we're solving for 'left' or 'top', then compute it now that we know the
// width/height
if ((NS_AUTOOFFSET == kidReflowState.mComputedOffsets.left) ||
(NS_AUTOOFFSET == kidReflowState.mComputedOffsets.top)) {
nscoord aContainingBlockWidth = aContainingBlock.width;
nscoord aContainingBlockHeight = aContainingBlock.height;
if (-1 == aContainingBlockWidth) {
// Get the containing block width/height
kidReflowState.ComputeContainingBlockRectangle(aPresContext,
@ -463,6 +454,21 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
nsRect rect(border.left + kidReflowState.mComputedOffsets.left + kidReflowState.mComputedMargin.left,
border.top + kidReflowState.mComputedOffsets.top + kidReflowState.mComputedMargin.top,
kidDesiredSize.width, kidDesiredSize.height);
// Offset the frame rect by the given origin of the absolute containing block.
// If the frame is auto-positioned on both sides of an axis, it will be
// positioned based on its containing block and we don't need to offset.
if (aContainingBlock.TopLeft() != nsPoint(0, 0)) {
if (!(kidReflowState.mStylePosition->mOffset.GetLeftUnit() == eStyleUnit_Auto &&
kidReflowState.mStylePosition->mOffset.GetRightUnit() == eStyleUnit_Auto)) {
rect.x += aContainingBlock.x;
}
if (!(kidReflowState.mStylePosition->mOffset.GetTopUnit() == eStyleUnit_Auto &&
kidReflowState.mStylePosition->mOffset.GetBottomUnit() == eStyleUnit_Auto)) {
rect.y += aContainingBlock.y;
}
}
aKidFrame->SetRect(rect);
nsView* view = aKidFrame->GetView();

Просмотреть файл

@ -86,14 +86,12 @@ public:
nsPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aReflowStatus,
nscoord aContainingBlockWidth,
nscoord aContainingBlockHeight,
const nsRect& aContainingBlock,
bool aConstrainHeight,
bool aCBWidthChanged,
bool aCBHeightChanged,
nsOverflowAreas* aOverflowAreas);
void DestroyFrames(nsIFrame* aDelegatingFrame,
nsIFrame* aDestructRoot);
@ -122,8 +120,7 @@ protected:
nsresult ReflowAbsoluteFrame(nsIFrame* aDelegatingFrame,
nsPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nscoord aContainingBlockWidth,
nscoord aContainingBlockHeight,
const nsRect& aContainingBlockRect,
bool aConstrainHeight,
nsIFrame* aKidFrame,
nsReflowStatus& aStatus,

Просмотреть файл

@ -1229,10 +1229,10 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
!(isRoot && NS_UNCONSTRAINEDSIZE == reflowState->ComputedHeight()) &&
aMetrics.height != oldSize.height;
nsRect containingBlock(nsPoint(0, 0), containingBlockSize);
absoluteContainer->Reflow(this, aPresContext, *reflowState,
state.mReflowStatus,
containingBlockSize.width,
containingBlockSize.height, true,
containingBlock, true,
cbWidthChanged, cbHeightChanged,
&aMetrics.mOverflowAreas);

Просмотреть файл

@ -1673,7 +1673,9 @@ WrapPreserve3DListInternal(nsIFrame* aFrame, nsDisplayListBuilder *aBuilder, nsD
// and then flush this list into aOutput by wrapping the whole lot with a single
// nsDisplayTransform.
if (childFrame && (childFrame->GetParent()->Preserves3DChildren() || childFrame == aFrame)) {
if (childFrame &&
childFrame->GetParent() &&
(childFrame->GetParent()->Preserves3DChildren() || childFrame == aFrame)) {
switch (item->GetType()) {
case nsDisplayItem::TYPE_TRANSFORM: {
if (!aTemp->IsEmpty()) {
@ -4114,8 +4116,9 @@ nsFrame::ReflowAbsoluteFrames(nsPresContext* aPresContext,
nsContainerFrame* container = do_QueryFrame(this);
NS_ASSERTION(container, "Abs-pos children only supported on container frames for now");
nsRect containingBlock(0, 0, containingBlockWidth, containingBlockHeight);
absoluteContainer->Reflow(container, aPresContext, aReflowState, aStatus,
containingBlockWidth, containingBlockHeight,
containingBlock,
aConstrainHeight, true, true, // XXX could be optimized
&aDesiredSize.mOverflowAreas);
}
@ -4583,7 +4586,14 @@ nsIFrame::AreLayersMarkedActive(nsChangeHint aChangeHint)
{
LayerActivity* layerActivity =
static_cast<LayerActivity*>(Properties().Get(LayerActivityProperty()));
return layerActivity && (layerActivity->mChangeHint & aChangeHint);
if (layerActivity && (layerActivity->mChangeHint & aChangeHint)) {
return true;
}
if (aChangeHint & nsChangeHint_UpdateTransformLayer &&
Preserves3D()) {
return GetParent()->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer);
}
return false;
}
/* static */ void

Просмотреть файл

@ -250,18 +250,20 @@ ViewportFrame::Reflow(nsPresContext* aPresContext,
// If a scroll position clamping scroll-port size has been set, layout
// fixed position elements to this size instead of the computed size.
nscoord width = reflowState.ComputedWidth();
nscoord height = reflowState.ComputedHeight();
nsRect rect(0, 0, reflowState.ComputedWidth(), reflowState.ComputedHeight());
if (aPresContext->PresShell()->IsScrollPositionClampingScrollPortSizeSet()) {
nsSize size = aPresContext->PresShell()->
GetScrollPositionClampingScrollPortSize();
width = size.width;
height = size.height;
rect.width = size.width;
rect.height = size.height;
}
// Make sure content document fixed-position margins are respected.
rect.Deflate(aPresContext->PresShell()->GetContentDocumentFixedPositionMargins());
// Just reflow all the fixed-pos frames.
rv = GetAbsoluteContainingBlock()->Reflow(this, aPresContext, reflowState, aStatus,
width, height,
rect,
false, true, true, // XXX could be optimized
&aDesiredSize.mOverflowAreas);
}

Просмотреть файл

@ -132,14 +132,7 @@ inDOMUtils::GetChildrenForNode(nsIDOMNode* aNode,
if (aShowingAnonymousContent) {
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
if (content) {
nsRefPtr<nsBindingManager> bindingManager =
inLayoutUtils::GetBindingManagerFor(aNode);
if (bindingManager) {
bindingManager->GetAnonymousNodesFor(content, getter_AddRefs(kids));
if (!kids) {
bindingManager->GetContentListFor(content, getter_AddRefs(kids));
}
}
kids = content->GetChildren(nsIContent::eAllChildren);
}
}

Просмотреть файл

@ -337,18 +337,12 @@ inDeepTreeWalker::PushNode(nsIDOMNode* aNode)
}
if (!kids) {
if (mShowAnonymousContent) {
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
nsRefPtr<nsBindingManager> bindingManager;
if (content &&
(bindingManager = inLayoutUtils::GetBindingManagerFor(aNode))) {
bindingManager->GetAnonymousNodesFor(content, getter_AddRefs(kids));
if (!kids)
bindingManager->GetContentListFor(content, getter_AddRefs(kids));
} else {
aNode->GetChildNodes(getter_AddRefs(kids));
if (content && mShowAnonymousContent) {
kids = content->GetChildren(nsIContent::eAllChildren);
}
} else
}
if (!kids) {
aNode->GetChildNodes(getter_AddRefs(kids));
}

Просмотреть файл

@ -114,11 +114,9 @@ ifdef MOZ_ENABLE_SKIA
SHARED_LIBRARY_LIBS += $(MOZ_SKIA_LIBS)
endif
ifdef MOZ_WEBVTT
SHARED_LIBRARY_LIBS += \
$(DEPTH)/media/webvtt/$(LIB_PREFIX)webvtt.$(LIB_SUFFIX) \
$(NULL)
endif
ifdef MOZ_WEBRTC
ifndef MOZ_WEBRTC_IN_LIBXUL

Просмотреть файл

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg">
<filter id="f"/>
<g filter="url(#f)">
<text>a&#x1e82f;</text>
</g>
<script>
window.addEventListener("load", function() {
var text = document.getElementsByTagName("text")[0];
text.firstChild.data = "d";
text.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "g"));
}, false);
</script>
</svg>

После

Ширина:  |  Высота:  |  Размер: 386 B

Просмотреть файл

@ -157,6 +157,7 @@ load 842009-1.svg
load 842630-1.svg
load 842909-1.svg
load 843072-1.svg
load 843917-1.svg
load 847139-1.svg
load 849688-1.svg
load 849688-2.svg

Просмотреть файл

@ -10,7 +10,7 @@
#include "nsSVGEffects.h"
#include "nsSVGElement.h"
#include "nsSVGUtils.h"
#include "SVGAnimatedTransformList.h"
#include "nsSVGAnimatedTransformList.h"
using namespace mozilla;
@ -179,7 +179,7 @@ nsSVGDisplayContainerFrame::IsSVGTransformed(gfxMatrix *aOwnTransform,
if (mContent->IsSVG()) {
nsSVGElement *content = static_cast<nsSVGElement*>(mContent);
SVGAnimatedTransformList* transformList =
nsSVGAnimatedTransformList* transformList =
content->GetAnimatedTransformList();
if ((transformList && transformList->HasTransform()) ||
content->GetAnimateMotionTransform()) {

Просмотреть файл

@ -192,7 +192,7 @@ nsSVGForeignObjectFrame::IsSVGTransformed(gfxMatrix *aOwnTransform,
}
nsSVGElement *content = static_cast<nsSVGElement*>(mContent);
SVGAnimatedTransformList* transformList =
nsSVGAnimatedTransformList* transformList =
content->GetAnimatedTransformList();
if (transformList && transformList->HasTransform()) {
if (aOwnTransform) {

Просмотреть файл

@ -14,7 +14,7 @@
#include "nsContentUtils.h"
#include "nsIDOMSVGAnimatedNumber.h"
#include "nsSVGEffects.h"
#include "SVGAnimatedTransformList.h"
#include "nsSVGAnimatedTransformList.h"
// XXX Tight coupling with content classes ahead!
@ -157,10 +157,10 @@ nsSVGGradientFrame::GetSpreadMethod()
return GetEnumValue(dom::SVGGradientElement::SPREADMETHOD);
}
const SVGAnimatedTransformList*
const nsSVGAnimatedTransformList*
nsSVGGradientFrame::GetGradientTransformList(nsIContent* aDefault)
{
SVGAnimatedTransformList *thisTransformList =
nsSVGAnimatedTransformList *thisTransformList =
static_cast<dom::SVGGradientElement*>(mContent)->GetAnimatedTransformList();
if (thisTransformList && thisTransformList->IsExplicitlySet())
@ -201,7 +201,7 @@ nsSVGGradientFrame::GetGradientTransform(nsIFrame *aSource,
gfxMatrix(bbox.Width(), 0, 0, bbox.Height(), bbox.X(), bbox.Y());
}
const SVGAnimatedTransformList* animTransformList =
const nsSVGAnimatedTransformList* animTransformList =
GetGradientTransformList(mContent);
if (!animTransformList)
return bboxMatrix;

Просмотреть файл

@ -22,7 +22,7 @@ class nsStyleContext;
struct gfxRect;
namespace mozilla {
class SVGAnimatedTransformList;
class nsSVGAnimatedTransformList;
namespace dom {
class SVGLinearGradientElement;
@ -79,7 +79,7 @@ private:
void GetStopInformation(int32_t aIndex,
float *aOffset, nscolor *aColor, float *aStopOpacity);
const mozilla::SVGAnimatedTransformList* GetGradientTransformList(
const mozilla::nsSVGAnimatedTransformList* GetGradientTransformList(
nsIContent* aDefault);
// Will be singular for gradientUnits="objectBoundingBox" with an empty bbox.
gfxMatrix GetGradientTransform(nsIFrame *aSource,

Просмотреть файл

@ -152,7 +152,7 @@ nsSVGPathGeometryFrame::IsSVGTransformed(gfxMatrix *aOwnTransform,
}
nsSVGElement *content = static_cast<nsSVGElement*>(mContent);
SVGAnimatedTransformList* transformList =
nsSVGAnimatedTransformList* transformList =
content->GetAnimatedTransformList();
if ((transformList && transformList->HasTransform()) ||
content->GetAnimateMotionTransform()) {

Просмотреть файл

@ -20,7 +20,7 @@
#include "nsSVGGeometryFrame.h"
#include "mozilla/dom/SVGPatternElement.h"
#include "nsSVGUtils.h"
#include "SVGAnimatedTransformList.h"
#include "nsSVGAnimatedTransformList.h"
#include "SVGContentUtils.h"
using namespace mozilla;
@ -443,10 +443,10 @@ nsSVGPatternFrame::GetEnumValue(uint32_t aIndex, nsIContent *aDefault)
mEnumAttributes[aIndex].GetAnimValue();
}
SVGAnimatedTransformList*
nsSVGAnimatedTransformList*
nsSVGPatternFrame::GetPatternTransformList(nsIContent* aDefault)
{
SVGAnimatedTransformList *thisTransformList =
nsSVGAnimatedTransformList *thisTransformList =
static_cast<SVGPatternElement *>(mContent)->GetAnimatedTransformList();
if (thisTransformList && thisTransformList->IsExplicitlySet())
@ -462,7 +462,7 @@ nsSVGPatternFrame::GetPatternTransformList(nsIContent* aDefault)
gfxMatrix
nsSVGPatternFrame::GetPatternTransform()
{
SVGAnimatedTransformList* animTransformList =
nsSVGAnimatedTransformList* animTransformList =
GetPatternTransformList(mContent);
if (!animTransformList)
return gfxMatrix();

Просмотреть файл

@ -18,7 +18,7 @@ class nsSVGViewBox;
namespace mozilla {
class SVGAnimatedPreserveAspectRatio;
class SVGAnimatedTransformList;
class nsSVGAnimatedTransformList;
} // namespace mozilla
typedef nsSVGPaintServerFrame nsSVGPatternFrameBase;
@ -90,7 +90,7 @@ protected:
{
return GetEnumValue(aIndex, mContent);
}
mozilla::SVGAnimatedTransformList* GetPatternTransformList(
mozilla::nsSVGAnimatedTransformList* GetPatternTransformList(
nsIContent* aDefault);
gfxMatrix GetPatternTransform();
const nsSVGViewBox &GetViewBox(nsIContent *aDefault);

Просмотреть файл

@ -2880,7 +2880,7 @@ void
GlyphMetricsUpdater::Run(nsSVGTextFrame2* aFrame)
{
aFrame->mPositioningDirty = true;
nsSVGUtils::InvalidateBounds(aFrame, false);
nsSVGEffects::InvalidateRenderingObservers(aFrame);
nsSVGUtils::ScheduleReflowSVG(aFrame);
aFrame->mGlyphMetricsUpdater = nullptr;
}

Просмотреть файл

@ -628,6 +628,9 @@ pref("ui.scrolling.overscroll_snap_limit", -1);
// The minimum amount of space that must be present for an axis to be considered scrollable,
// in 1/1000ths of pixels.
pref("ui.scrolling.min_scrollable_distance", -1);
// The axis lock mode for panning behaviour - set between standard, free and sticky
pref("ui.scrolling.axis_lock_mode", "standard");
// Enable accessibility mode if platform accessibility is enabled.
pref("accessibility.accessfu.activate", 2);

Просмотреть файл

@ -7,6 +7,7 @@ package org.mozilla.gecko.gfx;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.PrefsHelper;
import org.mozilla.gecko.Tab;
import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.ZoomConstraints;
@ -61,6 +62,12 @@ class JavaPanZoomController
// Angle from axis within which we stay axis-locked
private static final double AXIS_LOCK_ANGLE = Math.PI / 6.0; // 30 degrees
// Axis-lock breakout angle
private static final double AXIS_BREAKOUT_ANGLE = Math.PI / 8.0;
// The distance the user has to pan before we consider breaking out of a locked axis
public static final float AXIS_BREAKOUT_THRESHOLD = 1/32f * GeckoAppShell.getDpi();
// The maximum amount we allow you to zoom into a page
private static final float MAX_ZOOM = 4.0f;
@ -77,15 +84,16 @@ class JavaPanZoomController
NOTHING, /* no touch-start events received */
FLING, /* all touches removed, but we're still scrolling page */
TOUCHING, /* one touch-start event received */
PANNING_LOCKED, /* touch-start followed by move (i.e. panning with axis lock) */
PANNING_LOCKED_X, /* touch-start followed by move (i.e. panning with axis lock) X axis */
PANNING_LOCKED_Y, /* as above for Y axis */
PANNING, /* panning without axis lock */
PANNING_HOLD, /* in panning, but not moving.
* similar to TOUCHING but after starting a pan */
PANNING_HOLD_LOCKED, /* like PANNING_HOLD, but axis lock still in effect */
PANNING_HOLD_LOCKED_X, /* like PANNING_HOLD, but axis lock still in effect for X axis */
PANNING_HOLD_LOCKED_Y, /* as above but for Y axis */
PINCHING, /* nth touch-start, where n > 1. this mode allows pan and zoom */
ANIMATED_ZOOM, /* animated zoom to a new rect */
BOUNCE, /* in a bounce animation */
WAITING_LISTENERS, /* a state halfway between NOTHING and TOUCHING - the user has
put a finger down, but we don't yet know if a touch listener has
prevented the default actions yet. we still need to abort animations. */
@ -94,6 +102,12 @@ class JavaPanZoomController
started it, and it's velocity can be updated while it's running. */
}
private enum AxisLockMode {
STANDARD, /* Default axis locking mode that doesn't break out until finger release */
FREE, /* No locking at all */
STICKY /* Break out with hysteresis so that it feels as free as possible whilst locking */
}
private final PanZoomTarget mTarget;
private final SubdocumentScrollHelper mSubscroller;
private final Axis mX;
@ -113,6 +127,8 @@ class JavaPanZoomController
private PanZoomState mState;
/* The per-frame zoom delta for the currently-running AUTONAV animation. */
private float mAutonavZoomDelta;
/* The user selected panning mode */
private AxisLockMode mMode;
public JavaPanZoomController(PanZoomTarget target, View view, EventDispatcher eventDispatcher) {
mTarget = target;
@ -130,6 +146,26 @@ class JavaPanZoomController
registerEventListener(MESSAGE_ZOOM_PAGE);
registerEventListener(MESSAGE_TOUCH_LISTENER);
mMode = AxisLockMode.STANDARD;
PrefsHelper.getPref("ui.scrolling.axis_lock_mode", new PrefsHelper.PrefHandlerBase() {
@Override public void prefValue(String pref, String value) {
if (value.equals("standard")) {
mMode = AxisLockMode.STANDARD;
} else if (value.equals("free")) {
mMode = AxisLockMode.FREE;
} else {
mMode = AxisLockMode.STICKY;
}
}
@Override
public boolean isObserver() {
return true;
}
});
Axis.initPrefs();
}
@ -383,9 +419,11 @@ class JavaPanZoomController
return false;
case TOUCHING:
case PANNING:
case PANNING_LOCKED:
case PANNING_LOCKED_X:
case PANNING_LOCKED_Y:
case PANNING_HOLD:
case PANNING_HOLD_LOCKED:
case PANNING_HOLD_LOCKED_X:
case PANNING_HOLD_LOCKED_Y:
case PINCHING:
Log.e(LOGTAG, "Received impossible touch down while in " + mState);
return false;
@ -420,10 +458,15 @@ class JavaPanZoomController
track(event);
return true;
case PANNING_HOLD_LOCKED:
setState(PanZoomState.PANNING_LOCKED);
case PANNING_HOLD_LOCKED_X:
setState(PanZoomState.PANNING_LOCKED_X);
track(event);
return true;
case PANNING_HOLD_LOCKED_Y:
setState(PanZoomState.PANNING_LOCKED_Y);
// fall through
case PANNING_LOCKED:
case PANNING_LOCKED_X:
case PANNING_LOCKED_Y:
track(event);
return true;
@ -466,9 +509,11 @@ class JavaPanZoomController
return false;
case PANNING:
case PANNING_LOCKED:
case PANNING_LOCKED_X:
case PANNING_LOCKED_Y:
case PANNING_HOLD:
case PANNING_HOLD_LOCKED:
case PANNING_HOLD_LOCKED_X:
case PANNING_HOLD_LOCKED_Y:
setState(PanZoomState.FLING);
fling();
return true;
@ -571,17 +616,21 @@ class JavaPanZoomController
mY.startTouch(y);
mLastEventTime = time;
if (mMode == AxisLockMode.STANDARD || mMode == AxisLockMode.STICKY) {
if (!mX.scrollable() || !mY.scrollable()) {
setState(PanZoomState.PANNING);
} else if (angle < AXIS_LOCK_ANGLE || angle > (Math.PI - AXIS_LOCK_ANGLE)) {
mY.setScrollingDisabled(true);
setState(PanZoomState.PANNING_LOCKED);
setState(PanZoomState.PANNING_LOCKED_X);
} else if (Math.abs(angle - (Math.PI / 2)) < AXIS_LOCK_ANGLE) {
mX.setScrollingDisabled(true);
setState(PanZoomState.PANNING_LOCKED);
setState(PanZoomState.PANNING_LOCKED_Y);
} else {
setState(PanZoomState.PANNING);
}
} else if (mMode == AxisLockMode.FREE) {
setState(PanZoomState.PANNING);
}
}
private float panDistance(MotionEvent move) {
@ -599,6 +648,29 @@ class JavaPanZoomController
}
mLastEventTime = time;
// if we're axis-locked check if the user is trying to scroll away from the lock
if (mMode == AxisLockMode.STICKY) {
float dx = mX.panDistance(x);
float dy = mY.panDistance(y);
double angle = Math.atan2(dy, dx); // range [-pi, pi]
angle = Math.abs(angle); // range [0, pi]
if (Math.abs(dx) > AXIS_BREAKOUT_THRESHOLD || Math.abs(dy) > AXIS_BREAKOUT_THRESHOLD) {
if (mState == PanZoomState.PANNING_LOCKED_X) {
if (angle > AXIS_BREAKOUT_ANGLE && angle < (Math.PI - AXIS_BREAKOUT_ANGLE)) {
mY.setScrollingDisabled(false);
setState(PanZoomState.PANNING);
}
} else if (mState == PanZoomState.PANNING_LOCKED_Y) {
if (Math.abs(angle - (Math.PI / 2)) > AXIS_BREAKOUT_ANGLE) {
mX.setScrollingDisabled(false);
setState(PanZoomState.PANNING);
}
}
}
}
mX.updateWithTouchAt(x, timeDelta);
mY.updateWithTouchAt(y, timeDelta);
}
@ -617,12 +689,14 @@ class JavaPanZoomController
if (stopped()) {
if (mState == PanZoomState.PANNING) {
setState(PanZoomState.PANNING_HOLD);
} else if (mState == PanZoomState.PANNING_LOCKED) {
setState(PanZoomState.PANNING_HOLD_LOCKED);
} else if (mState == PanZoomState.PANNING_LOCKED_X) {
setState(PanZoomState.PANNING_HOLD_LOCKED_X);
} else if (mState == PanZoomState.PANNING_LOCKED_Y) {
setState(PanZoomState.PANNING_HOLD_LOCKED_Y);
} else {
// should never happen, but handle anyway for robustness
Log.e(LOGTAG, "Impossible case " + mState + " when stopped in track");
setState(PanZoomState.PANNING_HOLD_LOCKED);
setState(PanZoomState.PANNING_HOLD);
}
}

Просмотреть файл

@ -5,27 +5,14 @@
#include "nsContentUtils.h"
#include "mozilla/net/Dashboard.h"
#include "mozilla/net/HttpInfo.h"
#include "mozilla/dom/NetDashboardBinding.h"
#include "jsapi.h"
namespace mozilla {
namespace net {
NS_IMPL_THREADSAFE_ISUPPORTS2(Dashboard, nsIDashboard, nsIDashboardEventNotifier)
#define CREATE_ARRAY_OBJECT(object) \
JSObject* object = JS_NewArrayObject(cx, 0, nullptr); \
if (!object) \
return NS_ERROR_OUT_OF_MEMORY ; \
#define SET_ELEMENT(object, func, param, index) \
if (!JS_DefineElement(cx, object, index, func(param), \
nullptr, nullptr, JSPROP_ENUMERATE)) \
return NS_ERROR_OUT_OF_MEMORY; \
#define SET_PROPERTY(finalObject, object, property) \
val = OBJECT_TO_JSVAL(object); \
if (!JS_DefineProperty(cx, finalObject, #property, \
val, nullptr, nullptr, JSPROP_ENUMERATE)) \
return NS_ERROR_OUT_OF_MEMORY; \
using mozilla::dom::Sequence;
Dashboard::Dashboard()
{
@ -62,50 +49,53 @@ Dashboard::GetSocketsDispatch()
nsresult
Dashboard::GetSockets()
{
JS::Value val;
JSContext* cx = nsContentUtils::GetSafeJSContext();
JSAutoRequest request(cx);
JSObject* finalObject = JS_NewObject(cx, nullptr, nullptr, nullptr);
if (!finalObject)
mozilla::dom::SocketsDict dict;
dict.mHost.Construct();
dict.mPort.Construct();
dict.mActive.Construct();
dict.mTcp.Construct();
dict.mSocksent.Construct();
dict.mSockreceived.Construct();
dict.mSent = 0;
dict.mReceived = 0;
Sequence<uint32_t> &ports = dict.mPort.Value();
Sequence<nsString> &hosts = dict.mHost.Value();
Sequence<bool> &active = dict.mActive.Value();
Sequence<uint32_t> &tcp = dict.mTcp.Value();
Sequence<double> &sent = dict.mSocksent.Value();
Sequence<double> &received = dict.mSockreceived.Value();
uint32_t length = mSock.data.Length();
if (!ports.SetCapacity(length) || !hosts.SetCapacity(length) ||
!active.SetCapacity(length) || !tcp.SetCapacity(length) ||
!sent.SetCapacity(length) || !received.SetCapacity(length)) {
mSock.cb = nullptr;
mSock.data.Clear();
JS_ReportOutOfMemory(cx);
return NS_ERROR_OUT_OF_MEMORY;
CREATE_ARRAY_OBJECT(hostJs);
CREATE_ARRAY_OBJECT(portJs);
CREATE_ARRAY_OBJECT(activeJs);
CREATE_ARRAY_OBJECT(sentJs);
CREATE_ARRAY_OBJECT(receivedJs);
CREATE_ARRAY_OBJECT(tcpJs);
CREATE_ARRAY_OBJECT(sockSentJs);
CREATE_ARRAY_OBJECT(sockRecJs);
mSock.totalSent = 0;
mSock.totalRecv = 0;
for (uint32_t i = 0; i < mSock.data.Length(); i++) {
JSString* hostString = JS_NewStringCopyZ(cx, mSock.data[i].host.get());
SET_ELEMENT(hostJs, STRING_TO_JSVAL, hostString, i);
SET_ELEMENT(portJs, INT_TO_JSVAL, mSock.data[i].port, i);
SET_ELEMENT(activeJs, BOOLEAN_TO_JSVAL, mSock.data[i].active, i);
SET_ELEMENT(tcpJs, INT_TO_JSVAL, mSock.data[i].tcp, i);
SET_ELEMENT(sockSentJs, DOUBLE_TO_JSVAL, (double) mSock.data[i].sent, i);
SET_ELEMENT(sockRecJs, DOUBLE_TO_JSVAL, (double) mSock.data[i].received, i);
mSock.totalSent += mSock.data[i].sent;
mSock.totalRecv += mSock.data[i].received;
}
SET_ELEMENT(sentJs, DOUBLE_TO_JSVAL, (double) mSock.totalSent, 0);
SET_ELEMENT(receivedJs, DOUBLE_TO_JSVAL, (double) mSock.totalRecv, 0);
for (uint32_t i = 0; i < mSock.data.Length(); i++) {
CopyASCIItoUTF16(mSock.data[i].host, *hosts.AppendElement());
*ports.AppendElement() = mSock.data[i].port;
*active.AppendElement() = mSock.data[i].active;
*tcp.AppendElement() = mSock.data[i].tcp;
*sent.AppendElement() = (double) mSock.data[i].sent;
*received.AppendElement() = (double) mSock.data[i].received;
dict.mSent += mSock.data[i].sent;
dict.mReceived += mSock.data[i].received;
}
SET_PROPERTY(finalObject, hostJs, host);
SET_PROPERTY(finalObject, portJs, port);
SET_PROPERTY(finalObject, activeJs, active);
SET_PROPERTY(finalObject, tcpJs, tcp);
SET_PROPERTY(finalObject, sockSentJs, socksent);
SET_PROPERTY(finalObject, sockRecJs, sockreceived);
SET_PROPERTY(finalObject, sentJs, sent);
SET_PROPERTY(finalObject, receivedJs, received);
val = OBJECT_TO_JSVAL(finalObject);
JS::Value val;
if (!dict.ToObject(cx, nullptr, &val)) {
mSock.cb = nullptr;
mSock.data.Clear();
return NS_ERROR_FAILURE;
}
mSock.cb->OnDashboardDataAvailable(val);
mSock.cb = nullptr;
@ -138,60 +128,81 @@ Dashboard::GetHttpDispatch()
nsresult
Dashboard::GetHttpConnections()
{
JS::Value val;
JSContext* cx = nsContentUtils::GetSafeJSContext();
JSAutoRequest request(cx);
JSObject* finalObject = JS_NewObject(cx, nullptr, nullptr, nullptr);
if (!finalObject)
return NS_ERROR_OUT_OF_MEMORY;
mozilla::dom::HttpConnDict dict;
dict.mActive.Construct();
dict.mHost.Construct();
dict.mIdle.Construct();
dict.mPort.Construct();
dict.mSpdy.Construct();
dict.mSsl.Construct();
CREATE_ARRAY_OBJECT(hostJs);
CREATE_ARRAY_OBJECT(portJs);
CREATE_ARRAY_OBJECT(activeJs);
CREATE_ARRAY_OBJECT(idleJs);
CREATE_ARRAY_OBJECT(spdyJs);
CREATE_ARRAY_OBJECT(sslJs);
using mozilla::dom::HttpConnInfoDict;
Sequence<HttpConnInfoDict> &active = dict.mActive.Value();
Sequence<nsString> &hosts = dict.mHost.Value();
Sequence<HttpConnInfoDict> &idle = dict.mIdle.Value();
Sequence<uint32_t> &ports = dict.mPort.Value();
Sequence<bool> &spdy = dict.mSpdy.Value();
Sequence<bool> &ssl = dict.mSsl.Value();
uint32_t length = mHttp.data.Length();
if (!active.SetCapacity(length) || !hosts.SetCapacity(length) ||
!idle.SetCapacity(length) || !ports.SetCapacity(length) ||
!spdy.SetCapacity(length) || !ssl.SetCapacity(length)) {
mHttp.cb = nullptr;
mHttp.data.Clear();
JS_ReportOutOfMemory(cx);
return NS_ERROR_OUT_OF_MEMORY;
}
for (uint32_t i = 0; i < mHttp.data.Length(); i++) {
JSString* hostString = JS_NewStringCopyZ(cx, mHttp.data[i].host.get());
SET_ELEMENT(hostJs, STRING_TO_JSVAL, hostString, i);
SET_ELEMENT(portJs, INT_TO_JSVAL, mHttp.data[i].port, i);
JSObject* rtt_Active = JS_NewArrayObject(cx, 0, nullptr);
JSObject* timeToLive_Active = JS_NewArrayObject(cx, 0, nullptr);
CopyASCIItoUTF16(mHttp.data[i].host,*hosts.AppendElement());
*ports.AppendElement() = mHttp.data[i].port;
*spdy.AppendElement() = mHttp.data[i].spdy;
*ssl.AppendElement() = mHttp.data[i].ssl;
HttpConnInfoDict &activeInfo = *active.AppendElement();
activeInfo.mRtt.Construct();
activeInfo.mTtl.Construct();
Sequence<uint32_t> &active_rtt = activeInfo.mRtt.Value();
Sequence<uint32_t> &active_ttl = activeInfo.mTtl.Value();
if (!active_rtt.SetCapacity(mHttp.data[i].active.Length()) ||
!active_ttl.SetCapacity(mHttp.data[i].active.Length())) {
mHttp.cb = nullptr;
mHttp.data.Clear();
JS_ReportOutOfMemory(cx);
return NS_ERROR_OUT_OF_MEMORY;
}
for (uint32_t j = 0; j < mHttp.data[i].active.Length(); j++) {
SET_ELEMENT(rtt_Active, INT_TO_JSVAL, mHttp.data[i].active[j].rtt, j);
SET_ELEMENT(timeToLive_Active, INT_TO_JSVAL, mHttp.data[i].active[j].ttl, j);
*active_rtt.AppendElement() = mHttp.data[i].active[j].rtt;
*active_ttl.AppendElement() = mHttp.data[i].active[j].ttl;
}
JSObject* active = JS_NewObject(cx, nullptr, nullptr, nullptr);
SET_PROPERTY(active, rtt_Active, rtt);
SET_PROPERTY(active, timeToLive_Active, ttl);
SET_ELEMENT(activeJs, OBJECT_TO_JSVAL, active, i);
JSObject* rtt_Idle = JS_NewArrayObject(cx, 0, nullptr);
JSObject* timeToLive_Idle = JS_NewArrayObject(cx, 0, nullptr);
HttpConnInfoDict &idleInfo = *idle.AppendElement();
idleInfo.mRtt.Construct();
idleInfo.mTtl.Construct();
Sequence<uint32_t> &idle_rtt = idleInfo.mRtt.Value();
Sequence<uint32_t> &idle_ttl = idleInfo.mTtl.Value();
if (!idle_rtt.SetCapacity(mHttp.data[i].idle.Length()) ||
!idle_ttl.SetCapacity(mHttp.data[i].idle.Length())) {
mHttp.cb = nullptr;
mHttp.data.Clear();
JS_ReportOutOfMemory(cx);
return NS_ERROR_OUT_OF_MEMORY;
}
for (uint32_t j = 0; j < mHttp.data[i].idle.Length(); j++) {
SET_ELEMENT(rtt_Idle, INT_TO_JSVAL, mHttp.data[i].idle[j].rtt, j);
SET_ELEMENT(timeToLive_Idle, INT_TO_JSVAL, mHttp.data[i].idle[j].ttl, j);
*idle_rtt.AppendElement() = mHttp.data[i].idle[j].rtt;
*idle_ttl.AppendElement() = mHttp.data[i].idle[j].ttl;
}
JSObject* idle = JS_NewObject(cx, nullptr, nullptr, nullptr);
SET_PROPERTY(idle, rtt_Idle, rtt);
SET_PROPERTY(idle, timeToLive_Idle, ttl);
SET_ELEMENT(idleJs, OBJECT_TO_JSVAL, idle, i);
SET_ELEMENT(spdyJs, BOOLEAN_TO_JSVAL, mHttp.data[i].spdy, i);
SET_ELEMENT(sslJs, BOOLEAN_TO_JSVAL, mHttp.data[i].ssl, i);
}
SET_PROPERTY(finalObject, hostJs, host);
SET_PROPERTY(finalObject, portJs, port);
SET_PROPERTY(finalObject, activeJs, active);
SET_PROPERTY(finalObject, idleJs, idle);
SET_PROPERTY(finalObject, spdyJs, spdy);
SET_PROPERTY(finalObject, sslJs, ssl);
val = OBJECT_TO_JSVAL(finalObject);
JS::Value val;
if (!dict.ToObject(cx, nullptr, &val)) {
mHttp.cb = nullptr;
mHttp.data.Clear();
return NS_ERROR_FAILURE;
}
mHttp.cb->OnDashboardDataAvailable(val);
mHttp.cb = nullptr;
@ -288,41 +299,50 @@ Dashboard::RequestWebsocketConnections(NetDashboardCallback* cb)
nsresult
Dashboard::GetWebSocketConnections()
{
JS::Value val;
JSString* jsstring;
JSContext* cx = nsContentUtils::GetSafeJSContext();
JSAutoRequest request(cx);
JSObject* finalObject = JS_NewObject(cx, nullptr, nullptr, nullptr);
if (!finalObject)
return NS_ERROR_OUT_OF_MEMORY;
mozilla::dom::WebSocketDict dict;
dict.mEncrypted.Construct();
dict.mHostport.Construct();
dict.mMsgreceived.Construct();
dict.mMsgsent.Construct();
dict.mReceivedsize.Construct();
dict.mSentsize.Construct();
CREATE_ARRAY_OBJECT(hostJs);
CREATE_ARRAY_OBJECT(msgSentJs);
CREATE_ARRAY_OBJECT(msgRecvJs);
CREATE_ARRAY_OBJECT(sizeSentJs);
CREATE_ARRAY_OBJECT(sizeRecvJs);
CREATE_ARRAY_OBJECT(encryptJs);
Sequence<bool> &encrypted = dict.mEncrypted.Value();
Sequence<nsString> &hostport = dict.mHostport.Value();
Sequence<uint32_t> &received = dict.mMsgreceived.Value();
Sequence<uint32_t> &sent = dict.mMsgsent.Value();
Sequence<double> &receivedSize = dict.mReceivedsize.Value();
Sequence<double> &sentSize = dict.mSentsize.Value();
uint32_t length = mWs.data.Length();
if (!encrypted.SetCapacity(length) || !hostport.SetCapacity(length) ||
!received.SetCapacity(length) || !sent.SetCapacity(length) ||
!receivedSize.SetCapacity(length) || !sentSize.SetCapacity(length)) {
mWs.cb = nullptr;
mWs.data.Clear();
JS_ReportOutOfMemory(cx);
return NS_ERROR_OUT_OF_MEMORY;
}
mozilla::MutexAutoLock lock(mWs.lock);
for (uint32_t i = 0; i < mWs.data.Length(); i++) {
jsstring = JS_NewStringCopyN(cx, mWs.data[i].mHost.get(), mWs.data[i].mHost.Length());
SET_ELEMENT(hostJs, STRING_TO_JSVAL, jsstring, i);
SET_ELEMENT(msgSentJs, INT_TO_JSVAL, mWs.data[i].mMsgSent, i);
SET_ELEMENT(msgRecvJs, INT_TO_JSVAL, mWs.data[i].mMsgReceived, i);
SET_ELEMENT(sizeSentJs, DOUBLE_TO_JSVAL, (double) mWs.data[i].mSizeSent, i);
SET_ELEMENT(sizeRecvJs, DOUBLE_TO_JSVAL, (double) mWs.data[i].mSizeReceived, i);
SET_ELEMENT(encryptJs, BOOLEAN_TO_JSVAL, mWs.data[i].mEncrypted, i);
CopyASCIItoUTF16(mWs.data[i].mHost, *hostport.AppendElement());
*sent.AppendElement() = mWs.data[i].mMsgSent;
*received.AppendElement() = mWs.data[i].mMsgReceived;
*receivedSize.AppendElement() = mWs.data[i].mSizeSent;
*sentSize.AppendElement() = mWs.data[i].mSizeReceived;
*encrypted.AppendElement() = mWs.data[i].mEncrypted;
}
SET_PROPERTY(finalObject, hostJs, hostport);
SET_PROPERTY(finalObject, msgSentJs, msgsent);
SET_PROPERTY(finalObject, msgRecvJs, msgreceived);
SET_PROPERTY(finalObject, sizeSentJs, sentsize);
SET_PROPERTY(finalObject, sizeRecvJs, receivedsize);
SET_PROPERTY(finalObject, encryptJs, encrypted);
val = OBJECT_TO_JSVAL(finalObject);
JS::Value val;
if (!dict.ToObject(cx, nullptr, &val)) {
mWs.cb = nullptr;
mWs.data.Clear();
return NS_ERROR_FAILURE;
}
mWs.cb->OnDashboardDataAvailable(val);
mWs.cb = nullptr;
@ -362,50 +382,56 @@ Dashboard::GetDnsInfoDispatch()
nsresult
Dashboard::GetDNSCacheEntries()
{
JS::Value val;
JSContext* cx = nsContentUtils::GetSafeJSContext();
JSAutoRequest request(cx);
JSObject* finalObject = JS_NewObject(cx, nullptr, nullptr, nullptr);
if (!finalObject)
return NS_ERROR_OUT_OF_MEMORY;
mozilla::dom::DNSCacheDict dict;
dict.mExpiration.Construct();
dict.mFamily.Construct();
dict.mHostaddr.Construct();
dict.mHostname.Construct();
CREATE_ARRAY_OBJECT(nameJs);
CREATE_ARRAY_OBJECT(addrJs);
CREATE_ARRAY_OBJECT(familyJs);
CREATE_ARRAY_OBJECT(expiresJs);
Sequence<double> &expiration = dict.mExpiration.Value();
Sequence<nsString> &family = dict.mFamily.Value();
Sequence<Sequence<nsString>> &hostaddr = dict.mHostaddr.Value();
Sequence<nsString> &hostname = dict.mHostname.Value();
uint32_t length = mDns.data.Length();
if (!expiration.SetCapacity(length) || !family.SetCapacity(length) ||
!hostaddr.SetCapacity(length) || !hostname.SetCapacity(length)) {
mDns.cb = nullptr;
mDns.data.Clear();
JS_ReportOutOfMemory(cx);
return NS_ERROR_OUT_OF_MEMORY;
}
for (uint32_t i = 0; i < mDns.data.Length(); i++) {
JSString* hostnameString = JS_NewStringCopyZ(cx, mDns.data[i].hostname.get());
SET_ELEMENT(nameJs, STRING_TO_JSVAL, hostnameString, i);
CopyASCIItoUTF16(mDns.data[i].hostname, *hostname.AppendElement());
*expiration.AppendElement() = mDns.data[i].expiration;
JSObject* addrObject = JS_NewObject(cx, nullptr, nullptr, nullptr);
if (!addrObject)
Sequence<nsString> &addrs = *hostaddr.AppendElement();
if (!addrs.SetCapacity(mDns.data[i].hostaddr.Length())) {
mDns.cb = nullptr;
mDns.data.Clear();
JS_ReportOutOfMemory(cx);
return NS_ERROR_OUT_OF_MEMORY;
}
for (uint32_t j = 0; j < mDns.data[i].hostaddr.Length(); j++) {
JSString* addrString = JS_NewStringCopyZ(cx, mDns.data[i].hostaddr[j].get());
SET_ELEMENT(addrObject, STRING_TO_JSVAL, addrString, j);
CopyASCIItoUTF16(mDns.data[i].hostaddr[j], *addrs.AppendElement());
}
SET_ELEMENT(addrJs, OBJECT_TO_JSVAL, addrObject, i);
JSString* familyString;
if (mDns.data[i].family == PR_AF_INET6)
familyString = JS_NewStringCopyZ(cx, "ipv6");
CopyASCIItoUTF16("ipv6", *family.AppendElement());
else
familyString = JS_NewStringCopyZ(cx, "ipv4");
SET_ELEMENT(familyJs, STRING_TO_JSVAL, familyString, i);
SET_ELEMENT(expiresJs, DOUBLE_TO_JSVAL, (double) mDns.data[i].expiration, i);
CopyASCIItoUTF16("ipv4", *family.AppendElement());
}
SET_PROPERTY(finalObject, nameJs, hostname);
SET_PROPERTY(finalObject, addrJs, hostaddr);
SET_PROPERTY(finalObject, familyJs, family);
SET_PROPERTY(finalObject, expiresJs, expiration);
val = OBJECT_TO_JSVAL(finalObject);
JS::Value val;
if (!dict.ToObject(cx, nullptr, &val)) {
mDns.cb = nullptr;
mDns.data.Clear();
return NS_ERROR_FAILURE;
}
mDns.cb->OnDashboardDataAvailable(val);
mDns.cb = nullptr;

Просмотреть файл

@ -9,7 +9,6 @@
#include "nsIDashboardEventNotifier.h"
#include "nsTArray.h"
#include "nsString.h"
#include "jsapi.h"
#include "nsIDNSService.h"
#include "nsIServiceManager.h"
#include "nsIThread.h"

Просмотреть файл

@ -28,6 +28,8 @@ class ErrorCodes(object):
INVALID_XPATH_SELECTOR = 51
INVALID_XPATH_SELECTOR_RETURN_TYPER = 52
INVALID_RESPONSE = 53
FRAME_SEND_NOT_INITIALIZED_ERROR = 54
FRAME_SEND_FAILURE_ERROR = 55
MARIONETTE_ERROR = 500
class MarionetteException(Exception):
@ -97,3 +99,8 @@ class InvalidSelectorException(MarionetteException):
class MoveTargetOutOfBoundsException(MarionetteException):
pass
class FrameSendNotInitializedError(MarionetteException):
pass
class FrameSendFailureError(MarionetteException):
pass

Просмотреть файл

@ -372,7 +372,11 @@ class Marionette(object):
or status == ErrorCodes.INVALID_XPATH_SELECTOR_RETURN_TYPER:
raise InvalidSelectorException(message=message, status=status, stacktrace=stacktrace)
elif status == ErrorCodes.MOVE_TARGET_OUT_OF_BOUNDS:
MoveTargetOutOfBoundsException(message=message, status=status, stacktrace=stacktrace)
raise MoveTargetOutOfBoundsException(message=message, status=status, stacktrace=stacktrace)
elif status == ErrorCodes.FRAME_SEND_NOT_INITIALIZED_ERROR:
raise FrameSendNotInitializedError(message=message, status=status, stacktrace=stacktrace)
elif status == ErrorCodes.FRAME_SEND_FAILURE_ERROR:
raise FrameSendFailureError(message=message, status=status, stacktrace=stacktrace)
else:
raise MarionetteException(message=message, status=status, stacktrace=stacktrace)
raise MarionetteException(message=response, status=500)

Просмотреть файл

@ -5,6 +5,8 @@
import time
from marionette_test import MarionetteTestCase
"""
### Disabled due to bug 838607
class TestClick(MarionetteTestCase):
def test_click(self):
test_html = self.marionette.absolute_url("test.html")
@ -13,19 +15,19 @@ class TestClick(MarionetteTestCase):
link.click()
self.assertEqual("Clicked", self.marionette.execute_script("return document.getElementById('mozLink').innerHTML;"))
# disabled due to bug 860104
#def testClickingALinkMadeUpOfNumbersIsHandledCorrectly(self):
# test_html = self.marionette.absolute_url("clicks.html")
# self.marionette.navigate(test_html)
# self.marionette.find_element("link text", "333333").click()
# count = 0
# while len(self.marionette.find_elements("id", "username")) == 0:
# count += 1
# time.sleep(1)
# if count == 30:
# self.fail("Element id=username not found after 30 seconds")
def testClickingALinkMadeUpOfNumbersIsHandledCorrectly(self):
test_html = self.marionette.absolute_url("clicks.html")
self.marionette.navigate(test_html)
self.marionette.find_element("link text", "333333").click()
count = 0
while len(self.marionette.find_elements("id", "username")) == 0:
count += 1
time.sleep(1)
if count == 30:
self.fail("Element id=username not found after 30 seconds")
# self.assertEqual(self.marionette.title, "XHTML Test Page")
self.assertEqual(self.marionette.title, "XHTML Test Page")
"""
class TestClickChrome(MarionetteTestCase):
def setUp(self):

Просмотреть файл

@ -150,6 +150,27 @@ function MarionetteRemoteFrame(windowId, frameId) {
// persistent list of remote frames that Marionette has loaded a frame script in
let remoteFrames = [];
/*
* Custom exceptions
*/
function FrameSendNotInitializedError(frame) {
this.code = 54;
this.frame = frame;
this.message = "Error sending message to frame (NS_ERROR_NOT_INITIALIZED)";
this.toString = function() {
return this.message + " " + this.frame + "; frame has closed.";
}
}
function FrameSendFailureError(frame) {
this.code = 55;
this.frame = frame;
this.message = "Error sending message to frame (NS_ERROR_FAILURE)";
this.toString = function() {
return this.message + " " + this.frame + "; frame not responding.";
}
}
/**
* This actor is responsible for all marionette API calls. It gets created
* for each connection and manages all chrome and browser based calls. It
@ -203,11 +224,7 @@ MarionetteDriverActor.prototype = {
switchToGlobalMessageManager: function MDA_switchToGlobalMM() {
if (this.currentRemoteFrame !== null) {
this.removeMessageManagerListeners(this.messageManager);
try {
// this can fail if the frame is already gone
this.sendAsync("sleepSession");
}
catch(e) {}
this.sendAsync("sleepSession", null, null, true);
}
this.messageManager = this.globalMessageManager;
this.currentRemoteFrame = null;
@ -221,15 +238,40 @@ MarionetteDriverActor.prototype = {
* @param object values
* Object to send to the listener
*/
sendAsync: function MDA_sendAsync(name, values) {
sendAsync: function MDA_sendAsync(name, values, commandId, ignoreFailure) {
let success = true;
if (values instanceof Object && commandId) {
values.command_id = commandId;
}
if (this.currentRemoteFrame !== null) {
try {
this.messageManager.sendAsyncMessage(
"Marionette:" + name + this.currentRemoteFrame.targetFrameId, values);
}
catch(e) {
if (!ignoreFailure) {
success = false;
let error = e;
switch(e.result) {
case Components.results.NS_ERROR_FAILURE:
error = new FrameSendFailureError(this.currentRemoteFrame);
break;
case Components.results.NS_ERROR_NOT_INITIALIZED:
error = new FrameSendNotInitializedError(this.currentRemoteFrame);
break;
default:
break;
}
code = error.hasOwnProperty('code') ? e.code : 500;
this.sendError(error.toString(), code, error.stack, commandId);
}
}
}
else {
this.messageManager.broadcastAsyncMessage(
"Marionette:" + name + this.curBrowser.curFrameId, values);
}
return success;
},
/**
@ -764,12 +806,15 @@ MarionetteDriverActor.prototype = {
aRequest.newSandbox = true;
}
if (this.context == "content") {
this.sendAsync("executeScript", {value: aRequest.value,
this.sendAsync("executeScript",
{
value: aRequest.value,
args: aRequest.args,
newSandbox: aRequest.newSandbox,
timeout: timeout,
command_id: command_id,
specialPowers: aRequest.specialPowers});
specialPowers: aRequest.specialPowers
},
command_id);
return;
}
@ -852,13 +897,16 @@ MarionetteDriverActor.prototype = {
}
}
else {
this.sendAsync("executeJSScript", { value: aRequest.value,
this.sendAsync("executeJSScript",
{
value: aRequest.value,
args: aRequest.args,
newSandbox: aRequest.newSandbox,
async: aRequest.async,
timeout: timeout,
command_id: command_id,
specialPowers: aRequest.specialPowers });
specialPowers: aRequest.specialPowers
},
command_id);
}
},
@ -888,13 +936,16 @@ MarionetteDriverActor.prototype = {
}
if (this.context == "content") {
this.sendAsync("executeAsyncScript", {value: aRequest.value,
this.sendAsync("executeAsyncScript",
{
value: aRequest.value,
args: aRequest.args,
id: this.command_id,
newSandbox: aRequest.newSandbox,
timeout: timeout,
command_id: command_id,
specialPowers: aRequest.specialPowers});
specialPowers: aRequest.specialPowers
},
command_id);
return;
}
@ -994,7 +1045,7 @@ MarionetteDriverActor.prototype = {
if (this.context != "chrome") {
aRequest.command_id = command_id;
aRequest.pageTimeout = this.pageTimeout;
this.sendAsync("goUrl", aRequest);
this.sendAsync("goUrl", aRequest, command_id);
return;
}
@ -1031,7 +1082,7 @@ MarionetteDriverActor.prototype = {
this.sendResponse(this.getCurrentWindow().location.href, this.command_id);
}
else {
this.sendAsync("getUrl", {command_id: this.command_id});
this.sendAsync("getUrl", {}, this.command_id);
}
},
@ -1040,7 +1091,7 @@ MarionetteDriverActor.prototype = {
*/
getTitle: function MDA_getTitle() {
this.command_id = this.getCommandId();
this.sendAsync("getTitle", {command_id: this.command_id});
this.sendAsync("getTitle", {}, this.command_id);
},
/**
@ -1055,7 +1106,7 @@ MarionetteDriverActor.prototype = {
this.sendResponse(pageSource, this.command_id);
}
else {
this.sendAsync("getPageSource", {command_id: this.command_id});
this.sendAsync("getPageSource", {}, this.command_id);
}
},
@ -1064,7 +1115,7 @@ MarionetteDriverActor.prototype = {
*/
goBack: function MDA_goBack() {
this.command_id = this.getCommandId();
this.sendAsync("goBack", {command_id: this.command_id});
this.sendAsync("goBack", {}, this.command_id);
},
/**
@ -1072,7 +1123,7 @@ MarionetteDriverActor.prototype = {
*/
goForward: function MDA_goForward() {
this.command_id = this.getCommandId();
this.sendAsync("goForward", {command_id: this.command_id});
this.sendAsync("goForward", {}, this.command_id);
},
/**
@ -1080,7 +1131,7 @@ MarionetteDriverActor.prototype = {
*/
refresh: function MDA_refresh() {
this.command_id = this.getCommandId();
this.sendAsync("refresh", {command_id: this.command_id});
this.sendAsync("refresh", {}, this.command_id);
},
/**
@ -1245,7 +1296,7 @@ MarionetteDriverActor.prototype = {
this.switchToGlobalMessageManager();
}
aRequest.command_id = command_id;
this.sendAsync("switchToFrame", aRequest);
this.sendAsync("switchToFrame", aRequest, command_id);
}
},
@ -1267,8 +1318,9 @@ MarionetteDriverActor.prototype = {
}
}
else {
this.sendAsync("setSearchTimeout", {value: aRequest.value,
command_id: this.command_id});
this.sendAsync("setSearchTimeout",
{ value: aRequest.value },
this.command_id);
}
},
@ -1318,10 +1370,13 @@ MarionetteDriverActor.prototype = {
this.sendError("Not in Chrome", 500, null, this.command_id);
}
else {
this.sendAsync("singleTap", {value: serId,
this.sendAsync("singleTap",
{
value: serId,
corx: x,
cory: y,
command_id: this.command_id});
cory: y
},
this.command_id);
}
},
@ -1340,10 +1395,13 @@ MarionetteDriverActor.prototype = {
this.sendError("Not in Chrome", 500, null, this.command_id);
}
else {
this.sendAsync("doubleTap", {value: serId,
this.sendAsync("doubleTap",
{
value: serId,
corx: x,
cory: y,
command_id: this.command_id});
cory: y
},
this.command_id);
}
},
@ -1362,10 +1420,13 @@ MarionetteDriverActor.prototype = {
this.sendError("Not in Chrome", 500, null, this.command_id);
}
else {
this.sendAsync("press", {value: element,
this.sendAsync("press",
{
value: element,
corx: x,
cory: y,
command_id: this.command_id});
cory: y
},
this.command_id);
}
},
@ -1383,9 +1444,12 @@ MarionetteDriverActor.prototype = {
this.sendError("Not in Chrome", 500, null, this.command_id);
}
else {
this.sendAsync("cancelTouch", {value: element,
touchId: touchId,
command_id: this.command_id});
this.sendAsync("cancelTouch",
{
value: element,
touchId: touchId
},
this.command_id);
}
},
@ -1405,11 +1469,14 @@ MarionetteDriverActor.prototype = {
this.sendError("Not in Chrome", 500, null, this.command_id);
}
else {
this.sendAsync("release", {value: element,
this.sendAsync("release",
{
value: element,
touchId: touchId,
corx: x,
cory: y,
command_id: this.command_id});
cory: y
},
this.command_id);
}
},
@ -1425,9 +1492,12 @@ MarionetteDriverActor.prototype = {
this.sendError("Not in Chrome", 500, null, this.command_id);
}
else {
this.sendAsync("actionChain", {chain: aRequest.chain,
nextId: aRequest.nextId,
command_id: this.command_id});
this.sendAsync("actionChain",
{
chain: aRequest.chain,
nextId: aRequest.nextId
},
this.command_id);
}
},
@ -1446,9 +1516,12 @@ MarionetteDriverActor.prototype = {
this.sendError("Not in Chrome", 500, null, this.command_id);
}
else {
this.sendAsync("multiAction", {value: aRequest.value,
maxlen: aRequest.max_length,
command_id: this.command_id});
this.sendAsync("multiAction",
{
value: aRequest.value,
maxlen: aRequest.max_length
},
this.command_id);
}
},
@ -1480,10 +1553,13 @@ MarionetteDriverActor.prototype = {
}
}
else {
this.sendAsync("findElementContent", {value: aRequest.value,
this.sendAsync("findElementContent",
{
value: aRequest.value,
using: aRequest.using,
element: aRequest.element,
command_id: command_id});
element: aRequest.element
},
command_id);
}
},
@ -1514,10 +1590,13 @@ MarionetteDriverActor.prototype = {
}
}
else {
this.sendAsync("findElementsContent", {value: aRequest.value,
this.sendAsync("findElementsContent",
{
value: aRequest.value,
using: aRequest.using,
element: aRequest.element,
command_id: command_id});
element: aRequest.element
},
command_id);
}
},
@ -1526,7 +1605,7 @@ MarionetteDriverActor.prototype = {
*/
getActiveElement: function MDA_getActiveElement(){
let command_id = this.command_id = this.getCommandId();
this.sendAsync("getActiveElement", {command_id: command_id});
this.sendAsync("getActiveElement", {}, command_id);
},
/**
@ -1563,8 +1642,9 @@ MarionetteDriverActor.prototype = {
self.sendError("The frame closed during the click, recovering to allow further communications", 500, null, command_id);
};
curWindow.addEventListener('mozbrowserclose', this.mozBrowserClose, true);
this.sendAsync("clickElement", {element: aRequest.element,
command_id: command_id});
this.sendAsync("clickElement",
{ element: aRequest.element },
command_id);
}
},
@ -1590,9 +1670,12 @@ MarionetteDriverActor.prototype = {
}
}
else {
this.sendAsync("getElementAttribute", {element: aRequest.element,
name: aRequest.name,
command_id: command_id});
this.sendAsync("getElementAttribute",
{
element: aRequest.element,
name: aRequest.name
},
command_id);
}
},
@ -1620,8 +1703,9 @@ MarionetteDriverActor.prototype = {
}
}
else {
this.sendAsync("getElementText", {element: aRequest.element,
command_id: command_id});
this.sendAsync("getElementText",
{ element: aRequest.element },
command_id);
}
},
@ -1645,8 +1729,9 @@ MarionetteDriverActor.prototype = {
}
}
else {
this.sendAsync("getElementTagName", {element: aRequest.element,
command_id: command_id});
this.sendAsync("getElementTagName",
{ element: aRequest.element },
command_id);
}
},
@ -1670,8 +1755,9 @@ MarionetteDriverActor.prototype = {
}
}
else {
this.sendAsync("isElementDisplayed", {element:aRequest.element,
command_id: command_id});
this.sendAsync("isElementDisplayed",
{ element:aRequest.element },
command_id);
}
},
@ -1701,8 +1787,9 @@ MarionetteDriverActor.prototype = {
}
}
else {
this.sendAsync("isElementEnabled", {element:aRequest.element,
command_id: command_id});
this.sendAsync("isElementEnabled",
{ element:aRequest.element },
command_id);
}
},
@ -1735,8 +1822,9 @@ MarionetteDriverActor.prototype = {
}
}
else {
this.sendAsync("isElementSelected", {element:aRequest.element,
command_id: command_id});
this.sendAsync("isElementSelected",
{ element:aRequest.element },
command_id);
}
},
@ -1755,8 +1843,9 @@ MarionetteDriverActor.prototype = {
}
}
else {
this.sendAsync("getElementSize", {element:aRequest.element,
command_id: command_id});
this.sendAsync("getElementSize",
{ element:aRequest.element },
command_id);
}
},
@ -1783,9 +1872,12 @@ MarionetteDriverActor.prototype = {
}
}
else {
this.sendAsync("sendKeysToElement", {element:aRequest.element,
value: aRequest.value,
command_id: command_id});
this.sendAsync("sendKeysToElement",
{
element:aRequest.element,
value: aRequest.value
},
command_id);
}
},
@ -1798,8 +1890,9 @@ MarionetteDriverActor.prototype = {
this.command_id = this.getCommandId();
this.logRequest("setTestName", aRequest);
this.testName = aRequest.value;
this.sendAsync("setTestName", {value: aRequest.value,
command_id: this.command_id});
this.sendAsync("setTestName",
{ value: aRequest.value },
this.command_id);
},
/**
@ -1829,15 +1922,17 @@ MarionetteDriverActor.prototype = {
}
}
else {
this.sendAsync("clearElement", {element:aRequest.element,
command_id: command_id});
this.sendAsync("clearElement",
{ element:aRequest.element },
command_id);
}
},
getElementPosition: function MDA_getElementPosition(aRequest) {
this.command_id = this.getCommandId();
this.sendAsync("getElementPosition", {element:aRequest.element,
command_id: this.command_id});
this.sendAsync("getElementPosition",
{ element:aRequest.element },
this.command_id);
},
/**
@ -1845,8 +1940,9 @@ MarionetteDriverActor.prototype = {
*/
addCookie: function MDA_addCookie(aRequest) {
this.command_id = this.getCommandId();
this.sendAsync("addCookie", {cookie:aRequest.cookie,
command_id: this.command_id});
this.sendAsync("addCookie",
{ cookie:aRequest.cookie },
this.command_id);
},
/**
@ -1854,7 +1950,7 @@ MarionetteDriverActor.prototype = {
*/
getAllCookies: function MDA_getAllCookies() {
this.command_id = this.getCommandId();
this.sendAsync("getAllCookies", {command_id: this.command_id});
this.sendAsync("getAllCookies", {}, this.command_id);
},
/**
@ -1862,7 +1958,7 @@ MarionetteDriverActor.prototype = {
*/
deleteAllCookies: function MDA_deleteAllCookies() {
this.command_id = this.getCommandId();
this.sendAsync("deleteAllCookies", {command_id: this.command_id});
this.sendAsync("deleteAllCookies", {}, this.command_id);
},
/**
@ -1870,8 +1966,9 @@ MarionetteDriverActor.prototype = {
*/
deleteCookie: function MDA_deleteCookie(aRequest) {
this.command_id = this.getCommandId();
this.sendAsync("deleteCookie", {name:aRequest.name,
command_id: this.command_id});
this.sendAsync("deleteCookie",
{ name:aRequest.name },
this.command_id);
},
/**
@ -1970,7 +2067,7 @@ MarionetteDriverActor.prototype = {
*/
getAppCacheStatus: function MDA_getAppCacheStatus(aRequest) {
this.command_id = this.getCommandId();
this.sendAsync("getAppCacheStatus", {command_id: this.command_id});
this.sendAsync("getAppCacheStatus", {}, this.command_id);
},
_emu_cb_id: 0,
@ -1988,7 +2085,7 @@ MarionetteDriverActor.prototype = {
emulatorCmdResult: function emulatorCmdResult(message) {
if (this.context != "chrome") {
this.sendAsync("emulatorCmdResult", message);
this.sendAsync("emulatorCmdResult", message, -1);
return;
}
@ -2031,8 +2128,9 @@ MarionetteDriverActor.prototype = {
this.sendOk(command_id);
}
else {
this.sendAsync("importScript", {script: aRequest.script,
command_id: command_id});
this.sendAsync("importScript",
{ script: aRequest.script },
command_id);
}
},
@ -2042,9 +2140,12 @@ MarionetteDriverActor.prototype = {
*/
screenShot: function MDA_saveScreenshot(aRequest) {
this.command_id = this.getCommandId();
this.sendAsync("screenShot", {element: aRequest.element,
highlights: aRequest.highlights,
command_id: this.command_id});
this.sendAsync("screenShot",
{
element: aRequest.element,
highlights: aRequest.highlights
},
this.command_id);
},
/**
@ -2148,11 +2249,12 @@ MarionetteDriverActor.prototype = {
// XXX: Should have a better way of determining that this message
// is from a remote frame.
this.currentRemoteFrame.targetFrameId = this.generateFrameId(message.json.value);
this.sendAsync(
"setState",
{scriptTimeout: this.scriptTimeout,
searchTimeout: this.curBrowser.elementManager.searchTimeout,
command_id: this.currentRemoteFrame.command_id});
this.sendAsync("setState",
{
scriptTimeout: this.scriptTimeout,
searchTimeout: this.curBrowser.elementManager.searchTimeout
},
this.currentRemoteFrame.command_id);
}
let browserType;
@ -2169,7 +2271,11 @@ MarionetteDriverActor.prototype = {
this.curBrowser.elementManager.seenItems[reg.id] = Cu.getWeakReference(listenerWindow); //add to seenItems
reg.importedScripts = this.importedScripts.path;
if (nullPrevious && (this.curBrowser.curFrameId != null)) {
this.sendAsync("newSession", {B2G: (appName == "B2G")});
if (!this.sendAsync("newSession",
{ B2G: (appName == "B2G") },
this.newSessionCommandId)) {
return;
}
if (this.curBrowser.newSession) {
this.sendResponse(reg.id, this.newSessionCommandId);
this.newSessionCommandId = null;

Просмотреть файл

@ -978,24 +978,17 @@ function do_load_child_test_harness()
return;
do_load_child_test_harness.alreadyRun = 1;
function addQuotes (str) {
return '"' + str + '"';
}
var quoted_head_files = _HEAD_FILES.map(addQuotes);
var quoted_tail_files = _TAIL_FILES.map(addQuotes);
_XPCSHELL_PROCESS = "parent";
let command =
"const _HEAD_JS_PATH='" + _HEAD_JS_PATH + "'; "
+ "const _HTTPD_JS_PATH='" + _HTTPD_JS_PATH + "'; "
+ "const _HEAD_FILES=[" + quoted_head_files.join() + "];"
+ "const _TAIL_FILES=[" + quoted_tail_files.join() + "];"
"const _HEAD_JS_PATH=" + uneval(_HEAD_JS_PATH) + "; "
+ "const _HTTPD_JS_PATH=" + uneval(_HTTPD_JS_PATH) + "; "
+ "const _HEAD_FILES=" + uneval(_HEAD_FILES) + "; "
+ "const _TAIL_FILES=" + uneval(_TAIL_FILES) + "; "
+ "const _XPCSHELL_PROCESS='child';";
if (this._TESTING_MODULES_DIR) {
normalized = this._TESTING_MODULES_DIR.replace('\\', '\\\\', 'g');
command += "const _TESTING_MODULES_DIR='" + normalized + "'; ";
command += " const _TESTING_MODULES_DIR=" + uneval(_TESTING_MODULES_DIR) + ";";
}
command += " load(_HEAD_JS_PATH);";

Просмотреть файл

@ -549,13 +549,14 @@ File.makeDir = function makeDir(path, options) {
* @param {string} path The path to the file.
* @param {number=} bytes Optionally, an upper bound to the number of bytes
* to read.
* @param {JSON} options Additional options.
*
* @resolves {Uint8Array} A buffer holding the bytes
* read from the file.
*/
File.read = function read(path, bytes) {
File.read = function read(path, bytes, options) {
let promise = Scheduler.post("read",
[Type.path.toMsg(path), bytes], path);
[Type.path.toMsg(path), bytes, options], path);
return promise.then(
function onSuccess(data) {
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);

Просмотреть файл

@ -889,7 +889,11 @@ let test_duration = maketest("duration", function duration(test) {
let pathDest = OS.Path.join(OS.Constants.Path.tmpDir,
"osfile async test read writeAtomic.tmp");
let tmpPath = pathDest + ".tmp";
let contents = yield OS.File.read(pathSource);
let readOptions = {
outExecutionDuration: null
};
let contents = yield OS.File.read(pathSource, undefined, readOptions);
testOptions(readOptions);
// Options structure passed to a OS.File writeAtomic method.
let writeAtomicOptions = {
// This field should be first initialized with the actual

Просмотреть файл

@ -63,6 +63,7 @@ EXTRA_JS_MODULES = \
ColorConversion.js \
ClusterLib.js \
BookmarkJSONUtils.jsm \
PlacesBackups.jsm \
$(NULL)
EXTRA_PP_JS_MODULES = \

Просмотреть файл

@ -0,0 +1,222 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=2 sts=2 expandtab filetype=javascript
* 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/. */
this.EXPORTED_SYMBOLS = ["PlacesBackups"];
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/PlacesUtils.jsm");
Cu.import("resource://gre/modules/BookmarkJSONUtils.jsm");
Cu.import("resource://gre/modules/Task.jsm");
this.PlacesBackups = {
get _filenamesRegex() {
// Get the localized backup filename, will be used to clear out
// old backups with a localized name (bug 445704).
let localizedFilename =
PlacesUtils.getFormattedString("bookmarksArchiveFilename", [new Date()]);
let localizedFilenamePrefix =
localizedFilename.substr(0, localizedFilename.indexOf("-"));
delete this._filenamesRegex;
return this._filenamesRegex =
new RegExp("^(bookmarks|" + localizedFilenamePrefix + ")-([0-9-]+)\.(json|html)");
},
get folder() {
let bookmarksBackupDir = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
bookmarksBackupDir.append("bookmarkbackups");
if (!bookmarksBackupDir.exists()) {
bookmarksBackupDir.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("0700", 8));
if (!bookmarksBackupDir.exists())
throw("Unable to create bookmarks backup folder");
}
delete this.folder;
return this.folder = bookmarksBackupDir;
},
/**
* Cache current backups in a sorted (by date DESC) array.
*/
get entries() {
delete this.entries;
this.entries = [];
let files = this.folder.directoryEntries;
while (files.hasMoreElements()) {
let entry = files.getNext().QueryInterface(Ci.nsIFile);
// A valid backup is any file that matches either the localized or
// not-localized filename (bug 445704).
let matches = entry.leafName.match(this._filenamesRegex);
if (!entry.isHidden() && matches) {
// Remove bogus backups in future dates.
if (this.getDateForFile(entry) > new Date()) {
entry.remove(false);
continue;
}
this.entries.push(entry);
}
}
this.entries.sort((a, b) => {
let aDate = this.getDateForFile(a);
let bDate = this.getDateForFile(b);
return aDate < bDate ? 1 : aDate > bDate ? -1 : 0;
});
return this.entries;
},
/**
* Creates a filename for bookmarks backup files.
*
* @param [optional] aDateObj
* Date object used to build the filename.
* Will use current date if empty.
* @return A bookmarks backup filename.
*/
getFilenameForDate: function PB_getFilenameForDate(aDateObj) {
let dateObj = aDateObj || new Date();
// Use YYYY-MM-DD (ISO 8601) as it doesn't contain illegal characters
// and makes the alphabetical order of multiple backup files more useful.
return "bookmarks-" + dateObj.toLocaleFormat("%Y-%m-%d") + ".json";
},
/**
* Creates a Date object from a backup file. The date is the backup
* creation date.
*
* @param aBackupFile
* nsIFile of the backup.
* @return A Date object for the backup's creation time.
*/
getDateForFile: function PB_getDateForFile(aBackupFile) {
let filename = aBackupFile.leafName;
let matches = filename.match(this._filenamesRegex);
if (!matches)
throw("Invalid backup file name: " + filename);
return new Date(matches[2].replace(/-/g, "/"));
},
/**
* Get the most recent backup file.
*
* @param [optional] aFileExt
* Force file extension. Either "html" or "json".
* Will check for both if not defined.
* @returns nsIFile backup file
*/
getMostRecent: function PB_getMostRecent(aFileExt) {
let fileExt = aFileExt || "(json|html)";
for (let i = 0; i < this.entries.length; i++) {
let rx = new RegExp("\." + fileExt + "$");
if (this.entries[i].leafName.match(rx))
return this.entries[i];
}
return null;
},
/**
* Serializes bookmarks using JSON, and writes to the supplied file.
* Note: any item that should not be backed up must be annotated with
* "places/excludeFromBackup".
*
* @param aFile
* nsIFile where to save JSON backup.
* @return {Promise}
*/
saveBookmarksToJSONFile: function PB_saveBookmarksToJSONFile(aFile) {
return Task.spawn(function() {
if (!aFile.exists())
aFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("0600", 8));
if (!aFile.exists() || !aFile.isWritable()) {
throw new Error("Unable to create bookmarks backup file: " + aFile.leafName);
}
yield BookmarkJSONUtils.exportToFile(aFile);
if (aFile.parent.equals(this.folder)) {
// Update internal cache.
this.entries.push(aFile);
} else {
// If we are saving to a folder different than our backups folder, then
// we also want to copy this new backup to it.
// This way we ensure the latest valid backup is the same saved by the
// user. See bug 424389.
let latestBackup = this.getMostRecent("json");
if (!latestBackup || latestBackup != aFile) {
let name = this.getFilenameForDate();
let file = this.folder.clone();
file.append(name);
if (file.exists()) {
file.remove(false);
} else {
// Update internal cache if we are not replacing an existing
// backup file.
this.entries.push(file);
}
aFile.copyTo(this.folder, name);
}
}
}.bind(this));
},
/**
* Creates a dated backup in <profile>/bookmarkbackups.
* Stores the bookmarks using JSON.
* Note: any item that should not be backed up must be annotated with
* "places/excludeFromBackup".
*
* @param [optional] int aMaxBackups
* The maximum number of backups to keep.
* @param [optional] bool aForceBackup
* Forces creating a backup even if one was already
* created that day (overwrites).
* @return {Promise}
*/
create: function PB_create(aMaxBackups, aForceBackup) {
return Task.spawn(function() {
// Construct the new leafname.
let newBackupFilename = this.getFilenameForDate();
let mostRecentBackupFile = this.getMostRecent();
if (!aForceBackup) {
let numberOfBackupsToDelete = 0;
if (aMaxBackups !== undefined && aMaxBackups > -1)
numberOfBackupsToDelete = this.entries.length - aMaxBackups;
if (numberOfBackupsToDelete > 0) {
// If we don't have today's backup, remove one more so that
// the total backups after this operation does not exceed the
// number specified in the pref.
if (!mostRecentBackupFile ||
mostRecentBackupFile.leafName != newBackupFilename)
numberOfBackupsToDelete++;
while (numberOfBackupsToDelete--) {
let oldestBackup = this.entries.pop();
oldestBackup.remove(false);
}
}
// Do nothing if we already have this backup or we don't want backups.
if (aMaxBackups === 0 ||
(mostRecentBackupFile &&
mostRecentBackupFile.leafName == newBackupFilename))
return;
}
let newBackupFile = this.folder.clone();
newBackupFile.append(newBackupFilename);
if (aForceBackup && newBackupFile.exists())
newBackupFile.remove(false);
if (newBackupFile.exists())
return;
yield this.saveBookmarksToJSONFile(newBackupFile);
}.bind(this));
}
}

Просмотреть файл

@ -76,7 +76,6 @@ if CONFIG['MOZ_OPUS']:
if CONFIG['MOZ_WEBM']:
add_tier_dir('platform', 'media/libnestegg')
if CONFIG['MOZ_WEBVTT']:
add_tier_dir('platform', 'media/webvtt')
if CONFIG['MOZ_VP8'] and not CONFIG['MOZ_NATIVE_LIBVPX']:

Просмотреть файл

@ -20,8 +20,8 @@
/**
* Provides information about a specific implementation class. If you want
* your class to implement nsIClassInfo, see nsIClassInfo.h for instructions --
* you most likely do not want to inherit from nsIClassInfo.
* your class to implement nsIClassInfo, see nsIClassInfoImpl.h for
* instructions--you most likely do not want to inherit from nsIClassInfo.
*/
[scriptable, uuid(986c11d0-f340-11d4-9075-0010a4e73d9a)]