Merge the last PGO-green inbound changeset to m-c.

This commit is contained in:
Ryan VanderMeulen 2013-01-29 09:36:20 -05:00
Родитель 33258062d0 1a31b73a52
Коммит 69a47a12a9
181 изменённых файлов: 2627 добавлений и 2203 удалений

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

@ -119,8 +119,12 @@
gQueue.invoke(); // Will call SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
openBrowserWindow(doTest);
if (!MAC) {
SimpleTest.waitForExplicitFinish();
openBrowserWindow(doTest);
} else {
todo(false, "Re-enable on Mac after fixing bug 835338");
}
]]>
</script>

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

@ -445,6 +445,10 @@ pref("media.volume.steps", 10);
//Enable/disable marionette server, set listening port
pref("marionette.defaultPrefs.enabled", true);
pref("marionette.defaultPrefs.port", 2828);
#ifndef MOZ_WIDGET_GONK
// On desktop builds, we need to force the socket to listen on localhost only
pref("marionette.force-local", true);
#endif
#endif
#ifdef MOZ_UPDATER

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

@ -28,7 +28,7 @@ postflight_all:
ln -s $(call core_abspath,$(DIST_UNI)) $(DIST_ARCH_2)/universal
# Stage a package for buildsymbols to be happy. Doing so in OBJDIR_ARCH_1
# actually does a universal staging with both OBJDIR_ARCH_1 and OBJDIR_ARCH_2.
$(MAKE) -C $(OBJDIR_ARCH_1)/$(INSTALLER_DIR) \
$(MAKE) -C $(OBJDIR_ARCH_1)/$(MOZ_BUILD_APP)/installer \
PKG_SKIP_STRIP=1 stage-package
ifdef ENABLE_TESTS
# Now, repeat the process for the test package.

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

@ -1036,13 +1036,6 @@ protected:
*/
virtual Element* GetOffsetRect(nsRect& aRect);
/**
* Retrieve the size of the padding rect of this element.
*
* @param aSize the size of the padding rect
*/
nsIntSize GetPaddingRectSize();
nsIFrame* GetStyledFrame();
virtual Element* GetNameSpaceElement()

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

@ -241,6 +241,12 @@ DoesNotParticipateInAutoDirection(const Element* aElement)
nodeInfo->Equals(nsGkAtoms::textarea));
}
static inline bool
IsBdiWithoutDirAuto(const Element* aElement)
{
return aElement->IsHTML(nsGkAtoms::bdi) && !aElement->HasDirAuto();
}
/**
* Returns true if aElement is one of the element whose text content should not
* affect the direction of ancestors with dir=auto (though it may affect its own
@ -250,7 +256,7 @@ static bool
DoesNotAffectDirectionOfAncestors(const Element* aElement)
{
return (DoesNotParticipateInAutoDirection(aElement) ||
aElement->IsHTML(nsGkAtoms::bdi) ||
IsBdiWithoutDirAuto(aElement) ||
aElement->HasFixedDir());
}
@ -643,7 +649,7 @@ void
WalkDescendantsSetDirAuto(Element* aElement, bool aNotify)
{
if (!DoesNotParticipateInAutoDirection(aElement) &&
!aElement->IsHTML(nsGkAtoms::bdi)) {
!IsBdiWithoutDirAuto(aElement)) {
bool setAncestorDirAutoFlag =
#ifdef DEBUG

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

@ -514,20 +514,6 @@ Element::GetOffsetRect(nsRect& aRect)
return nullptr;
}
nsIntSize
Element::GetPaddingRectSize()
{
nsIFrame* frame = GetStyledFrame();
if (!frame) {
return nsIntSize(0, 0);
}
NS_ASSERTION(frame->GetParent(), "Styled frame has no parent");
nsRect rcFrame = nsLayoutUtils::GetAllInFlowPaddingRectsUnion(frame, frame->GetParent());
return nsIntSize(nsPresContext::AppUnitsToIntCSSPixels(rcFrame.width),
nsPresContext::AppUnitsToIntCSSPixels(rcFrame.height));
}
nsIScrollableFrame*
Element::GetScrollFrame(nsIFrame **aStyledFrame)
{
@ -597,6 +583,20 @@ Element::ScrollIntoView(bool aTop)
nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
}
static nsSize GetScrollRectSizeForOverflowVisibleFrame(nsIFrame* aFrame)
{
if (!aFrame) {
return nsSize(0,0);
}
nsRect paddingRect = aFrame->GetPaddingRectRelativeToSelf();
nsOverflowAreas overflowAreas(paddingRect, paddingRect);
nsLayoutUtils::UnionChildOverflow(aFrame, overflowAreas);
return nsLayoutUtils::GetScrolledRect(aFrame,
overflowAreas.ScrollableOverflow(), paddingRect.Size(),
aFrame->GetStyleVisibility()->mDirection).Size();
}
int32_t
Element::ScrollHeight()
{
@ -604,11 +604,13 @@ Element::ScrollHeight()
return 0;
nsIScrollableFrame* sf = GetScrollFrame();
if (!sf) {
return GetPaddingRectSize().height;
nscoord height;
if (sf) {
height = sf->GetScrollRange().height + sf->GetScrollPortRect().height;
} else {
height = GetScrollRectSizeForOverflowVisibleFrame(GetStyledFrame()).height;
}
nscoord height = sf->GetScrollRange().height + sf->GetScrollPortRect().height;
return nsPresContext::AppUnitsToIntCSSPixels(height);
}
@ -619,11 +621,13 @@ Element::ScrollWidth()
return 0;
nsIScrollableFrame* sf = GetScrollFrame();
if (!sf) {
return GetPaddingRectSize().width;
nscoord width;
if (sf) {
width = sf->GetScrollRange().width + sf->GetScrollPortRect().width;
} else {
width = GetScrollRectSizeForOverflowVisibleFrame(GetStyledFrame()).width;
}
nscoord width = sf->GetScrollRange().width + sf->GetScrollPortRect().width;
return nsPresContext::AppUnitsToIntCSSPixels(width);
}

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

@ -6380,6 +6380,16 @@ nsContentUtils::FindInternalContentViewer(const char* aType,
}
#endif
#ifdef MOZ_DASH
if (DecoderTraits::IsDASHMPDType(nsDependentCString(aType))) {
docFactory = do_GetService("@mozilla.org/content/document-loader-factory;1");
if (docFactory && aLoaderType) {
*aLoaderType = TYPE_CONTENT;
}
return docFactory.forget();
}
#endif
#ifdef MOZ_GSTREAMER
if (DecoderTraits::IsGStreamerSupportedType(nsDependentCString(aType))) {
docFactory = do_GetService("@mozilla.org/content/document-loader-factory;1");

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

@ -37,6 +37,7 @@ GK_ATOM(mozframetype, "mozframetype")
GK_ATOM(mozallowfullscreen, "mozallowfullscreen")
GK_ATOM(moztype, "_moz-type")
GK_ATOM(mozdirty, "_moz_dirty")
GK_ATOM(mozdisallowselectionprint, "mozdisallowselectionprint")
GK_ATOM(mozdonotsend, "moz-do-not-send")
GK_ATOM(mozeditorbogusnode, "_moz_editor_bogus_node")
GK_ATOM(mozgeneratedcontentbefore, "_moz_generated_content_before")

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

@ -163,10 +163,13 @@ public:
return CurrentState().globalAlpha;
}
// Useful for silencing cast warnings
static mozilla::gfx::Float ToFloat(double aValue) { return mozilla::gfx::Float(aValue); }
void SetGlobalAlpha(double globalAlpha)
{
if (globalAlpha >= 0.0 && globalAlpha <= 1.0) {
CurrentState().globalAlpha = globalAlpha;
CurrentState().globalAlpha = ToFloat(globalAlpha);
}
}
@ -204,7 +207,7 @@ public:
void SetShadowOffsetX(double shadowOffsetX)
{
CurrentState().shadowOffset.x = shadowOffsetX;
CurrentState().shadowOffset.x = ToFloat(shadowOffsetX);
}
double ShadowOffsetY()
@ -214,7 +217,7 @@ public:
void SetShadowOffsetY(double shadowOffsetY)
{
CurrentState().shadowOffset.y = shadowOffsetY;
CurrentState().shadowOffset.y = ToFloat(shadowOffsetY);
}
double ShadowBlur()
@ -225,7 +228,7 @@ public:
void SetShadowBlur(double shadowBlur)
{
if (shadowBlur >= 0.0) {
CurrentState().shadowBlur = shadowBlur;
CurrentState().shadowBlur = ToFloat(shadowBlur);
}
}
@ -297,7 +300,7 @@ public:
void SetLineWidth(double width)
{
if (width > 0.0) {
CurrentState().lineWidth = width;
CurrentState().lineWidth = ToFloat(width);
}
}
void GetLineCap(nsAString& linecap);
@ -313,7 +316,7 @@ public:
void SetMiterLimit(double miter)
{
if (miter > 0.0) {
CurrentState().miterLimit = miter;
CurrentState().miterLimit = ToFloat(miter);
}
}
@ -344,10 +347,10 @@ public:
EnsureWritablePath();
if (mPathBuilder) {
mPathBuilder->MoveTo(mozilla::gfx::Point(x, y));
mPathBuilder->MoveTo(mozilla::gfx::Point(ToFloat(x), ToFloat(y)));
} else {
mDSPathBuilder->MoveTo(mTarget->GetTransform() *
mozilla::gfx::Point(x, y));
mozilla::gfx::Point(ToFloat(x), ToFloat(y)));
}
}
@ -355,7 +358,7 @@ public:
{
EnsureWritablePath();
LineTo(mozilla::gfx::Point(x, y));
LineTo(mozilla::gfx::Point(ToFloat(x), ToFloat(y)));
}
void QuadraticCurveTo(double cpx, double cpy, double x, double y)
@ -363,14 +366,14 @@ public:
EnsureWritablePath();
if (mPathBuilder) {
mPathBuilder->QuadraticBezierTo(mozilla::gfx::Point(cpx, cpy),
mozilla::gfx::Point(x, y));
mPathBuilder->QuadraticBezierTo(mozilla::gfx::Point(ToFloat(cpx), ToFloat(cpy)),
mozilla::gfx::Point(ToFloat(x), ToFloat(y)));
} else {
mozilla::gfx::Matrix transform = mTarget->GetTransform();
mDSPathBuilder->QuadraticBezierTo(transform *
mozilla::gfx::Point(cpx, cpy),
mozilla::gfx::Point(ToFloat(cpx), ToFloat(cpy)),
transform *
mozilla::gfx::Point(x, y));
mozilla::gfx::Point(ToFloat(x), ToFloat(y)));
}
}
@ -378,9 +381,9 @@ public:
{
EnsureWritablePath();
BezierTo(mozilla::gfx::Point(cp1x, cp1y),
mozilla::gfx::Point(cp2x, cp2y),
mozilla::gfx::Point(x, y));
BezierTo(mozilla::gfx::Point(ToFloat(cp1x), ToFloat(cp1y)),
mozilla::gfx::Point(ToFloat(cp2x), ToFloat(cp2y)),
mozilla::gfx::Point(ToFloat(x), ToFloat(y)));
}
void ArcTo(double x1, double y1, double x2, double y2, double radius,

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

@ -490,7 +490,7 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
if (aEvent->mFlags.mRetargetToNonNativeAnonymous) {
nsCOMPtr<nsIContent> content = do_QueryInterface(target);
if (content && content->IsInNativeAnonymousSubtree()) {
nsCOMPtr<nsPIDOMEventTarget> newTarget =
nsCOMPtr<nsIDOMEventTarget> newTarget =
do_QueryInterface(content->FindFirstNonChromeOnlyAccessContent());
NS_ENSURE_STATE(newTarget);

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

@ -919,8 +919,7 @@ HTMLTableElement::ParseAttribute(int32_t aNamespaceID,
aAttribute == nsGkAtoms::cellpadding) {
return aResult.ParseNonNegativeIntValue(aValue);
}
if (aAttribute == nsGkAtoms::cols ||
aAttribute == nsGkAtoms::border) {
if (aAttribute == nsGkAtoms::border) {
return aResult.ParseIntWithBounds(aValue, 0);
}
if (aAttribute == nsGkAtoms::height) {
@ -1005,15 +1004,6 @@ MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
if (value && value->Type() == nsAttrValue::eEnum)
tableLayout->SetIntValue(value->GetEnumValue(), eCSSUnit_Enumerated);
}
// cols
value = aAttributes->GetAttr(nsGkAtoms::cols);
if (value) {
nsCSSValue* cols = aData->ValueForCols();
if (value->Type() == nsAttrValue::eInteger)
cols->SetIntValue(value->GetIntegerValue(), eCSSUnit_Integer);
else // COLS had no value, so it refers to all columns
cols->SetIntValue(NS_STYLE_TABLE_COLS_ALL, eCSSUnit_Enumerated);
}
}
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Margin)) {
// align; Check for enumerated type (it may be another type if
@ -1135,7 +1125,6 @@ HTMLTableElement::IsAttributeMapped(const nsIAtom* aAttribute) const
{ &nsGkAtoms::layout },
{ &nsGkAtoms::cellpadding },
{ &nsGkAtoms::cellspacing },
{ &nsGkAtoms::cols },
{ &nsGkAtoms::border },
{ &nsGkAtoms::width },
{ &nsGkAtoms::height },

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

@ -824,6 +824,8 @@ nsGenericHTMLElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
} else {
ClearHasValidDir();
ClearHasFixedDir();
ClearHasDirAuto();
ClearHasDirAutoSet();
if (NodeInfo()->Equals(nsGkAtoms::bdi)) {
SetHasDirAuto();
} else {

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

@ -64,6 +64,16 @@ nsTimeRanges::Add(double aStart, double aEnd)
mRanges.AppendElement(TimeRange(aStart,aEnd));
}
double
nsTimeRanges::GetFinalEndTime()
{
if (mRanges.IsEmpty()) {
return -1.0;
}
uint32_t finalIndex = mRanges.Length() - 1;
return mRanges[finalIndex].mEnd;
}
void
nsTimeRanges::Normalize()
{

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

@ -24,6 +24,9 @@ public:
void Add(double aStart, double aEnd);
// Returns the end time of the last range, or -1 if no ranges added.
double GetFinalEndTime();
// See http://www.whatwg.org/html/#normalized-timeranges-object
void Normalize();

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

@ -1629,10 +1629,6 @@ MediaCacheStream::NotifyDataStarted(int64_t aOffset)
// the stream is at least that long.
mStreamLength = std::max(mStreamLength, mChannelOffset);
}
// Ensure that |mDownloadCancelled| is set to false since we have new data.
if (mDownloadCancelled) {
mDownloadCancelled = false;
}
}
bool
@ -1802,24 +1798,6 @@ MediaCacheStream::NotifyDataEnded(nsresult aStatus)
gMediaCache->QueueUpdate();
}
void
MediaCacheStream::NotifyDownloadCancelled()
{
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
ReentrantMonitorAutoEnter mon(gMediaCache->GetReentrantMonitor());
MediaCache::ResourceStreamIterator iter(mResourceID);
while (MediaCacheStream* stream = iter.Next()) {
// The remainder of the download was cancelled; in order to cancel any
// waiting reads, assume length is equal to current channel offset.
stream->mDownloadCancelled = true;
}
// Wake up waiting streams so they will stop reading.
mon.NotifyAll();
}
MediaCacheStream::~MediaCacheStream()
{
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
@ -2164,11 +2142,6 @@ MediaCacheStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes)
// that out.
return NS_ERROR_FAILURE;
}
// If the download was cancelled, stop reading and return silently.
if (mDownloadCancelled) {
mDownloadCancelled = false;
return NS_OK;
}
continue;
}

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

@ -194,7 +194,6 @@ public:
MediaCacheStream(ChannelMediaResource* aClient)
: mClient(aClient), mInitialized(false),
mHasHadUpdate(false),
mDownloadCancelled(false),
mClosed(false),
mDidNotifyDataEnded(false), mResourceID(0),
mIsTransportSeekable(false), mCacheSuspended(false),
@ -279,13 +278,6 @@ public:
void FlushPartialBlock();
// Notifies the cache that the channel has closed with the given status.
void NotifyDataEnded(nsresult aStatus);
// Notifies the cache that the download was cancelled. Sets
// |mDownloadCancelled| to false and notifies any thread waiting on the media
// cache monitor. In this way, if |Read| is waiting when a download is
// cancelled, it will be wakened and should stop trying to read.
// Note: |mDownloadCancelled| is set to false when |Read| is awakened, and in
// |NotifyDataStarted|, when new data starts downloading.
void NotifyDownloadCancelled();
// These methods can be called on any thread.
// Cached blocks associated with this stream will not be evicted
@ -448,9 +440,6 @@ private:
// Set to true when MediaCache::Update() has finished while this stream
// was present.
bool mHasHadUpdate;
// True if the download was cancelled. Set true in NotifyDownloadCancelled.
// Set false in NotifyDataStarted.
bool mDownloadCancelled;
// Set to true when the stream has been closed either explicitly or
// due to an internal cache error
bool mClosed;

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

@ -317,7 +317,7 @@ MediaDecoder::MediaDecoder() :
mReentrantMonitor("media.decoder"),
mPlayState(PLAY_STATE_PAUSED),
mNextState(PLAY_STATE_PAUSED),
mResourceLoaded(false),
mCalledResourceLoaded(false),
mIgnoreProgressData(false),
mInfiniteStream(false),
mTriggerPlaybackEndedWhenSourceStreamFinishes(false),
@ -650,6 +650,16 @@ void MediaDecoder::QueueMetadata(int64_t aPublishTime,
mDecoderStateMachine->QueueMetadata(aPublishTime, aChannels, aRate, aHasAudio, aHasVideo, aTags);
}
bool
MediaDecoder::IsDataCachedToEndOfResource()
{
NS_ASSERTION(!mShuttingDown, "Don't call during shutdown!");
GetReentrantMonitor().AssertCurrentThreadIn();
return (mResource &&
mResource->IsDataCachedToEndOfResource(mDecoderPosition));
}
void MediaDecoder::MetadataLoaded(int aChannels, int aRate, bool aHasAudio, bool aHasVideo, MetadataTags* aTags)
{
MOZ_ASSERT(NS_IsMainThread());
@ -675,7 +685,7 @@ void MediaDecoder::MetadataLoaded(int aChannels, int aRate, bool aHasAudio, bool
mOwner->MetadataLoaded(aChannels, aRate, aHasAudio, aHasVideo, aTags);
}
if (!mResourceLoaded) {
if (!mCalledResourceLoaded) {
StartProgress();
} else if (mOwner) {
// Resource was loaded during metadata loading, when progress
@ -686,10 +696,10 @@ void MediaDecoder::MetadataLoaded(int aChannels, int aRate, bool aHasAudio, bool
// Only inform the element of FirstFrameLoaded if not doing a load() in order
// to fulfill a seek, otherwise we'll get multiple loadedfirstframe events.
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
bool resourceIsLoaded = !mResourceLoaded && mResource &&
mResource->IsDataCachedToEndOfResource(mDecoderPosition);
bool notifyResourceIsLoaded = !mCalledResourceLoaded &&
IsDataCachedToEndOfResource();
if (mOwner) {
mOwner->FirstFrameLoaded(resourceIsLoaded);
mOwner->FirstFrameLoaded(notifyResourceIsLoaded);
}
// This can run cache callbacks.
@ -708,7 +718,7 @@ void MediaDecoder::MetadataLoaded(int aChannels, int aRate, bool aHasAudio, bool
}
}
if (resourceIsLoaded) {
if (notifyResourceIsLoaded) {
ResourceLoaded();
}
@ -732,12 +742,12 @@ void MediaDecoder::ResourceLoaded()
// If we are seeking or loading then the resource loaded notification we get
// should be ignored, since it represents the end of the seek request.
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
if (mIgnoreProgressData || mResourceLoaded || mPlayState == PLAY_STATE_LOADING)
if (mIgnoreProgressData || mCalledResourceLoaded || mPlayState == PLAY_STATE_LOADING)
return;
Progress(false);
mResourceLoaded = true;
mCalledResourceLoaded = true;
StopProgress();
}

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

@ -502,7 +502,7 @@ public:
// from a content header. Must be called from the main thread only.
virtual void SetDuration(double aDuration);
void SetMediaDuration(int64_t aDuration) MOZ_FINAL MOZ_OVERRIDE;
void SetMediaDuration(int64_t aDuration) MOZ_OVERRIDE;
// Set a flag indicating whether seeking is supported
virtual void SetMediaSeekable(bool aMediaSeekable) MOZ_OVERRIDE;
@ -611,11 +611,11 @@ public:
// Stop updating the bytes downloaded for progress notifications. Called
// when seeking to prevent wild changes to the progress notification.
// Must be called with the decoder monitor held.
void StopProgressUpdates();
virtual void StopProgressUpdates();
// Allow updating the bytes downloaded for progress notifications. Must
// be called with the decoder monitor held.
void StartProgressUpdates();
virtual void StartProgressUpdates();
// Something has changed that could affect the computed playback rate,
// so recompute it. The monitor must be held.
@ -683,6 +683,10 @@ public:
// Call on the main thread only.
void FirstFrameLoaded();
// Returns true if the resource has been loaded. Must be in monitor.
// Call from any thread.
virtual bool IsDataCachedToEndOfResource();
// Called when the video has completed playing.
// Call on the main thread only.
void PlaybackEnded();
@ -1012,7 +1016,7 @@ public:
// True when we have fully loaded the resource and reported that
// to the element (i.e. reached NETWORK_LOADED state).
// Accessed on the main thread only.
bool mResourceLoaded;
bool mCalledResourceLoaded;
// True when seeking or otherwise moving the play position around in
// such a manner that progress event data is inaccurate. This is set

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

@ -550,18 +550,6 @@ ChannelMediaResource::OpenByteRange(nsIStreamListener** aStreamListener,
return OpenChannel(aStreamListener);
}
void
ChannelMediaResource::CancelByteRangeOpen()
{
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
// Byte range download will be cancelled in |CacheClientSeek|. Here, we only
// need to notify the cache to in turn notify any waiting reads.
if (mByteRangeDownloads) {
mCacheStream.NotifyDownloadCancelled();
}
}
nsresult ChannelMediaResource::Open(nsIStreamListener **aStreamListener)
{
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");

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

@ -347,12 +347,6 @@ public:
return Open(aStreamListener);
}
/**
* Cancels current byte range requests previously opened via
* OpenByteRange.
*/
virtual void CancelByteRangeOpen() { }
/**
* Fills aRanges with MediaByteRanges representing the data which is cached
* in the media cache. Stream should be pinned during call and while
@ -461,7 +455,6 @@ public:
virtual nsresult Open(nsIStreamListener** aStreamListener);
virtual nsresult OpenByteRange(nsIStreamListener** aStreamListener,
MediaByteRange const & aByteRange);
virtual void CancelByteRangeOpen();
virtual nsresult Close();
virtual void Suspend(bool aCloseImmediately);
virtual void Resume();

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

@ -714,6 +714,15 @@ DASHDecoder::NotifyDownloadEnded(DASHRepDecoder* aRepDecoder,
}
}
// Check that decoder is valid.
if (!decoder || (decoder != AudioRepDecoder() &&
decoder != VideoRepDecoder())) {
LOG("Invalid decoder [%p]: video idx [%d] audio idx [%d]",
decoder.get(), AudioRepDecoder(), VideoRepDecoder());
DecodeError();
return;
}
// Before loading, note the index of the decoder which will downloaded the
// next video subsegment.
if (decoder == VideoRepDecoder()) {
@ -738,20 +747,22 @@ DASHDecoder::NotifyDownloadEnded(DASHRepDecoder* aRepDecoder,
// Load the next range of data bytes. If the range is already cached,
// this function will be called again to adaptively download the next
// subsegment.
#ifdef PR_LOGGING
bool resourceLoaded = false;
if (decoder.get() == AudioRepDecoder()) {
LOG("Requesting load for audio decoder [%p] subsegment [%d].",
decoder.get(), mAudioSubsegmentIdx);
if (mAudioSubsegmentIdx >= decoder->GetNumDataByteRanges()) {
resourceLoaded = true;
}
} else if (decoder.get() == VideoRepDecoder()) {
LOG("Requesting load for video decoder [%p] subsegment [%d].",
decoder.get(), mVideoSubsegmentIdx);
if (mVideoSubsegmentIdx >= decoder->GetNumDataByteRanges()) {
resourceLoaded = true;
}
}
#endif
if (!decoder || (decoder != AudioRepDecoder() &&
decoder != VideoRepDecoder())) {
LOG("Invalid decoder [%p]: video idx [%d] audio idx [%d]",
decoder.get(), AudioRepDecoder(), VideoRepDecoder());
DecodeError();
if (resourceLoaded) {
ResourceLoaded();
return;
}
decoder->LoadNextByteRange();
@ -1042,20 +1053,9 @@ DASHDecoder::Seek(double aTime)
{
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
// We want to stop the current series of downloads and restart later with
// the appropriate subsegment.
// 1 - Set the seeking flag, so that when current subsegments download (if
// Set the seeking flag, so that when current subsegments download (if
// any), the next subsegment will not be downloaded.
mSeeking = true;
// 2 - Cancel all current downloads to reset for seeking.
for (uint32_t i = 0; i < mAudioRepDecoders.Length(); i++) {
mAudioRepDecoders[i]->CancelByteRangeLoad();
}
for (uint32_t i = 0; i < mVideoRepDecoders.Length(); i++) {
mVideoRepDecoders[i]->CancelByteRangeLoad();
}
}
return MediaDecoder::Seek(aTime);
@ -1304,4 +1304,59 @@ DASHDecoder::GetStatistics()
return result;
}
bool
DASHDecoder::IsDataCachedToEndOfResource()
{
NS_ASSERTION(!mShuttingDown, "Don't call during shutdown!");
GetReentrantMonitor().AssertCurrentThreadIn();
if (!mMPDManager || !mResource) {
return false;
}
bool resourceIsLoaded = false;
if (VideoRepDecoder()) {
resourceIsLoaded = VideoRepDecoder()->IsDataCachedToEndOfResource();
LOG("IsDataCachedToEndOfResource for VideoRepDecoder %p = %s",
VideoRepDecoder(), resourceIsLoaded ? "yes" : "no");
}
if (AudioRepDecoder()) {
bool isAudioResourceLoaded =
AudioRepDecoder()->IsDataCachedToEndOfResource();
LOG("IsDataCachedToEndOfResource for AudioRepDecoder %p = %s",
AudioRepDecoder(), isAudioResourceLoaded ? "yes" : "no");
resourceIsLoaded = resourceIsLoaded && isAudioResourceLoaded;
}
return resourceIsLoaded;
}
void
DASHDecoder::StopProgressUpdates()
{
MOZ_ASSERT(OnStateMachineThread() || OnDecodeThread());
GetReentrantMonitor().AssertCurrentThreadIn();
mIgnoreProgressData = true;
for (uint32_t i = 0; i < mVideoRepDecoders.Length(); i++) {
mVideoRepDecoders[i]->StopProgressUpdates();
}
for (uint32_t i = 0; i < mAudioRepDecoders.Length(); i++) {
mAudioRepDecoders[i]->StopProgressUpdates();
}
}
void
DASHDecoder::StartProgressUpdates()
{
MOZ_ASSERT(OnStateMachineThread() || OnDecodeThread());
GetReentrantMonitor().AssertCurrentThreadIn();
mIgnoreProgressData = false;
for (uint32_t i = 0; i < mVideoRepDecoders.Length(); i++) {
mVideoRepDecoders[i]->StartProgressUpdates();
}
for (uint32_t i = 0; i < mAudioRepDecoders.Length(); i++) {
mAudioRepDecoders[i]->StartProgressUpdates();
}
}
} // namespace mozilla

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

@ -91,6 +91,10 @@ public:
// decoders. Called on the decode thread.
void OnReadMetadataCompleted(DASHRepDecoder* aRepDecoder);
// Returns true if all subsegments from current decode position are
// downloaded. Must be in monitor. Call from any thread.
bool IsDataCachedToEndOfResource() MOZ_OVERRIDE;
// Refers to downloading data bytes, i.e. non metadata.
// Returns true if |aRepDecoder| is an active audio or video sub decoder AND
// if metadata for all audio or video decoders has been read.
@ -162,6 +166,14 @@ public:
return (-1);
}
// Returns the total number of subsegments that have been loaded. Will enter
// monitor for read access off the decode thread.
uint32_t GetNumSubsegmentLoads() {
ReentrantMonitorConditionallyEnter mon(!OnDecodeThread(),
GetReentrantMonitor());
return mVideoSubsegmentLoads.Length();
}
// Returns the index of the rep decoder used to load a subsegment. Will enter
// monitor for read access off the decode thread.
int32_t GetRepIdxForVideoSubsegmentLoad(int32_t aSubsegmentIdx)
@ -207,6 +219,15 @@ public:
// audio and video rep decoders.
void UpdatePlaybackRate() MOZ_OVERRIDE;
// Stop updating the bytes downloaded for progress notifications. Called
// when seeking to prevent wild changes to the progress notification.
// Forwarded to sub-decoders. Must be called with the decoder monitor held.
void StopProgressUpdates() MOZ_OVERRIDE;
// Allow updating the bytes downloaded for progress notifications.
// Forwarded to sub-decoders. Must be called with the decoder monitor held.
void StartProgressUpdates() MOZ_OVERRIDE;
// Used to estimate rates of data passing through the decoder's channel.
// Records activity starting on the channel. The monitor must be held.
virtual void NotifyPlaybackStarted() MOZ_OVERRIDE;

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

@ -316,43 +316,131 @@ DASHReader::GetBuffered(nsTimeRanges* aBuffered,
MediaResource* resource = nullptr;
AbstractMediaDecoder* decoder = nullptr;
// Need to find intersect of |nsTimeRanges| for audio and video.
nsTimeRanges audioBuffered, videoBuffered;
uint32_t audioRangeCount, videoRangeCount;
uint32_t audioRangeCount = 0, videoRangeCount = 0;
bool audioCachedAtEnd = false, videoCachedAtEnd = false;
nsresult rv = NS_OK;
// First, get buffered ranges for sub-readers.
// Get all audio and video buffered ranges. Include inactive streams, since
// we may have carried out a seek and future subsegments may be in currently
// inactive decoders.
ReentrantMonitorConditionallyEnter mon(!mDecoder->OnDecodeThread(),
mDecoder->GetReentrantMonitor());
if (mAudioReader) {
decoder = mAudioReader->GetDecoder();
for (uint32_t i = 0; i < mAudioReaders.Length(); i++) {
decoder = mAudioReaders[i]->GetDecoder();
NS_ENSURE_TRUE(decoder, NS_ERROR_NULL_POINTER);
resource = decoder->GetResource();
NS_ENSURE_TRUE(resource, NS_ERROR_NULL_POINTER);
resource->Pin();
rv = mAudioReader->GetBuffered(&audioBuffered, aStartTime);
rv = mAudioReaders[i]->GetBuffered(&audioBuffered, aStartTime);
NS_ENSURE_SUCCESS(rv, rv);
// If data was cached at the end, then the final timestamp refers to the
// end of the data. Use this later to extend end time if necessary.
if (!audioCachedAtEnd) {
audioCachedAtEnd = mAudioReaders[i]->IsDataCachedAtEndOfSubsegments();
}
resource->Unpin();
rv = audioBuffered.GetLength(&audioRangeCount);
NS_ENSURE_SUCCESS(rv, rv);
}
if (mVideoReader) {
decoder = mVideoReader->GetDecoder();
for (uint32_t i = 0; i < mVideoReaders.Length(); i++) {
decoder = mVideoReaders[i]->GetDecoder();
NS_ENSURE_TRUE(decoder, NS_ERROR_NULL_POINTER);
resource = decoder->GetResource();
NS_ENSURE_TRUE(resource, NS_ERROR_NULL_POINTER);
resource->Pin();
rv = mVideoReader->GetBuffered(&videoBuffered, aStartTime);
rv = mVideoReaders[i]->GetBuffered(&videoBuffered, aStartTime);
NS_ENSURE_SUCCESS(rv, rv);
// If data was cached at the end, then the final timestamp refers to the
// end of the data. Use this later to extend end time if necessary.
if (!videoCachedAtEnd) {
videoCachedAtEnd = mVideoReaders[i]->IsDataCachedAtEndOfSubsegments();
}
resource->Unpin();
rv = videoBuffered.GetLength(&videoRangeCount);
NS_ENSURE_SUCCESS(rv, rv);
}
// Now determine buffered data for available sub-readers.
if (mAudioReader && mVideoReader) {
// Calculate intersecting ranges.
audioBuffered.Normalize();
videoBuffered.Normalize();
rv = audioBuffered.GetLength(&audioRangeCount);
NS_ENSURE_SUCCESS(rv, rv);
rv = videoBuffered.GetLength(&videoRangeCount);
NS_ENSURE_SUCCESS(rv, rv);
#ifdef PR_LOGGING
double start = 0, end = 0;
for (uint32_t i = 0; i < audioRangeCount; i++) {
rv = audioBuffered.Start(i, &start);
NS_ENSURE_SUCCESS(rv, rv);
rv = audioBuffered.End(i, &end);
NS_ENSURE_SUCCESS(rv, rv);
LOG("audioBuffered[%d] = (%f, %f)",
i, start, end);
}
for (uint32_t i = 0; i < videoRangeCount; i++) {
rv = videoBuffered.Start(i, &start);
NS_ENSURE_SUCCESS(rv, rv);
rv = videoBuffered.End(i, &end);
NS_ENSURE_SUCCESS(rv, rv);
LOG("videoBuffered[%d] = (%f, %f)",
i, start, end);
}
#endif
// If audio and video are cached to the end of their subsegments, extend the
// end time of the shorter of the two. Presentation of the shorter stream
// will stop at the end, while the other continues until the combined
// playback is complete.
// Note: Only in cases where the shorter stream is fully cached, and the
// longer stream is partially cached, but with more time buffered than the
// shorter stream.
//
// Audio ========|
// 20
// Video ============|----|
// 30 40
// Combo ============| <----- End time EXTENDED.
//
// For example, audio is fully cached to 20s, but video is partially cached
// to 30s, full duration 40s. In this case, the buffered end time should be
// extended to the video's end time.
//
// Audio =================|
// 40
// Video ========|----|
// 20 30
// Combo ========| <------ End time NOT EXTENDED.
//
// Conversely, if the longer stream is fully cached, but the shorter one is
// not, no extension of end time should occur - we should consider the
// partially cached, shorter end time to be the end time of the combined
// stream
if (audioCachedAtEnd || videoCachedAtEnd) {
NS_ENSURE_TRUE(audioRangeCount, NS_ERROR_FAILURE);
NS_ENSURE_TRUE(videoRangeCount, NS_ERROR_FAILURE);
double audioEndTime = 0, videoEndTime = 0;
// Get end time of the last range of buffered audio.
audioEndTime = audioBuffered.GetFinalEndTime();
NS_ENSURE_TRUE(audioEndTime > 0, NS_ERROR_ILLEGAL_VALUE);
// Get end time of the last range of buffered video.
videoEndTime = videoBuffered.GetFinalEndTime();
NS_ENSURE_TRUE(videoEndTime > 0, NS_ERROR_ILLEGAL_VALUE);
// API for nsTimeRanges requires extending through adding and normalizing.
if (videoCachedAtEnd && audioEndTime > videoEndTime) {
videoBuffered.Add(videoEndTime, audioEndTime);
videoBuffered.Normalize();
LOG("videoBuffered extended to %f", audioEndTime);
} else if (audioCachedAtEnd && videoEndTime > audioEndTime) {
audioBuffered.Add(audioEndTime, videoEndTime);
audioBuffered.Normalize();
LOG("audioBuffered extended to %f", videoEndTime);
}
}
// Calculate intersecting ranges for video and audio.
if (!mAudioReaders.IsEmpty() && !mVideoReaders.IsEmpty()) {
for (uint32_t i = 0; i < audioRangeCount; i++) {
// |A|udio, |V|ideo, |I|ntersect.
double startA, startV, startI;
@ -382,9 +470,9 @@ DASHReader::GetBuffered(nsTimeRanges* aBuffered,
aBuffered->Add(startI, endI);
}
}
} else if (mAudioReader) {
} else if (!mAudioReaders.IsEmpty()) {
*aBuffered = audioBuffered;
} else if (mVideoReader) {
} else if (!mVideoReaders.IsEmpty()) {
*aBuffered = videoBuffered;
} else {
return NS_ERROR_NOT_INITIALIZED;

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

@ -236,6 +236,16 @@ private:
return mSubReaderList.Length();
}
// Returns true if |mSubReaderList| is empty. Will assert that threads
// other than the decode thread are "in monitor".
bool IsEmpty() const
{
NS_ASSERTION(mReader->GetDecoder(), "Decoder is null!");
if (!mReader->GetDecoder()->OnDecodeThread()) {
mReader->GetDecoder()->GetReentrantMonitor().AssertCurrentThreadIn();
}
return mSubReaderList.IsEmpty();
}
// Override '[]' to assert threads other than the decode thread are "in
// monitor" for accessing individual elems. Note: elems returned do not
// have monitor assertions builtin like |MonitoredSubReader| objects.

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

@ -280,23 +280,6 @@ DASHRepDecoder::LoadNextByteRange()
}
}
void
DASHRepDecoder::CancelByteRangeLoad()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
NS_ASSERTION(mResource, "Error: resource is reported as null!");
if (mCurrentByteRange.IsNull() || mSubsegmentIdx < 0) {
LOG1("Canceling current byte range load: none to cancel.");
return;
}
LOG("Canceling current byte range load: [%lld] to [%lld] subsegment "
"[%lld]", mCurrentByteRange.mStart, mCurrentByteRange.mEnd,
mSubsegmentIdx);
mResource->CancelByteRangeOpen();
}
bool
DASHRepDecoder::IsSubsegmentCached(int32_t aSubsegmentIdx)
{
@ -520,4 +503,16 @@ DASHRepDecoder::ReleaseStateMachine()
MediaDecoder::ReleaseStateMachine();
}
void DASHRepDecoder::StopProgressUpdates()
{
NS_ENSURE_TRUE_VOID(mMainDecoder);
MediaDecoder::StopProgressUpdates();
}
void DASHRepDecoder::StartProgressUpdates()
{
NS_ENSURE_TRUE_VOID(mMainDecoder);
MediaDecoder::StartProgressUpdates();
}
} // namespace mozilla

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

@ -81,9 +81,6 @@ public:
// thread only.
void LoadNextByteRange();
// Cancels current byte range loads. Called on the main thread only.
void CancelByteRangeLoad();
// Returns true if the subsegment is already in the media cache.
bool IsSubsegmentCached(int32_t aSubsegmentIdx);
@ -94,6 +91,10 @@ public:
// thread only.
void NetworkError();
// Called from reader during ReadMetadata. This should be ignored here, and
// instead, duration should be set following MPD parsing.
void SetMediaDuration(int64_t aDuration) MOZ_OVERRIDE { };
// Set the duration of the media resource in units of seconds.
// This is called via a channel listener if it can pick up the duration
// from a content header. Must be called from the main thread only.
@ -155,21 +156,30 @@ public:
void PrepareForSwitch();
// Returns true if the current thread is the state machine thread.
bool OnStateMachineThread() const;
bool OnStateMachineThread() const MOZ_OVERRIDE;
// Returns true if the current thread is the decode thread.
bool OnDecodeThread() const;
bool OnDecodeThread() const MOZ_OVERRIDE;
// Returns main decoder's monitor for synchronised access.
ReentrantMonitor& GetReentrantMonitor() MOZ_OVERRIDE;
// Called on the decode thread from WebMReader.
ImageContainer* GetImageContainer();
ImageContainer* GetImageContainer() MOZ_OVERRIDE;
// Called when Metadata has been read; notifies that index data is read.
// Called on the decode thread only.
void OnReadMetadataCompleted() MOZ_OVERRIDE;
// Stop updating the bytes downloaded for progress notifications. Called
// when seeking to prevent wild changes to the progress notification.
// Must be called with the decoder monitor held.
void StopProgressUpdates() MOZ_OVERRIDE;
// Allow updating the bytes downloaded for progress notifications. Must
// be called with the decoder monitor held.
void StartProgressUpdates() MOZ_OVERRIDE;
// Overridden to cleanup ref to |DASHDecoder|. Called on main thread only.
void Shutdown() {
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");

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

@ -58,6 +58,9 @@ public:
// Should be implemented by a sub-reader, e.g. |nsDASHWebMReader|.
virtual void RequestSwitchAtSubsegment(int32_t aCluster,
MediaDecoderReader* aNextReader) = 0;
// Returns true if data at the end of the final subsegment has been cached.
virtual bool IsDataCachedAtEndOfSubsegments() = 0;
};
}// namespace mozilla

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

@ -27,6 +27,7 @@ var gProgressTests = [
{ name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.266, size:28942 },
{ name:"seek.webm", type:"video/webm", duration:3.966, size:215529 },
{ name:"gizmo.mp4", type:"video/mp4", duration:5.56, size:383631 },
{ name:"dash-manifest.mpd", type:"application/dash+xml", duration:3.966 },
{ name:"bogus.duh", type:"bogus/duh" }
];
@ -38,6 +39,7 @@ var gPlayedTests = [
{ name:"seek.webm", type:"video/webm", duration:3.966 },
{ name:"gizmo.mp4", type:"video/mp4", duration:5.56 },
{ name:"owl.mp3", type:"audio/mpeg", duration:3.29 },
{ name:"dash-manifest.mpd", type:"application/dash+xml", duration:3.966 },
];
// Used by test_mozLoadFrom. Need one test file per decoder backend, plus
@ -161,6 +163,9 @@ var gPlayTests = [
{ name:"small-shot.mp3", type:"audio/mpeg", duration:0.27 },
{ name:"owl.mp3", type:"audio/mpeg", duration:3.29 },
// DASH WebM MPD
{ name:"dash-manifest.mpd", type:"application/dash+xml", duration:3.966 },
// Invalid file
{ name:"bogus.duh", type:"bogus/duh", duration:Number.NaN }
];
@ -255,6 +260,12 @@ var gInfoLeakTests = [
}, {
type: 'video/webm',
src: fileUriToSrc("tests/content/media/test/404.webm", false),
}, {
type: 'application/dash+xml',
src: fileUriToSrc("tests/content/media/test/dash-manifest.mpd", true),
}, {
type: 'application/dash+xml',
src: fileUriToSrc("tests/content/media/test/404.mpd", false),
}, {
type: 'video/ogg',
src: 'http://localhost/404.ogv',
@ -264,6 +275,9 @@ var gInfoLeakTests = [
}, {
type: 'video/webm',
src: 'http://localhost/404.webm',
}, {
type: 'application/dash+xml',
src: 'http://localhost/404.mpd',
}, {
type: 'video/ogg',
src: 'http://example.com/tests/content/media/test/test_info_leak.html'

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

@ -81,7 +81,7 @@ function listener(evt) {
}
function createMedia(type, src, token) {
var tag = /^video/.test(type) ? "video" : "audio";
var tag = getMajorMimeType(test.type);
var v = document.createElement(tag);
for (var i=0; i<gEventTypes.length; i++) {
v.addEventListener(gEventTypes[i], listener, false);

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

@ -207,7 +207,7 @@ function createTestArray() {
}
function startTest(test, token) {
var elemType = /^audio/.test(test.type) ? "audio" : "video";
var elemType = getMajorMimeType(test.type);
var element = document.createElement(elemType);
element.src = test.name;
element.token = token;

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

@ -50,7 +50,7 @@ function createTestArray() {
}
function startTest(test, token) {
var elemType = /^audio/.test(test.type) ? "audio" : "video";
var elemType = getMajorMimeType(test.type);
var element = document.createElement(elemType);
element.src = test.name;
element.token = token;

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

@ -18,8 +18,8 @@ for (var i=0; i<gSmallTests.length; ++i) {
// We can't play WAV files in stand alone documents, so just don't
// run the test on non-video content types.
var isVideo = /^video/.test(test.type) ? true : false;
if (!isVideo || !document.createElement("video").canPlayType(test.type))
var tag = getMajorMimeType(test.type);
if (tag != "video" || !document.createElement("video").canPlayType(test.type))
continue;
var f = document.createElement("iframe");

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

@ -20,15 +20,10 @@ namespace dom {
* This class will be instantiated with different template arguments for testing and
* production code.
*
* FloatArrayWrapper is a type which satisfies the following:
* - Is copy-constructible.
* - Implements a Data() method returning a float*, representing an array.
* - Implements a Length() method returning a uint32_t, representing the array length.
* - Implements an inited() method returning true for valid objects.
* ErrorResult is a type which satisfies the following:
* - Implements a Throw() method taking an nsresult argument, representing an error code.
*/
template <class FloatArrayWrapper, class ErrorResult>
template <class ErrorResult>
class AudioEventTimeline
{
private:
@ -42,15 +37,17 @@ private:
};
Event(Type aType, double aTime, float aValue, double aTimeConstant = 0.0,
float aDuration = 0.0, FloatArrayWrapper aCurve = FloatArrayWrapper())
float aDuration = 0.0, float* aCurve = nullptr, uint32_t aCurveLength = 0)
: mType(aType)
, mValue(aValue)
, mTime(aTime)
, mTimeConstant(aTimeConstant)
, mDuration(aDuration)
{
if (aCurve.inited()) {
if (aType == Event::SetValueCurve) {
mCurve = aCurve;
mCurveLength = aCurveLength;
} else {
mValue = aValue;
mTime = aTime;
}
}
@ -63,31 +60,28 @@ private:
}
Type mType;
float mValue;
double mTime;
union {
float mValue;
uint32_t mCurveLength;
};
union {
double mTime;
float* mCurve;
};
double mTimeConstant;
double mDuration;
FloatArrayWrapper mCurve;
private:
static bool IsValid(float value)
static bool IsValid(double value)
{
return MOZ_DOUBLE_IS_FINITE(value);
}
};
public:
AudioEventTimeline(float aDefaultValue,
float aMinValue,
float aMaxValue)
explicit AudioEventTimeline(float aDefaultValue)
: mValue(aDefaultValue)
, mDefaultValue(aDefaultValue)
, mMinValue(aMinValue)
, mMaxValue(aMaxValue)
{
MOZ_ASSERT(aDefaultValue >= aMinValue);
MOZ_ASSERT(aDefaultValue <= aMaxValue);
MOZ_ASSERT(aMinValue < aMaxValue);
}
float Value() const
@ -110,21 +104,6 @@ public:
return 0;
}
float MinValue() const
{
return mMinValue;
}
float MaxValue() const
{
return mMaxValue;
}
float DefaultValue() const
{
return mDefaultValue;
}
void SetValueAtTime(float aValue, double aStartTime, ErrorResult& aRv)
{
InsertEvent(Event(Event::SetValue, aStartTime, aValue), aRv);
@ -145,10 +124,11 @@ public:
InsertEvent(Event(Event::SetTarget, aStartTime, aTarget, aTimeConstant), aRv);
}
void SetValueCurveAtTime(const FloatArrayWrapper& aValues, double aStartTime, double aDuration, ErrorResult& aRv)
void SetValueCurveAtTime(const float* aValues, uint32_t aValuesLength, double aStartTime, double aDuration, ErrorResult& aRv)
{
// TODO: implement
// InsertEvent(Event(Event::SetValueCurve, aStartTime, 0.0f, 0.0f, aDuration, aValues), aRv);
// Note that we will need to copy the buffer here.
// InsertEvent(Event(Event::SetValueCurve, aStartTime, 0.0f, 0.0f, aDuration, aValues, aValuesLength), aRv);
}
void CancelScheduledValues(double aStartTime)
@ -377,9 +357,6 @@ private:
// being a bottleneck.
nsTArray<Event> mEvents;
float mValue;
const float mDefaultValue;
const float mMinValue;
const float mMaxValue;
};
}

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

