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;
};
}

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

@ -25,14 +25,41 @@ NS_IMPL_RELEASE_INHERITED(DelayNode, AudioNode)
class DelayNodeEngine : public AudioNodeEngine
{
class PlayingRefChanged : public nsRunnable
{
public:
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:
explicit DelayNodeEngine(AudioDestinationNode* aDestination)
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
buffer[writeIndex] = input[i];
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()
{
Context()->UnregisterPannerNode(this);
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;
}
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;
return SVGAnimatedTransformListBinding::Wrap(aCx, aScope, this);
}
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,
nsSVGElement *aElement)
already_AddRefed<DOMSVGTransformList>
SVGAnimatedTransformList::AnimVal()
{
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());
}
if (!mAnimVal) {
mAnimVal = new SVGTransformList();
mAnimVal = new DOMSVGTransformList(this, InternalAList().GetAnimValue());
}
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;
nsRefPtr<DOMSVGTransformList> animVal = mAnimVal;
return animVal.forget();
}
/* static */ already_AddRefed<SVGAnimatedTransformList>
SVGAnimatedTransformList::GetDOMWrapper(nsSVGAnimatedTransformList *aList,
nsSVGElement *aElement)
{
nsRefPtr<SVGAnimatedTransformList> wrapper =
sSVGAnimatedTransformListTearoffTable.GetTearoff(aList);
if (!wrapper) {
wrapper = new SVGAnimatedTransformList(aElement);
sSVGAnimatedTransformListTearoffTable.AddTearoff(aList, wrapper);
}
aElement->DidAnimateTransformList();
return NS_OK;
return wrapper.forget();
}
/* static */ SVGAnimatedTransformList*
SVGAnimatedTransformList::GetDOMWrapperIfExists(
nsSVGAnimatedTransformList *aList)
{
return sSVGAnimatedTransformListTearoffTable.GetTearoff(aList);
}
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,31 +2731,37 @@ WifiWorker.prototype = {
return;
}
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;
}
let self = this;
let configured = this.configuredNetworks[networkKey];
this._reconnectOnDisconnect = (this.currentNetwork &&
(this.currentNetwork.ssid === ssid));
WifiManager.removeNetwork(configured.netId, function(ok) {
this._reloadConfiguredNetworks((function(ok) {
// Give it a chance to remove the network even if reload is failed.
if (!ok) {
self._sendMessage(message, false, "Unable to remove the network", msg);
self._reconnectOnDisconnect = false;
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;
}
WifiManager.saveConfig(function() {
self._reloadConfiguredNetworks(function() {
self._sendMessage(message, true, true, msg);
let self = this;
let configured = this.configuredNetworks[networkKey];
this._reconnectOnDisconnect = (this.currentNetwork &&
(this.currentNetwork.ssid === ssid));
WifiManager.removeNetwork(configured.netId, function(ok) {
if (!ok) {
self._sendMessage(message, false, "Unable to remove the network", msg);
self._reconnectOnDisconnect = false;
return;
}
WifiManager.saveConfig(function() {
self._reloadConfiguredNetworks(function() {
self._sendMessage(message, true, true, msg);
});
});
});
});
}).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,10 +104,10 @@ ContentClientRemote::EndPaint()
}
}
TemporaryRef<DrawTarget>
ContentClientRemote::CreateDTBuffer(ContentType aType,
const nsIntRect& aRect,
uint32_t aFlags)
void
ContentClientRemote::BuildTextureClient(ContentType aType,
const nsIntRect& aRect,
uint32_t aFlags)
{
NS_ABORT_IF_FALSE(!mIsNewBuffer,
"Bad! Did we create a buffer twice without painting?");
@ -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,17 +642,24 @@ 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 (anchor.x > 0) {
translation.x -= aFixedLayerMargins.right - fixedMargins.right;
} else {
translation.x += aFixedLayerMargins.left - fixedMargins.left;
if (fixedMargins.left >= 0) {
if (anchor.x > 0) {
translation.x -= aFixedLayerMargins.right - fixedMargins.right;
} else {
translation.x += aFixedLayerMargins.left - fixedMargins.left;
}
}
if (anchor.y > 0) {
translation.y -= aFixedLayerMargins.bottom - fixedMargins.bottom;
} else {
translation.y += aFixedLayerMargins.top - fixedMargins.top;
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

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

@ -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();
@ -348,10 +348,9 @@ nsAbsoluteContainingBlock::DoMarkFramesDirty(bool aMarkAllDirty)
nsresult
nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegatingFrame,
nsPresContext* aPresContext,
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,19 +337,13 @@ 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));
}
} else
aNode->GetChildNodes(getter_AddRefs(kids));
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
if (content && mShowAnonymousContent) {
kids = content->GetChildren(nsIContent::eAllChildren);
}
}
if (!kids) {
aNode->GetChildNodes(getter_AddRefs(kids));
}
item.kids = 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;
@ -74,24 +81,31 @@ class JavaPanZoomController
private static final int BOUNCE_ANIMATION_DURATION = 250;
private enum PanZoomState {
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, /* 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 */
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 */
NOTHING, /* no touch-start events received */
FLING, /* all touches removed, but we're still scrolling page */
TOUCHING, /* one touch-start event received */
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_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. */
AUTONAV, /* We are scrolling using an AutonavRunnable animation. This is similar
to the FLING state except that it must be stopped manually by the code that
started it, and it's velocity can be updated while it's running. */
}
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. */
AUTONAV, /* We are scrolling using an AutonavRunnable animation. This is similar
to the FLING state except that it must be stopped manually by the code that
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;
@ -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,15 +616,19 @@ class JavaPanZoomController
mY.startTouch(y);
mLastEventTime = time;
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);
} else if (Math.abs(angle - (Math.PI / 2)) < AXIS_LOCK_ANGLE) {
mX.setScrollingDisabled(true);
setState(PanZoomState.PANNING_LOCKED);
} else {
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_X);
} else if (Math.abs(angle - (Math.PI / 2)) < AXIS_LOCK_ANGLE) {
mX.setScrollingDisabled(true);
setState(PanZoomState.PANNING_LOCKED_Y);
} else {
setState(PanZoomState.PANNING);
}
} else if (mMode == AxisLockMode.FREE) {
setState(PanZoomState.PANNING);
}
}
@ -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)
return NS_ERROR_OUT_OF_MEMORY;
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;
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;
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();
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;
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;
}
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();
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);
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);
}
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);
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);
}
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);
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;
}
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);
for (uint32_t i = 0; i < mHttp.data.Length(); i++) {
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++) {
*active_rtt.AppendElement() = mHttp.data[i].active[j].rtt;
*active_ttl.AppendElement() = mHttp.data[i].active[j].ttl;
}
val = OBJECT_TO_JSVAL(finalObject);
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++) {
*idle_rtt.AppendElement() = mHttp.data[i].idle[j].rtt;
*idle_ttl.AppendElement() = mHttp.data[i].idle[j].ttl;
}
}
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();
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);
JSObject* addrObject = JS_NewObject(cx, nullptr, nullptr, nullptr);
if (!addrObject)
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 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);
}
SET_ELEMENT(addrJs, OBJECT_TO_JSVAL, addrObject, i);
JSString* familyString;
if (mDns.data[i].family == PR_AF_INET6)
familyString = JS_NewStringCopyZ(cx, "ipv6");
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);
}
SET_PROPERTY(finalObject, nameJs, hostname);
SET_PROPERTY(finalObject, addrJs, hostaddr);
SET_PROPERTY(finalObject, familyJs, family);
SET_PROPERTY(finalObject, expiresJs, expiration);
for (uint32_t i = 0; i < mDns.data.Length(); i++) {
CopyASCIItoUTF16(mDns.data[i].hostname, *hostname.AppendElement());
*expiration.AppendElement() = mDns.data[i].expiration;
val = OBJECT_TO_JSVAL(finalObject);
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++) {
CopyASCIItoUTF16(mDns.data[i].hostaddr[j], *addrs.AppendElement());
}
if (mDns.data[i].family == PR_AF_INET6)
CopyASCIItoUTF16("ipv6", *family.AppendElement());
else
CopyASCIItoUTF16("ipv4", *family.AppendElement());
}
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) {
this.messageManager.sendAsyncMessage(
"Marionette:" + name + this.currentRemoteFrame.targetFrameId, values);
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,
args: aRequest.args,
newSandbox: aRequest.newSandbox,
timeout: timeout,
command_id: command_id,
specialPowers: aRequest.specialPowers});
this.sendAsync("executeScript",
{
value: aRequest.value,
args: aRequest.args,
newSandbox: aRequest.newSandbox,
timeout: timeout,
specialPowers: aRequest.specialPowers
},
command_id);
return;
}
@ -852,13 +897,16 @@ MarionetteDriverActor.prototype = {
}
}
else {
this.sendAsync("executeJSScript", { value: aRequest.value,
args: aRequest.args,
newSandbox: aRequest.newSandbox,
async: aRequest.async,
timeout: timeout,
command_id: command_id,
specialPowers: aRequest.specialPowers });
this.sendAsync("executeJSScript",
{
value: aRequest.value,
args: aRequest.args,
newSandbox: aRequest.newSandbox,
async: aRequest.async,
timeout: timeout,
specialPowers: aRequest.specialPowers
},
command_id);
}
},
@ -888,13 +936,16 @@ MarionetteDriverActor.prototype = {
}
if (this.context == "content") {
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});
this.sendAsync("executeAsyncScript",
{
value: aRequest.value,
args: aRequest.args,
id: this.command_id,
newSandbox: aRequest.newSandbox,
timeout: timeout,
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,
corx: x,
cory: y,
command_id: this.command_id});
this.sendAsync("singleTap",
{
value: serId,
corx: x,
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,
corx: x,
cory: y,
command_id: this.command_id});
this.sendAsync("doubleTap",
{
value: serId,
corx: x,
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,
corx: x,
cory: y,
command_id: this.command_id});
this.sendAsync("press",
{
value: element,
corx: x,
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,
touchId: touchId,
corx: x,
cory: y,
command_id: this.command_id});
this.sendAsync("release",
{
value: element,
touchId: touchId,
corx: x,
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,
using: aRequest.using,
element: aRequest.element,
command_id: command_id});
this.sendAsync("findElementContent",
{
value: aRequest.value,
using: aRequest.using,
element: aRequest.element
},
command_id);
}
},
@ -1514,10 +1590,13 @@ MarionetteDriverActor.prototype = {
}
}
else {
this.sendAsync("findElementsContent", {value: aRequest.value,
using: aRequest.using,
element: aRequest.element,
command_id: command_id});
this.sendAsync("findElementsContent",
{
value: aRequest.value,
using: aRequest.using,
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;

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

@ -977,28 +977,21 @@ function do_load_child_test_harness()
if (typeof do_load_child_test_harness.alreadyRun != "undefined")
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);";
command += " load(_HEAD_JS_PATH);";
sendCommand(command);
}

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

@ -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,8 +76,7 @@ if CONFIG['MOZ_OPUS']:
if CONFIG['MOZ_WEBM']:
add_tier_dir('platform', 'media/libnestegg')
if CONFIG['MOZ_WEBVTT']:
add_tier_dir('platform', 'media/webvtt')
add_tier_dir('platform', 'media/webvtt')
if CONFIG['MOZ_VP8'] and not CONFIG['MOZ_NATIVE_LIBVPX']:
add_tier_dir('platform', 'media/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)]