@ -40,20 +40,20 @@ public:
virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope,
bool* aTriedToWrap);
double DopplerFactor() const
float DopplerFactor() const
{
return mDopplerFactor;
}
void SetDopplerFactor(double aDopplerFactor)
void SetDopplerFactor(float aDopplerFactor)
{
mDopplerFactor = aDopplerFactor;
}
double SpeedOfSound() const
float SpeedOfSound() const
{
return mSpeedOfSound;
}
void SetSpeedOfSound(double aSpeedOfSound)
void SetSpeedOfSound(float aSpeedOfSound)
{
mSpeedOfSound = aSpeedOfSound;
}
@ -89,8 +89,8 @@ private:
ThreeDPoint mOrientation;
ThreeDPoint mUpVector;
ThreeDPoint mVelocity;
double mDopplerFactor;
double mSpeedOfSound;
float mDopplerFactor;
float mSpeedOfSound;
};
}

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

@ -22,9 +22,15 @@ AudioParam::AudioParam(AudioContext* aContext,
float aDefaultValue,
float aMinValue,
float aMaxValue)
: AudioParamTimeline(aDefaultValue, aMinValue, aMaxValue)
: AudioParamTimeline(aDefaultValue)
, mContext(aContext)
, mDefaultValue(aDefaultValue)
, mMinValue(aMinValue)
, mMaxValue(aMaxValue)
{
MOZ_ASSERT(aDefaultValue >= aMinValue);
MOZ_ASSERT(aDefaultValue <= aMaxValue);
MOZ_ASSERT(aMinValue < aMaxValue);
SetIsDOMBinding();
}

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

@ -26,57 +26,7 @@ class ErrorResult;
namespace dom {
namespace detail {
// This class wraps a JS typed array so that AudioEventTimeline does not need
// to know about JSObjects directly.
class FloatArrayWrapper
{
public:
FloatArrayWrapper() // creates an uninitialized object
{
}
FloatArrayWrapper(const Float32Array& array)
{
mArray.construct(array);
}
FloatArrayWrapper(const FloatArrayWrapper& rhs)
{
MOZ_ASSERT(!rhs.mArray.empty());
mArray.construct(rhs.mArray.ref());
}
FloatArrayWrapper& operator=(const FloatArrayWrapper& rhs)
{
MOZ_ASSERT(!rhs.mArray.empty());
mArray.destroyIfConstructed();
mArray.construct(rhs.mArray.ref());
return *this;
}
// Expose the API used by AudioEventTimeline
float* Data() const
{
MOZ_ASSERT(inited());
return mArray.ref().Data();
}
uint32_t Length() const
{
MOZ_ASSERT(inited());
return mArray.ref().Length();
}
bool inited() const
{
return !mArray.empty();
}
private:
Maybe<Float32Array> mArray;
};
}
typedef AudioEventTimeline<detail::FloatArrayWrapper, ErrorResult> AudioParamTimeline;
typedef AudioEventTimeline<ErrorResult> AudioParamTimeline;
class AudioParam MOZ_FINAL : public nsWrapperCache,
public EnableWebAudioCheck,
@ -104,12 +54,30 @@ public:
// object.
void SetValueCurveAtTime(JSContext* cx, const Float32Array& aValues, double aStartTime, double aDuration, ErrorResult& aRv)
{
AudioParamTimeline::SetValueCurveAtTime(detail::FloatArrayWrapper(aValues),
AudioParamTimeline::SetValueCurveAtTime(aValues.Data(), aValues.Length(),
aStartTime, aDuration, aRv);
}
float MinValue() const
{
return mMinValue;
}
float MaxValue() const
{
return mMaxValue;
}
float DefaultValue() const
{
return mDefaultValue;
}
private:
nsRefPtr<AudioContext> mContext;
const float mDefaultValue;
const float mMinValue;
const float mMaxValue;
};
}

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

@ -53,24 +53,6 @@ void is(const float& a, const float& b, const char* msg)
ok(fabsf(a - b) < kEpsilon, ss.str().c_str());
}
class FloatArrayMock
{
public:
// This implementation is not used for now, so let's just return dummy values.
float* Data() const
{
return nullptr;
}
uint32_t Length() const
{
return 0;
}
bool inited() const
{
return true;
}
};
class ErrorResultMock
{
public:
@ -92,15 +74,13 @@ private:
nsresult mRv;
};
typedef AudioEventTimeline<FloatArrayMock, ErrorResultMock> Timeline;
typedef AudioEventTimeline<ErrorResultMock> Timeline;
void TestSpecExample()
{
// First, run the basic tests
Timeline timeline(10.0f, .1f, 20.0f);
is(timeline.DefaultValue(), 10.0f, "Correct default value returned");
is(timeline.MinValue(), .1f, "Correct min value returned");
is(timeline.MaxValue(), 20.0f, "Correct max value returned");
Timeline timeline(10.0f);
is(timeline.Value(), 10.0f, "Correct default value returned");
ErrorResultMock rv;
@ -152,7 +132,7 @@ void TestInvalidEvents()
MOZ_STATIC_ASSERT(numeric_limits<float>::has_quiet_NaN, "Platform must have a quiet NaN");
const float NaN = numeric_limits<float>::quiet_NaN();
const float Infinity = numeric_limits<float>::infinity();
Timeline timeline(10.0f, .1f, 20.0f);
Timeline timeline(10.0f);
ErrorResultMock rv;
@ -191,7 +171,7 @@ void TestInvalidEvents()
void TestEventReplacement()
{
Timeline timeline(10.0f, .1f, 20.0f);
Timeline timeline(10.0f);
ErrorResultMock rv;
@ -210,7 +190,7 @@ void TestEventReplacement()
void TestEventRemoval()
{
Timeline timeline(10.0f, .1f, 20.0f);
Timeline timeline(10.0f);
ErrorResultMock rv;
@ -229,7 +209,7 @@ void TestEventRemoval()
void TestBeforeFirstEvent()
{
Timeline timeline(10.0f, .1f, 20.0f);
Timeline timeline(10.0f);
ErrorResultMock rv;
@ -239,7 +219,7 @@ void TestBeforeFirstEvent()
void TestAfterLastValueEvent()
{
Timeline timeline(10.0f, .1f, 20.0f);
Timeline timeline(10.0f);
ErrorResultMock rv;
@ -249,7 +229,7 @@ void TestAfterLastValueEvent()
void TestAfterLastTargetValueEvent()
{
Timeline timeline(10.0f, .1f, 20.0f);
Timeline timeline(10.0f);
ErrorResultMock rv;
@ -259,7 +239,7 @@ void TestAfterLastTargetValueEvent()
void TestAfterLastTargetValueEventWithValueSet()
{
Timeline timeline(10.0f, .1f, 20.0f);
Timeline timeline(10.0f);
ErrorResultMock rv;
@ -270,7 +250,7 @@ void TestAfterLastTargetValueEventWithValueSet()
void TestValue()
{
Timeline timeline(10.0f, .1f, 20.0f);
Timeline timeline(10.0f);
ErrorResultMock rv;
@ -286,7 +266,7 @@ void TestValue()
void TestLinearRampAtZero()
{
Timeline timeline(10.0f, .1f, 20.0f);
Timeline timeline(10.0f);
ErrorResultMock rv;
@ -296,7 +276,7 @@ void TestLinearRampAtZero()
void TestExponentialRampAtZero()
{
Timeline timeline(10.0f, .1f, 20.0f);
Timeline timeline(10.0f);
ErrorResultMock rv;
@ -306,7 +286,7 @@ void TestExponentialRampAtZero()
void TestLinearRampAtSameTime()
{
Timeline timeline(10.0f, .1f, 20.0f);
Timeline timeline(10.0f);
ErrorResultMock rv;
@ -317,7 +297,7 @@ void TestLinearRampAtSameTime()
void TestExponentialRampAtSameTime()
{
Timeline timeline(10.0f, .1f, 20.0f);
Timeline timeline(10.0f);
ErrorResultMock rv;
@ -328,7 +308,7 @@ void TestExponentialRampAtSameTime()
void TestSetTargetZeroTimeConstant()
{
Timeline timeline(10.0f, .1f, 20.0f);
Timeline timeline(10.0f);
ErrorResultMock rv;

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

@ -49,6 +49,7 @@ PRLogModuleInfo* gNesteggLog;
static const unsigned NS_PER_USEC = 1000;
static const double NS_PER_S = 1e9;
static const double USEC_PER_S = 1e6;
// If a seek request is within SEEK_DECODE_MARGIN microseconds of the
// current time, decode ahead from the current frame rather than performing
@ -918,6 +919,38 @@ nsresult WebMReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime,
return DecodeToTarget(aTarget);
}
#ifdef MOZ_DASH
bool WebMReader::IsDataCachedAtEndOfSubsegments()
{
MediaResource* resource = mDecoder->GetResource();
NS_ENSURE_TRUE(resource, false);
if (resource->IsDataCachedToEndOfResource(0)) {
return true;
}
if (mClusterByteRanges.IsEmpty()) {
return false;
}
nsTArray<MediaByteRange> ranges;
nsresult rv = resource->GetCachedRanges(ranges);
NS_ENSURE_SUCCESS(rv, false);
if (ranges.IsEmpty()) {
return false;
}
// Return true if data at the end of the final subsegment is cached.
uint32_t finalSubsegmentIndex = mClusterByteRanges.Length()-1;
uint64_t finalSubEndOffset = mClusterByteRanges[finalSubsegmentIndex].mEnd;
uint32_t finalRangeIndex = ranges.Length()-1;
uint64_t finalRangeStartOffset = ranges[finalRangeIndex].mStart;
uint64_t finalRangeEndOffset = ranges[finalRangeIndex].mEnd;
return (finalRangeStartOffset < finalSubEndOffset &&
finalSubEndOffset <= finalRangeEndOffset);
}
#endif
nsresult WebMReader::GetBuffered(nsTimeRanges* aBuffered, int64_t aStartTime)
{
MediaResource* resource = mDecoder->GetResource();
@ -955,7 +988,29 @@ nsresult WebMReader::GetBuffered(nsTimeRanges* aBuffered, int64_t aStartTime)
if (rv) {
double startTime = start * timecodeScale / NS_PER_S - aStartTime;
double endTime = end * timecodeScale / NS_PER_S - aStartTime;
#ifdef MOZ_DASH
// If this range extends to the end of a cluster, the true end time is
// the cluster's end timestamp. Since WebM frames do not have an end
// timestamp, a fully cached cluster must be reported with the correct
// end time of its final frame. Otherwise, buffered ranges could be
// reported with missing frames at cluster boundaries, specifically
// boundaries where stream switching has occurred.
if (!mClusterByteRanges.IsEmpty()) {
for (uint32_t clusterIndex = 0;
clusterIndex < (mClusterByteRanges.Length()-1);
clusterIndex++) {
if (ranges[index].mEnd >= mClusterByteRanges[clusterIndex].mEnd) {
double clusterEndTime =
mClusterByteRanges[clusterIndex+1].mStartTime / USEC_PER_S;
if (endTime < clusterEndTime) {
LOG(PR_LOG_DEBUG, ("End of cluster: endTime becoming %0.3fs",
clusterEndTime));
endTime = clusterEndTime;
}
}
}
}
#endif
// If this range extends to the end of the file, the true end time
// is the file's duration.
if (resource->IsDataCachedToEndOfResource(ranges[index].mStart)) {

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

@ -208,6 +208,9 @@ public:
// Seeks to the beginning of the specified cluster. Called on the decode
// thread.
void SeekToCluster(uint32_t aIdx);
// Returns true if data at the end of the final subsegment has been cached.
bool IsDataCachedAtEndOfSubsegments() MOZ_OVERRIDE;
#endif
protected:

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

@ -481,7 +481,6 @@ using mozilla::dom::workers::ResolveWorkerClasses;
#include "BluetoothManager.h"
#include "BluetoothAdapter.h"
#include "BluetoothDevice.h"
#include "BluetoothPropertyEvent.h"
#endif
#include "nsIDOMNavigatorSystemMessages.h"
@ -1518,11 +1517,9 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(BluetoothManager, nsEventTargetSH,
EVENTTARGET_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(BluetoothAdapter, nsEventTargetSH,
EVENTTARGET_SCRIPTABLE_FLAGS)
EVENTTARGET_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(BluetoothDevice, nsEventTargetSH,
EVENTTARGET_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(BluetoothPropertyEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
#endif
NS_DEFINE_CLASSINFO_DATA(CameraManager, nsDOMGenericSH,
@ -3945,15 +3942,10 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_BEGIN(BluetoothAdapter, nsIDOMBluetoothAdapter)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothAdapter)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(BluetoothDevice, nsIDOMBluetoothDevice)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothDevice)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(BluetoothPropertyEvent, nsIDOMBluetoothPropertyEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothPropertyEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent)
DOM_CLASSINFO_MAP_END
#endif
DOM_CLASSINFO_MAP_BEGIN(CameraManager, nsIDOMCameraManager)

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

@ -445,7 +445,6 @@ DOMCI_CLASS(FMRadio)
DOMCI_CLASS(BluetoothManager)
DOMCI_CLASS(BluetoothAdapter)
DOMCI_CLASS(BluetoothDevice)
DOMCI_CLASS(BluetoothPropertyEvent)
#endif
DOMCI_CLASS(CameraManager)

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

@ -5848,7 +5848,9 @@ class CGProxyUnwrap(CGAbstractMethod):
def declare(self):
return ""
def definition_body(self):
return """ if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
return """ MOZ_ASSERT(js::IsProxy(obj));
if (js::GetProxyHandler(obj) != DOMProxyHandler::getInstance()) {
MOZ_ASSERT(xpc::WrapperFactory::IsXrayWrapper(obj));
obj = js::UnwrapObject(obj);
}
MOZ_ASSERT(IsProxy(obj));

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

@ -273,7 +273,7 @@ PrimitiveConversionTraits_Clamp(JSContext* cx, const double& d, T* retval)
// the correct result. If N is even, plus or minus N is the correct result.
double toTruncate = (d < 0) ? d - 0.5 : d + 0.5;
T truncated(toTruncate);
T truncated = static_cast<T>(toTruncate);
if (truncated == toTruncate) {
/*
@ -339,8 +339,8 @@ bool ValueToPrimitive(JSContext* cx, JS::Value v, T* retval)
if (!PrimitiveConversionTraits<T, B>::converter(cx, v, &t))
return false;
*retval =
static_cast<typename PrimitiveConversionTraits<T, B>::intermediateType>(t);
*retval = static_cast<T>(
static_cast<typename PrimitiveConversionTraits<T, B>::intermediateType>(t));
return true;
}

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

@ -7,7 +7,6 @@
#include "base/basictypes.h"
#include "BluetoothAdapter.h"
#include "BluetoothDevice.h"
#include "BluetoothPropertyEvent.h"
#include "BluetoothReplyRunnable.h"
#include "BluetoothService.h"
#include "BluetoothUtils.h"
@ -15,13 +14,11 @@
#include "nsContentUtils.h"
#include "nsDOMClassInfo.h"
#include "nsDOMEvent.h"
#include "nsIDOMBluetoothDeviceAddressEvent.h"
#include "nsIDOMBluetoothDeviceEvent.h"
#include "nsIDOMDOMRequest.h"
#include "nsTArrayHelpers.h"
#include "DOMRequest.h"
#include "nsThreadUtils.h"
#include "nsXPCOMCIDInternal.h"
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
#include "mozilla/dom/ContentChild.h"
@ -72,24 +69,30 @@ public:
virtual bool ParseSuccessfulReply(jsval* aValue)
{
*aValue = JSVAL_VOID;
BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
if (v.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
NS_WARNING("Not a BluetoothNamedValue array!");
SetError(NS_LITERAL_STRING("BluetoothReplyTypeError"));
return false;
}
const InfallibleTArray<BluetoothNamedValue>& reply =
mReply->get_BluetoothReplySuccess().value().get_ArrayOfBluetoothNamedValue();
const InfallibleTArray<BluetoothNamedValue>& values =
v.get_ArrayOfBluetoothNamedValue();
nsTArray<nsRefPtr<BluetoothDevice> > devices;
JSObject* JsDevices;
for (uint32_t i = 0; i < reply.Length(); i++) {
if (reply[i].value().type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
for (uint32_t i = 0; i < values.Length(); i++) {
const BluetoothValue properties = values[i].value();
if (properties.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
NS_WARNING("Not a BluetoothNamedValue array!");
SetError(NS_LITERAL_STRING("BluetoothReplyTypeError"));
return false;
}
nsRefPtr<BluetoothDevice> d = BluetoothDevice::Create(mAdapterPtr->GetOwner(),
mAdapterPtr->GetPath(),
reply[i].value());
nsRefPtr<BluetoothDevice> d =
BluetoothDevice::Create(mAdapterPtr->GetOwner(),
mAdapterPtr->GetPath(),
properties);
devices.AppendElement(d);
}
@ -97,18 +100,18 @@ public:
nsIScriptContext* sc = mAdapterPtr->GetContextForEventHandlers(&rv);
if (!sc) {
NS_WARNING("Cannot create script context!");
SetError(NS_LITERAL_STRING("BluetoothScriptContextError"));
return false;
}
rv = nsTArrayToJSArray(sc->GetNativeContext(), devices, &JsDevices);
if (JsDevices) {
aValue->setObject(*JsDevices);
}
else {
NS_WARNING("Paird not yet set!");
if (!JsDevices) {
NS_WARNING("Cannot create JS array!");
SetError(NS_LITERAL_STRING("BluetoothError"));
return false;
}
aValue->setObject(*JsDevices);
return true;
}
@ -124,18 +127,35 @@ private:
static int kCreatePairedDeviceTimeout = 50000; // unit: msec
BluetoothAdapter::BluetoothAdapter(nsPIDOMWindow* aOwner, const BluetoothValue& aValue)
: BluetoothPropertyContainer(BluetoothObjectType::TYPE_ADAPTER)
, mEnabled(false)
, mDiscoverable(false)
, mDiscovering(false)
, mPairable(false)
, mPowered(false)
, mJsUuids(nullptr)
, mJsDeviceAddresses(nullptr)
, mIsRooted(false)
nsresult
PrepareDOMRequest(nsIDOMWindow* aWindow, nsIDOMDOMRequest** aRequest)
{
BindToOwner(aOwner);
MOZ_ASSERT(aWindow);
nsCOMPtr<nsIDOMRequestService> rs =
do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
nsresult rv = rs->CreateRequest(aWindow, aRequest);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
BluetoothAdapter::BluetoothAdapter(nsPIDOMWindow* aWindow,
const BluetoothValue& aValue)
: BluetoothPropertyContainer(BluetoothObjectType::TYPE_ADAPTER)
, mDiscoverable(false)
, mDiscovering(false)
, mPairable(false)
, mPowered(false)
, mJsUuids(nullptr)
, mJsDeviceAddresses(nullptr)
, mIsRooted(false)
{
MOZ_ASSERT(aWindow);
BindToOwner(aWindow);
const InfallibleTArray<BluetoothNamedValue>& values =
aValue.get_ArrayOfBluetoothNamedValue();
for (uint32_t i = 0; i < values.Length(); ++i) {
@ -148,8 +168,6 @@ BluetoothAdapter::~BluetoothAdapter()
BluetoothService* bs = BluetoothService::Get();
// We can be null on shutdown, where this might happen
if (bs) {
// XXXbent I don't see anything about LOCAL_AGENT_PATH or REMOTE_AGENT_PATH
// here. Probably a bug? Maybe use UnregisterAll.
bs->UnregisterBluetoothSignalHandler(mPath, this);
}
Unroot();
@ -188,8 +206,6 @@ BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue)
mAddress = value.get_nsString();
} else if (name.EqualsLiteral("Path")) {
mPath = value.get_nsString();
} else if (name.EqualsLiteral("Enabled")) {
mEnabled = value.get_bool();
} else if (name.EqualsLiteral("Discoverable")) {
mDiscoverable = value.get_bool();
} else if (name.EqualsLiteral("Discovering")) {
@ -208,33 +224,24 @@ BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue)
mUuids = value.get_ArrayOfnsString();
nsresult rv;
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
if (sc) {
rv =
nsTArrayToJSArray(sc->GetNativeContext(), mUuids, &mJsUuids);
if (NS_FAILED(rv)) {
NS_WARNING("Cannot set JS UUIDs object!");
return;
}
Root();
} else {
NS_WARNING("Could not get context!");
NS_ENSURE_SUCCESS_VOID(rv);
if (!SetJsObject(sc->GetNativeContext(), value, mJsUuids)) {
NS_WARNING("Cannot set JS UUIDs object!");
return;
}
Root();
} else if (name.EqualsLiteral("Devices")) {
mDeviceAddresses = value.get_ArrayOfnsString();
nsresult rv;
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
if (sc) {
rv =
nsTArrayToJSArray(sc->GetNativeContext(), mDeviceAddresses,
&mJsDeviceAddresses);
if (NS_FAILED(rv)) {
NS_WARNING("Cannot set JS Device Addresses object!");
return;
}
Root();
} else {
NS_WARNING("Could not get context!");
NS_ENSURE_SUCCESS_VOID(rv);
if (!SetJsObject(sc->GetNativeContext(), value, mJsDeviceAddresses)) {
NS_WARNING("Cannot set JS Devices object!");
return;
}
Root();
} else {
#ifdef DEBUG
nsCString warningMsg;
@ -247,16 +254,15 @@ BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue)
// static
already_AddRefed<BluetoothAdapter>
BluetoothAdapter::Create(nsPIDOMWindow* aOwner, const BluetoothValue& aValue)
BluetoothAdapter::Create(nsPIDOMWindow* aWindow, const BluetoothValue& aValue)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aWindow);
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
NS_WARNING("BluetoothService not available!");
return nullptr;
}
nsRefPtr<BluetoothAdapter> adapter = new BluetoothAdapter(aOwner, aValue);
NS_ENSURE_TRUE(bs, nullptr);
nsRefPtr<BluetoothAdapter> adapter = new BluetoothAdapter(aWindow, aValue);
bs->RegisterBluetoothSignalHandler(adapter->GetPath(), adapter);
return adapter.forget();
@ -267,6 +273,9 @@ BluetoothAdapter::Notify(const BluetoothSignal& aData)
{
InfallibleTArray<BluetoothNamedValue> arr;
BT_LOG("[A] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
BluetoothValue v = aData.value();
if (aData.name().EqualsLiteral("DeviceFound")) {
nsRefPtr<BluetoothDevice> device = BluetoothDevice::Create(GetOwner(), mPath, aData.value());
nsCOMPtr<nsIDOMEvent> event;
@ -301,16 +310,14 @@ BluetoothAdapter::Notify(const BluetoothSignal& aData)
false, false, device);
DispatchTrustedEvent(e);
} else if (aData.name().EqualsLiteral("PropertyChanged")) {
NS_ASSERTION(aData.value().type() == BluetoothValue::TArrayOfBluetoothNamedValue,
NS_ASSERTION(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue,
"PropertyChanged: Invalid value type");
arr = aData.value().get_ArrayOfBluetoothNamedValue();
const InfallibleTArray<BluetoothNamedValue>& arr =
v.get_ArrayOfBluetoothNamedValue();
NS_ASSERTION(arr.Length() == 1, "Got more than one property in a change message!");
BluetoothNamedValue v = arr[0];
SetPropertyByValue(v);
nsRefPtr<BluetoothPropertyEvent> e = BluetoothPropertyEvent::Create(v.name());
e->Dispatch(ToIDOMEventTarget(), NS_LITERAL_STRING("propertychanged"));
NS_ASSERTION(arr.Length() == 1,
"Got more than one property in a change message!");
SetPropertyByValue(arr[0]);
} else {
#ifdef DEBUG
nsCString warningMsg;
@ -324,42 +331,30 @@ BluetoothAdapter::Notify(const BluetoothSignal& aData)
nsresult
BluetoothAdapter::StartStopDiscovery(bool aStart, nsIDOMDOMRequest** aRequest)
{
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
NS_WARNING("BluetoothService not available!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
if (!rs) {
NS_WARNING("No DOMRequest Service!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
if (NS_FAILED(rv)) {
NS_WARNING("Can't create DOMRequest!");
return NS_ERROR_FAILURE;
}
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsRefPtr<BluetoothVoidReplyRunnable> results = new BluetoothVoidReplyRunnable(req);
nsRefPtr<BluetoothVoidReplyRunnable> results =
new BluetoothVoidReplyRunnable(req);
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
if (aStart) {
rv = bs->StartDiscoveryInternal(mPath, results);
} else {
rv = bs->StopDiscoveryInternal(mPath, results);
}
if (NS_FAILED(rv)) {
NS_WARNING("Starting discovery failed!");
if(NS_FAILED(rv)) {
NS_WARNING("Start/Stop Discovery failed!");
return NS_ERROR_FAILURE;
}
req.forget(aRequest);
// mDiscovering is not set here, we'll get a Property update from our external
// protocol to tell us that it's been set.
req.forget(aRequest);
return NS_OK;
}
@ -433,11 +428,11 @@ BluetoothAdapter::GetDevices(JSContext* aCx, jsval* aDevices)
else {
NS_WARNING("Devices not yet set!\n");
return NS_ERROR_FAILURE;
}
}
return NS_OK;
}
nsresult
NS_IMETHODIMP
BluetoothAdapter::GetUuids(JSContext* aCx, jsval* aValue)
{
if (mJsUuids) {
@ -490,30 +485,23 @@ BluetoothAdapter::SetDiscoverableTimeout(const uint32_t aDiscoverableTimeout,
NS_IMETHODIMP
BluetoothAdapter::GetPairedDevices(nsIDOMDOMRequest** aRequest)
{
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsRefPtr<BluetoothReplyRunnable> results =
new GetPairedDevicesTask(this, req);
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
NS_WARNING("BluetoothService not available!");
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
if (NS_FAILED(bs->GetPairedDevicePropertiesInternal(mDeviceAddresses,
results))) {
NS_WARNING("GetPairedDevices failed!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
if (!rs) {
NS_WARNING("No DOMRequest Service!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMDOMRequest> request;
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(request));
if (NS_FAILED(rv)) {
NS_WARNING("Can't create DOMRequest!");
return NS_ERROR_FAILURE;
}
nsRefPtr<BluetoothReplyRunnable> results = new GetPairedDevicesTask(this, request);
if (NS_FAILED(bs->GetPairedDevicePropertiesInternal(mDeviceAddresses, results))) {
return NS_ERROR_FAILURE;
}
request.forget(aRequest);
req.forget(aRequest);
return NS_OK;
}
@ -522,30 +510,19 @@ BluetoothAdapter::PairUnpair(bool aPair,
nsIDOMBluetoothDevice* aDevice,
nsIDOMDOMRequest** aRequest)
{
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
NS_WARNING("BluetoothService not available!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
if (!rs) {
NS_WARNING("No DOMRequest Service!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
if (NS_FAILED(rv)) {
NS_WARNING("Can't create DOMRequest!");
return NS_ERROR_FAILURE;
}
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsRefPtr<BluetoothVoidReplyRunnable> results = new BluetoothVoidReplyRunnable(req);
nsRefPtr<BluetoothVoidReplyRunnable> results =
new BluetoothVoidReplyRunnable(req);
nsString addr;
aDevice->GetAddress(addr);
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
if (aPair) {
rv = bs->CreatePairedDeviceInternal(mPath,
addr,
@ -561,18 +538,19 @@ BluetoothAdapter::PairUnpair(bool aPair,
}
req.forget(aRequest);
return NS_OK;
}
nsresult
BluetoothAdapter::Pair(nsIDOMBluetoothDevice* aDevice, nsIDOMDOMRequest** aRequest)
BluetoothAdapter::Pair(nsIDOMBluetoothDevice* aDevice,
nsIDOMDOMRequest** aRequest)
{
return PairUnpair(true, aDevice, aRequest);
}
nsresult
BluetoothAdapter::Unpair(nsIDOMBluetoothDevice* aDevice, nsIDOMDOMRequest** aRequest)
BluetoothAdapter::Unpair(nsIDOMBluetoothDevice* aDevice,
nsIDOMDOMRequest** aRequest)
{
return PairUnpair(false, aDevice, aRequest);
}
@ -582,29 +560,17 @@ BluetoothAdapter::SetPinCode(const nsAString& aDeviceAddress,
const nsAString& aPinCode,
nsIDOMDOMRequest** aRequest)
{
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
NS_WARNING("BluetoothService not available!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
if (!rs) {
NS_WARNING("No DOMRequest Service!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
if (NS_FAILED(rv)) {
NS_WARNING("Can't create DOMRequest!");
return NS_ERROR_FAILURE;
}
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsRefPtr<BluetoothVoidReplyRunnable> results = new BluetoothVoidReplyRunnable(req);
nsRefPtr<BluetoothVoidReplyRunnable> results =
new BluetoothVoidReplyRunnable(req);
bool result = bs->SetPinCodeInternal(aDeviceAddress, aPinCode, results);
if(!result) {
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
if(!bs->SetPinCodeInternal(aDeviceAddress, aPinCode, results)) {
NS_WARNING("SetPinCode failed!");
return NS_ERROR_FAILURE;
}
@ -617,29 +583,17 @@ nsresult
BluetoothAdapter::SetPasskey(const nsAString& aDeviceAddress, uint32_t aPasskey,
nsIDOMDOMRequest** aRequest)
{
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
NS_WARNING("BluetoothService not available!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
if (!rs) {
NS_WARNING("No DOMRequest Service!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
if (NS_FAILED(rv)) {
NS_WARNING("Can't create DOMRequest!");
return NS_ERROR_FAILURE;
}
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsRefPtr<BluetoothVoidReplyRunnable> results = new BluetoothVoidReplyRunnable(req);
nsRefPtr<BluetoothVoidReplyRunnable> results =
new BluetoothVoidReplyRunnable(req);
bool result = bs->SetPasskeyInternal(aDeviceAddress, aPasskey, results);
if(!result) {
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
if(bs->SetPasskeyInternal(aDeviceAddress, aPasskey, results)) {
NS_WARNING("SetPasskeyInternal failed!");
return NS_ERROR_FAILURE;
}
@ -653,29 +607,19 @@ BluetoothAdapter::SetPairingConfirmation(const nsAString& aDeviceAddress,
bool aConfirmation,
nsIDOMDOMRequest** aRequest)
{
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
NS_WARNING("BluetoothService not available!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
if (!rs) {
NS_WARNING("No DOMRequest Service!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
if (NS_FAILED(rv)) {
NS_WARNING("Can't create DOMRequest!");
return NS_ERROR_FAILURE;
}
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsRefPtr<BluetoothVoidReplyRunnable> results = new BluetoothVoidReplyRunnable(req);
nsRefPtr<BluetoothVoidReplyRunnable> results =
new BluetoothVoidReplyRunnable(req);
bool result = bs->SetPairingConfirmationInternal(aDeviceAddress, aConfirmation, results);
if(!result) {
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
if(!bs->SetPairingConfirmationInternal(aDeviceAddress,
aConfirmation,
results)) {
NS_WARNING("SetPairingConfirmation failed!");
return NS_ERROR_FAILURE;
}
@ -688,29 +632,17 @@ nsresult
BluetoothAdapter::SetAuthorization(const nsAString& aDeviceAddress, bool aAllow,
nsIDOMDOMRequest** aRequest)
{
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
NS_WARNING("BluetoothService not available!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
if (!rs) {
NS_WARNING("No DOMRequest Service!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
if (NS_FAILED(rv)) {
NS_WARNING("Can't create DOMRequest!");
return NS_ERROR_FAILURE;
}
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsRefPtr<BluetoothVoidReplyRunnable> results = new BluetoothVoidReplyRunnable(req);
nsRefPtr<BluetoothVoidReplyRunnable> results =
new BluetoothVoidReplyRunnable(req);
bool result = bs->SetAuthorizationInternal(aDeviceAddress, aAllow, results);
if(!result) {
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
if(!bs->SetAuthorizationInternal(aDeviceAddress, aAllow, results)) {
NS_WARNING("SetAuthorization failed!");
return NS_ERROR_FAILURE;
}
@ -724,24 +656,13 @@ BluetoothAdapter::Connect(const nsAString& aDeviceAddress,
uint16_t aProfileId,
nsIDOMDOMRequest** aRequest)
{
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
NS_WARNING("BluetoothService not available!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
if (!rs) {
NS_WARNING("No DOMRequest Service!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
if (NS_FAILED(rv)) {
NS_WARNING("Can't create DOMRequest!");
return NS_ERROR_FAILURE;
}
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
nsRefPtr<BluetoothVoidReplyRunnable> results =
new BluetoothVoidReplyRunnable(req);
@ -755,28 +676,17 @@ NS_IMETHODIMP
BluetoothAdapter::Disconnect(uint16_t aProfileId,
nsIDOMDOMRequest** aRequest)
{
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
NS_WARNING("BluetoothService not available!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
if (!rs) {
NS_WARNING("No DOMRequest Service!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
if (NS_FAILED(rv)) {
NS_WARNING("Can't create DOMRequest!");
return NS_ERROR_FAILURE;
}
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsRefPtr<BluetoothVoidReplyRunnable> result =
nsRefPtr<BluetoothVoidReplyRunnable> results =
new BluetoothVoidReplyRunnable(req);
bs->Disconnect(aProfileId, result);
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
bs->Disconnect(aProfileId, results);
req.forget(aRequest);
return NS_OK;
@ -787,37 +697,26 @@ BluetoothAdapter::SendFile(const nsAString& aDeviceAddress,
nsIDOMBlob* aBlob,
nsIDOMDOMRequest** aRequest)
{
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
NS_WARNING("BluetoothService not available!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
if (!rs) {
NS_WARNING("No DOMRequest Service!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
if (NS_FAILED(rv)) {
NS_WARNING("Can't create DOMRequest!");
return NS_ERROR_FAILURE;
}
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsRefPtr<BluetoothVoidReplyRunnable> results =
new BluetoothVoidReplyRunnable(req);
BlobChild* actor =
mozilla::dom::ContentChild::GetSingleton()->GetOrCreateActorForBlob(aBlob);
mozilla::dom::ContentChild::GetSingleton()->GetOrCreateActorForBlob(aBlob);
if (!actor) {
NS_WARNING("Can't create actor");
return NS_ERROR_FAILURE;
}
nsRefPtr<BluetoothVoidReplyRunnable> result = new BluetoothVoidReplyRunnable(req);
bs->SendFile(aDeviceAddress, nullptr, actor, result);
req.forget(aRequest);
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
bs->SendFile(aDeviceAddress, nullptr, actor, results);
req.forget(aRequest);
return NS_OK;
}
@ -825,29 +724,19 @@ NS_IMETHODIMP
BluetoothAdapter::StopSendingFile(const nsAString& aDeviceAddress,
nsIDOMDOMRequest** aRequest)
{
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
NS_WARNING("BluetoothService not available!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
if (!rs) {
NS_WARNING("No DOMRequest Service!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
if (NS_FAILED(rv)) {
NS_WARNING("Can't create DOMRequest!");
return NS_ERROR_FAILURE;
}
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsRefPtr<BluetoothVoidReplyRunnable> results =
new BluetoothVoidReplyRunnable(req);
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
bs->StopSendingFile(aDeviceAddress, results);
nsRefPtr<BluetoothVoidReplyRunnable> result = new BluetoothVoidReplyRunnable(req);
bs->StopSendingFile(aDeviceAddress, result);
req.forget(aRequest);
return NS_OK;
}
@ -856,33 +745,19 @@ BluetoothAdapter::ConfirmReceivingFile(const nsAString& aDeviceAddress,
bool aConfirmation,
nsIDOMDOMRequest** aRequest)
{
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
NS_WARNING("BluetoothService not available!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMRequestService> rs =
do_GetService("@mozilla.org/dom/dom-request-service;1");
if (!rs) {
NS_WARNING("No DOMRequest Service!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
if (NS_FAILED(rv)) {
NS_WARNING("Can't create DOMRequest!");
return NS_ERROR_FAILURE;
}
nsresult rv;
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsRefPtr<BluetoothVoidReplyRunnable> result =
nsRefPtr<BluetoothVoidReplyRunnable> results =
new BluetoothVoidReplyRunnable(req);
bs->ConfirmReceivingFile(aDeviceAddress, aConfirmation, result);
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
bs->ConfirmReceivingFile(aDeviceAddress, aConfirmation, results);
req.forget(aRequest);
return NS_OK;
}

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

@ -11,6 +11,34 @@
#include "nsStringGlue.h"
#include "nsTArray.h"
extern bool gBluetoothDebugFlag;
#define SWITCH_BT_DEBUG(V) (gBluetoothDebugFlag = V)
#undef BT_LOG
#if defined(MOZ_WIDGET_GONK)
#include <android/log.h>
#define BT_LOG(args...) \
do { \
if (gBluetoothDebugFlag) { \
__android_log_print(ANDROID_LOG_INFO, "GeckoBluetooth", args); \
} \
} while(0)
#define BT_WARNING(args...) \
__android_log_print(ANDROID_LOG_WARN, "GeckoBluetooth", args)
#else
#define BT_LOG(args, ...) \
do { \
if (gBluetoothDebugFlag) { \
printf(args, ##__VA_ARGS__); \
} \
} while(0)
#define BT_WARNING(args, ...) printf(args, ##__VA_ARGS__)
#endif
#define BEGIN_BLUETOOTH_NAMESPACE \
namespace mozilla { namespace dom { namespace bluetooth {
#define END_BLUETOOTH_NAMESPACE \

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

@ -6,15 +6,12 @@
#include "base/basictypes.h"
#include "BluetoothDevice.h"
#include "BluetoothPropertyEvent.h"
#include "BluetoothReplyRunnable.h"
#include "BluetoothService.h"
#include "BluetoothUtils.h"
#include "nsIDOMDOMRequest.h"
#include "nsDOMClassInfo.h"
#include "nsContentUtils.h"
#include "nsTArrayHelpers.h"
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
USING_BLUETOOTH_NAMESPACE
@ -27,12 +24,12 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(BluetoothDevice,
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsServices)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothDevice,
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothDevice,
nsDOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothDevice,
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothDevice,
nsDOMEventTargetHelper)
tmp->Unroot();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@ -45,7 +42,7 @@ NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
NS_IMPL_ADDREF_INHERITED(BluetoothDevice, nsDOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(BluetoothDevice, nsDOMEventTargetHelper)
BluetoothDevice::BluetoothDevice(nsPIDOMWindow* aOwner,
BluetoothDevice::BluetoothDevice(nsPIDOMWindow* aWindow,
const nsAString& aAdapterPath,
const BluetoothValue& aValue) :
BluetoothPropertyContainer(BluetoothObjectType::TYPE_DEVICE),
@ -54,7 +51,9 @@ BluetoothDevice::BluetoothDevice(nsPIDOMWindow* aOwner,
mAdapterPath(aAdapterPath),
mIsRooted(false)
{
BindToOwner(aOwner);
MOZ_ASSERT(aWindow);
BindToOwner(aWindow);
const InfallibleTArray<BluetoothNamedValue>& values =
aValue.get_ArrayOfBluetoothNamedValue();
for (uint32_t i = 0; i < values.Length(); ++i) {
@ -116,58 +115,46 @@ BluetoothDevice::SetPropertyByValue(const BluetoothNamedValue& aValue)
mUuids = value.get_ArrayOfnsString();
nsresult rv;
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
if (sc) {
rv =
nsTArrayToJSArray(sc->GetNativeContext(), mUuids, &mJsUuids);
if (NS_FAILED(rv)) {
NS_WARNING("Cannot set JS UUIDs object!");
return;
}
Root();
} else {
NS_WARNING("Could not get context!");
NS_ENSURE_SUCCESS_VOID(rv);
if (!SetJsObject(sc->GetNativeContext(), value, mJsUuids)) {
NS_WARNING("Cannot set JS UUIDs object!");
return;
}
Root();
} else if (name.EqualsLiteral("Services")) {
mServices = value.get_ArrayOfnsString();
nsresult rv;
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
if (sc) {
rv =
nsTArrayToJSArray(sc->GetNativeContext(), mServices, &mJsServices);
if (NS_FAILED(rv)) {
NS_WARNING("Cannot set JS Services object!");
return;
}
Root();
} else {
NS_WARNING("Could not get context!");
NS_ENSURE_SUCCESS_VOID(rv);
if (!SetJsObject(sc->GetNativeContext(), value, mJsServices)) {
NS_WARNING("Cannot set JS Devices object!");
return;
}
#ifdef DEBUG
Root();
} else {
nsCString warningMsg;
warningMsg.AssignLiteral("Not handling device property: ");
warningMsg.Append(NS_ConvertUTF16toUTF8(name));
NS_WARNING(warningMsg.get());
#endif
}
}
// static
already_AddRefed<BluetoothDevice>
BluetoothDevice::Create(nsPIDOMWindow* aOwner,
BluetoothDevice::Create(nsPIDOMWindow* aWindow,
const nsAString& aAdapterPath,
const BluetoothValue& aValue)
{
// Make sure we at least have a service
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aWindow);
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
NS_WARNING("BluetoothService not available!");
return nullptr;
}
nsRefPtr<BluetoothDevice> device = new BluetoothDevice(aOwner, aAdapterPath,
aValue);
NS_ENSURE_TRUE(bs, nullptr);
nsRefPtr<BluetoothDevice> device =
new BluetoothDevice(aWindow, aAdapterPath, aValue);
bs->RegisterBluetoothSignalHandler(device->mPath, device);
return device.forget();
@ -176,23 +163,18 @@ BluetoothDevice::Create(nsPIDOMWindow* aOwner,
void
BluetoothDevice::Notify(const BluetoothSignal& aData)
{
BT_LOG("[D] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
BluetoothValue v = aData.value();
if (aData.name().EqualsLiteral("PropertyChanged")) {
NS_ASSERTION(aData.value().type() == BluetoothValue::TArrayOfBluetoothNamedValue,
NS_ASSERTION(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue,
"PropertyChanged: Invalid value type");
InfallibleTArray<BluetoothNamedValue> arr(aData.value().get_ArrayOfBluetoothNamedValue());
const InfallibleTArray<BluetoothNamedValue>& arr =
v.get_ArrayOfBluetoothNamedValue();
NS_ASSERTION(arr.Length() == 1, "Got more than one property in a change message!");
BluetoothNamedValue v = arr[0];
nsString name = v.name();
SetPropertyByValue(v);
if (name.EqualsLiteral("Connected")) {
DispatchTrustedEvent(mConnected ? NS_LITERAL_STRING("connected")
: NS_LITERAL_STRING("disconnected"));
} else {
nsRefPtr<BluetoothPropertyEvent> e = BluetoothPropertyEvent::Create(name);
e->Dispatch(ToIDOMEventTarget(), NS_LITERAL_STRING("propertychanged"));
}
NS_ASSERTION(arr.Length() == 1,
"Got more than one property in a change message!");
SetPropertyByValue(arr[0]);
} else {
#ifdef DEBUG
nsCString warningMsg;

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

@ -51,8 +51,12 @@ public:
*aValue = JSVAL_VOID;
const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
if (v.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
NS_WARNING("Not a BluetoothNamedValue array!");
SetError(NS_LITERAL_STRING("BluetoothReplyTypeError"));
return false;
}
MOZ_ASSERT(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
const InfallibleTArray<BluetoothNamedValue>& values =
v.get_ArrayOfBluetoothNamedValue();
nsCOMPtr<nsIDOMBluetoothAdapter> adapter;
@ -204,6 +208,8 @@ NS_NewBluetoothManager(nsPIDOMWindow* aWindow,
void
BluetoothManager::Notify(const BluetoothSignal& aData)
{
BT_LOG("[M] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
if (aData.name().EqualsLiteral("AdapterAdded")) {
DispatchTrustedEvent(NS_LITERAL_STRING("adapteradded"));
} else {

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

@ -7,7 +7,7 @@
#include "base/basictypes.h"
#include "BluetoothPropertyContainer.h"
#include "BluetoothService.h"
#include "nsIDOMDOMRequest.h"
#include "DOMRequest.h"
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
USING_BLUETOOTH_NAMESPACE
@ -16,12 +16,9 @@ nsresult
BluetoothPropertyContainer::FirePropertyAlreadySet(nsIDOMWindow* aOwner,
nsIDOMDOMRequest** aRequest)
{
nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
if (!rs) {
NS_WARNING("No DOMRequest Service!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMRequestService> rs =
do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv = rs->CreateRequest(aOwner, getter_AddRefs(req));
@ -45,12 +42,10 @@ BluetoothPropertyContainer::SetProperty(nsIDOMWindow* aOwner,
NS_WARNING("Bluetooth service not available!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
if (!rs) {
NS_WARNING("No DOMRequest Service!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMRequestService> rs =
do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMDOMRequest> req;
nsresult rv = rs->CreateRequest(aOwner, getter_AddRefs(req));

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

@ -1,51 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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 "base/basictypes.h"
#include "BluetoothPropertyEvent.h"
#include "nsDOMClassInfo.h"
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
USING_BLUETOOTH_NAMESPACE
// static
already_AddRefed<BluetoothPropertyEvent>
BluetoothPropertyEvent::Create(const nsAString& aPropertyName)
{
NS_ASSERTION(!aPropertyName.IsEmpty(), "Empty Property String!");
nsRefPtr<BluetoothPropertyEvent> event = new BluetoothPropertyEvent();
event->mPropertyName = aPropertyName;
return event.forget();
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothPropertyEvent,
nsDOMEvent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothPropertyEvent,
nsDOMEvent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothPropertyEvent)
NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothPropertyEvent)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothPropertyEvent)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
NS_IMPL_ADDREF_INHERITED(BluetoothPropertyEvent, nsDOMEvent)
NS_IMPL_RELEASE_INHERITED(BluetoothPropertyEvent, nsDOMEvent)
DOMCI_DATA(BluetoothPropertyEvent, BluetoothPropertyEvent)
NS_IMETHODIMP
BluetoothPropertyEvent::GetProperty(nsAString& aPropertyName)
{
aPropertyName = mPropertyName;
return NS_OK;
}

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

@ -1,64 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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_dom_bluetooth_propertyevent_h__
#define mozilla_dom_bluetooth_propertyevent_h__
#include "BluetoothCommon.h"
#include "nsIDOMBluetoothPropertyEvent.h"
#include "nsIDOMEventTarget.h"
#include "nsDOMEvent.h"
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothPropertyEvent : public nsDOMEvent
, public nsIDOMBluetoothPropertyEvent
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_TO_NSDOMEVENT
NS_DECL_NSIDOMBLUETOOTHPROPERTYEVENT
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothPropertyEvent, nsDOMEvent)
static already_AddRefed<BluetoothPropertyEvent>
Create(const nsAString& aPropertyName);
nsresult
Dispatch(nsIDOMEventTarget* aTarget, const nsAString& aEventType)
{
NS_ASSERTION(aTarget, "Null pointer!");
NS_ASSERTION(!aEventType.IsEmpty(), "Empty event type!");
nsresult rv = InitEvent(aEventType, false, false);
NS_ENSURE_SUCCESS(rv, rv);
SetTrusted(true);
nsDOMEvent* thisEvent = this;
bool dummy;
rv = aTarget->DispatchEvent(thisEvent, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
private:
BluetoothPropertyEvent()
: nsDOMEvent(nullptr, nullptr)
{ }
~BluetoothPropertyEvent()
{ }
nsString mPropertyName;
};
END_BLUETOOTH_NAMESPACE
#endif

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

@ -6,7 +6,7 @@
#include "base/basictypes.h"
#include "BluetoothReplyRunnable.h"
#include "nsIDOMDOMRequest.h"
#include "DOMRequest.h"
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
USING_BLUETOOTH_NAMESPACE
@ -34,14 +34,9 @@ nsresult
BluetoothReplyRunnable::FireReply(const jsval& aVal)
{
nsCOMPtr<nsIDOMRequestService> rs =
do_GetService("@mozilla.org/dom/dom-request-service;1");
if (!rs) {
NS_WARNING("No DOMRequest Service!");
return NS_ERROR_FAILURE;
}
do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
return mReply->type() == BluetoothReply::TBluetoothReplySuccess ?
rs->FireSuccessAsync(mDOMRequest, aVal) :
rs->FireErrorAsync(mDOMRequest, mReply->get_BluetoothReplyError().error());
@ -52,12 +47,8 @@ BluetoothReplyRunnable::FireErrorString()
{
nsCOMPtr<nsIDOMRequestService> rs =
do_GetService("@mozilla.org/dom/dom-request-service;1");
if (!rs) {
NS_WARNING("No DOMRequest Service!");
return NS_ERROR_FAILURE;
}
NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
return rs->FireErrorAsync(mDOMRequest, mErrorString);
}

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

@ -64,11 +64,9 @@ BluetoothRilListener::BluetoothRilListener()
bool
BluetoothRilListener::StartListening()
{
nsCOMPtr<nsIRILContentHelper> ril = do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
if (!ril) {
NS_ERROR("No RIL Service!");
return false;
}
nsCOMPtr<nsIRILContentHelper> ril =
do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
NS_ENSURE_TRUE(ril, false);
nsresult rv = ril->RegisterTelephonyCallback(mRILTelephonyCallback);
NS_ENSURE_SUCCESS(rv, false);
@ -81,11 +79,9 @@ BluetoothRilListener::StartListening()
bool
BluetoothRilListener::StopListening()
{
nsCOMPtr<nsIRILContentHelper> ril = do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
if (!ril) {
NS_ERROR("No RIL Service!");
return false;
}
nsCOMPtr<nsIRILContentHelper> ril =
do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
NS_ENSURE_TRUE(ril, false);
nsresult rv = ril->UnregisterTelephonyCallback(mRILTelephonyCallback);

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

@ -68,11 +68,9 @@ void
BluetoothScoManager::NotifyAudioManager(const nsAString& aAddress) {
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIObserverService> obs = do_GetService("@mozilla.org/observer-service;1");
if (!obs) {
NS_WARNING("Failed to get observser service!");
return;
}
nsCOMPtr<nsIObserverService> obs =
do_GetService("@mozilla.org/observer-service;1");
NS_ENSURE_TRUE_VOID(obs);
if (aAddress.IsEmpty()) {
if (NS_FAILED(obs->NotifyObservers(nullptr, BLUETOOTH_SCO_STATUS_CHANGED, nullptr))) {
@ -86,11 +84,9 @@ BluetoothScoManager::NotifyAudioManager(const nsAString& aAddress) {
}
}
nsCOMPtr<nsIAudioManager> am = do_GetService("@mozilla.org/telephony/audiomanager;1");
if (!am) {
NS_WARNING("Failed to get AudioManager service!");
return;
}
nsCOMPtr<nsIAudioManager> am =
do_GetService("@mozilla.org/telephony/audiomanager;1");
NS_ENSURE_TRUE_VOID(am);
am->SetForceForUse(am->USE_COMMUNICATION, am->FORCE_BT_SCO);
}

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

@ -40,11 +40,14 @@
# endif
#endif
#define MOZSETTINGS_CHANGED_ID "mozsettings-changed"
#define BLUETOOTH_ENABLED_SETTING "bluetooth.enabled"
#define MOZSETTINGS_CHANGED_ID "mozsettings-changed"
#define BLUETOOTH_ENABLED_SETTING "bluetooth.enabled"
#define BLUETOOTH_DEBUGGING_SETTING "bluetooth.debugging.enabled"
#define DEFAULT_SHUTDOWN_TIMER_MS 5000
bool gBluetoothDebugFlag = false;
using namespace mozilla;
using namespace mozilla::dom;
USING_BLUETOOTH_NAMESPACE
@ -314,12 +317,15 @@ BluetoothService::Cleanup()
}
void
BluetoothService::RegisterBluetoothSignalHandler(const nsAString& aNodeName,
BluetoothSignalObserver* aHandler)
BluetoothService::RegisterBluetoothSignalHandler(
const nsAString& aNodeName,
BluetoothSignalObserver* aHandler)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aHandler);
BT_LOG("[S] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aNodeName).get());
BluetoothSignalObserverList* ol;
if (!mBluetoothSignalObserverTable.Get(aNodeName, &ol)) {
ol = new BluetoothSignalObserverList();
@ -331,12 +337,15 @@ BluetoothService::RegisterBluetoothSignalHandler(const nsAString& aNodeName,
}
void
BluetoothService::UnregisterBluetoothSignalHandler(const nsAString& aNodeName,
BluetoothSignalObserver* aHandler)
BluetoothService::UnregisterBluetoothSignalHandler(
const nsAString& aNodeName,
BluetoothSignalObserver* aHandler)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aHandler);
BT_LOG("[S] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aNodeName).get());
BluetoothSignalObserverList* ol;
if (mBluetoothSignalObserverTable.Get(aNodeName, &ol)) {
ol->RemoveObserver(aHandler);
@ -551,38 +560,59 @@ BluetoothService::HandleSettingsChanged(const nsAString& aData)
return NS_OK;
}
// First, check if the string equals to BLUETOOTH_DEBUGGING_SETTING
JSBool match;
if (!JS_StringEqualsAscii(cx, key.toString(), BLUETOOTH_ENABLED_SETTING,
&match)) {
if (!JS_StringEqualsAscii(cx, key.toString(), BLUETOOTH_DEBUGGING_SETTING, &match)) {
MOZ_ASSERT(!JS_IsExceptionPending(cx));
return NS_ERROR_OUT_OF_MEMORY;
}
if (!match) {
if (match) {
JS::Value value;
if (!JS_GetProperty(cx, &obj, "value", &value)) {
MOZ_ASSERT(!JS_IsExceptionPending(cx));
return NS_ERROR_OUT_OF_MEMORY;
}
if (!value.isBoolean()) {
MOZ_ASSERT(false, "Expecting a boolean for 'bluetooth.debugging.enabled'!");
return NS_ERROR_UNEXPECTED;
}
SWITCH_BT_DEBUG(value.toBoolean());
return NS_OK;
}
JS::Value value;
if (!JS_GetProperty(cx, &obj, "value", &value)) {
// Second, check if the string is BLUETOOTH_ENABLED_SETTING
if (!JS_StringEqualsAscii(cx, key.toString(), BLUETOOTH_ENABLED_SETTING, &match)) {
MOZ_ASSERT(!JS_IsExceptionPending(cx));
return NS_ERROR_OUT_OF_MEMORY;
}
if (!value.isBoolean()) {
MOZ_ASSERT(false, "Expecting a boolean for 'bluetooth.enabled'!");
return NS_ERROR_UNEXPECTED;
if (match) {
JS::Value value;
if (!JS_GetProperty(cx, &obj, "value", &value)) {
MOZ_ASSERT(!JS_IsExceptionPending(cx));
return NS_ERROR_OUT_OF_MEMORY;
}
if (!value.isBoolean()) {
MOZ_ASSERT(false, "Expecting a boolean for 'bluetooth.enabled'!");
return NS_ERROR_UNEXPECTED;
}
if (gToggleInProgress || value.toBoolean() == IsEnabled()) {
// Nothing to do here.
return NS_OK;
}
gToggleInProgress = true;
nsresult rv = StartStopBluetooth(value.toBoolean());
NS_ENSURE_SUCCESS(rv, rv);
}
if (gToggleInProgress || value.toBoolean() == IsEnabled()) {
// Nothing to do here.
return NS_OK;
}
gToggleInProgress = true;
nsresult rv = StartStopBluetooth(value.toBoolean());
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
@ -726,7 +756,6 @@ BluetoothService::Observe(nsISupports* aSubject, const char* aTopic,
void
BluetoothService::Notify(const BluetoothSignal& aData)
{
InfallibleTArray<BluetoothNamedValue> arr(aData.value().get_ArrayOfBluetoothNamedValue());
nsString type;
JSContext* cx = nsContentUtils::GetSafeJSContext();
@ -740,29 +769,36 @@ BluetoothService::Notify(const BluetoothSignal& aData)
return;
}
bool ok = SetJsObject(cx, obj, arr);
if (!ok) {
if (!SetJsObject(cx, aData.value(), obj)) {
NS_WARNING("Failed to set properties of system message!");
return;
}
BT_LOG("[S] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
if (aData.name().EqualsLiteral("RequestConfirmation")) {
NS_ASSERTION(arr.Length() == 3, "RequestConfirmation: Wrong length of parameters");
NS_ASSERTION(aData.value().get_ArrayOfBluetoothNamedValue().Length() == 3,
"RequestConfirmation: Wrong length of parameters");
type.AssignLiteral("bluetooth-requestconfirmation");
} else if (aData.name().EqualsLiteral("RequestPinCode")) {
NS_ASSERTION(arr.Length() == 2, "RequestPinCode: Wrong length of parameters");
NS_ASSERTION(aData.value().get_ArrayOfBluetoothNamedValue().Length() == 2,
"RequestPinCode: Wrong length of parameters");
type.AssignLiteral("bluetooth-requestpincode");
} else if (aData.name().EqualsLiteral("RequestPasskey")) {
NS_ASSERTION(arr.Length() == 2, "RequestPinCode: Wrong length of parameters");
NS_ASSERTION(aData.value().get_ArrayOfBluetoothNamedValue().Length() == 2,
"RequestPinCode: Wrong length of parameters");
type.AssignLiteral("bluetooth-requestpasskey");
} else if (aData.name().EqualsLiteral("Authorize")) {
NS_ASSERTION(arr.Length() == 2, "Authorize: Wrong length of parameters");
NS_ASSERTION(aData.value().get_ArrayOfBluetoothNamedValue().Length() == 2,
"Authorize: Wrong length of parameters");
type.AssignLiteral("bluetooth-authorize");
} else if (aData.name().EqualsLiteral("Cancel")) {
NS_ASSERTION(arr.Length() == 0, "Cancel: Wrong length of parameters");
NS_ASSERTION(aData.value().get_ArrayOfBluetoothNamedValue().Length() == 0,
"Cancel: Wrong length of parameters");
type.AssignLiteral("bluetooth-cancel");
} else if (aData.name().EqualsLiteral("PairedStatusChanged")) {
NS_ASSERTION(arr.Length() == 1, "PairedStatusChagned: Wrong length of parameters");
NS_ASSERTION(aData.value().get_ArrayOfBluetoothNamedValue().Length() == 1,
"PairedStatusChagned: Wrong length of parameters");
type.AssignLiteral("bluetooth-pairedstatuschanged");
} else {
#ifdef DEBUG

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

@ -166,20 +166,6 @@ public:
BluetoothReplyRunnable* aRunnable) = 0;
/**
* Fetches the propertes for the specified object
*
* @param aType Type of the object (see BluetoothObjectType in BluetoothCommon.h)
* @param aPath Path of the object
* @param aRunnable Runnable to return to after receiving callback
*
* @return NS_OK on function run, NS_ERROR_FAILURE otherwise
*/
virtual nsresult
GetProperties(BluetoothObjectType aType,
const nsAString& aPath,
BluetoothReplyRunnable* aRunnable) = 0;
/**
* Fetches the propertes for the specified device
*
* @param aSignal BluetoothSignal to be distrubuted after retrieving device properties
@ -312,9 +298,6 @@ public:
protected:
BluetoothService()
: mEnabled(false)
#ifdef DEBUG
, mLastRequestedEnable(false)
#endif
{
mBluetoothSignalObserverTable.Init();
}
@ -403,10 +386,6 @@ protected:
BluetoothManagerList mLiveManagers;
bool mEnabled;
#ifdef DEBUG
bool mLastRequestedEnable;
#endif
};
END_BLUETOOTH_NAMESPACE

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

@ -35,15 +35,6 @@
#include "BluetoothUnixSocketConnector.h"
#include "nsThreadUtils.h"
#undef LOG
#if defined(MOZ_WIDGET_GONK)
#include <android/log.h>
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GonkDBus", args);
#else
#define BTDEBUG true
#define LOG(args...) if (BTDEBUG) printf(args);
#endif
USING_BLUETOOTH_NAMESPACE
static const int RFCOMM_SO_SNDBUF = 70 * 1024; // 70 KB send buffer

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

@ -12,42 +12,68 @@
#include "mozilla/Scoped.h"
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
#include "nsContentUtils.h"
#include "nsIScriptContext.h"
#include "nsISystemMessagesInternal.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsTArrayHelpers.h"
BEGIN_BLUETOOTH_NAMESPACE
bool
SetJsObject(JSContext* aContext,
JSObject* aObj,
const InfallibleTArray<BluetoothNamedValue>& aData)
const BluetoothValue& aValue,
JSObject* aObj)
{
for (uint32_t i = 0; i < aData.Length(); i++) {
jsval v;
if (aData[i].value().type() == BluetoothValue::TnsString) {
nsString data = aData[i].value().get_nsString();
JSString* JsData = JS_NewUCStringCopyN(aContext,
data.BeginReading(),
data.Length());
NS_ENSURE_TRUE(JsData, false);
v = STRING_TO_JSVAL(JsData);
} else if (aData[i].value().type() == BluetoothValue::Tuint32_t) {
int data = aData[i].value().get_uint32_t();
v = INT_TO_JSVAL(data);
} else if (aData[i].value().type() == BluetoothValue::Tbool) {
bool data = aData[i].value().get_bool();
v = BOOLEAN_TO_JSVAL(data);
} else {
NS_WARNING("SetJsObject: Parameter is not handled");
}
MOZ_ASSERT(aContext && aObj);
if (!JS_SetProperty(aContext, aObj,
NS_ConvertUTF16toUTF8(aData[i].name()).get(),
&v)) {
if (aValue.type() == BluetoothValue::TArrayOfnsString) {
const nsTArray<nsString>& sourceArray = aValue.get_ArrayOfnsString();
if (NS_FAILED(nsTArrayToJSArray(aContext, sourceArray, &aObj))) {
NS_WARNING("Cannot set JS UUIDs object!");
return false;
}
} else if (aValue.type() == BluetoothValue::TArrayOfBluetoothNamedValue) {
const nsTArray<BluetoothNamedValue>& arr =
aValue.get_ArrayOfBluetoothNamedValue();
for (uint32_t i = 0; i < arr.Length(); i++) {
jsval val;
const BluetoothValue& v = arr[i].value();
JSString* JsData;
switch(v.type()) {
case BluetoothValue::TnsString:
JsData =
JS_NewStringCopyN(aContext,
NS_ConvertUTF16toUTF8(v.get_nsString()).get(),
v.get_nsString().Length());
NS_ENSURE_TRUE(JsData, NS_ERROR_FAILURE);
val = STRING_TO_JSVAL(JsData);
break;
case BluetoothValue::Tuint32_t:
val = INT_TO_JSVAL(v.get_uint32_t());
break;
case BluetoothValue::Tbool:
val = BOOLEAN_TO_JSVAL(v.get_bool());
break;
default:
NS_WARNING("SetJsObject: Parameter is not handled");
break;
}
if (!JS_SetProperty(aContext, aObj,
NS_ConvertUTF16toUTF8(arr[i].name()).get(),
&val)) {
NS_WARNING("Failed to set property");
return NS_ERROR_FAILURE;
}
}
} else {
NS_WARNING("Not handle the type of BluetoothValue!");
return false;
}
return true;
}
@ -97,18 +123,14 @@ BroadcastSystemMessage(const nsAString& aType,
return false;
}
if (!SetJsObject(cx, obj, aData)) {
if (!SetJsObject(cx, aData, obj)) {
NS_WARNING("Failed to set properties of system message!");
return false;
}
nsCOMPtr<nsISystemMessagesInternal> systemMessenger =
do_GetService("@mozilla.org/system-message-internal;1");
if (!systemMessenger) {
NS_WARNING("Failed to get SystemMessenger service!");
return false;
}
NS_ENSURE_TRUE(systemMessenger, false);
systemMessenger->BroadcastMessage(aType, OBJECT_TO_JSVAL(obj));

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

@ -8,7 +8,6 @@
#define mozilla_dom_bluetooth_bluetoothutils_h__
#include "BluetoothCommon.h"
#include "nsTArray.h"
struct JSContext;
class JSObject;
@ -21,8 +20,8 @@ class BluetoothReplyRunnable;
bool
SetJsObject(JSContext* aContext,
JSObject* aObj,
const InfallibleTArray<BluetoothNamedValue>& aData);
const BluetoothValue& aValue,
JSObject* aObj);
nsString
GetObjectPathFromAddress(const nsAString& aAdapterPath,

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

@ -44,7 +44,6 @@ CPPSRCS += \
BluetoothManager.cpp \
BluetoothAdapter.cpp \
BluetoothDevice.cpp \
BluetoothPropertyEvent.cpp \
BluetoothReplyRunnable.cpp \
BluetoothPropertyContainer.cpp \
BluetoothUtils.cpp \
@ -70,7 +69,6 @@ XPIDLSRCS = \
nsIDOMBluetoothDevice.idl \
nsIDOMBluetoothDeviceEvent.idl \
nsIDOMBluetoothDeviceAddressEvent.idl \
nsIDOMBluetoothPropertyEvent.idl \
$(NULL)
ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))

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

@ -189,8 +189,6 @@ BluetoothParent::RecvPBluetoothRequestConstructor(
return actor->DoRequest(aRequest.get_DefaultAdapterPathRequest());
case Request::TSetPropertyRequest:
return actor->DoRequest(aRequest.get_SetPropertyRequest());
case Request::TGetPropertyRequest:
return actor->DoRequest(aRequest.get_GetPropertyRequest());
case Request::TStartDiscoveryRequest:
return actor->DoRequest(aRequest.get_StartDiscoveryRequest());
case Request::TStopDiscoveryRequest:
@ -318,20 +316,6 @@ BluetoothRequestParent::DoRequest(const SetPropertyRequest& aRequest)
return true;
}
bool
BluetoothRequestParent::DoRequest(const GetPropertyRequest& aRequest)
{
MOZ_ASSERT(mService);
MOZ_ASSERT(mRequestType == Request::TGetPropertyRequest);
nsresult rv =
mService->GetProperties(aRequest.type(), aRequest.path(),
mReplyRunnable.get());
NS_ENSURE_SUCCESS(rv, false);
return true;
}
bool
BluetoothRequestParent::DoRequest(const StartDiscoveryRequest& aRequest)
{

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

@ -140,15 +140,6 @@ BluetoothServiceChildProcess::StartDiscoveryInternal(
return NS_OK;
}
nsresult
BluetoothServiceChildProcess::GetProperties(BluetoothObjectType aType,
const nsAString& aPath,
BluetoothReplyRunnable* aRunnable)
{
SendRequest(aRunnable, GetPropertyRequest(aType, nsString(aPath)));
return NS_OK;
}
nsresult
BluetoothServiceChildProcess::SetProperty(BluetoothObjectType aType,
const nsAString& aPath,

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

@ -59,11 +59,6 @@ public:
StartDiscoveryInternal(const nsAString& aAdapterPath,
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
virtual nsresult
GetProperties(BluetoothObjectType aType,
const nsAString& aPath,
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
virtual nsresult
SetProperty(BluetoothObjectType aType,
const nsAString& aPath,

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

@ -59,15 +59,6 @@ using namespace mozilla;
using namespace mozilla::ipc;
USING_BLUETOOTH_NAMESPACE
#undef LOG
#if defined(MOZ_WIDGET_GONK)
#include <android/log.h>
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GonkDBus", args);
#else
#define BTDEBUG true
#define LOG(args...) if (BTDEBUG) printf(args);
#endif
#define B2G_AGENT_CAPABILITIES "DisplayYesNo"
#define DBUS_MANAGER_IFACE BLUEZ_DBUS_BASE_IFC ".Manager"
#define DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter"
@ -309,10 +300,7 @@ public:
// Get device properties and then send to BluetoothAdapter
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
NS_WARNING("BluetoothService not available!");
return NS_ERROR_FAILURE;
}
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
// Due to the fact that we need to queue the dbus call to the command thread
// inside the bluetoothservice, we have to route the call down to the main
@ -365,6 +353,8 @@ static void
UnpackIntMessage(DBusMessage* aMsg, DBusError* aErr,
BluetoothValue& aValue, nsAString& aErrorStr)
{
MOZ_ASSERT(aMsg);
DBusError err;
dbus_error_init(&err);
if (!IsDBusMessageError(aMsg, aErr, aErrorStr)) {
@ -420,13 +410,17 @@ static DBusHandlerResult
AgentEventFilter(DBusConnection *conn, DBusMessage *msg, void *data)
{
if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_METHOD_CALL) {
LOG("%s: agent handler not interested (not a method call).\n", __FUNCTION__);
BT_WARNING("%s: agent handler not interested (not a method call).\n", __FUNCTION__);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
DBusError err;
dbus_error_init(&err);
BT_LOG("%s: %s, %s", __FUNCTION__,
dbus_message_get_path(msg),
dbus_message_get_member(msg));
nsString signalPath = NS_ConvertUTF8toUTF16(dbus_message_get_path(msg));
nsString signalName = NS_ConvertUTF8toUTF16(dbus_message_get_member(msg));
nsString errorStr;
@ -460,7 +454,7 @@ AgentEventFilter(DBusConnection *conn, DBusMessage *msg, void *data)
DBUS_TYPE_OBJECT_PATH, &objectPath,
DBUS_TYPE_STRING, &uuid,
DBUS_TYPE_INVALID)) {
LOG("%s: Invalid arguments for Authorize() method", __FUNCTION__);
BT_WARNING("%s: Invalid arguments for Authorize() method", __FUNCTION__);
errorStr.AssignLiteral("Invalid arguments for Authorize() method");
} else {
nsString deviceAddress =
@ -492,11 +486,12 @@ AgentEventFilter(DBusConnection *conn, DBusMessage *msg, void *data)
DBUS_TYPE_OBJECT_PATH, &objectPath,
DBUS_TYPE_UINT32, &passkey,
DBUS_TYPE_INVALID)) {
LOG("%s: Invalid arguments for RequestConfirmation() method", __FUNCTION__);
BT_WARNING("%s: Invalid arguments for RequestConfirmation() method",
__FUNCTION__);
errorStr.AssignLiteral("Invalid arguments for RequestConfirmation() method");
} else {
parameters.AppendElement(BluetoothNamedValue(
NS_LITERAL_STRING("address"),
NS_LITERAL_STRING("path"),
NS_ConvertUTF8toUTF16(objectPath)));
parameters.AppendElement(BluetoothNamedValue(
NS_LITERAL_STRING("passkey"),
@ -524,11 +519,12 @@ AgentEventFilter(DBusConnection *conn, DBusMessage *msg, void *data)
if (!dbus_message_get_args(msg, NULL,
DBUS_TYPE_OBJECT_PATH, &objectPath,
DBUS_TYPE_INVALID)) {
LOG("%s: Invalid arguments for RequestPinCode() method", __FUNCTION__);
BT_WARNING("%s: Invalid arguments for RequestPinCode() method",
__FUNCTION__);
errorStr.AssignLiteral("Invalid arguments for RequestPinCode() method");
} else {
parameters.AppendElement(BluetoothNamedValue(
NS_LITERAL_STRING("address"),
NS_LITERAL_STRING("path"),
NS_ConvertUTF8toUTF16(objectPath)));
KeepDBusPairingMessage(GetAddressFromObjectPath(
@ -552,11 +548,12 @@ AgentEventFilter(DBusConnection *conn, DBusMessage *msg, void *data)
if (!dbus_message_get_args(msg, NULL,
DBUS_TYPE_OBJECT_PATH, &objectPath,
DBUS_TYPE_INVALID)) {
LOG("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__);
BT_WARNING("%s: Invalid arguments for RequestPasskey() method",
__FUNCTION__);
errorStr.AssignLiteral("Invalid arguments for RequestPasskey() method");
} else {
parameters.AppendElement(BluetoothNamedValue(
NS_LITERAL_STRING("address"),
NS_LITERAL_STRING("path"),
NS_ConvertUTF8toUTF16(objectPath)));
KeepDBusPairingMessage(GetAddressFromObjectPath(
@ -590,7 +587,7 @@ AgentEventFilter(DBusConnection *conn, DBusMessage *msg, void *data)
}
} else {
#ifdef DEBUG
LOG("agent handler %s: Unhandled event. Ignore.", __FUNCTION__);
BT_WARNING("agent handler %s: Unhandled event. Ignore.", __FUNCTION__);
#endif
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
@ -631,7 +628,7 @@ RegisterLocalAgent(const char* adapterPath,
agentPath,
&agentVtable,
NULL)) {
LOG("%s: Can't register object path %s for agent!",
BT_WARNING("%s: Can't register object path %s for agent!",
__FUNCTION__, agentPath);
return false;
}
@ -640,7 +637,7 @@ RegisterLocalAgent(const char* adapterPath,
dbus_message_new_method_call("org.bluez", adapterPath,
DBUS_ADAPTER_IFACE, "RegisterAgent");
if (!msg) {
LOG("%s: Can't allocate new method call for agent!", __FUNCTION__);
BT_WARNING("%s: Can't allocate new method call for agent!", __FUNCTION__);
return false;
}
@ -648,7 +645,7 @@ RegisterLocalAgent(const char* adapterPath,
DBUS_TYPE_OBJECT_PATH, &agentPath,
DBUS_TYPE_STRING, &capabilities,
DBUS_TYPE_INVALID)) {
LOG("%s: Couldn't append arguments to dbus message.", __FUNCTION__);
BT_WARNING("%s: Couldn't append arguments to dbus message.", __FUNCTION__);
return false;
}
@ -665,11 +662,11 @@ RegisterLocalAgent(const char* adapterPath,
if (!strcmp(err.name, "org.bluez.Error.AlreadyExists")) {
LOG_AND_FREE_DBUS_ERROR(&err);
#ifdef DEBUG
LOG("Agent already registered, still returning true");
BT_WARNING("Agent already registered, still returning true");
#endif
} else {
LOG_AND_FREE_DBUS_ERROR(&err);
LOG("%s: Can't register agent!", __FUNCTION__);
BT_WARNING("%s: Can't register agent!", __FUNCTION__);
return false;
}
}
@ -699,7 +696,7 @@ RegisterAgent(const nsAString& aAdapterPath)
REMOTE_AGENT_PATH,
&agentVtable,
NULL)) {
LOG("%s: Can't register object path %s for remote device agent!",
BT_WARNING("%s: Can't register object path %s for remote device agent!",
__FUNCTION__, REMOTE_AGENT_PATH);
return false;
@ -721,7 +718,7 @@ ExtractHandles(DBusMessage *aReply, nsTArray<uint32_t>& aOutHandles)
DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &handles, &len,
DBUS_TYPE_INVALID)) {
if (!handles) {
LOG("Null array in extract_handles");
BT_WARNING("Null array in extract_handles");
} else {
for (int i = 0; i < len; ++i) {
aOutHandles.AppendElement(handles[i]);
@ -775,7 +772,7 @@ BluetoothDBusService::AddReservedServicesInternal(const nsAString& aAdapterPath,
&services, length, DBUS_TYPE_INVALID);
if (!reply) {
LOG("Null DBus message. Couldn't extract handles.");
BT_WARNING("Null DBus message. Couldn't extract handles.");
return false;
}
@ -1307,21 +1304,27 @@ EventFilter(DBusConnection* aConn, DBusMessage* aMsg, void* aData)
NS_ASSERTION(!NS_IsMainThread(), "Shouldn't be called from Main Thread!");
if (dbus_message_get_type(aMsg) != DBUS_MESSAGE_TYPE_SIGNAL) {
LOG("%s: event handler not interested in %s (not a signal).\n",
BT_WARNING("%s: event handler not interested in %s (not a signal).\n",
__FUNCTION__, dbus_message_get_member(aMsg));
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
if (dbus_message_get_path(aMsg) == NULL) {
LOG("DBusMessage %s has no bluetooth destination, ignoring\n",
BT_WARNING("DBusMessage %s has no bluetooth destination, ignoring\n",
dbus_message_get_member(aMsg));
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
DBusError err;
dbus_error_init(&err);
nsString signalPath;
nsString signalName;
dbus_error_init(&err);
BT_LOG("%s: %s, %s", __FUNCTION__,
dbus_message_get_path(aMsg),
dbus_message_get_member(aMsg));
signalPath = NS_ConvertUTF8toUTF16(dbus_message_get_path(aMsg));
signalName = NS_ConvertUTF8toUTF16(dbus_message_get_member(aMsg));
nsString errorStr;
@ -1635,13 +1638,13 @@ BluetoothDBusService::StopInternal()
if (!dbus_connection_unregister_object_path(gThreadConnection->GetConnection(),
LOCAL_AGENT_PATH)) {
LOG("%s: Can't unregister object path %s for agent!",
BT_WARNING("%s: Can't unregister object path %s for agent!",
__FUNCTION__, LOCAL_AGENT_PATH);
}
if (!dbus_connection_unregister_object_path(gThreadConnection->GetConnection(),
REMOTE_AGENT_PATH)) {
LOG("%s: Can't unregister object path %s for agent!",
BT_WARNING("%s: Can't unregister object path %s for agent!",
__FUNCTION__, LOCAL_AGENT_PATH);
}
@ -1779,68 +1782,54 @@ public:
MOZ_ASSERT(NS_IsMainThread());
}
~BluetoothDevicePropertiesRunnable()
{
}
NS_IMETHOD Run()
{
MOZ_ASSERT(!NS_IsMainThread());
nsString devicePath;
BluetoothValue v = mSignal.value();
if (v.type() == BluetoothValue::TArrayOfBluetoothNamedValue &&
v.get_ArrayOfBluetoothNamedValue().Length() ) {
const InfallibleTArray<BluetoothNamedValue>& arr = v.get_ArrayOfBluetoothNamedValue();
NS_ASSERTION(arr[0].value().type() == BluetoothValue::TnsString, "failed to get_nsString");
devicePath = arr[0].value().get_nsString();
}
else if (v.type() == BluetoothValue::TnsString) {
devicePath = v.get_nsString();
}
else {
if (v.type() != BluetoothValue::TArrayOfBluetoothNamedValue ||
v.get_ArrayOfBluetoothNamedValue().Length() == 0) {
NS_WARNING("Invalid value type for GetDeviceProperties() method");
return NS_ERROR_FAILURE;
}
const InfallibleTArray<BluetoothNamedValue>& arr =
v.get_ArrayOfBluetoothNamedValue();
NS_ASSERTION(arr[0].name().EqualsLiteral("path"), "failed to get object path");
NS_ASSERTION(arr[0].value().type() == BluetoothValue::TnsString,
"failed to get_nsString");
devicePath = arr[0].value().get_nsString();
BluetoothValue prop;
if (!GetPropertiesInternal(devicePath, DBUS_DEVICE_IFACE, prop)) {
NS_WARNING("Getting properties failed!");
return NS_ERROR_FAILURE;
}
InfallibleTArray<BluetoothNamedValue> properties(prop.get_ArrayOfBluetoothNamedValue());
if (v.type() == BluetoothValue::TArrayOfBluetoothNamedValue) {
// Return original dbus message parameters and also device name
// for agent events "RequestConfirmation", "RequestPinCode", and "RequestPasskey"
InfallibleTArray<BluetoothNamedValue> parameters(v.get_ArrayOfBluetoothNamedValue());
InfallibleTArray<BluetoothNamedValue>& properties =
prop.get_ArrayOfBluetoothNamedValue();
// For consistency, append path
nsString path = parameters[0].value();
BluetoothNamedValue pathprop;
pathprop.name().AssignLiteral("Path");
pathprop.value() = path;
parameters.AppendElement(pathprop);
// Return original dbus message parameters and also device name
// for agent events "RequestConfirmation", "RequestPinCode", and "RequestPasskey"
InfallibleTArray<BluetoothNamedValue>& parameters =
v.get_ArrayOfBluetoothNamedValue();
// Replace object path with device address
nsString address = GetAddressFromObjectPath(path);
parameters[0].value() = address;
// Replace object path with device address
nsString address = GetAddressFromObjectPath(devicePath);
parameters[0].name().AssignLiteral("address");
parameters[0].value() = address;
uint8_t i;
for (i = 0; i < properties.Length(); i++) {
// Append device name
if (properties[i].name().EqualsLiteral("Name")) {
properties[i].name().AssignLiteral("name");
parameters.AppendElement(properties[i]);
mSignal.value() = parameters;
break;
}
uint8_t i;
for (i = 0; i < properties.Length(); i++) {
// Append device name
if (properties[i].name().EqualsLiteral("Name")) {
properties[i].name().AssignLiteral("name");
parameters.AppendElement(properties[i]);
mSignal.value() = parameters;
break;
}
NS_ASSERTION(i != properties.Length(), "failed to get device name");
} else {
// Return all device properties for event "DeviceCreated", including device path
properties.AppendElement(BluetoothNamedValue(NS_LITERAL_STRING("Path"), mSignal.value()));
mSignal.value() = properties;
}
NS_ASSERTION(i != properties.Length(), "failed to get device name");
nsRefPtr<DistributeBluetoothSignalTask> t =
new DistributeBluetoothSignalTask(mSignal);
@ -1921,36 +1910,6 @@ private:
nsTArray<nsString> mDeviceAddresses;
};
nsresult
BluetoothDBusService::GetProperties(BluetoothObjectType aType,
const nsAString& aPath,
BluetoothReplyRunnable* aRunnable)
{
NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
MOZ_ASSERT(aType < ArrayLength(sBluetoothDBusIfaces));
MOZ_ASSERT(aType < ArrayLength(sBluetoothDBusPropCallbacks));
const char* interface = sBluetoothDBusIfaces[aType];
DBusCallback callback = sBluetoothDBusPropCallbacks[aType];
nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
if (!dbus_func_args_async(mConnection,
1000,
callback,
(void*)aRunnable,
NS_ConvertUTF16toUTF8(aPath).get(),
interface,
"GetProperties",
DBUS_TYPE_INVALID)) {
NS_WARNING("Could not start async function!");
return NS_ERROR_FAILURE;
}
runnable.forget();
return NS_OK;
}
nsresult
BluetoothDBusService::GetDevicePropertiesInternal(const BluetoothSignal& aSignal)
{
@ -2229,7 +2188,7 @@ BluetoothDBusService::SetPinCodeInternal(const nsAString& aDeviceAddress,
BluetoothValue v = true;
DBusMessage *msg;
if (!sPairingReqTable.Get(aDeviceAddress, &msg)) {
LOG("%s: Couldn't get original request message.", __FUNCTION__);
BT_WARNING("%s: Couldn't get original request message.", __FUNCTION__);
errorStr.AssignLiteral("Couldn't get original request message.");
DispatchBluetoothReply(aRunnable, v, errorStr);
return false;
@ -2238,7 +2197,7 @@ BluetoothDBusService::SetPinCodeInternal(const nsAString& aDeviceAddress,
DBusMessage *reply = dbus_message_new_method_return(msg);
if (!reply) {
LOG("%s: Memory can't be allocated for the message.", __FUNCTION__);
BT_WARNING("%s: Memory can't be allocated for the message.", __FUNCTION__);
dbus_message_unref(msg);
errorStr.AssignLiteral("Memory can't be allocated for the message.");
DispatchBluetoothReply(aRunnable, v, errorStr);
@ -2253,7 +2212,7 @@ BluetoothDBusService::SetPinCodeInternal(const nsAString& aDeviceAddress,
if (!dbus_message_append_args(reply,
DBUS_TYPE_STRING, &pinCode,
DBUS_TYPE_INVALID)) {
LOG("%s: Couldn't append arguments to dbus message.", __FUNCTION__);
BT_WARNING("%s: Couldn't append arguments to dbus message.", __FUNCTION__);
errorStr.AssignLiteral("Couldn't append arguments to dbus message.");
result = false;
} else {
@ -2277,7 +2236,7 @@ BluetoothDBusService::SetPasskeyInternal(const nsAString& aDeviceAddress,
BluetoothValue v = true;
DBusMessage *msg;
if (!sPairingReqTable.Get(aDeviceAddress, &msg)) {
LOG("%s: Couldn't get original request message.", __FUNCTION__);
BT_WARNING("%s: Couldn't get original request message.", __FUNCTION__);
errorStr.AssignLiteral("Couldn't get original request message.");
DispatchBluetoothReply(aRunnable, v, errorStr);
return false;
@ -2286,7 +2245,7 @@ BluetoothDBusService::SetPasskeyInternal(const nsAString& aDeviceAddress,
DBusMessage *reply = dbus_message_new_method_return(msg);
if (!reply) {
LOG("%s: Memory can't be allocated for the message.", __FUNCTION__);
BT_WARNING("%s: Memory can't be allocated for the message.", __FUNCTION__);
dbus_message_unref(msg);
errorStr.AssignLiteral("Memory can't be allocated for the message.");
DispatchBluetoothReply(aRunnable, v, errorStr);
@ -2299,7 +2258,7 @@ BluetoothDBusService::SetPasskeyInternal(const nsAString& aDeviceAddress,
if (!dbus_message_append_args(reply,
DBUS_TYPE_UINT32, &passkey,
DBUS_TYPE_INVALID)) {
LOG("%s: Couldn't append arguments to dbus message.", __FUNCTION__);
BT_WARNING("%s: Couldn't append arguments to dbus message.", __FUNCTION__);
errorStr.AssignLiteral("Couldn't append arguments to dbus message.");
result = false;
} else {
@ -2323,7 +2282,7 @@ BluetoothDBusService::SetPairingConfirmationInternal(const nsAString& aDeviceAdd
BluetoothValue v = true;
DBusMessage *msg;
if (!sPairingReqTable.Get(aDeviceAddress, &msg)) {
LOG("%s: Couldn't get original request message.", __FUNCTION__);
BT_WARNING("%s: Couldn't get original request message.", __FUNCTION__);
errorStr.AssignLiteral("Couldn't get original request message.");
DispatchBluetoothReply(aRunnable, v, errorStr);
return false;
@ -2339,7 +2298,7 @@ BluetoothDBusService::SetPairingConfirmationInternal(const nsAString& aDeviceAdd
}
if (!reply) {
LOG("%s: Memory can't be allocated for the message.", __FUNCTION__);
BT_WARNING("%s: Memory can't be allocated for the message.", __FUNCTION__);
dbus_message_unref(msg);
errorStr.AssignLiteral("Memory can't be allocated for the message.");
DispatchBluetoothReply(aRunnable, v, errorStr);
@ -2368,7 +2327,7 @@ BluetoothDBusService::SetAuthorizationInternal(const nsAString& aDeviceAddress,
DBusMessage *msg;
if (!sAuthorizeReqTable.Get(aDeviceAddress, &msg)) {
LOG("%s: Couldn't get original request message.", __FUNCTION__);
BT_WARNING("%s: Couldn't get original request message.", __FUNCTION__);
errorStr.AssignLiteral("Couldn't get original request message.");
DispatchBluetoothReply(aRunnable, v, errorStr);
return false;
@ -2384,7 +2343,7 @@ BluetoothDBusService::SetAuthorizationInternal(const nsAString& aDeviceAddress,
}
if (!reply) {
LOG("%s: Memory can't be allocated for the message.", __FUNCTION__);
BT_WARNING("%s: Memory can't be allocated for the message.", __FUNCTION__);
dbus_message_unref(msg);
errorStr.AssignLiteral("Memory can't be allocated for the message.");
DispatchBluetoothReply(aRunnable, v, errorStr);

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

@ -41,11 +41,6 @@ public:
virtual nsresult StopDiscoveryInternal(const nsAString& aAdapterPath,
BluetoothReplyRunnable* aRunnable);
virtual nsresult
GetProperties(BluetoothObjectType aType,
const nsAString& aPath,
BluetoothReplyRunnable* aRunnable);
virtual nsresult
GetDevicePropertiesInternal(const BluetoothSignal& aSignal);

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

@ -1,274 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#include "BluetoothUtils.h"
#include <cstdio>
#include <dbus/dbus.h>
#include "nsAutoPtr.h"
#include "nsThreadUtils.h"
#include "nsDebug.h"
#include "nsClassHashtable.h"
#include "mozilla/ipc/DBusUtils.h"
#include "mozilla/ipc/RawDBusConnection.h"
using namespace mozilla::ipc;
namespace mozilla {
namespace dom {
namespace bluetooth {
static nsAutoPtr<RawDBusConnection> sDBusConnection;
#undef LOG
#if defined(MOZ_WIDGET_GONK)
#include <android/log.h>
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GonkDBus", args);
#else
#define BTDEBUG true
#define LOG(args...) if (BTDEBUG) printf(args);
#endif
#define DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter"
#define DBUS_DEVICE_IFACE BLUEZ_DBUS_BASE_IFC ".Device"
#define BLUEZ_DBUS_BASE_PATH "/org/bluez"
#define BLUEZ_DBUS_BASE_IFC "org.bluez"
#define BLUEZ_ERROR_IFC "org.bluez.Error"
static const char* BLUETOOTH_DBUS_SIGNALS[] =
{
"type='signal',interface='org.freedesktop.DBus'",
"type='signal',interface='org.bluez.Adapter'",
"type='signal',interface='org.bluez.Manager'",
"type='signal',interface='org.bluez.Device'",
"type='signal',interface='org.bluez.Input'",
"type='signal',interface='org.bluez.Network'",
"type='signal',interface='org.bluez.NetworkServer'",
"type='signal',interface='org.bluez.HealthDevice'",
"type='signal',interface='org.bluez.AudioSink'"
};
typedef nsClassHashtable<nsCStringHashKey, BluetoothEventObserverList >
BluetoothEventObserverTable;
static nsAutoPtr<BluetoothEventObserverTable> sBluetoothEventObserverTable;
nsresult
RegisterBluetoothEventHandler(const nsCString& aNodeName,
BluetoothEventObserver* aHandler)
{
MOZ_ASSERT(NS_IsMainThread());
BluetoothEventObserverList *ol;
NS_ENSURE_TRUE(sBluetoothEventObserverTable, NS_ERROR_FAILURE);
if (!sBluetoothEventObserverTable->Get(aNodeName, &ol)) {
sBluetoothEventObserverTable->Put(aNodeName,
new BluetoothEventObserverList());
}
sBluetoothEventObserverTable->Get(aNodeName, &ol);
ol->AddObserver(aHandler);
return NS_OK;
}
nsresult
UnregisterBluetoothEventHandler(const nsCString& aNodeName,
BluetoothEventObserver* aHandler)
{
MOZ_ASSERT(NS_IsMainThread());
BluetoothEventObserverList *ol;
NS_ENSURE_TRUE(sBluetoothEventObserverTable, NS_ERROR_FAILURE);
if (!sBluetoothEventObserverTable->Get(aNodeName, &ol)) {
NS_WARNING("Node does not exist to remove BluetoothEventListener from!");
return NS_ERROR_FAILURE;
}
sBluetoothEventObserverTable->Get(aNodeName, &ol);
ol->RemoveObserver(aHandler);
if (ol->Length() == 0) {
sBluetoothEventObserverTable->Remove(aNodeName);
}
return NS_OK;
}
struct DistributeDBusMessageTask : public nsRunnable {
DistributeDBusMessageTask(DBusMessage* aMsg) : mMsg(aMsg)
{
}
NS_IMETHOD Run()
{
if (dbus_message_get_path(mMsg.get()) == NULL) {
return NS_OK;
}
MOZ_ASSERT(NS_IsMainThread());
// Notify observers that a message has been sent
nsDependentCString path(dbus_message_get_path(mMsg.get()));
nsDependentCString member(dbus_message_get_member(mMsg.get()));
BluetoothEventObserverList *ol;
if (!sBluetoothEventObserverTable->Get(path, &ol)) {
LOG("No objects registered for %s, returning\n",
dbus_message_get_path(mMsg.get()));
return NS_OK;
}
BluetoothEvent e;
e.mEventName = member;
ol->Broadcast(e);
return NS_OK;
}
DBusMessageRefPtr mMsg;
};
// Called by dbus during WaitForAndDispatchEventNative()
// This function is called on the IOThread
static DBusHandlerResult
EventFilter(DBusConnection *aConn, DBusMessage *aMsg,
void *aData)
{
DBusError err;
dbus_error_init(&err);
if (dbus_message_get_type(aMsg) != DBUS_MESSAGE_TYPE_SIGNAL) {
LOG("%s: not interested (not a signal).\n", __FUNCTION__);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
LOG("%s: Received signal %s:%s from %s\n", __FUNCTION__,
dbus_message_get_interface(aMsg), dbus_message_get_member(aMsg),
dbus_message_get_path(aMsg));
// TODO: Parse DBusMessage* on the IOThread and return as a BluetoothEvent so
// we aren't passing the pointer at all, as well as offloading parsing (not
// that it's that heavy.)
nsCOMPtr<DistributeDBusMessageTask> t(new DistributeDBusMessageTask(aMsg));
if (NS_FAILED(NS_DispatchToMainThread(t))) {
NS_WARNING("Failed to dispatch to main thread!");
}
return DBUS_HANDLER_RESULT_HANDLED;
}
nsresult
StartBluetoothConnection()
{
if (sDBusConnection) {
NS_WARNING("DBusConnection already established, skipping");
return NS_OK;
}
sBluetoothEventObserverTable = new BluetoothEventObserverTable();
sBluetoothEventObserverTable->Init(100);
sDBusConnection = new RawDBusConnection();
sDBusConnection->EstablishDBusConnection();
// Add a filter for all incoming messages_base
if (!dbus_connection_add_filter(sDBusConnection->mConnection, EventFilter,
NULL, NULL)) {
NS_WARNING("Cannot create DBus Event Filter for DBus Thread!");
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
StopBluetoothConnection()
{
if (!sDBusConnection) {
NS_WARNING("DBusConnection does not exist, nothing to stop, skipping.");
return NS_OK;
}
dbus_connection_remove_filter(sDBusConnection->mConnection, EventFilter, NULL);
sDBusConnection = NULL;
sBluetoothEventObserverTable->Clear();
sBluetoothEventObserverTable = NULL;
return NS_OK;
}
nsresult
GetDefaultAdapterPathInternal(nsCString& aAdapterPath)
{
DBusMessage *msg = NULL, *reply = NULL;
DBusError err;
const char *device_path = NULL;
int attempt = 0;
for (attempt = 0; attempt < 1000 && reply == NULL; attempt ++) {
msg = dbus_message_new_method_call("org.bluez", "/",
"org.bluez.Manager", "DefaultAdapter");
if (!msg) {
LOG("%s: Can't allocate new method call for get_adapter_path!",
__FUNCTION__);
return NS_ERROR_FAILURE;
}
dbus_message_append_args(msg, DBUS_TYPE_INVALID);
dbus_error_init(&err);
reply = dbus_connection_send_with_reply_and_block(
sDBusConnection->mConnection, msg, -1, &err);
if (!reply) {
if (dbus_error_is_set(&err)) {
if (dbus_error_has_name(&err,
"org.freedesktop.DBus.Error.ServiceUnknown")) {
// bluetoothd is still down, retry
LOG("Service unknown\n");
dbus_error_free(&err);
//usleep(10000); // 10 ms
continue;
} else if (dbus_error_has_name(&err,
"org.bluez.Error.NoSuchAdapter")) {
LOG("No adapter found\n");
dbus_error_free(&err);
goto failed;
} else {
// Some other error we weren't expecting
LOG("other error\n");
dbus_error_free(&err);
}
}
}
}
if (attempt == 1000) {
LOG("timeout\n");
//printfE("Time out while trying to get Adapter path, is bluetoothd up ?");
goto failed;
}
if (!dbus_message_get_args(reply, &err, DBUS_TYPE_OBJECT_PATH,
&device_path, DBUS_TYPE_INVALID)
|| !device_path) {
if (dbus_error_is_set(&err)) {
dbus_error_free(&err);
}
goto failed;
}
dbus_message_unref(msg);
aAdapterPath = nsDependentCString(device_path);
return NS_OK;
failed:
dbus_message_unref(msg);
return NS_ERROR_FAILURE;
}
}
}
}

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

@ -1,13 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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 "nsIDOMEvent.idl"
[scriptable, builtinclass, uuid(ce268e66-2d1a-491a-833c-fb27dc50dc46)]
interface nsIDOMBluetoothPropertyEvent : nsIDOMEvent
{
readonly attribute DOMString property;
};

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

@ -186,7 +186,7 @@ interface nsIDOMEventTarget : nsISupports
raises(DOMException);
/**
* Returns the nsPIDOMEventTarget object which should be used as the target
* Returns the nsIDOMEventTarget object which should be used as the target
* of DOMEvents.
* Usually |this| is returned, but for example global object returns
* the outer object.
@ -194,7 +194,7 @@ interface nsIDOMEventTarget : nsISupports
[notxpcom, nostdcall] nsIDOMEventTarget GetTargetForDOMEvent();
/**
* Returns the nsPIDOMEventTarget object which should be used as the target
* Returns the nsIDOMEventTarget object which should be used as the target
* of the event and when constructing event target chain.
* Usually |this| is returned, but for example global object returns
* the inner object.
@ -286,11 +286,9 @@ interface nsIDOMEventTarget : nsISupports
%{C++
typedef nsIDOMEventTarget nsPIDOMEventTarget;
#define NS_IMPL_DOMTARGET_DEFAULTS(_class) \
nsPIDOMEventTarget* _class::GetTargetForDOMEvent() { return this; } \
nsPIDOMEventTarget* _class::GetTargetForEventTargetChain() { return this; } \
nsIDOMEventTarget* _class::GetTargetForDOMEvent() { return this; } \
nsIDOMEventTarget* _class::GetTargetForEventTargetChain() { return this; } \
nsresult _class::WillHandleEvent(nsEventChainPostVisitor& aVisitor) { return NS_OK; } \
JSContext* _class::GetJSContextForEventHandlers() { return nullptr; }

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

@ -85,9 +85,12 @@ TabParent::TabParent(const TabContext& aContext)
, mIMECompositionStart(0)
, mIMESeqno(0)
, mEventCaptureDepth(0)
, mRect(0, 0, 0, 0)
, mDimensions(0, 0)
, mOrientation(0)
, mDPI(0)
, mShown(false)
, mUpdatedDimensions(false)
, mMarkedDestroying(false)
, mIsDestroyed(false)
{
@ -265,12 +268,20 @@ TabParent::UpdateDimensions(const nsRect& rect, const nsIntSize& size)
}
hal::ScreenConfiguration config;
hal::GetCurrentScreenConfiguration(&config);
ScreenOrientation orientation = config.orientation();
unused << SendUpdateDimensions(rect, size, config.orientation());
if (RenderFrameParent* rfp = GetRenderFrame()) {
rfp->NotifyDimensionsChanged(size.width, size.height);
if (!mUpdatedDimensions || mOrientation != orientation ||
mDimensions != size || !mRect.IsEqualEdges(rect)) {
mUpdatedDimensions = true;
mRect = rect;
mDimensions = size;
mOrientation = orientation;
unused << SendUpdateDimensions(mRect, mDimensions, mOrientation);
if (RenderFrameParent* rfp = GetRenderFrame()) {
rfp->NotifyDimensionsChanged(mDimensions.width, mDimensions.height);
}
}
mDimensions = size;
}
void

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

@ -276,9 +276,12 @@ protected:
// The number of event series we're currently capturing.
int32_t mEventCaptureDepth;
nsRect mRect;
nsIntSize mDimensions;
ScreenOrientation mOrientation;
float mDPI;
bool mShown;
bool mUpdatedDimensions;
private:
already_AddRefed<nsFrameLoader> GetFrameLoader() const;

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

@ -764,8 +764,9 @@ SmsDatabaseService.prototype = {
saveSendingMessage: function saveSendingMessage(
aReceiver, aBody, aDeliveryStatus, aDate, aCallback) {
let sender = this.mRIL.rilContext.icc
? this.mRIL.rilContext.icc.msisdn
let rilContext = this.mRIL.rilContext;
let sender = rilContext.icc
? rilContext.icc.msisdn
: null;
// Workaround an xpconnect issue with undefined string objects.
@ -775,18 +776,21 @@ SmsDatabaseService.prototype = {
}
let receiver = aReceiver;
if (receiver) {
let parsedNumber = PhoneNumberUtils.parse(receiver.toString());
receiver = (parsedNumber && parsedNumber.internationalNumber)
? parsedNumber.internationalNumber
: receiver;
}
if (sender) {
let parsedNumber = PhoneNumberUtils.parse(sender.toString());
sender = (parsedNumber && parsedNumber.internationalNumber)
? parsedNumber.internationalNumber
: sender;
if (rilContext.voice.network.mcc === rilContext.icc.mcc) {
if (receiver) {
let parsedNumber = PhoneNumberUtils.parse(receiver.toString());
receiver = (parsedNumber && parsedNumber.internationalNumber)
? parsedNumber.internationalNumber
: receiver;
}
if (sender) {
let parsedNumber = PhoneNumberUtils.parse(sender.toString());
sender = (parsedNumber && parsedNumber.internationalNumber)
? parsedNumber.internationalNumber
: sender;
}
}
let message = {

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

@ -101,12 +101,12 @@ nsVolume::LogState() const
{
if (mState == nsIVolume::STATE_MOUNTED) {
LOG("nsVolume: %s state %s @ '%s' gen %d locked %d",
NameStr(), StateStr(), MountPointStr(),
NameStr().get(), StateStr(), MountPointStr().get(),
MountGeneration(), (int)IsMountLocked());
return;
}
LOG("nsVolume: %s state %s", NameStr(), StateStr());
LOG("nsVolume: %s state %s", NameStr().get(), StateStr());
}
void nsVolume::Set(const nsVolume* aVolume)

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

@ -60,13 +60,13 @@ public:
void LogState() const;
const nsString& Name() const { return mName; }
const char* NameStr() const { return NS_LossyConvertUTF16toASCII(mName).get(); }
nsCString NameStr() const { return NS_LossyConvertUTF16toASCII(mName); }
int32_t MountGeneration() const { return mMountGeneration; }
bool IsMountLocked() const { return mMountLocked; }
const nsString& MountPoint() const { return mMountPoint; }
const char* MountPointStr() const { return NS_LossyConvertUTF16toASCII(mMountPoint).get(); }
nsCString MountPointStr() const { return NS_LossyConvertUTF16toASCII(mMountPoint); }
int32_t State() const { return mState; }
const char* StateStr() const { return NS_VolumeStateStr(mState); }

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

@ -129,7 +129,7 @@ NS_IMETHODIMP nsVolumeService::BroadcastVolume(const nsAString& aVolName)
nsCOMPtr<nsIObserverService> obs = GetObserverService();
NS_ENSURE_TRUE(obs, NS_NOINTERFACE);
DBG("nsVolumeService::BroadcastVolume for '%s'", vol->NameStr());
DBG("nsVolumeService::BroadcastVolume for '%s'", vol->NameStr().get());
nsString stateStr(NS_ConvertUTF8toUTF16(vol->StateStr()));
obs->NotifyObservers(vol, NS_VOLUME_STATE_CHANGED, stateStr.get());
return NS_OK;
@ -291,8 +291,8 @@ public:
{
MOZ_ASSERT(NS_IsMainThread());
DBG("UpdateVolumeRunnable::Run '%s' state %s gen %d locked %d",
mVolume->NameStr(), mVolume->StateStr(), mVolume->MountGeneration(),
(int)mVolume->IsMountLocked());
mVolume->NameStr().get(), mVolume->StateStr(),
mVolume->MountGeneration(), (int)mVolume->IsMountLocked());
mVolumeService->UpdateVolume(mVolume);
mVolumeService = NULL;

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

@ -60,6 +60,11 @@
value="This button is much longer than the others">
</p></div>
<div id="overflow-visible" style="width:100px; height:100px;">
<div id="overflow-visible-1" style="width:200px; height:1px; background:yellow;"></div>
<div id="overflow-visible-2" style="height:200px; background:lime;"></div>
</div>
<input id="input-displaynone" style="display: none; border: 0; padding: 0;"
_offsetParent="null">
<p id="p3" style="margin: 2px; border: 0; padding: 1px;"

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

@ -60,6 +60,7 @@ function testElement(element)
offsetParent, element.id);
var scrollWidth, scrollHeight, clientWidth, clientHeight;
var doScrollCheck = true;
if (element.id == "scrollbox") {
var lastchild = $("lastline");
scrollWidth = lastchild.getBoundingClientRect().width + paddingLeft + paddingRight;
@ -69,18 +70,29 @@ function testElement(element)
scrollHeight = contentsHeight + paddingTop + paddingBottom;
clientWidth = paddingLeft + width + paddingRight - scrollbarWidth;
clientHeight = paddingTop + height + paddingBottom - scrollbarHeight;
}
else {
scrollWidth = paddingLeft + width + paddingRight;
scrollHeight = paddingTop + height + paddingBottom;
} else {
clientWidth = paddingLeft + width + paddingRight;
clientHeight = paddingTop + height + paddingBottom;
if (element.id == "overflow-visible") {
scrollWidth = 200;
scrollHeight = 201;
} else if (element.scrollWidth > clientWidth ||
element.scrollHeight > clientHeight) {
// The element overflows. Don't check scrollWidth/scrollHeight since the
// above calculation is not correct.
doScrollCheck = false;
} else {
scrollWidth = clientWidth;
scrollHeight = clientHeight;
}
}
if (element instanceof SVGElement)
checkScrollState(element, 0, 0, 0, 0, element.id);
else
checkScrollState(element, 0, 0, scrollWidth, scrollHeight, element.id);
if (doScrollCheck) {
if (element instanceof SVGElement)
checkScrollState(element, 0, 0, 0, 0, element.id);
else
checkScrollState(element, 0, 0, scrollWidth, scrollHeight, element.id);
}
if (element instanceof SVGElement)
checkClientState(element, 0, 0, 0, 0, element.id);

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

@ -1822,7 +1822,7 @@ public:
#endif
#ifdef MOZ_WIDGET_GONK
if (gUseBackingSurface) {
if (gUseBackingSurface && aSize.width >= 64) {
mGLContext->MakeCurrent(true);
PixelFormat format = PixelFormatForImage(mUpdateFormat);
uint32_t usage = GraphicBuffer::USAGE_HW_TEXTURE |

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

@ -13,9 +13,7 @@ MODULE = gl
LIBRARY_NAME = gl
LIBXUL_LIBRARY = 1
EXPORT_LIBRARY = 1
ifndef _MSC_VER
FAIL_ON_WARNINGS = 1
endif # !_MSC_VER
EXPORTS = \
GLDefs.h \

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

@ -294,6 +294,13 @@ ShadowLayerForwarder::PlatformAllocBuffer(const gfxIntSize& aSize,
uint32_t aCaps,
SurfaceDescriptor* aBuffer)
{
// Some GL implementations fail to render gralloc textures with
// width < 64. There's not much point in gralloc'ing buffers that
// small anyway, so fall back on shared memory plus a texture
// upload.
if (aSize.width < 64) {
return false;
}
SAMPLE_LABEL("ShadowLayerForwarder", "PlatformAllocBuffer");
// Gralloc buffers are efficiently mappable as gfxImageSurface, so
// no need to check |aCaps & MAP_AS_IMAGE_SURFACE|.

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

@ -14,6 +14,10 @@ LIBRARY_NAME = thebes
LIBXUL_LIBRARY = 1
EXPORT_LIBRARY = 1
ifndef _MSC_VER
FAIL_ON_WARNINGS = 1
endif # !_MSC_VER
EXPORTS = \
gfx2DGlue.h \
gfx3DMatrix.h \

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

@ -1012,83 +1012,6 @@ CopySwapUTF16(const uint16_t *aInBuf, uint16_t *aOutBuf, uint32_t aLen)
}
}
static bool
ValidateKernTable(const uint8_t *aKernTable, uint32_t aKernLength)
{
// -- kern table can cause crashes if invalid, so do some basic sanity-checking
const KernTableVersion0 *kernTable0 = reinterpret_cast<const KernTableVersion0*>(aKernTable);
if (aKernLength < sizeof(KernTableVersion0)) {
return false;
}
if (uint16_t(kernTable0->version) == 0) {
if (aKernLength < sizeof(KernTableVersion0) +
uint16_t(kernTable0->nTables) * sizeof(KernTableSubtableHeaderVersion0)) {
return false;
}
// at least the table is big enough to contain the subtable headers;
// we could go further and check the actual subtable sizes....
// for now, assume this is OK
return true;
}
const KernTableVersion1 *kernTable1 = reinterpret_cast<const KernTableVersion1*>(aKernTable);
if (aKernLength < sizeof(KernTableVersion1)) {
return false;
}
if (kernTable1->version == 0x00010000) {
if (aKernLength < sizeof(KernTableVersion1) +
kernTable1->nTables * sizeof(KernTableSubtableHeaderVersion1)) {
return false;
}
// at least the table is big enough to contain the subtable headers;
// we could go further and check the actual subtable sizes....
// for now, assume this is OK
return true;
}
// neither the old Windows version nor the newer Apple one; refuse to use it
return false;
}
static bool
ValidateLocaTable(const uint8_t* aLocaTable, uint32_t aLocaLen,
uint32_t aGlyfLen, int16_t aLocaFormat, uint16_t aNumGlyphs)
{
if (aLocaFormat == 0) {
if (aLocaLen < uint32_t(aNumGlyphs + 1) * sizeof(uint16_t)) {
return false;
}
const AutoSwap_PRUint16 *p =
reinterpret_cast<const AutoSwap_PRUint16*>(aLocaTable);
uint32_t prev = 0;
for (uint32_t i = 0; i <= aNumGlyphs; ++i) {
uint32_t current = uint16_t(*p++) * 2;
if (current < prev || current > aGlyfLen) {
return false;
}
prev = current;
}
return true;
}
if (aLocaFormat == 1) {
if (aLocaLen < (aNumGlyphs + 1) * sizeof(uint32_t)) {
return false;
}
const AutoSwap_PRUint32 *p =
reinterpret_cast<const AutoSwap_PRUint32*>(aLocaTable);
uint32_t prev = 0;
for (uint32_t i = 0; i <= aNumGlyphs; ++i) {
uint32_t current = *p++;
if (current < prev || current > aGlyfLen) {
return false;
}
prev = current;
}
return true;
}
return false;
}
gfxUserFontType
gfxFontUtils::DetermineFontDataType(const uint8_t *aFontData, uint32_t aFontDataLength)
{

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

@ -12,6 +12,7 @@ include $(DEPTH)/config/autoconf.mk
MODULE = imgicon
LIBRARY_NAME = imgiconandroid_s
LIBXUL_LIBRARY = 1
FAIL_ON_WARNINGS := 1
CPPSRCS = nsIconChannel.cpp

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

@ -41,7 +41,7 @@ const size_t CellSize = size_t(1) << CellShift;
const size_t CellMask = CellSize - 1;
/* These are magic constants derived from actual offsets in gc/Heap.h. */
const size_t ChunkMarkBitmapOffset = 1032376;
const size_t ChunkMarkBitmapOffset = 1032368;
const size_t ChunkMarkBitmapBits = 129024;
/*

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

@ -406,6 +406,9 @@ class Vector : private AllocPolicy
/* Clears and releases any heap-allocated storage. */
void clearAndFree();
/* If true, appending |needed| elements will not call realloc(). */
bool canAppendWithoutRealloc(size_t needed) const;
/*
* Potentially fallible append operations.
*
@ -772,6 +775,13 @@ Vector<T,N,AP>::clearAndFree()
#endif
}
template <class T, size_t N, class AP>
inline bool
Vector<T,N,AP>::canAppendWithoutRealloc(size_t needed) const
{
return mLength + needed <= mCapacity;
}
template <class T, size_t N, class AP>
template <class U>
JS_ALWAYS_INLINE bool

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

@ -12,10 +12,12 @@
#include "jsapi.h"
#include "jsatom.h"
#include "jscntxt.h"
#include "jsinterp.h"
#include "jsobj.h"
#include "builtin/Intl.h"
#include "vm/GlobalObject.h"
#include "vm/Stack.h"
#include "jsobjinlines.h"
@ -27,8 +29,23 @@ static bool
IntlInitialize(JSContext *cx, HandleObject obj, Handle<PropertyName*> initializer,
HandleValue locales, HandleValue options)
{
// ??? stub - initializer to be implemented as self-hosted function
return true;
RootedValue initializerValue(cx);
if (!cx->global()->getIntrinsicValue(cx, initializer, &initializerValue))
return false;
JS_ASSERT(initializerValue.isObject());
JS_ASSERT(initializerValue.toObject().isFunction());
InvokeArgsGuard args;
if (!cx->stack.pushInvokeArgs(cx, 3, &args))
return false;
args.setCallee(initializerValue);
args.setThis(NullValue());
args[0] = ObjectValue(*obj);
args[1] = locales;
args[2] = options;
return Invoke(cx, args);
}
/******************** Collator ********************/
@ -55,10 +72,12 @@ collator_toSource(JSContext *cx, unsigned argc, Value *vp)
#endif
static JSFunctionSpec collator_static_methods[] = {
{"supportedLocalesOf", JSOP_NULLWRAPPER, 1, JSFunction::INTERPRETED, "Intl_Collator_supportedLocalesOf"},
JS_FS_END
};
static JSFunctionSpec collator_methods[] = {
{"resolvedOptions", JSOP_NULLWRAPPER, 0, JSFunction::INTERPRETED, "Intl_Collator_resolvedOptions"},
#if JS_HAS_TOSOURCE
JS_FN(js_toSource_str, collator_toSource, 0, 0),
#endif
@ -139,6 +158,21 @@ InitCollatorClass(JSContext *cx, HandleObject Intl, Handle<GlobalObject*> global
if (!JS_DefineFunctions(cx, proto, collator_methods))
return NULL;
/*
* Install the getter for Collator.prototype.compare, which returns a bound
* comparison function for the specified Collator object (suitable for
* passing to methods like Array.prototype.sort).
*/
RootedValue getter(cx);
if (!cx->global()->getIntrinsicValue(cx, cx->names().CollatorCompare, &getter))
return NULL;
RootedValue undefinedValue(cx, UndefinedValue());
if (!JSObject::defineProperty(cx, proto, cx->names().compare, undefinedValue,
JS_DATA_TO_FUNC_PTR(JSPropertyOp, &getter.toObject()),
NULL, JSPROP_GETTER)) {
return NULL;
}
// 10.2.1 and 10.3
RootedValue locales(cx, UndefinedValue());
RootedValue options(cx, UndefinedValue());
@ -190,10 +224,12 @@ numberFormat_toSource(JSContext *cx, unsigned argc, Value *vp)
#endif
static JSFunctionSpec numberFormat_static_methods[] = {
{"supportedLocalesOf", JSOP_NULLWRAPPER, 1, JSFunction::INTERPRETED, "Intl_NumberFormat_supportedLocalesOf"},
JS_FS_END
};
static JSFunctionSpec numberFormat_methods[] = {
{"resolvedOptions", JSOP_NULLWRAPPER, 0, JSFunction::INTERPRETED, "Intl_NumberFormat_resolvedOptions"},
#if JS_HAS_TOSOURCE
JS_FN(js_toSource_str, numberFormat_toSource, 0, 0),
#endif
@ -274,6 +310,21 @@ InitNumberFormatClass(JSContext *cx, HandleObject Intl, Handle<GlobalObject*> gl
if (!JS_DefineFunctions(cx, proto, numberFormat_methods))
return NULL;
/*
* Install the getter for NumberFormat.prototype.format, which returns a
* bound formatting function for the specified NumberFormat object (suitable
* for passing to methods like Array.prototype.map).
*/
RootedValue getter(cx);
if (!cx->global()->getIntrinsicValue(cx, cx->names().NumberFormatFormat, &getter))
return NULL;
RootedValue undefinedValue(cx, UndefinedValue());
if (!JSObject::defineProperty(cx, proto, cx->names().format, undefinedValue,
JS_DATA_TO_FUNC_PTR(JSPropertyOp, &getter.toObject()),
NULL, JSPROP_GETTER)) {
return NULL;
}
// 11.2.1 and 11.3
RootedValue locales(cx, UndefinedValue());
RootedValue options(cx, UndefinedValue());
@ -325,10 +376,12 @@ dateTimeFormat_toSource(JSContext *cx, unsigned argc, Value *vp)
#endif
static JSFunctionSpec dateTimeFormat_static_methods[] = {
{"supportedLocalesOf", JSOP_NULLWRAPPER, 1, JSFunction::INTERPRETED, "Intl_DateTimeFormat_supportedLocalesOf"},
JS_FS_END
};
static JSFunctionSpec dateTimeFormat_methods[] = {
{"resolvedOptions", JSOP_NULLWRAPPER, 0, JSFunction::INTERPRETED, "Intl_DateTimeFormat_resolvedOptions"},
#if JS_HAS_TOSOURCE
JS_FN(js_toSource_str, dateTimeFormat_toSource, 0, 0),
#endif
@ -409,6 +462,21 @@ InitDateTimeFormatClass(JSContext *cx, HandleObject Intl, Handle<GlobalObject*>
if (!JS_DefineFunctions(cx, proto, dateTimeFormat_methods))
return NULL;
/*
* Install the getter for DateTimeFormat.prototype.format, which returns a
* bound formatting function for the specified DateTimeFormat object
* (suitable for passing to methods like Array.prototype.map).
*/
RootedValue getter(cx);
if (!cx->global()->getIntrinsicValue(cx, cx->names().DateTimeFormatFormat, &getter))
return NULL;
RootedValue undefinedValue(cx, UndefinedValue());
if (!JSObject::defineProperty(cx, proto, cx->names().format, undefinedValue,
JS_DATA_TO_FUNC_PTR(JSPropertyOp, &getter.toObject()),
NULL, JSPROP_GETTER)) {
return NULL;
}
// 12.2.1 and 12.3
RootedValue locales(cx, UndefinedValue());
RootedValue options(cx, UndefinedValue());
@ -493,12 +561,17 @@ js_InitIntlClass(JSContext *cx, HandleObject obj)
if (!JS_DefineFunctions(cx, Intl, intl_static_methods))
return NULL;
if (!InitCollatorClass(cx, Intl, global))
return NULL;
if (!InitNumberFormatClass(cx, Intl, global))
return NULL;
if (!InitDateTimeFormatClass(cx, Intl, global))
return NULL;
// Skip initialization of the Intl constructors during initialization of the
// self-hosting global as we may get here before self-hosted code is compiled,
// and no core code refers to the Intl classes.
if (!cx->runtime->isSelfHostingGlobal(cx->global())) {
if (!InitCollatorClass(cx, Intl, global))
return NULL;
if (!InitNumberFormatClass(cx, Intl, global))
return NULL;
if (!InitDateTimeFormatClass(cx, Intl, global))
return NULL;
}
MarkStandardClassInitializedNoProto(global, &IntlClass);
@ -508,7 +581,9 @@ js_InitIntlClass(JSContext *cx, HandleObject obj)
bool
GlobalObject::initIntlObject(JSContext *cx, Handle<GlobalObject*> global)
{
RootedObject Intl(cx, NewObjectWithClassProto(cx, &IntlClass, NULL, global));
RootedObject Intl(cx);
Intl = NewObjectWithGivenProto(cx, &IntlClass,
global->getOrCreateObjectPrototype(cx), global);
if (!Intl || !JSObject::setSingletonType(cx, Intl))
return false;

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

@ -5396,10 +5396,15 @@ EmitCallOrNew(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
* will just cause the inner scripts to be repeatedly cloned.
*/
JS_ASSERT(!bce->emittingRunOnceLambda);
bce->emittingRunOnceLambda = true;
if (!EmitTree(cx, bce, pn2))
return false;
bce->emittingRunOnceLambda = false;
if (bce->checkSingletonContext()) {
bce->emittingRunOnceLambda = true;
if (!EmitTree(cx, bce, pn2))
return false;
bce->emittingRunOnceLambda = false;
} else {
if (!EmitTree(cx, bce, pn2))
return false;
}
callop = false;
break;
default:

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

@ -85,6 +85,7 @@ struct Cell
MOZ_ALWAYS_INLINE bool markIfUnmarked(uint32_t color = BLACK) const;
MOZ_ALWAYS_INLINE void unmark(uint32_t color) const;
inline JSRuntime *runtime() const;
inline JSCompartment *compartment() const;
inline Zone *zone() const;
@ -593,7 +594,7 @@ struct ChunkInfo
* Calculating sizes and offsets is simpler if sizeof(ChunkInfo) is
* architecture-independent.
*/
char padding[12];
char padding[16];
#endif
/*
@ -611,6 +612,9 @@ struct ChunkInfo
/* Number of GC cycles this chunk has survived. */
uint32_t age;
/* This is findable from any address in the Chunk by aligning to 1MiB. */
JSRuntime *runtime;
};
/*
@ -947,6 +951,12 @@ Cell::chunk() const
return reinterpret_cast<Chunk *>(addr);
}
inline JSRuntime *
Cell::runtime() const
{
return chunk()->info.runtime;
}
AllocKind
Cell::getAllocKind() const
{

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

@ -55,10 +55,10 @@ EdgeCaseAnalysis::AllUsesTruncate(MInstruction *m)
int ret = 1;
for (MUseIterator use = m->usesBegin(); use != m->usesEnd(); use++) {
// See #809485 why this is allowed
if (use->node()->isResumePoint())
if (use->consumer()->isResumePoint())
continue;
MDefinition *def = use->node()->toDefinition();
MDefinition *def = use->consumer()->toDefinition();
if (def->isTruncateToInt32())
continue;
if (def->isBitAnd())

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

@ -103,11 +103,11 @@ ion::EliminateDeadResumePointOperands(MIRGenerator *mir, MIRGraph &graph)
// Walk the uses a second time, removing any in resume points after
// the last use in a definition.
for (MUseIterator uses(ins->usesBegin()); uses != ins->usesEnd(); ) {
if (uses->node()->isDefinition()) {
if (uses->consumer()->isDefinition()) {
uses++;
continue;
}
MResumePoint *mrp = uses->node()->toResumePoint();
MResumePoint *mrp = uses->consumer()->toResumePoint();
if (mrp->block() != *block ||
!mrp->instruction() ||
mrp->instruction() == *ins ||
@ -188,8 +188,8 @@ IsPhiObservable(MPhi *phi, Observability observe)
case ConservativeObservability:
for (MUseIterator iter(phi->usesBegin()); iter != phi->usesEnd(); iter++) {
if (!iter->node()->isDefinition() ||
!iter->node()->toDefinition()->isPhi())
if (!iter->consumer()->isDefinition() ||
!iter->consumer()->toDefinition()->isPhi())
return true;
}
break;
@ -879,16 +879,30 @@ CheckPredecessorImpliesSuccessor(MBasicBlock *A, MBasicBlock *B)
}
static bool
CheckMarkedAsUse(MInstruction *ins, MDefinition *operand)
CheckOperandImpliesUse(MInstruction *ins, MDefinition *operand)
{
for (MUseIterator i = operand->usesBegin(); i != operand->usesEnd(); i++) {
if (i->node()->isDefinition()) {
if (ins == i->node()->toDefinition())
return true;
}
if (i->consumer()->isDefinition() && i->consumer()->toDefinition() == ins)
return true;
}
return false;
}
static bool
CheckUseImpliesOperand(MInstruction *ins, MUse *use)
{
MNode *consumer = use->consumer();
uint32_t index = use->index();
if (consumer->isDefinition()) {
MDefinition *def = consumer->toDefinition();
return (def->getOperand(index) == ins);
}
JS_ASSERT(consumer->isResumePoint());
MResumePoint *res = consumer->toResumePoint();
return (res->getOperand(index) == ins);
}
#endif // DEBUG
#ifdef DEBUG
@ -926,9 +940,14 @@ ion::AssertGraphCoherency(MIRGraph &graph)
for (size_t i = 0; i < block->numPredecessors(); i++)
JS_ASSERT(CheckPredecessorImpliesSuccessor(*block, block->getPredecessor(i)));
// Assert that use chains are valid for this instruction.
for (MInstructionIterator ins = block->begin(); ins != block->end(); ins++) {
for (uint32_t i = 0; i < ins->numOperands(); i++)
JS_ASSERT(CheckMarkedAsUse(*ins, ins->getOperand(i)));
JS_ASSERT(CheckOperandImpliesUse(*ins, ins->getOperand(i)));
}
for (MInstructionIterator ins = block->begin(); ins != block->end(); ins++) {
for (MUseIterator i(ins->usesBegin()); i != ins->usesEnd(); i++)
JS_ASSERT(CheckUseImpliesOperand(*ins, *i));
}
}

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

@ -2957,14 +2957,16 @@ IonBuilder::patchInlinedReturns(CallInfo &callInfo, MIRGraphExits &exits, MBasic
// would have been returned.
JS_ASSERT(exits.length() > 0);
MPhi *retDef = NULL;
// In the case of a single return, no phi is necessary.
MPhi *phi = NULL;
if (exits.length() > 1) {
retDef = MPhi::New(bottom->stackDepth());
bottom->addPhi(retDef);
phi = MPhi::New(bottom->stackDepth());
phi->initLength(exits.length());
bottom->addPhi(phi);
}
for (MBasicBlock **it = exits.begin(), **end = exits.end(); it != end; ++it) {
MBasicBlock *exitBlock = *it;
for (size_t i = 0; i < exits.length(); i++) {
MBasicBlock *exitBlock = exits[i];
MDefinition *rval = exitBlock->lastIns()->toReturn()->getOperand(0);
exitBlock->discardLastIns();
@ -2988,10 +2990,10 @@ IonBuilder::patchInlinedReturns(CallInfo &callInfo, MIRGraphExits &exits, MBasic
if (exits.length() == 1)
return rval;
retDef->addInput(rval);
phi->setOperand(i, rval);
}
return retDef;
return phi;
}
bool
@ -3529,11 +3531,16 @@ IonBuilder::inlineScriptedCalls(AutoObjectVector &targets, AutoObjectVector &ori
MPhi *phi = MPhi::New(inlineBottom->stackDepth() - callInfo.argc() - 2);
inlineBottom->addPhi(phi);
if (!phi->initLength(retvalDefns.length()))
return false;
size_t index = 0;
MDefinition **it = retvalDefns.begin(), **end = retvalDefns.end();
for (; it != end; ++it) {
if (!phi->addInput(*it))
return false;
}
for (; it != end; it++, index++)
phi->setOperand(index, *it);
JS_ASSERT(index == retvalDefns.length());
// retvalDefns should become a singleton vector of 'phi'
retvalDefns.clear();
if (!retvalDefns.append(phi))
@ -3578,10 +3585,16 @@ IonBuilder::inlineScriptedCalls(AutoObjectVector &targets, AutoObjectVector &ori
MPhi *phi = MPhi::New(bottom->stackDepth());
bottom->addPhi(phi);
for (MDefinition **it = retvalDefns.begin(), **end = retvalDefns.end(); it != end; ++it) {
if (!phi->addInput(*it))
return false;
}
if (!phi->initLength(retvalDefns.length()))
return false;
size_t index = 0;
MDefinition **it = retvalDefns.begin(), **end = retvalDefns.end();
for (; it != end; it++, index++)
phi->setOperand(index, *it);
JS_ASSERT(index == retvalDefns.length());
retvalDefn = phi;
} else {
retvalDefn = retvalDefns.back();
@ -4216,10 +4229,13 @@ IonBuilder::makeCallHelper(HandleFunction target, CallInfo &callInfo,
return NULL;
}
MPassArg *newThis = MPassArg::New(create);
// Unwrap the MPassArg before discarding: it may have been captured by an MResumePoint.
thisArg->replaceAllUsesWith(thisArg->getArgument());
thisArg->block()->discard(thisArg);
MPassArg *newThis = MPassArg::New(create);
current->add(newThis);
thisArg = newThis;
}

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

@ -551,7 +551,7 @@ CanEmitCompareAtUses(MInstruction *ins)
bool foundTest = false;
for (MUseIterator iter(ins->usesBegin()); iter != ins->usesEnd(); iter++) {
MNode *node = iter->node();
MNode *node = iter->consumer();
if (!node->isDefinition())
return false;
if (!node->toDefinition()->isTest())

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

@ -248,43 +248,70 @@ MDefinition::removeUse(MUseIterator use)
}
MUseIterator
MNode::replaceOperand(MUseIterator use, MDefinition *ins)
MNode::replaceOperand(MUseIterator use, MDefinition *def)
{
MDefinition *used = getOperand(use->index());
if (used == ins)
JS_ASSERT(def != NULL);
uint32_t index = use->index();
MDefinition *prev = use->producer();
JS_ASSERT(use->index() < numOperands());
JS_ASSERT(use->producer() == getOperand(index));
JS_ASSERT(use->consumer() == this);
if (prev == def)
return use;
MUse *save = *use;
MUseIterator result(used->removeUse(use));
if (ins) {
setOperand(save->index(), ins);
ins->linkUse(save);
}
MUseIterator result(prev->removeUse(use));
setOperand(index, def);
return result;
}
void
MNode::replaceOperand(size_t index, MDefinition *def)
{
MDefinition *d = getOperand(index);
for (MUseIterator i(d->usesBegin()); i != d->usesEnd(); i++) {
if (i->index() == index && i->node() == this) {
replaceOperand(i, def);
return;
}
}
JS_ASSERT(def != NULL);
MUse *use = getUseFor(index);
MDefinition *prev = use->producer();
JS_NOT_REACHED("could not find use");
JS_ASSERT(use->index() == index);
JS_ASSERT(use->index() < numOperands());
JS_ASSERT(use->producer() == getOperand(index));
JS_ASSERT(use->consumer() == this);
if (prev == def)
return;
prev->removeUse(use);
setOperand(index, def);
}
void
MNode::discardOperand(size_t index)
{
MUse *use = getUseFor(index);
JS_ASSERT(use->index() == index);
JS_ASSERT(use->producer() == getOperand(index));
JS_ASSERT(use->consumer() == this);
use->producer()->removeUse(use);
#ifdef DEBUG
// Causes any producer/consumer lookups to trip asserts.
use->set(NULL, NULL, index);
#endif
}
void
MDefinition::replaceAllUsesWith(MDefinition *dom)
{
for (MUseIterator i(uses_.begin()); i != uses_.end(); ) {
MUse *use = *i;
i = uses_.removeAt(i);
use->node()->setOperand(use->index(), dom);
dom->linkUse(use);
JS_ASSERT(dom != NULL);
if (dom == this)
return;
for (MUseIterator i(usesBegin()); i != usesEnd(); ) {
JS_ASSERT(i->producer() == this);
i = i->consumer()->replaceOperand(i, dom);
}
}
@ -474,18 +501,27 @@ MPhi::New(uint32_t slot)
void
MPhi::removeOperand(size_t index)
{
MUse *use = getUseFor(index);
JS_ASSERT(index < inputs_.length());
JS_ASSERT(inputs_.length() > 1);
JS_ASSERT(use->index() == index);
JS_ASSERT(use->producer() == getOperand(index));
JS_ASSERT(use->consumer() == this);
// Remove use from producer's use chain.
use->producer()->removeUse(use);
// If we have phi(..., a, b, c, d, ..., z) and we plan
// on removing a, then first shift downward so that we have
// phi(..., b, c, d, ..., z, z):
size_t length = inputs_.length();
for (size_t i = index + 1; i < length; i++)
replaceOperand(i - 1, getOperand(i));
// remove the final operand that now appears twice:
replaceOperand(length - 1, NULL);
for (size_t i = index; i < length - 1; i++) {
MUse *next = MPhi::getUseFor(i + 1);
next->producer()->removeUse(next);
MPhi::setOperand(i, next->producer());
}
// truncate the inputs_ list:
inputs_.shrinkBy(1);
@ -523,17 +559,56 @@ MPhi::congruentTo(MDefinition *const &ins) const
}
bool
MPhi::addInput(MDefinition *ins)
MPhi::initLength(size_t length)
{
ins->addUse(this, inputs_.length());
return inputs_.append(ins);
// Initializes a new MPhi to have an Operand vector of at least the given
// length. This permits use of setOperand() instead of addInputSlow(), the
// latter of which may call realloc().
JS_ASSERT(numOperands() == 0);
return inputs_.resizeUninitialized(length);
}
bool
MPhi::addInputSlow(MDefinition *ins)
{
// The list of inputs to an MPhi is given as a vector of MUse nodes,
// each of which is in the list of the producer MDefinition.
// Because appending to a vector may reallocate the vector, it is possible
// that this operation may cause the producers' linked lists to reference
// invalid memory. Therefore, in the event of moving reallocation, each
// MUse must be removed and reinserted from/into its producer's use chain.
uint32_t index = inputs_.length();
bool performingRealloc = !inputs_.canAppendWithoutRealloc(1);
// Remove all MUses from all use lists, in case realloc() moves.
if (performingRealloc) {
for (uint32_t i = 0; i < index; i++) {
MUse *use = &inputs_[i];
use->producer()->removeUse(use);
}
}
// Insert the new input.
if (!inputs_.append(MUse()))
return false;
MPhi::setOperand(index, ins);
// Add all previously-removed MUses back.
if (performingRealloc) {
for (uint32_t i = 0; i < index; i++) {
MUse *use = &inputs_[i];
use->producer()->addUse(use);
}
}
return true;
}
uint32_t
MPrepareCall::argc() const
{
JS_ASSERT(useCount() == 1);
MCall *call = usesBegin()->node()->toDefinition()->toCall();
MCall *call = usesBegin()->consumer()->toDefinition()->toCall();
return call->numStackArgs();
}
@ -555,7 +630,7 @@ MCall::addArg(size_t argnum, MPassArg *arg)
// The operand vector is initialized in reverse order by the IonBuilder.
// It cannot be checked for consistency until all arguments are added.
arg->setArgnum(argnum);
MNode::initOperand(argnum + NumNonArgumentOperands, arg->toDefinition());
setOperand(argnum + NumNonArgumentOperands, arg->toDefinition());
}
void
@ -647,10 +722,10 @@ NeedNegativeZeroCheck(MDefinition *def)
{
// Test if all uses have the same semantics for -0 and 0
for (MUseIterator use = def->usesBegin(); use != def->usesEnd(); use++) {
if (use->node()->isResumePoint())
if (use->consumer()->isResumePoint())
continue;
MDefinition *use_def = use->node()->toDefinition();
MDefinition *use_def = use->consumer()->toDefinition();
switch (use_def->op()) {
case MDefinition::Op_Add: {
// If add is truncating -0 and 0 are observed as the same.
@ -1427,7 +1502,7 @@ MResumePoint *
MResumePoint::New(MBasicBlock *block, jsbytecode *pc, MResumePoint *parent, Mode mode)
{
MResumePoint *resume = new MResumePoint(block, pc, parent, mode);
if (!resume->init(block))
if (!resume->init())
return NULL;
resume->inherit(block);
return resume;
@ -1444,15 +1519,6 @@ MResumePoint::MResumePoint(MBasicBlock *block, jsbytecode *pc, MResumePoint *cal
{
}
bool
MResumePoint::init(MBasicBlock *block)
{
operands_ = block->graph().allocate<MDefinition *>(stackDepth());
if (!operands_)
return false;
return true;
}
void
MResumePoint::inherit(MBasicBlock *block)
{
@ -1462,7 +1528,7 @@ MResumePoint::inherit(MBasicBlock *block)
// and LStackArg does not define a value.
if (def->isPassArg())
def = def->toPassArg()->getArgument();
initOperand(i, def);
setOperand(i, def);
}
}

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

@ -67,32 +67,51 @@ class MResumePoint;
static inline bool isOSRLikeValue (MDefinition *def);
// Represents a use of a node.
class MUse : public TempObject, public InlineForwardListNode<MUse>
class MUse : public TempObject, public InlineListNode<MUse>
{
friend class MDefinition;
MNode *node_; // The node that is using this operand.
uint32_t index_; // The index of this operand in its owner.
MDefinition *producer_; // MDefinition that is being used.
MNode *consumer_; // The node that is using this operand.
uint32_t index_; // The index of this operand in its consumer.
MUse(MNode *owner, uint32_t index)
: node_(owner),
MUse(MDefinition *producer, MNode *consumer, uint32_t index)
: producer_(producer),
consumer_(consumer),
index_(index)
{ }
public:
static inline MUse *New(MNode *owner, uint32_t index) {
return new MUse(owner, index);
// Default constructor for use in vectors.
MUse()
: producer_(NULL), consumer_(NULL), index_(0)
{ }
static inline MUse *New(MDefinition *producer, MNode *consumer, uint32_t index) {
return new MUse(producer, consumer, index);
}
MNode *node() const {
return node_;
// Set data inside the MUse.
void set(MDefinition *producer, MNode *consumer, uint32_t index) {
producer_ = producer;
consumer_ = consumer;
index_ = index;
}
MDefinition *producer() const {
JS_ASSERT(producer_ != NULL);
return producer_;
}
MNode *consumer() const {
JS_ASSERT(consumer_ != NULL);
return consumer_;
}
uint32_t index() const {
return index_;
}
};
typedef InlineForwardList<MUse>::iterator MUseIterator;
typedef InlineList<MUse>::iterator MUseIterator;
// A node is an entry in the MIR graph. It has two kinds:
// MInstruction: an instruction which appears in the IR stream.
@ -114,9 +133,12 @@ class MNode : public TempObject
ResumePoint
};
MNode() : block_(NULL)
MNode()
: block_(NULL)
{ }
MNode(MBasicBlock *block) : block_(block)
MNode(MBasicBlock *block)
: block_(block)
{ }
virtual Kind kind() const = 0;
@ -141,20 +163,25 @@ class MNode : public TempObject
return NULL;
}
// Replaces an operand, taking care to update use chains. No memory is
// allocated; the existing data structures are re-linked.
// Replaces an already-set operand during iteration over a use chain.
MUseIterator replaceOperand(MUseIterator use, MDefinition *ins);
// Replaces an already-set operand, updating use information.
void replaceOperand(size_t index, MDefinition *ins);
// Resets the operand to an uninitialized state, breaking the link
// with the previous operand's producer.
void discardOperand(size_t index);
inline MDefinition *toDefinition();
inline MResumePoint *toResumePoint();
protected:
// Sets a raw operand, ignoring updating use information.
// Sets an unset operand, updating use information.
virtual void setOperand(size_t index, MDefinition *operand) = 0;
// Initializes an operand for the first time.
inline void initOperand(size_t index, MDefinition *ins);
// Gets the MUse corresponding to given operand.
virtual MUse *getUseFor(size_t index) = 0;
};
class AliasSet {
@ -230,8 +257,8 @@ class MDefinition : public MNode
};
private:
InlineForwardList<MUse> uses_; // Use chain.
uint32_t id_; // Instruction ID, which after block re-ordering
InlineList<MUse> uses_; // Use chain.
uint32_t id_; // Instruction ID, which after block re-ordering
// is sorted within a basic block.
ValueNumberData *valueNumber_; // The instruction's value number (see GVN for details in use)
Range *range_; // Any computed range for this def.
@ -377,6 +404,9 @@ class MDefinition : public MNode
// Removes a use at the given position
MUseIterator removeUse(MUseIterator use);
void removeUse(MUse *use) {
uses_.remove(use);
}
// Number of uses of this instruction.
size_t useCount() const;
@ -389,8 +419,8 @@ class MDefinition : public MNode
return false;
}
void addUse(MNode *node, size_t index) {
uses_.pushFront(MUse::New(node, index));
void addUse(MUse *use) {
uses_.pushFront(use);
}
void replaceAllUsesWith(MDefinition *dom);
@ -406,13 +436,6 @@ class MDefinition : public MNode
return true;
}
// Adds a use from a node that is being recycled during operand
// replacement.
void linkUse(MUse *use) {
JS_ASSERT(use->node()->getOperand(use->index()) == this);
uses_.pushFront(use);
}
void setVirtualRegister(uint32_t vreg) {
virtualRegister_ = vreg;
#ifdef DEBUG
@ -494,7 +517,7 @@ class MUseDefIterator
MUseIterator search(MUseIterator start) {
MUseIterator i(start);
for (; i != def_->usesEnd(); i++) {
if (i->node()->isDefinition())
if (i->consumer()->isDefinition())
return i;
}
return def_->usesEnd();
@ -504,8 +527,7 @@ class MUseDefIterator
MUseDefIterator(MDefinition *def)
: def_(def),
current_(search(def->usesBegin()))
{
}
{ }
operator bool() const {
return current_ != def_->usesEnd();
@ -521,7 +543,7 @@ class MUseDefIterator
return *current_;
}
MDefinition *def() const {
return current_->node()->toDefinition();
return current_->consumer()->toDefinition();
}
size_t index() const {
return current_->index();
@ -564,15 +586,20 @@ template <size_t Arity>
class MAryInstruction : public MInstruction
{
protected:
FixedArityList<MDefinition*, Arity> operands_;
FixedArityList<MUse, Arity> operands_;
void setOperand(size_t index, MDefinition *operand) {
operands_[index] = operand;
operands_[index].set(operand, this, index);
operand->addUse(&operands_[index]);
}
MUse *getUseFor(size_t index) {
return &operands_[index];
}
public:
MDefinition *getOperand(size_t index) const {
return operands_[index];
return operands_[index].producer();
}
size_t numOperands() const {
return Arity;
@ -758,7 +785,7 @@ class MTableSwitch
// Contains the blocks/cases that still need to get build
Vector<MBasicBlock*, 0, IonAllocPolicy> blocks_;
MDefinition *operand_;
MUse operand_;
int32_t low_;
int32_t high_;
@ -768,13 +795,19 @@ class MTableSwitch
low_(low),
high_(high)
{
initOperand(0, ins);
setOperand(0, ins);
}
protected:
void setOperand(size_t index, MDefinition *operand) {
JS_ASSERT(index == 0);
operand_ = operand;
operand_.set(operand, this, index);
operand->addUse(&operand_);
}
MUse *getUseFor(size_t index) {
JS_ASSERT(index == 0);
return &operand_;
}
public:
@ -846,7 +879,7 @@ class MTableSwitch
MDefinition *getOperand(size_t index) const {
JS_ASSERT(index == 0);
return operand_;
return operand_.producer();
}
size_t numOperands() const {
@ -857,20 +890,25 @@ class MTableSwitch
template <size_t Arity, size_t Successors>
class MAryControlInstruction : public MControlInstruction
{
FixedArityList<MDefinition *, Arity> operands_;
FixedArityList<MUse, Arity> operands_;
FixedArityList<MBasicBlock *, Successors> successors_;
protected:
void setOperand(size_t index, MDefinition *operand) {
operands_[index] = operand;
operands_[index].set(operand, this, index);
operand->addUse(&operands_[index]);
}
void setSuccessor(size_t index, MBasicBlock *successor) {
successors_[index] = successor;
}
MUse *getUseFor(size_t index) {
return &operands_[index];
}
public:
MDefinition *getOperand(size_t index) const {
return operands_[index];
return operands_[index].producer();
}
size_t numOperands() const {
return Arity;
@ -927,7 +965,7 @@ class MTest
MTest(MDefinition *ins, MBasicBlock *if_true, MBasicBlock *if_false)
: operandMightEmulateUndefined_(true)
{
initOperand(0, ins);
setOperand(0, ins);
setSuccessor(0, if_true);
setSuccessor(1, if_false);
}
@ -970,7 +1008,7 @@ class MReturn
public BoxInputsPolicy
{
MReturn(MDefinition *ins) {
initOperand(0, ins);
setOperand(0, ins);
}
public:
@ -992,7 +1030,7 @@ class MThrow
public BoxInputsPolicy
{
MThrow(MDefinition *ins) {
initOperand(0, ins);
setOperand(0, ins);
}
public:
@ -1093,8 +1131,8 @@ class MInitProp
MInitProp(MDefinition *obj, HandlePropertyName name, MDefinition *value)
: name_(name)
{
initOperand(0, obj);
initOperand(1, value);
setOperand(0, obj);
setOperand(1, value);
setResultType(MIRType_None);
}
@ -1141,7 +1179,7 @@ class MPrepareCall : public MNullaryInstruction
class MVariadicInstruction : public MInstruction
{
FixedList<MDefinition *> operands_;
FixedList<MUse> operands_;
protected:
bool init(size_t length) {
@ -1151,13 +1189,18 @@ class MVariadicInstruction : public MInstruction
public:
// Will assert if called before initialization.
MDefinition *getOperand(size_t index) const {
return operands_[index];
return operands_[index].producer();
}
size_t numOperands() const {
return operands_.length();
}
void setOperand(size_t index, MDefinition *operand) {
operands_[index] = operand;
operands_[index].set(operand, this, index);
operand->addUse(&operands_[index]);
}
MUse *getUseFor(size_t index) {
return &operands_[index];
}
};
@ -1199,11 +1242,11 @@ class MCall
void initPrepareCall(MDefinition *start) {
JS_ASSERT(start->isPrepareCall());
return initOperand(PrepareCallOperandIndex, start);
return setOperand(PrepareCallOperandIndex, start);
}
void initFunction(MDefinition *func) {
JS_ASSERT(!func->isPassArg());
return initOperand(FunctionOperandIndex, func);
return setOperand(FunctionOperandIndex, func);
}
MDefinition *getFunction() const {
@ -1264,9 +1307,9 @@ class MApplyArgs
MApplyArgs(JSFunction *target, MDefinition *fun, MDefinition *argc, MDefinition *self)
: target_(target)
{
initOperand(0, fun);
initOperand(1, argc);
initOperand(2, self);
setOperand(0, fun);
setOperand(1, argc);
setOperand(2, self);
setResultType(MIRType_Value);
}
@ -1301,7 +1344,7 @@ class MUnaryInstruction : public MAryInstruction<1>
protected:
MUnaryInstruction(MDefinition *ins)
{
initOperand(0, ins);
setOperand(0, ins);
}
};
@ -1310,8 +1353,8 @@ class MBinaryInstruction : public MAryInstruction<2>
protected:
MBinaryInstruction(MDefinition *left, MDefinition *right)
{
initOperand(0, left);
initOperand(1, right);
setOperand(0, left);
setOperand(1, right);
}
public:
@ -1375,9 +1418,9 @@ class MTernaryInstruction : public MAryInstruction<3>
protected:
MTernaryInstruction(MDefinition *first, MDefinition *second, MDefinition *third)
{
initOperand(0, first);
initOperand(1, second);
initOperand(2, third);
setOperand(0, first);
setOperand(1, second);
setOperand(2, third);
}
protected:
@ -1778,8 +1821,8 @@ class MReturnFromCtor
public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >
{
MReturnFromCtor(MDefinition *value, MDefinition *object) {
initOperand(0, value);
initOperand(1, object);
setOperand(0, value);
setOperand(1, object);
setResultType(MIRType_Object);
}
@ -2932,10 +2975,12 @@ class MFromCharCode
class MPhi : public MDefinition, public InlineForwardListNode<MPhi>
{
js::Vector<MDefinition *, 2, IonAllocPolicy> inputs_;
js::Vector<MUse, 2, IonAllocPolicy> inputs_;
uint32_t slot_;
bool triedToSpecialize_;
bool isIterator_;
MPhi(uint32_t slot)
: slot_(slot),
triedToSpecialize_(false),
@ -2945,18 +2990,25 @@ class MPhi : public MDefinition, public InlineForwardListNode<MPhi>
}
protected:
void setOperand(size_t index, MDefinition *operand) {
inputs_[index] = operand;
MUse *getUseFor(size_t index) {
return &inputs_[index];
}
public:
INSTRUCTION_HEADER(Phi)
static MPhi *New(uint32_t slot);
// Unsafe to use unless space has already been reserved via initLength().
void setOperand(size_t index, MDefinition *operand) {
JS_ASSERT(index < numOperands());
inputs_[index].set(operand, this, index);
operand->addUse(&inputs_[index]);
}
void removeOperand(size_t index);
MDefinition *getOperand(size_t index) const {
return inputs_[index];
return inputs_[index].producer();
}
size_t numOperands() const {
return inputs_.length();
@ -2971,7 +3023,14 @@ class MPhi : public MDefinition, public InlineForwardListNode<MPhi>
triedToSpecialize_ = true;
setResultType(type);
}
bool addInput(MDefinition *ins);
// Initializes the operands vector to the given length,
// permitting use of setOperand() instead of addInputSlow().
bool initLength(size_t length);
// Appends a new input to the input vector. May call realloc().
// Prefer initLength() and setOperand() instead, where possible.
bool addInputSlow(MDefinition *ins);
MDefinition *foldsTo(bool useValueNumbers);
@ -3476,8 +3535,8 @@ class MSetInitializedLength
{
MSetInitializedLength(MDefinition *elements, MDefinition *index)
{
initOperand(0, elements);
initOperand(1, index);
setOperand(0, elements);
setOperand(1, index);
}
public:
@ -3855,9 +3914,9 @@ class MStoreElement
bool needsHoleCheck_;
MStoreElement(MDefinition *elements, MDefinition *index, MDefinition *value, bool needsHoleCheck) {
initOperand(0, elements);
initOperand(1, index);
initOperand(2, value);
setOperand(0, elements);
setOperand(1, index);
setOperand(2, value);
needsHoleCheck_ = needsHoleCheck;
JS_ASSERT(elements->type() == MIRType_Elements);
JS_ASSERT(index->type() == MIRType_Int32);
@ -3904,10 +3963,10 @@ class MStoreElementHole
{
MStoreElementHole(MDefinition *object, MDefinition *elements,
MDefinition *index, MDefinition *value) {
initOperand(0, object);
initOperand(1, elements);
initOperand(2, index);
initOperand(3, value);
setOperand(0, object);
setOperand(1, elements);
setOperand(2, index);
setOperand(3, value);
JS_ASSERT(elements->type() == MIRType_Elements);
JS_ASSERT(index->type() == MIRType_Int32);
}
@ -4517,39 +4576,45 @@ class MPolyInlineDispatch : public MControlInstruction, public SingleObjectPolic
};
Vector<Entry, 4, IonAllocPolicy> dispatchTable_;
MDefinition *operand_;
MUse operand_;
InlinePropertyTable *inlinePropertyTable_;
MBasicBlock *fallbackPrepBlock_;
MBasicBlock *fallbackMidBlock_;
MBasicBlock *fallbackEndBlock_;
MPolyInlineDispatch(MDefinition *ins)
: dispatchTable_(), operand_(NULL),
: dispatchTable_(),
inlinePropertyTable_(NULL),
fallbackPrepBlock_(NULL),
fallbackMidBlock_(NULL),
fallbackEndBlock_(NULL)
{
initOperand(0, ins);
setOperand(0, ins);
}
MPolyInlineDispatch(MDefinition *ins, InlinePropertyTable *inlinePropertyTable,
MBasicBlock *fallbackPrepBlock,
MBasicBlock *fallbackMidBlock,
MBasicBlock *fallbackEndBlock)
: dispatchTable_(), operand_(NULL),
: dispatchTable_(),
inlinePropertyTable_(inlinePropertyTable),
fallbackPrepBlock_(fallbackPrepBlock),
fallbackMidBlock_(fallbackMidBlock),
fallbackEndBlock_(fallbackEndBlock)
{
initOperand(0, ins);
setOperand(0, ins);
}
protected:
virtual void setOperand(size_t index, MDefinition *operand) {
JS_ASSERT(index == 0);
operand_ = operand;
operand_.set(operand, this, index);
operand->addUse(&operand_);
}
MUse *getUseFor(size_t index) {
JS_ASSERT(index == 0);
return &operand_;
}
void setSuccessor(size_t i, MBasicBlock *successor) {
@ -4565,7 +4630,7 @@ class MPolyInlineDispatch : public MControlInstruction, public SingleObjectPolic
virtual MDefinition *getOperand(size_t index) const {
JS_ASSERT(index == 0);
return operand_;
return operand_.producer();
}
virtual size_t numOperands() const {
@ -5247,9 +5312,9 @@ class MCallSetElement
public CallSetElementPolicy
{
MCallSetElement(MDefinition *object, MDefinition *index, MDefinition *value) {
initOperand(0, object);
initOperand(1, index);
initOperand(2, value);
setOperand(0, object);
setOperand(1, index);
setOperand(2, value);
}
public:
@ -5282,8 +5347,8 @@ class MSetDOMProperty
MSetDOMProperty(const JSJitPropertyOp func, MDefinition *obj, MDefinition *val)
: func_(func)
{
initOperand(0, obj);
initOperand(1, val);
setOperand(0, obj);
setOperand(1, val);
}
public:
@ -5323,10 +5388,10 @@ class MGetDOMProperty
{
JS_ASSERT(jitinfo);
initOperand(0, obj);
setOperand(0, obj);
// Pin the guard as an operand if we want to hoist later
initOperand(1, guard);
setOperand(1, guard);
// We are movable iff the jitinfo says we can be.
if (jitinfo->isConstant)
@ -6023,7 +6088,7 @@ class MResumePoint : public MNode
private:
friend class MBasicBlock;
MDefinition **operands_;
FixedList<MUse> operands_;
uint32_t stackDepth_;
jsbytecode *pc_;
MResumePoint *caller_;
@ -6031,14 +6096,24 @@ class MResumePoint : public MNode
Mode mode_;
MResumePoint(MBasicBlock *block, jsbytecode *pc, MResumePoint *parent, Mode mode);
bool init(MBasicBlock *state);
void inherit(MBasicBlock *state);
protected:
// Initializes operands_ to an empty array of a fixed length.
// The array may then be filled in by inherit().
bool init() {
return operands_.init(stackDepth_);
}
// Overwrites an operand without updating its Uses.
void setOperand(size_t index, MDefinition *operand) {
JS_ASSERT(index < stackDepth_);
operands_[index] = operand;
operands_[index].set(operand, this, index);
operand->addUse(&operands_[index]);
}
MUse *getUseFor(size_t index) {
return &operands_[index];
}
public:
@ -6052,7 +6127,7 @@ class MResumePoint : public MNode
}
MDefinition *getOperand(size_t index) const {
JS_ASSERT(index < stackDepth_);
return operands_[index];
return operands_[index].producer();
}
jsbytecode *pc() const {
return pc_;
@ -6151,11 +6226,6 @@ MInstruction *MDefinition::toInstruction()
return (MInstruction *)this;
}
void MNode::initOperand(size_t index, MDefinition *ins)
{
setOperand(index, ins);
ins->addUse(this, index);
}
static inline bool isOSRLikeValue (MDefinition *def) {
if (def->isOsrValue())
return true;

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

@ -194,7 +194,7 @@ MBasicBlock::inherit(MBasicBlock *pred, uint32_t popped)
// Create a resume point using our initial stack state.
entryResumePoint_ = new MResumePoint(this, pc(), callerResumePoint, MResumePoint::ResumeAt);
if (!entryResumePoint_->init(this))
if (!entryResumePoint_->init())
return false;
if (pred) {
@ -204,15 +204,16 @@ MBasicBlock::inherit(MBasicBlock *pred, uint32_t popped)
if (kind_ == PENDING_LOOP_HEADER) {
for (size_t i = 0; i < stackDepth(); i++) {
MPhi *phi = MPhi::New(i);
if (!phi->addInput(pred->getSlot(i)))
if (!phi->initLength(1))
return false;
phi->setOperand(0, pred->getSlot(i));
addPhi(phi);
setSlot(i, phi);
entryResumePoint()->initOperand(i, phi);
entryResumePoint()->setOperand(i, phi);
}
} else {
for (size_t i = 0; i < stackDepth(); i++)
entryResumePoint()->initOperand(i, getSlot(i));
entryResumePoint()->setOperand(i, getSlot(i));
}
}
@ -265,7 +266,7 @@ void
MBasicBlock::initSlot(uint32_t slot, MDefinition *ins)
{
slots_[slot] = ins;
entryResumePoint()->initOperand(slot, ins);
entryResumePoint()->setOperand(slot, ins);
}
void
@ -464,11 +465,22 @@ MBasicBlock::moveBefore(MInstruction *at, MInstruction *ins)
at->block()->insertBefore(at, ins);
}
static inline void
AssertSafelyDiscardable(MDefinition *def)
{
#ifdef DEBUG
// Instructions captured by resume points cannot be safely discarded, since
// they are necessary for interpreter frame reconstruction in case of bailout.
JS_ASSERT(def->useCount() == 0);
#endif
}
void
MBasicBlock::discard(MInstruction *ins)
{
AssertSafelyDiscardable(ins);
for (size_t i = 0; i < ins->numOperands(); i++)
ins->replaceOperand(i, NULL);
ins->discardOperand(i);
instructions_.remove(ins);
}
@ -476,8 +488,9 @@ MBasicBlock::discard(MInstruction *ins)
MInstructionIterator
MBasicBlock::discardAt(MInstructionIterator &iter)
{
AssertSafelyDiscardable(*iter);
for (size_t i = 0; i < iter->numOperands(); i++)
iter->replaceOperand(i, NULL);
iter->discardOperand(i);
return instructions_.removeAt(iter);
}
@ -485,8 +498,9 @@ MBasicBlock::discardAt(MInstructionIterator &iter)
MInstructionReverseIterator
MBasicBlock::discardAt(MInstructionReverseIterator &iter)
{
AssertSafelyDiscardable(*iter);
for (size_t i = 0; i < iter->numOperands(); i++)
iter->replaceOperand(i, NULL);
iter->discardOperand(i);
return instructions_.removeAt(iter);
}
@ -555,7 +569,7 @@ MBasicBlock::discardPhiAt(MPhiIterator &at)
JS_ASSERT(!phis_.empty());
for (size_t i = 0; i < at->numOperands(); i++)
at->replaceOperand(i, NULL);
at->discardOperand(i);
MPhiIterator result = phis_.removeAt(at);
@ -587,33 +601,32 @@ MBasicBlock::addPredecessorPopN(MBasicBlock *pred, uint32_t popped)
MDefinition *other = pred->getSlot(i);
if (mine != other) {
MPhi *phi;
// If the current instruction is a phi, and it was created in this
// basic block, then we have already placed this phi and should
// instead append to its operands.
if (mine->isPhi() && mine->block() == this) {
JS_ASSERT(predecessors_.length());
phi = mine->toPhi();
if (!mine->toPhi()->addInputSlow(other))
return false;
} else {
// Otherwise, create a new phi node.
phi = MPhi::New(i);
MPhi *phi = MPhi::New(i);
addPhi(phi);
// Prime the phi for each predecessor, so input(x) comes from
// predecessor(x).
if (!phi->initLength(predecessors_.length() + 1))
return false;
for (size_t j = 0; j < predecessors_.length(); j++) {
JS_ASSERT(predecessors_[j]->getSlot(i) == mine);
if (!phi->addInput(mine))
return false;
phi->setOperand(j, mine);
}
phi->setOperand(predecessors_.length(), other);
setSlot(i, phi);
entryResumePoint()->replaceOperand(i, phi);
}
if (!phi->addInput(other))
return false;
}
}
@ -639,8 +652,8 @@ MBasicBlock::assertUsesAreNotWithin(MUseIterator use, MUseIterator end)
{
#ifdef DEBUG
for (; use != end; use++) {
JS_ASSERT_IF(use->node()->isDefinition(),
use->node()->toDefinition()->block()->id() < id());
JS_ASSERT_IF(use->consumer()->isDefinition(),
use->consumer()->toDefinition()->block()->id() < id());
}
#endif
}
@ -683,7 +696,7 @@ MBasicBlock::setBackedge(MBasicBlock *pred)
exitDef = entryDef->getOperand(0);
}
if (!entryDef->addInput(exitDef))
if (!entryDef->addInputSlow(exitDef))
return false;
JS_ASSERT(entryDef->slot() < pred->stackDepth());

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

@ -83,7 +83,7 @@ RangeAnalysis::RangeAnalysis(MIRGraph &graph)
static bool
IsDominatedUse(MBasicBlock *block, MUse *use)
{
MNode *n = use->node();
MNode *n = use->consumer();
bool isPhi = n->isDefinition() && n->toDefinition()->isPhi();
if (isPhi)
@ -110,8 +110,8 @@ RangeAnalysis::replaceDominatedUsesWith(MDefinition *orig, MDefinition *dom,
MBasicBlock *block)
{
for (MUseIterator i(orig->usesBegin()); i != orig->usesEnd(); ) {
if (i->node() != dom && IsDominatedUse(block, *i))
i = i->node()->replaceOperand(i, dom);
if (i->consumer() != dom && IsDominatedUse(block, *i))
i = i->consumer()->replaceOperand(i, dom);
else
i++;
}

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

@ -112,7 +112,7 @@ void
UnreachableCodeElimination::removeUsesFromUnmarkedBlocks(MDefinition *instr)
{
for (MUseIterator iter(instr->usesBegin()); iter != instr->usesEnd(); ) {
if (!iter->node()->block()->isMarked())
if (!iter->consumer()->block()->isMarked())
iter = instr->removeUse(iter);
else
iter++;

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

@ -19,5 +19,5 @@ function doParseIntTests() {
}
doParseIntTests();
assertEq(parseInt("08"), 0);
assertEq(parseInt("09"), 0);
assertEq(parseInt("08"), 8);
assertEq(parseInt("09"), 9);

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

@ -1,16 +1,16 @@
"use strict";
assertEq(parseInt("08"), 0);
assertEq(parseInt("09"), 0);
assertEq(parseInt("014"), 12);
assertEq(parseInt("08"), 8);
assertEq(parseInt("09"), 9);
assertEq(parseInt("014"), 14);
assertEq(parseInt("0xA"), 10);
assertEq(parseInt("00123"), 83);
assertEq(parseInt("00123"), 123);
for (var i = 0; i < 5; i++)
{
assertEq(parseInt("08"), 0);
assertEq(parseInt("09"), 0);
assertEq(parseInt("014"), 12);
assertEq(parseInt("08"), 8);
assertEq(parseInt("09"), 9);
assertEq(parseInt("014"), 14);
assertEq(parseInt("0xA"), 10);
assertEq(parseInt("00123"), 83);
assertEq(parseInt("00123"), 123);
}

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

@ -0,0 +1,41 @@
function dumpArgs(i) { if (i == 90) return funapply.arguments.length; return [i]; }
function funapply() { return dumpArgs.apply({}, arguments); }
function test(i) { return funapply(i); }
assertEq(test(89)[0], 89);
assertEq(test(90), 1);
function dumpArgs2(i,b) { if (i == 90) return funapply2.arguments.length; return [i]; }
function funapply2() { return dumpArgs2.apply({}, arguments); }
function test2(i,b) { return funapply2(i,b); }
assertEq(test2(89, 10)[0], 89);
assertEq(test2(90, 10), 2);
function dumpArgs3(i,b) { if (i == 90) return funapply3.arguments.length; return [i]; }
function funapply3() { return dumpArgs3.apply({}, arguments); }
function test3(i,b, c) { return funapply3(i,b,c); }
assertEq(test3(89, 10, 11)[0], 89);
assertEq(test3(90, 10, 11), 3);
function dumpArgs4(i) { if (i == 90) return funapply4.arguments.length; return [i]; }
function funapply4() { return dumpArgs4.apply({}, arguments); }
function test4(i,b) { return funapply4(i,b,1,2); }
assertEq(test4(89,10)[0], 89);
assertEq(test4(90,10), 4);
function dumpArgs5(i,j,k,l) { if (i == 90) return funapply5.arguments.length*10 + l; return [i]; }
function funapply5() { return dumpArgs5.apply({}, arguments); }
function test5(i,b) { return funapply5(i,b,1,2); }
assertEq(test5(89,10)[0], 89);
assertEq(test5(90,10), 42);
function dumpArgs6(i) { if (i == 90) return funapply6.arguments.length; return [i]; }
function funapply6() { return dumpArgs6.apply({}, arguments); }
function test6(i) { return funapply6(i,1,2,3); }
assertEq(test6(89)[0], 89);
assertEq(test6(90), 4);

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

@ -397,8 +397,8 @@ DaylightSavingTA(double t, DateTimeInfo *dtInfo)
t = MakeDate(day, TimeWithinDay(t));
}
int64_t timeMilliseconds = static_cast<int64_t>(t);
int64_t offsetMilliseconds = dtInfo->getDSTOffsetMilliseconds(timeMilliseconds);
int64_t utcMilliseconds = static_cast<int64_t>(t);
int64_t offsetMilliseconds = dtInfo->getDSTOffsetMilliseconds(utcMilliseconds);
return static_cast<double>(offsetMilliseconds);
}

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

@ -281,60 +281,7 @@ num_parseFloat(JSContext *cx, unsigned argc, Value *vp)
return JS_TRUE;
}
static bool
ParseIntStringHelper(JSContext *cx, const jschar *ws, const jschar *end, int maybeRadix,
bool stripPrefix, double *dp)
{
JS_ASSERT(maybeRadix == 0 || (2 <= maybeRadix && maybeRadix <= 36));
JS_ASSERT(ws <= end);
const jschar *s = SkipSpace(ws, end);
JS_ASSERT(ws <= s);
JS_ASSERT(s <= end);
/* 15.1.2.2 steps 3-4. */
bool negative = (s != end && s[0] == '-');
/* 15.1.2.2 step 5. */
if (s != end && (s[0] == '-' || s[0] == '+'))
s++;
/* 15.1.2.2 step 9. */
int radix = maybeRadix;
if (radix == 0) {
if (end - s >= 2 && s[0] == '0' && (s[1] != 'x' && s[1] != 'X')) {
/*
* Non-standard: ES5 requires that parseInt interpret leading-zero
* strings not starting with "0x" or "0X" as decimal (absent an
* explicitly specified non-zero radix), but we continue to
* interpret such strings as octal, as per ES3 and web practice.
*/
radix = 8;
} else {
radix = 10;
}
}
/* 15.1.2.2 step 10. */
if (stripPrefix) {
if (end - s >= 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
s += 2;
radix = 16;
}
}
/* 15.1.2.2 steps 11-14. */
const jschar *actualEnd;
if (!GetPrefixInteger(cx, s, end, radix, &actualEnd, dp))
return false;
if (s == actualEnd)
*dp = js_NaN;
else if (negative)
*dp = -*dp;
return true;
}
/* See ECMA 15.1.2.2. */
/* ES5 15.1.2.2. */
JSBool
js::num_parseInt(JSContext *cx, unsigned argc, Value *vp)
{
@ -352,6 +299,7 @@ js::num_parseInt(JSContext *cx, unsigned argc, Value *vp)
args.rval().set(args[0]);
return true;
}
/*
* Step 1 is |inputString = ToString(string)|. When string >=
* 1e21, ToString(string) is in the form "NeM". 'e' marks the end of
@ -386,13 +334,17 @@ js::num_parseInt(JSContext *cx, unsigned argc, Value *vp)
return false;
args[0].setString(inputString);
/* 15.1.2.2 steps 6-8. */
/* Steps 6-9. */
bool stripPrefix = true;
int32_t radix = 0;
if (args.length() > 1) {
int32_t radix;
if (!args.hasDefined(1)) {
radix = 10;
} else {
if (!ToInt32(cx, args[1], &radix))
return false;
if (radix != 0) {
if (radix == 0) {
radix = 10;
} else {
if (radix < 2 || radix > 36) {
args.rval().setDouble(js_NaN);
return true;
@ -402,18 +354,44 @@ js::num_parseInt(JSContext *cx, unsigned argc, Value *vp)
}
}
/* Steps 2-5, 9-14. */
const jschar *ws = inputString->getChars(cx);
if (!ws)
return false;
const jschar *end = ws + inputString->length();
/* Step 2. */
const jschar *s;
const jschar *end;
{
const jschar *ws = inputString->getChars(cx);
if (!ws)
return false;
end = ws + inputString->length();
s = SkipSpace(ws, end);
MOZ_ASSERT(ws <= s);
MOZ_ASSERT(s <= end);
}
/* Steps 3-4. */
bool negative = (s != end && s[0] == '-');
/* Step 5. */
if (s != end && (s[0] == '-' || s[0] == '+'))
s++;
/* Step 10. */
if (stripPrefix) {
if (end - s >= 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
s += 2;
radix = 16;
}
}
/* Steps 11-15. */
const jschar *actualEnd;
double number;
if (!ParseIntStringHelper(cx, ws, end, radix, stripPrefix, &number))
if (!GetPrefixInteger(cx, s, end, radix, &actualEnd, &number))
return false;
/* Step 15. */
args.rval().setNumber(number);
if (s == actualEnd)
args.rval().setNumber(js_NaN);
else
args.rval().setNumber(negative ? -number : number);
return true;
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше