зеркало из https://github.com/mozilla/gecko-dev.git
Merge the last PGO-green inbound changeset to m-c.
This commit is contained in:
Коммит
69a47a12a9
|
@ -119,8 +119,12 @@
|
||||||
gQueue.invoke(); // Will call SimpleTest.finish();
|
gQueue.invoke(); // Will call SimpleTest.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
if (!MAC) {
|
||||||
openBrowserWindow(doTest);
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
openBrowserWindow(doTest);
|
||||||
|
} else {
|
||||||
|
todo(false, "Re-enable on Mac after fixing bug 835338");
|
||||||
|
}
|
||||||
]]>
|
]]>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -445,6 +445,10 @@ pref("media.volume.steps", 10);
|
||||||
//Enable/disable marionette server, set listening port
|
//Enable/disable marionette server, set listening port
|
||||||
pref("marionette.defaultPrefs.enabled", true);
|
pref("marionette.defaultPrefs.enabled", true);
|
||||||
pref("marionette.defaultPrefs.port", 2828);
|
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
|
#endif
|
||||||
|
|
||||||
#ifdef MOZ_UPDATER
|
#ifdef MOZ_UPDATER
|
||||||
|
|
|
@ -28,7 +28,7 @@ postflight_all:
|
||||||
ln -s $(call core_abspath,$(DIST_UNI)) $(DIST_ARCH_2)/universal
|
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
|
# 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.
|
# 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
|
PKG_SKIP_STRIP=1 stage-package
|
||||||
ifdef ENABLE_TESTS
|
ifdef ENABLE_TESTS
|
||||||
# Now, repeat the process for the test package.
|
# Now, repeat the process for the test package.
|
||||||
|
|
|
@ -1036,13 +1036,6 @@ protected:
|
||||||
*/
|
*/
|
||||||
virtual Element* GetOffsetRect(nsRect& aRect);
|
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();
|
nsIFrame* GetStyledFrame();
|
||||||
|
|
||||||
virtual Element* GetNameSpaceElement()
|
virtual Element* GetNameSpaceElement()
|
||||||
|
|
|
@ -241,6 +241,12 @@ DoesNotParticipateInAutoDirection(const Element* aElement)
|
||||||
nodeInfo->Equals(nsGkAtoms::textarea));
|
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
|
* 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
|
* affect the direction of ancestors with dir=auto (though it may affect its own
|
||||||
|
@ -250,7 +256,7 @@ static bool
|
||||||
DoesNotAffectDirectionOfAncestors(const Element* aElement)
|
DoesNotAffectDirectionOfAncestors(const Element* aElement)
|
||||||
{
|
{
|
||||||
return (DoesNotParticipateInAutoDirection(aElement) ||
|
return (DoesNotParticipateInAutoDirection(aElement) ||
|
||||||
aElement->IsHTML(nsGkAtoms::bdi) ||
|
IsBdiWithoutDirAuto(aElement) ||
|
||||||
aElement->HasFixedDir());
|
aElement->HasFixedDir());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -643,7 +649,7 @@ void
|
||||||
WalkDescendantsSetDirAuto(Element* aElement, bool aNotify)
|
WalkDescendantsSetDirAuto(Element* aElement, bool aNotify)
|
||||||
{
|
{
|
||||||
if (!DoesNotParticipateInAutoDirection(aElement) &&
|
if (!DoesNotParticipateInAutoDirection(aElement) &&
|
||||||
!aElement->IsHTML(nsGkAtoms::bdi)) {
|
!IsBdiWithoutDirAuto(aElement)) {
|
||||||
|
|
||||||
bool setAncestorDirAutoFlag =
|
bool setAncestorDirAutoFlag =
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
|
@ -514,20 +514,6 @@ Element::GetOffsetRect(nsRect& aRect)
|
||||||
return nullptr;
|
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*
|
nsIScrollableFrame*
|
||||||
Element::GetScrollFrame(nsIFrame **aStyledFrame)
|
Element::GetScrollFrame(nsIFrame **aStyledFrame)
|
||||||
{
|
{
|
||||||
|
@ -597,6 +583,20 @@ Element::ScrollIntoView(bool aTop)
|
||||||
nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
|
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
|
int32_t
|
||||||
Element::ScrollHeight()
|
Element::ScrollHeight()
|
||||||
{
|
{
|
||||||
|
@ -604,11 +604,13 @@ Element::ScrollHeight()
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
nsIScrollableFrame* sf = GetScrollFrame();
|
nsIScrollableFrame* sf = GetScrollFrame();
|
||||||
if (!sf) {
|
nscoord height;
|
||||||
return GetPaddingRectSize().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);
|
return nsPresContext::AppUnitsToIntCSSPixels(height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -619,11 +621,13 @@ Element::ScrollWidth()
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
nsIScrollableFrame* sf = GetScrollFrame();
|
nsIScrollableFrame* sf = GetScrollFrame();
|
||||||
if (!sf) {
|
nscoord width;
|
||||||
return GetPaddingRectSize().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);
|
return nsPresContext::AppUnitsToIntCSSPixels(width);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6380,6 +6380,16 @@ nsContentUtils::FindInternalContentViewer(const char* aType,
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
#ifdef MOZ_GSTREAMER
|
||||||
if (DecoderTraits::IsGStreamerSupportedType(nsDependentCString(aType))) {
|
if (DecoderTraits::IsGStreamerSupportedType(nsDependentCString(aType))) {
|
||||||
docFactory = do_GetService("@mozilla.org/content/document-loader-factory;1");
|
docFactory = do_GetService("@mozilla.org/content/document-loader-factory;1");
|
||||||
|
|
|
@ -37,6 +37,7 @@ GK_ATOM(mozframetype, "mozframetype")
|
||||||
GK_ATOM(mozallowfullscreen, "mozallowfullscreen")
|
GK_ATOM(mozallowfullscreen, "mozallowfullscreen")
|
||||||
GK_ATOM(moztype, "_moz-type")
|
GK_ATOM(moztype, "_moz-type")
|
||||||
GK_ATOM(mozdirty, "_moz_dirty")
|
GK_ATOM(mozdirty, "_moz_dirty")
|
||||||
|
GK_ATOM(mozdisallowselectionprint, "mozdisallowselectionprint")
|
||||||
GK_ATOM(mozdonotsend, "moz-do-not-send")
|
GK_ATOM(mozdonotsend, "moz-do-not-send")
|
||||||
GK_ATOM(mozeditorbogusnode, "_moz_editor_bogus_node")
|
GK_ATOM(mozeditorbogusnode, "_moz_editor_bogus_node")
|
||||||
GK_ATOM(mozgeneratedcontentbefore, "_moz_generated_content_before")
|
GK_ATOM(mozgeneratedcontentbefore, "_moz_generated_content_before")
|
||||||
|
|
|
@ -163,10 +163,13 @@ public:
|
||||||
return CurrentState().globalAlpha;
|
return CurrentState().globalAlpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Useful for silencing cast warnings
|
||||||
|
static mozilla::gfx::Float ToFloat(double aValue) { return mozilla::gfx::Float(aValue); }
|
||||||
|
|
||||||
void SetGlobalAlpha(double globalAlpha)
|
void SetGlobalAlpha(double globalAlpha)
|
||||||
{
|
{
|
||||||
if (globalAlpha >= 0.0 && globalAlpha <= 1.0) {
|
if (globalAlpha >= 0.0 && globalAlpha <= 1.0) {
|
||||||
CurrentState().globalAlpha = globalAlpha;
|
CurrentState().globalAlpha = ToFloat(globalAlpha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,7 +207,7 @@ public:
|
||||||
|
|
||||||
void SetShadowOffsetX(double shadowOffsetX)
|
void SetShadowOffsetX(double shadowOffsetX)
|
||||||
{
|
{
|
||||||
CurrentState().shadowOffset.x = shadowOffsetX;
|
CurrentState().shadowOffset.x = ToFloat(shadowOffsetX);
|
||||||
}
|
}
|
||||||
|
|
||||||
double ShadowOffsetY()
|
double ShadowOffsetY()
|
||||||
|
@ -214,7 +217,7 @@ public:
|
||||||
|
|
||||||
void SetShadowOffsetY(double shadowOffsetY)
|
void SetShadowOffsetY(double shadowOffsetY)
|
||||||
{
|
{
|
||||||
CurrentState().shadowOffset.y = shadowOffsetY;
|
CurrentState().shadowOffset.y = ToFloat(shadowOffsetY);
|
||||||
}
|
}
|
||||||
|
|
||||||
double ShadowBlur()
|
double ShadowBlur()
|
||||||
|
@ -225,7 +228,7 @@ public:
|
||||||
void SetShadowBlur(double shadowBlur)
|
void SetShadowBlur(double shadowBlur)
|
||||||
{
|
{
|
||||||
if (shadowBlur >= 0.0) {
|
if (shadowBlur >= 0.0) {
|
||||||
CurrentState().shadowBlur = shadowBlur;
|
CurrentState().shadowBlur = ToFloat(shadowBlur);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,7 +300,7 @@ public:
|
||||||
void SetLineWidth(double width)
|
void SetLineWidth(double width)
|
||||||
{
|
{
|
||||||
if (width > 0.0) {
|
if (width > 0.0) {
|
||||||
CurrentState().lineWidth = width;
|
CurrentState().lineWidth = ToFloat(width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void GetLineCap(nsAString& linecap);
|
void GetLineCap(nsAString& linecap);
|
||||||
|
@ -313,7 +316,7 @@ public:
|
||||||
void SetMiterLimit(double miter)
|
void SetMiterLimit(double miter)
|
||||||
{
|
{
|
||||||
if (miter > 0.0) {
|
if (miter > 0.0) {
|
||||||
CurrentState().miterLimit = miter;
|
CurrentState().miterLimit = ToFloat(miter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,10 +347,10 @@ public:
|
||||||
EnsureWritablePath();
|
EnsureWritablePath();
|
||||||
|
|
||||||
if (mPathBuilder) {
|
if (mPathBuilder) {
|
||||||
mPathBuilder->MoveTo(mozilla::gfx::Point(x, y));
|
mPathBuilder->MoveTo(mozilla::gfx::Point(ToFloat(x), ToFloat(y)));
|
||||||
} else {
|
} else {
|
||||||
mDSPathBuilder->MoveTo(mTarget->GetTransform() *
|
mDSPathBuilder->MoveTo(mTarget->GetTransform() *
|
||||||
mozilla::gfx::Point(x, y));
|
mozilla::gfx::Point(ToFloat(x), ToFloat(y)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,7 +358,7 @@ public:
|
||||||
{
|
{
|
||||||
EnsureWritablePath();
|
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)
|
void QuadraticCurveTo(double cpx, double cpy, double x, double y)
|
||||||
|
@ -363,14 +366,14 @@ public:
|
||||||
EnsureWritablePath();
|
EnsureWritablePath();
|
||||||
|
|
||||||
if (mPathBuilder) {
|
if (mPathBuilder) {
|
||||||
mPathBuilder->QuadraticBezierTo(mozilla::gfx::Point(cpx, cpy),
|
mPathBuilder->QuadraticBezierTo(mozilla::gfx::Point(ToFloat(cpx), ToFloat(cpy)),
|
||||||
mozilla::gfx::Point(x, y));
|
mozilla::gfx::Point(ToFloat(x), ToFloat(y)));
|
||||||
} else {
|
} else {
|
||||||
mozilla::gfx::Matrix transform = mTarget->GetTransform();
|
mozilla::gfx::Matrix transform = mTarget->GetTransform();
|
||||||
mDSPathBuilder->QuadraticBezierTo(transform *
|
mDSPathBuilder->QuadraticBezierTo(transform *
|
||||||
mozilla::gfx::Point(cpx, cpy),
|
mozilla::gfx::Point(ToFloat(cpx), ToFloat(cpy)),
|
||||||
transform *
|
transform *
|
||||||
mozilla::gfx::Point(x, y));
|
mozilla::gfx::Point(ToFloat(x), ToFloat(y)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,9 +381,9 @@ public:
|
||||||
{
|
{
|
||||||
EnsureWritablePath();
|
EnsureWritablePath();
|
||||||
|
|
||||||
BezierTo(mozilla::gfx::Point(cp1x, cp1y),
|
BezierTo(mozilla::gfx::Point(ToFloat(cp1x), ToFloat(cp1y)),
|
||||||
mozilla::gfx::Point(cp2x, cp2y),
|
mozilla::gfx::Point(ToFloat(cp2x), ToFloat(cp2y)),
|
||||||
mozilla::gfx::Point(x, y));
|
mozilla::gfx::Point(ToFloat(x), ToFloat(y)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArcTo(double x1, double y1, double x2, double y2, double radius,
|
void ArcTo(double x1, double y1, double x2, double y2, double radius,
|
||||||
|
|
|
@ -490,7 +490,7 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
|
||||||
if (aEvent->mFlags.mRetargetToNonNativeAnonymous) {
|
if (aEvent->mFlags.mRetargetToNonNativeAnonymous) {
|
||||||
nsCOMPtr<nsIContent> content = do_QueryInterface(target);
|
nsCOMPtr<nsIContent> content = do_QueryInterface(target);
|
||||||
if (content && content->IsInNativeAnonymousSubtree()) {
|
if (content && content->IsInNativeAnonymousSubtree()) {
|
||||||
nsCOMPtr<nsPIDOMEventTarget> newTarget =
|
nsCOMPtr<nsIDOMEventTarget> newTarget =
|
||||||
do_QueryInterface(content->FindFirstNonChromeOnlyAccessContent());
|
do_QueryInterface(content->FindFirstNonChromeOnlyAccessContent());
|
||||||
NS_ENSURE_STATE(newTarget);
|
NS_ENSURE_STATE(newTarget);
|
||||||
|
|
||||||
|
|
|
@ -919,8 +919,7 @@ HTMLTableElement::ParseAttribute(int32_t aNamespaceID,
|
||||||
aAttribute == nsGkAtoms::cellpadding) {
|
aAttribute == nsGkAtoms::cellpadding) {
|
||||||
return aResult.ParseNonNegativeIntValue(aValue);
|
return aResult.ParseNonNegativeIntValue(aValue);
|
||||||
}
|
}
|
||||||
if (aAttribute == nsGkAtoms::cols ||
|
if (aAttribute == nsGkAtoms::border) {
|
||||||
aAttribute == nsGkAtoms::border) {
|
|
||||||
return aResult.ParseIntWithBounds(aValue, 0);
|
return aResult.ParseIntWithBounds(aValue, 0);
|
||||||
}
|
}
|
||||||
if (aAttribute == nsGkAtoms::height) {
|
if (aAttribute == nsGkAtoms::height) {
|
||||||
|
@ -1005,15 +1004,6 @@ MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||||
if (value && value->Type() == nsAttrValue::eEnum)
|
if (value && value->Type() == nsAttrValue::eEnum)
|
||||||
tableLayout->SetIntValue(value->GetEnumValue(), eCSSUnit_Enumerated);
|
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)) {
|
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Margin)) {
|
||||||
// align; Check for enumerated type (it may be another type if
|
// align; Check for enumerated type (it may be another type if
|
||||||
|
@ -1135,7 +1125,6 @@ HTMLTableElement::IsAttributeMapped(const nsIAtom* aAttribute) const
|
||||||
{ &nsGkAtoms::layout },
|
{ &nsGkAtoms::layout },
|
||||||
{ &nsGkAtoms::cellpadding },
|
{ &nsGkAtoms::cellpadding },
|
||||||
{ &nsGkAtoms::cellspacing },
|
{ &nsGkAtoms::cellspacing },
|
||||||
{ &nsGkAtoms::cols },
|
|
||||||
{ &nsGkAtoms::border },
|
{ &nsGkAtoms::border },
|
||||||
{ &nsGkAtoms::width },
|
{ &nsGkAtoms::width },
|
||||||
{ &nsGkAtoms::height },
|
{ &nsGkAtoms::height },
|
||||||
|
|
|
@ -824,6 +824,8 @@ nsGenericHTMLElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||||
} else {
|
} else {
|
||||||
ClearHasValidDir();
|
ClearHasValidDir();
|
||||||
ClearHasFixedDir();
|
ClearHasFixedDir();
|
||||||
|
ClearHasDirAuto();
|
||||||
|
ClearHasDirAutoSet();
|
||||||
if (NodeInfo()->Equals(nsGkAtoms::bdi)) {
|
if (NodeInfo()->Equals(nsGkAtoms::bdi)) {
|
||||||
SetHasDirAuto();
|
SetHasDirAuto();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -64,6 +64,16 @@ nsTimeRanges::Add(double aStart, double aEnd)
|
||||||
mRanges.AppendElement(TimeRange(aStart,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
|
void
|
||||||
nsTimeRanges::Normalize()
|
nsTimeRanges::Normalize()
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,6 +24,9 @@ public:
|
||||||
|
|
||||||
void Add(double aStart, double aEnd);
|
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
|
// See http://www.whatwg.org/html/#normalized-timeranges-object
|
||||||
void Normalize();
|
void Normalize();
|
||||||
|
|
||||||
|
|
|
@ -1629,10 +1629,6 @@ MediaCacheStream::NotifyDataStarted(int64_t aOffset)
|
||||||
// the stream is at least that long.
|
// the stream is at least that long.
|
||||||
mStreamLength = std::max(mStreamLength, mChannelOffset);
|
mStreamLength = std::max(mStreamLength, mChannelOffset);
|
||||||
}
|
}
|
||||||
// Ensure that |mDownloadCancelled| is set to false since we have new data.
|
|
||||||
if (mDownloadCancelled) {
|
|
||||||
mDownloadCancelled = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -1802,24 +1798,6 @@ MediaCacheStream::NotifyDataEnded(nsresult aStatus)
|
||||||
gMediaCache->QueueUpdate();
|
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()
|
MediaCacheStream::~MediaCacheStream()
|
||||||
{
|
{
|
||||||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
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.
|
// that out.
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
// If the download was cancelled, stop reading and return silently.
|
|
||||||
if (mDownloadCancelled) {
|
|
||||||
mDownloadCancelled = false;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -194,7 +194,6 @@ public:
|
||||||
MediaCacheStream(ChannelMediaResource* aClient)
|
MediaCacheStream(ChannelMediaResource* aClient)
|
||||||
: mClient(aClient), mInitialized(false),
|
: mClient(aClient), mInitialized(false),
|
||||||
mHasHadUpdate(false),
|
mHasHadUpdate(false),
|
||||||
mDownloadCancelled(false),
|
|
||||||
mClosed(false),
|
mClosed(false),
|
||||||
mDidNotifyDataEnded(false), mResourceID(0),
|
mDidNotifyDataEnded(false), mResourceID(0),
|
||||||
mIsTransportSeekable(false), mCacheSuspended(false),
|
mIsTransportSeekable(false), mCacheSuspended(false),
|
||||||
|
@ -279,13 +278,6 @@ public:
|
||||||
void FlushPartialBlock();
|
void FlushPartialBlock();
|
||||||
// Notifies the cache that the channel has closed with the given status.
|
// Notifies the cache that the channel has closed with the given status.
|
||||||
void NotifyDataEnded(nsresult aStatus);
|
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.
|
// These methods can be called on any thread.
|
||||||
// Cached blocks associated with this stream will not be evicted
|
// 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
|
// Set to true when MediaCache::Update() has finished while this stream
|
||||||
// was present.
|
// was present.
|
||||||
bool mHasHadUpdate;
|
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
|
// Set to true when the stream has been closed either explicitly or
|
||||||
// due to an internal cache error
|
// due to an internal cache error
|
||||||
bool mClosed;
|
bool mClosed;
|
||||||
|
|
|
@ -317,7 +317,7 @@ MediaDecoder::MediaDecoder() :
|
||||||
mReentrantMonitor("media.decoder"),
|
mReentrantMonitor("media.decoder"),
|
||||||
mPlayState(PLAY_STATE_PAUSED),
|
mPlayState(PLAY_STATE_PAUSED),
|
||||||
mNextState(PLAY_STATE_PAUSED),
|
mNextState(PLAY_STATE_PAUSED),
|
||||||
mResourceLoaded(false),
|
mCalledResourceLoaded(false),
|
||||||
mIgnoreProgressData(false),
|
mIgnoreProgressData(false),
|
||||||
mInfiniteStream(false),
|
mInfiniteStream(false),
|
||||||
mTriggerPlaybackEndedWhenSourceStreamFinishes(false),
|
mTriggerPlaybackEndedWhenSourceStreamFinishes(false),
|
||||||
|
@ -650,6 +650,16 @@ void MediaDecoder::QueueMetadata(int64_t aPublishTime,
|
||||||
mDecoderStateMachine->QueueMetadata(aPublishTime, aChannels, aRate, aHasAudio, aHasVideo, aTags);
|
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)
|
void MediaDecoder::MetadataLoaded(int aChannels, int aRate, bool aHasAudio, bool aHasVideo, MetadataTags* aTags)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
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);
|
mOwner->MetadataLoaded(aChannels, aRate, aHasAudio, aHasVideo, aTags);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mResourceLoaded) {
|
if (!mCalledResourceLoaded) {
|
||||||
StartProgress();
|
StartProgress();
|
||||||
} else if (mOwner) {
|
} else if (mOwner) {
|
||||||
// Resource was loaded during metadata loading, when progress
|
// 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
|
// Only inform the element of FirstFrameLoaded if not doing a load() in order
|
||||||
// to fulfill a seek, otherwise we'll get multiple loadedfirstframe events.
|
// to fulfill a seek, otherwise we'll get multiple loadedfirstframe events.
|
||||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||||
bool resourceIsLoaded = !mResourceLoaded && mResource &&
|
bool notifyResourceIsLoaded = !mCalledResourceLoaded &&
|
||||||
mResource->IsDataCachedToEndOfResource(mDecoderPosition);
|
IsDataCachedToEndOfResource();
|
||||||
if (mOwner) {
|
if (mOwner) {
|
||||||
mOwner->FirstFrameLoaded(resourceIsLoaded);
|
mOwner->FirstFrameLoaded(notifyResourceIsLoaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This can run cache callbacks.
|
// This can run cache callbacks.
|
||||||
|
@ -708,7 +718,7 @@ void MediaDecoder::MetadataLoaded(int aChannels, int aRate, bool aHasAudio, bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resourceIsLoaded) {
|
if (notifyResourceIsLoaded) {
|
||||||
ResourceLoaded();
|
ResourceLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -732,12 +742,12 @@ void MediaDecoder::ResourceLoaded()
|
||||||
// If we are seeking or loading then the resource loaded notification we get
|
// 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.
|
// should be ignored, since it represents the end of the seek request.
|
||||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||||
if (mIgnoreProgressData || mResourceLoaded || mPlayState == PLAY_STATE_LOADING)
|
if (mIgnoreProgressData || mCalledResourceLoaded || mPlayState == PLAY_STATE_LOADING)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Progress(false);
|
Progress(false);
|
||||||
|
|
||||||
mResourceLoaded = true;
|
mCalledResourceLoaded = true;
|
||||||
StopProgress();
|
StopProgress();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -502,7 +502,7 @@ public:
|
||||||
// from a content header. Must be called from the main thread only.
|
// from a content header. Must be called from the main thread only.
|
||||||
virtual void SetDuration(double aDuration);
|
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
|
// Set a flag indicating whether seeking is supported
|
||||||
virtual void SetMediaSeekable(bool aMediaSeekable) MOZ_OVERRIDE;
|
virtual void SetMediaSeekable(bool aMediaSeekable) MOZ_OVERRIDE;
|
||||||
|
@ -611,11 +611,11 @@ public:
|
||||||
// Stop updating the bytes downloaded for progress notifications. Called
|
// Stop updating the bytes downloaded for progress notifications. Called
|
||||||
// when seeking to prevent wild changes to the progress notification.
|
// when seeking to prevent wild changes to the progress notification.
|
||||||
// Must be called with the decoder monitor held.
|
// Must be called with the decoder monitor held.
|
||||||
void StopProgressUpdates();
|
virtual void StopProgressUpdates();
|
||||||
|
|
||||||
// Allow updating the bytes downloaded for progress notifications. Must
|
// Allow updating the bytes downloaded for progress notifications. Must
|
||||||
// be called with the decoder monitor held.
|
// be called with the decoder monitor held.
|
||||||
void StartProgressUpdates();
|
virtual void StartProgressUpdates();
|
||||||
|
|
||||||
// Something has changed that could affect the computed playback rate,
|
// Something has changed that could affect the computed playback rate,
|
||||||
// so recompute it. The monitor must be held.
|
// so recompute it. The monitor must be held.
|
||||||
|
@ -683,6 +683,10 @@ public:
|
||||||
// Call on the main thread only.
|
// Call on the main thread only.
|
||||||
void FirstFrameLoaded();
|
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.
|
// Called when the video has completed playing.
|
||||||
// Call on the main thread only.
|
// Call on the main thread only.
|
||||||
void PlaybackEnded();
|
void PlaybackEnded();
|
||||||
|
@ -1012,7 +1016,7 @@ public:
|
||||||
// True when we have fully loaded the resource and reported that
|
// True when we have fully loaded the resource and reported that
|
||||||
// to the element (i.e. reached NETWORK_LOADED state).
|
// to the element (i.e. reached NETWORK_LOADED state).
|
||||||
// Accessed on the main thread only.
|
// Accessed on the main thread only.
|
||||||
bool mResourceLoaded;
|
bool mCalledResourceLoaded;
|
||||||
|
|
||||||
// True when seeking or otherwise moving the play position around in
|
// True when seeking or otherwise moving the play position around in
|
||||||
// such a manner that progress event data is inaccurate. This is set
|
// such a manner that progress event data is inaccurate. This is set
|
||||||
|
|
|
@ -550,18 +550,6 @@ ChannelMediaResource::OpenByteRange(nsIStreamListener** aStreamListener,
|
||||||
return OpenChannel(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)
|
nsresult ChannelMediaResource::Open(nsIStreamListener **aStreamListener)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||||
|
|
|
@ -347,12 +347,6 @@ public:
|
||||||
return Open(aStreamListener);
|
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
|
* Fills aRanges with MediaByteRanges representing the data which is cached
|
||||||
* in the media cache. Stream should be pinned during call and while
|
* in the media cache. Stream should be pinned during call and while
|
||||||
|
@ -461,7 +455,6 @@ public:
|
||||||
virtual nsresult Open(nsIStreamListener** aStreamListener);
|
virtual nsresult Open(nsIStreamListener** aStreamListener);
|
||||||
virtual nsresult OpenByteRange(nsIStreamListener** aStreamListener,
|
virtual nsresult OpenByteRange(nsIStreamListener** aStreamListener,
|
||||||
MediaByteRange const & aByteRange);
|
MediaByteRange const & aByteRange);
|
||||||
virtual void CancelByteRangeOpen();
|
|
||||||
virtual nsresult Close();
|
virtual nsresult Close();
|
||||||
virtual void Suspend(bool aCloseImmediately);
|
virtual void Suspend(bool aCloseImmediately);
|
||||||
virtual void Resume();
|
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
|
// Before loading, note the index of the decoder which will downloaded the
|
||||||
// next video subsegment.
|
// next video subsegment.
|
||||||
if (decoder == VideoRepDecoder()) {
|
if (decoder == VideoRepDecoder()) {
|
||||||
|
@ -738,20 +747,22 @@ DASHDecoder::NotifyDownloadEnded(DASHRepDecoder* aRepDecoder,
|
||||||
// Load the next range of data bytes. If the range is already cached,
|
// Load the next range of data bytes. If the range is already cached,
|
||||||
// this function will be called again to adaptively download the next
|
// this function will be called again to adaptively download the next
|
||||||
// subsegment.
|
// subsegment.
|
||||||
#ifdef PR_LOGGING
|
bool resourceLoaded = false;
|
||||||
if (decoder.get() == AudioRepDecoder()) {
|
if (decoder.get() == AudioRepDecoder()) {
|
||||||
LOG("Requesting load for audio decoder [%p] subsegment [%d].",
|
LOG("Requesting load for audio decoder [%p] subsegment [%d].",
|
||||||
decoder.get(), mAudioSubsegmentIdx);
|
decoder.get(), mAudioSubsegmentIdx);
|
||||||
|
if (mAudioSubsegmentIdx >= decoder->GetNumDataByteRanges()) {
|
||||||
|
resourceLoaded = true;
|
||||||
|
}
|
||||||
} else if (decoder.get() == VideoRepDecoder()) {
|
} else if (decoder.get() == VideoRepDecoder()) {
|
||||||
LOG("Requesting load for video decoder [%p] subsegment [%d].",
|
LOG("Requesting load for video decoder [%p] subsegment [%d].",
|
||||||
decoder.get(), mVideoSubsegmentIdx);
|
decoder.get(), mVideoSubsegmentIdx);
|
||||||
|
if (mVideoSubsegmentIdx >= decoder->GetNumDataByteRanges()) {
|
||||||
|
resourceLoaded = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
if (resourceLoaded) {
|
||||||
if (!decoder || (decoder != AudioRepDecoder() &&
|
ResourceLoaded();
|
||||||
decoder != VideoRepDecoder())) {
|
|
||||||
LOG("Invalid decoder [%p]: video idx [%d] audio idx [%d]",
|
|
||||||
decoder.get(), AudioRepDecoder(), VideoRepDecoder());
|
|
||||||
DecodeError();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
decoder->LoadNextByteRange();
|
decoder->LoadNextByteRange();
|
||||||
|
@ -1042,20 +1053,9 @@ DASHDecoder::Seek(double aTime)
|
||||||
|
|
||||||
{
|
{
|
||||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||||
// We want to stop the current series of downloads and restart later with
|
// Set the seeking flag, so that when current subsegments download (if
|
||||||
// the appropriate subsegment.
|
|
||||||
|
|
||||||
// 1 - Set the seeking flag, so that when current subsegments download (if
|
|
||||||
// any), the next subsegment will not be downloaded.
|
// any), the next subsegment will not be downloaded.
|
||||||
mSeeking = true;
|
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);
|
return MediaDecoder::Seek(aTime);
|
||||||
|
@ -1304,4 +1304,59 @@ DASHDecoder::GetStatistics()
|
||||||
return result;
|
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
|
} // namespace mozilla
|
||||||
|
|
|
@ -91,6 +91,10 @@ public:
|
||||||
// decoders. Called on the decode thread.
|
// decoders. Called on the decode thread.
|
||||||
void OnReadMetadataCompleted(DASHRepDecoder* aRepDecoder);
|
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.
|
// Refers to downloading data bytes, i.e. non metadata.
|
||||||
// Returns true if |aRepDecoder| is an active audio or video sub decoder AND
|
// Returns true if |aRepDecoder| is an active audio or video sub decoder AND
|
||||||
// if metadata for all audio or video decoders has been read.
|
// if metadata for all audio or video decoders has been read.
|
||||||
|
@ -162,6 +166,14 @@ public:
|
||||||
return (-1);
|
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
|
// Returns the index of the rep decoder used to load a subsegment. Will enter
|
||||||
// monitor for read access off the decode thread.
|
// monitor for read access off the decode thread.
|
||||||
int32_t GetRepIdxForVideoSubsegmentLoad(int32_t aSubsegmentIdx)
|
int32_t GetRepIdxForVideoSubsegmentLoad(int32_t aSubsegmentIdx)
|
||||||
|
@ -207,6 +219,15 @@ public:
|
||||||
// audio and video rep decoders.
|
// audio and video rep decoders.
|
||||||
void UpdatePlaybackRate() MOZ_OVERRIDE;
|
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.
|
// Used to estimate rates of data passing through the decoder's channel.
|
||||||
// Records activity starting on the channel. The monitor must be held.
|
// Records activity starting on the channel. The monitor must be held.
|
||||||
virtual void NotifyPlaybackStarted() MOZ_OVERRIDE;
|
virtual void NotifyPlaybackStarted() MOZ_OVERRIDE;
|
||||||
|
|
|
@ -316,43 +316,131 @@ DASHReader::GetBuffered(nsTimeRanges* aBuffered,
|
||||||
MediaResource* resource = nullptr;
|
MediaResource* resource = nullptr;
|
||||||
AbstractMediaDecoder* decoder = nullptr;
|
AbstractMediaDecoder* decoder = nullptr;
|
||||||
|
|
||||||
// Need to find intersect of |nsTimeRanges| for audio and video.
|
|
||||||
nsTimeRanges audioBuffered, videoBuffered;
|
nsTimeRanges audioBuffered, videoBuffered;
|
||||||
uint32_t audioRangeCount, videoRangeCount;
|
uint32_t audioRangeCount = 0, videoRangeCount = 0;
|
||||||
|
bool audioCachedAtEnd = false, videoCachedAtEnd = false;
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
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(),
|
ReentrantMonitorConditionallyEnter mon(!mDecoder->OnDecodeThread(),
|
||||||
mDecoder->GetReentrantMonitor());
|
mDecoder->GetReentrantMonitor());
|
||||||
if (mAudioReader) {
|
for (uint32_t i = 0; i < mAudioReaders.Length(); i++) {
|
||||||
decoder = mAudioReader->GetDecoder();
|
decoder = mAudioReaders[i]->GetDecoder();
|
||||||
NS_ENSURE_TRUE(decoder, NS_ERROR_NULL_POINTER);
|
NS_ENSURE_TRUE(decoder, NS_ERROR_NULL_POINTER);
|
||||||
resource = decoder->GetResource();
|
resource = decoder->GetResource();
|
||||||
NS_ENSURE_TRUE(resource, NS_ERROR_NULL_POINTER);
|
NS_ENSURE_TRUE(resource, NS_ERROR_NULL_POINTER);
|
||||||
resource->Pin();
|
resource->Pin();
|
||||||
rv = mAudioReader->GetBuffered(&audioBuffered, aStartTime);
|
rv = mAudioReaders[i]->GetBuffered(&audioBuffered, aStartTime);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
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();
|
resource->Unpin();
|
||||||
rv = audioBuffered.GetLength(&audioRangeCount);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
}
|
}
|
||||||
if (mVideoReader) {
|
for (uint32_t i = 0; i < mVideoReaders.Length(); i++) {
|
||||||
decoder = mVideoReader->GetDecoder();
|
decoder = mVideoReaders[i]->GetDecoder();
|
||||||
NS_ENSURE_TRUE(decoder, NS_ERROR_NULL_POINTER);
|
NS_ENSURE_TRUE(decoder, NS_ERROR_NULL_POINTER);
|
||||||
resource = decoder->GetResource();
|
resource = decoder->GetResource();
|
||||||
NS_ENSURE_TRUE(resource, NS_ERROR_NULL_POINTER);
|
NS_ENSURE_TRUE(resource, NS_ERROR_NULL_POINTER);
|
||||||
resource->Pin();
|
resource->Pin();
|
||||||
rv = mVideoReader->GetBuffered(&videoBuffered, aStartTime);
|
rv = mVideoReaders[i]->GetBuffered(&videoBuffered, aStartTime);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
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();
|
resource->Unpin();
|
||||||
rv = videoBuffered.GetLength(&videoRangeCount);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now determine buffered data for available sub-readers.
|
audioBuffered.Normalize();
|
||||||
if (mAudioReader && mVideoReader) {
|
videoBuffered.Normalize();
|
||||||
// Calculate intersecting ranges.
|
|
||||||
|
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++) {
|
for (uint32_t i = 0; i < audioRangeCount; i++) {
|
||||||
// |A|udio, |V|ideo, |I|ntersect.
|
// |A|udio, |V|ideo, |I|ntersect.
|
||||||
double startA, startV, startI;
|
double startA, startV, startI;
|
||||||
|
@ -382,9 +470,9 @@ DASHReader::GetBuffered(nsTimeRanges* aBuffered,
|
||||||
aBuffered->Add(startI, endI);
|
aBuffered->Add(startI, endI);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (mAudioReader) {
|
} else if (!mAudioReaders.IsEmpty()) {
|
||||||
*aBuffered = audioBuffered;
|
*aBuffered = audioBuffered;
|
||||||
} else if (mVideoReader) {
|
} else if (!mVideoReaders.IsEmpty()) {
|
||||||
*aBuffered = videoBuffered;
|
*aBuffered = videoBuffered;
|
||||||
} else {
|
} else {
|
||||||
return NS_ERROR_NOT_INITIALIZED;
|
return NS_ERROR_NOT_INITIALIZED;
|
||||||
|
|
|
@ -236,6 +236,16 @@ private:
|
||||||
return mSubReaderList.Length();
|
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
|
// Override '[]' to assert threads other than the decode thread are "in
|
||||||
// monitor" for accessing individual elems. Note: elems returned do not
|
// monitor" for accessing individual elems. Note: elems returned do not
|
||||||
// have monitor assertions builtin like |MonitoredSubReader| objects.
|
// 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
|
bool
|
||||||
DASHRepDecoder::IsSubsegmentCached(int32_t aSubsegmentIdx)
|
DASHRepDecoder::IsSubsegmentCached(int32_t aSubsegmentIdx)
|
||||||
{
|
{
|
||||||
|
@ -520,4 +503,16 @@ DASHRepDecoder::ReleaseStateMachine()
|
||||||
MediaDecoder::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
|
} // namespace mozilla
|
||||||
|
|
|
@ -81,9 +81,6 @@ public:
|
||||||
// thread only.
|
// thread only.
|
||||||
void LoadNextByteRange();
|
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.
|
// Returns true if the subsegment is already in the media cache.
|
||||||
bool IsSubsegmentCached(int32_t aSubsegmentIdx);
|
bool IsSubsegmentCached(int32_t aSubsegmentIdx);
|
||||||
|
|
||||||
|
@ -94,6 +91,10 @@ public:
|
||||||
// thread only.
|
// thread only.
|
||||||
void NetworkError();
|
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.
|
// 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
|
// 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.
|
// from a content header. Must be called from the main thread only.
|
||||||
|
@ -155,21 +156,30 @@ public:
|
||||||
void PrepareForSwitch();
|
void PrepareForSwitch();
|
||||||
|
|
||||||
// Returns true if the current thread is the state machine thread.
|
// 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.
|
// 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.
|
// Returns main decoder's monitor for synchronised access.
|
||||||
ReentrantMonitor& GetReentrantMonitor() MOZ_OVERRIDE;
|
ReentrantMonitor& GetReentrantMonitor() MOZ_OVERRIDE;
|
||||||
|
|
||||||
// Called on the decode thread from WebMReader.
|
// 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 when Metadata has been read; notifies that index data is read.
|
||||||
// Called on the decode thread only.
|
// Called on the decode thread only.
|
||||||
void OnReadMetadataCompleted() MOZ_OVERRIDE;
|
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.
|
// Overridden to cleanup ref to |DASHDecoder|. Called on main thread only.
|
||||||
void Shutdown() {
|
void Shutdown() {
|
||||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||||
|
|
|
@ -58,6 +58,9 @@ public:
|
||||||
// Should be implemented by a sub-reader, e.g. |nsDASHWebMReader|.
|
// Should be implemented by a sub-reader, e.g. |nsDASHWebMReader|.
|
||||||
virtual void RequestSwitchAtSubsegment(int32_t aCluster,
|
virtual void RequestSwitchAtSubsegment(int32_t aCluster,
|
||||||
MediaDecoderReader* aNextReader) = 0;
|
MediaDecoderReader* aNextReader) = 0;
|
||||||
|
|
||||||
|
// Returns true if data at the end of the final subsegment has been cached.
|
||||||
|
virtual bool IsDataCachedAtEndOfSubsegments() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}// namespace mozilla
|
}// namespace mozilla
|
||||||
|
|
|
@ -27,6 +27,7 @@ var gProgressTests = [
|
||||||
{ name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.266, size:28942 },
|
{ 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:"seek.webm", type:"video/webm", duration:3.966, size:215529 },
|
||||||
{ name:"gizmo.mp4", type:"video/mp4", duration:5.56, size:383631 },
|
{ 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" }
|
{ name:"bogus.duh", type:"bogus/duh" }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -38,6 +39,7 @@ var gPlayedTests = [
|
||||||
{ name:"seek.webm", type:"video/webm", duration:3.966 },
|
{ name:"seek.webm", type:"video/webm", duration:3.966 },
|
||||||
{ name:"gizmo.mp4", type:"video/mp4", duration:5.56 },
|
{ name:"gizmo.mp4", type:"video/mp4", duration:5.56 },
|
||||||
{ name:"owl.mp3", type:"audio/mpeg", duration:3.29 },
|
{ 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
|
// 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:"small-shot.mp3", type:"audio/mpeg", duration:0.27 },
|
||||||
{ name:"owl.mp3", type:"audio/mpeg", duration:3.29 },
|
{ 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
|
// Invalid file
|
||||||
{ name:"bogus.duh", type:"bogus/duh", duration:Number.NaN }
|
{ name:"bogus.duh", type:"bogus/duh", duration:Number.NaN }
|
||||||
];
|
];
|
||||||
|
@ -255,6 +260,12 @@ var gInfoLeakTests = [
|
||||||
}, {
|
}, {
|
||||||
type: 'video/webm',
|
type: 'video/webm',
|
||||||
src: fileUriToSrc("tests/content/media/test/404.webm", false),
|
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',
|
type: 'video/ogg',
|
||||||
src: 'http://localhost/404.ogv',
|
src: 'http://localhost/404.ogv',
|
||||||
|
@ -264,6 +275,9 @@ var gInfoLeakTests = [
|
||||||
}, {
|
}, {
|
||||||
type: 'video/webm',
|
type: 'video/webm',
|
||||||
src: 'http://localhost/404.webm',
|
src: 'http://localhost/404.webm',
|
||||||
|
}, {
|
||||||
|
type: 'application/dash+xml',
|
||||||
|
src: 'http://localhost/404.mpd',
|
||||||
}, {
|
}, {
|
||||||
type: 'video/ogg',
|
type: 'video/ogg',
|
||||||
src: 'http://example.com/tests/content/media/test/test_info_leak.html'
|
src: 'http://example.com/tests/content/media/test/test_info_leak.html'
|
||||||
|
|
|
@ -81,7 +81,7 @@ function listener(evt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMedia(type, src, token) {
|
function createMedia(type, src, token) {
|
||||||
var tag = /^video/.test(type) ? "video" : "audio";
|
var tag = getMajorMimeType(test.type);
|
||||||
var v = document.createElement(tag);
|
var v = document.createElement(tag);
|
||||||
for (var i=0; i<gEventTypes.length; i++) {
|
for (var i=0; i<gEventTypes.length; i++) {
|
||||||
v.addEventListener(gEventTypes[i], listener, false);
|
v.addEventListener(gEventTypes[i], listener, false);
|
||||||
|
|
|
@ -207,7 +207,7 @@ function createTestArray() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function startTest(test, token) {
|
function startTest(test, token) {
|
||||||
var elemType = /^audio/.test(test.type) ? "audio" : "video";
|
var elemType = getMajorMimeType(test.type);
|
||||||
var element = document.createElement(elemType);
|
var element = document.createElement(elemType);
|
||||||
element.src = test.name;
|
element.src = test.name;
|
||||||
element.token = token;
|
element.token = token;
|
||||||
|
|
|
@ -50,7 +50,7 @@ function createTestArray() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function startTest(test, token) {
|
function startTest(test, token) {
|
||||||
var elemType = /^audio/.test(test.type) ? "audio" : "video";
|
var elemType = getMajorMimeType(test.type);
|
||||||
var element = document.createElement(elemType);
|
var element = document.createElement(elemType);
|
||||||
element.src = test.name;
|
element.src = test.name;
|
||||||
element.token = token;
|
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
|
// We can't play WAV files in stand alone documents, so just don't
|
||||||
// run the test on non-video content types.
|
// run the test on non-video content types.
|
||||||
var isVideo = /^video/.test(test.type) ? true : false;
|
var tag = getMajorMimeType(test.type);
|
||||||
if (!isVideo || !document.createElement("video").canPlayType(test.type))
|
if (tag != "video" || !document.createElement("video").canPlayType(test.type))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var f = document.createElement("iframe");
|
var f = document.createElement("iframe");
|
||||||
|
|
|
@ -20,15 +20,10 @@ namespace dom {
|
||||||
* This class will be instantiated with different template arguments for testing and
|
* This class will be instantiated with different template arguments for testing and
|
||||||
* production code.
|
* 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:
|
* ErrorResult is a type which satisfies the following:
|
||||||
* - Implements a Throw() method taking an nsresult argument, representing an error code.
|
* - Implements a Throw() method taking an nsresult argument, representing an error code.
|
||||||
*/
|
*/
|
||||||
template <class FloatArrayWrapper, class ErrorResult>
|
template <class ErrorResult>
|
||||||
class AudioEventTimeline
|
class AudioEventTimeline
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
@ -42,15 +37,17 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
Event(Type aType, double aTime, float aValue, double aTimeConstant = 0.0,
|
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)
|
: mType(aType)
|
||||||
, mValue(aValue)
|
|
||||||
, mTime(aTime)
|
|
||||||
, mTimeConstant(aTimeConstant)
|
, mTimeConstant(aTimeConstant)
|
||||||
, mDuration(aDuration)
|
, mDuration(aDuration)
|
||||||
{
|
{
|
||||||
if (aCurve.inited()) {
|
if (aType == Event::SetValueCurve) {
|
||||||
mCurve = aCurve;
|
mCurve = aCurve;
|
||||||
|
mCurveLength = aCurveLength;
|
||||||
|
} else {
|
||||||
|
mValue = aValue;
|
||||||
|
mTime = aTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,31 +60,28 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
Type mType;
|
Type mType;
|
||||||
float mValue;
|
union {
|
||||||
double mTime;
|
float mValue;
|
||||||
|
uint32_t mCurveLength;
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
double mTime;
|
||||||
|
float* mCurve;
|
||||||
|
};
|
||||||
double mTimeConstant;
|
double mTimeConstant;
|
||||||
double mDuration;
|
double mDuration;
|
||||||
FloatArrayWrapper mCurve;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool IsValid(float value)
|
static bool IsValid(double value)
|
||||||
{
|
{
|
||||||
return MOZ_DOUBLE_IS_FINITE(value);
|
return MOZ_DOUBLE_IS_FINITE(value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AudioEventTimeline(float aDefaultValue,
|
explicit AudioEventTimeline(float aDefaultValue)
|
||||||
float aMinValue,
|
|
||||||
float aMaxValue)
|
|
||||||
: mValue(aDefaultValue)
|
: mValue(aDefaultValue)
|
||||||
, mDefaultValue(aDefaultValue)
|
|
||||||
, mMinValue(aMinValue)
|
|
||||||
, mMaxValue(aMaxValue)
|
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aDefaultValue >= aMinValue);
|
|
||||||
MOZ_ASSERT(aDefaultValue <= aMaxValue);
|
|
||||||
MOZ_ASSERT(aMinValue < aMaxValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float Value() const
|
float Value() const
|
||||||
|
@ -110,21 +104,6 @@ public:
|
||||||
return 0;
|
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)
|
void SetValueAtTime(float aValue, double aStartTime, ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
InsertEvent(Event(Event::SetValue, aStartTime, aValue), aRv);
|
InsertEvent(Event(Event::SetValue, aStartTime, aValue), aRv);
|
||||||
|
@ -145,10 +124,11 @@ public:
|
||||||
InsertEvent(Event(Event::SetTarget, aStartTime, aTarget, aTimeConstant), aRv);
|
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
|
// 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)
|
void CancelScheduledValues(double aStartTime)
|
||||||
|
@ -377,9 +357,6 @@ private:
|
||||||
// being a bottleneck.
|
// being a bottleneck.
|
||||||
nsTArray<Event> mEvents;
|
nsTArray<Event> mEvents;
|
||||||
float mValue;
|
float mValue;
|
||||||
const float mDefaultValue;
|
|
||||||
const float mMinValue;
|
|
||||||
const float mMaxValue;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,20 +40,20 @@ public:
|
||||||
virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope,
|
virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope,
|
||||||
bool* aTriedToWrap);
|
bool* aTriedToWrap);
|
||||||
|
|
||||||
double DopplerFactor() const
|
float DopplerFactor() const
|
||||||
{
|
{
|
||||||
return mDopplerFactor;
|
return mDopplerFactor;
|
||||||
}
|
}
|
||||||
void SetDopplerFactor(double aDopplerFactor)
|
void SetDopplerFactor(float aDopplerFactor)
|
||||||
{
|
{
|
||||||
mDopplerFactor = aDopplerFactor;
|
mDopplerFactor = aDopplerFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
double SpeedOfSound() const
|
float SpeedOfSound() const
|
||||||
{
|
{
|
||||||
return mSpeedOfSound;
|
return mSpeedOfSound;
|
||||||
}
|
}
|
||||||
void SetSpeedOfSound(double aSpeedOfSound)
|
void SetSpeedOfSound(float aSpeedOfSound)
|
||||||
{
|
{
|
||||||
mSpeedOfSound = aSpeedOfSound;
|
mSpeedOfSound = aSpeedOfSound;
|
||||||
}
|
}
|
||||||
|
@ -89,8 +89,8 @@ private:
|
||||||
ThreeDPoint mOrientation;
|
ThreeDPoint mOrientation;
|
||||||
ThreeDPoint mUpVector;
|
ThreeDPoint mUpVector;
|
||||||
ThreeDPoint mVelocity;
|
ThreeDPoint mVelocity;
|
||||||
double mDopplerFactor;
|
float mDopplerFactor;
|
||||||
double mSpeedOfSound;
|
float mSpeedOfSound;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,9 +22,15 @@ AudioParam::AudioParam(AudioContext* aContext,
|
||||||
float aDefaultValue,
|
float aDefaultValue,
|
||||||
float aMinValue,
|
float aMinValue,
|
||||||
float aMaxValue)
|
float aMaxValue)
|
||||||
: AudioParamTimeline(aDefaultValue, aMinValue, aMaxValue)
|
: AudioParamTimeline(aDefaultValue)
|
||||||
, mContext(aContext)
|
, mContext(aContext)
|
||||||
|
, mDefaultValue(aDefaultValue)
|
||||||
|
, mMinValue(aMinValue)
|
||||||
|
, mMaxValue(aMaxValue)
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(aDefaultValue >= aMinValue);
|
||||||
|
MOZ_ASSERT(aDefaultValue <= aMaxValue);
|
||||||
|
MOZ_ASSERT(aMinValue < aMaxValue);
|
||||||
SetIsDOMBinding();
|
SetIsDOMBinding();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,57 +26,7 @@ class ErrorResult;
|
||||||
|
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
namespace detail {
|
typedef AudioEventTimeline<ErrorResult> AudioParamTimeline;
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
class AudioParam MOZ_FINAL : public nsWrapperCache,
|
class AudioParam MOZ_FINAL : public nsWrapperCache,
|
||||||
public EnableWebAudioCheck,
|
public EnableWebAudioCheck,
|
||||||
|
@ -104,12 +54,30 @@ public:
|
||||||
// object.
|
// object.
|
||||||
void SetValueCurveAtTime(JSContext* cx, const Float32Array& aValues, double aStartTime, double aDuration, ErrorResult& aRv)
|
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);
|
aStartTime, aDuration, aRv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float MinValue() const
|
||||||
|
{
|
||||||
|
return mMinValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float MaxValue() const
|
||||||
|
{
|
||||||
|
return mMaxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float DefaultValue() const
|
||||||
|
{
|
||||||
|
return mDefaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsRefPtr<AudioContext> mContext;
|
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());
|
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
|
class ErrorResultMock
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -92,15 +74,13 @@ private:
|
||||||
nsresult mRv;
|
nsresult mRv;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef AudioEventTimeline<FloatArrayMock, ErrorResultMock> Timeline;
|
typedef AudioEventTimeline<ErrorResultMock> Timeline;
|
||||||
|
|
||||||
void TestSpecExample()
|
void TestSpecExample()
|
||||||
{
|
{
|
||||||
// First, run the basic tests
|
// First, run the basic tests
|
||||||
Timeline timeline(10.0f, .1f, 20.0f);
|
Timeline timeline(10.0f);
|
||||||
is(timeline.DefaultValue(), 10.0f, "Correct default value returned");
|
is(timeline.Value(), 10.0f, "Correct default value returned");
|
||||||
is(timeline.MinValue(), .1f, "Correct min value returned");
|
|
||||||
is(timeline.MaxValue(), 20.0f, "Correct max value returned");
|
|
||||||
|
|
||||||
ErrorResultMock rv;
|
ErrorResultMock rv;
|
||||||
|
|
||||||
|
@ -152,7 +132,7 @@ void TestInvalidEvents()
|
||||||
MOZ_STATIC_ASSERT(numeric_limits<float>::has_quiet_NaN, "Platform must have a quiet NaN");
|
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 NaN = numeric_limits<float>::quiet_NaN();
|
||||||
const float Infinity = numeric_limits<float>::infinity();
|
const float Infinity = numeric_limits<float>::infinity();
|
||||||
Timeline timeline(10.0f, .1f, 20.0f);
|
Timeline timeline(10.0f);
|
||||||
|
|
||||||
ErrorResultMock rv;
|
ErrorResultMock rv;
|
||||||
|
|
||||||
|
@ -191,7 +171,7 @@ void TestInvalidEvents()
|
||||||
|
|
||||||
void TestEventReplacement()
|
void TestEventReplacement()
|
||||||
{
|
{
|
||||||
Timeline timeline(10.0f, .1f, 20.0f);
|
Timeline timeline(10.0f);
|
||||||
|
|
||||||
ErrorResultMock rv;
|
ErrorResultMock rv;
|
||||||
|
|
||||||
|
@ -210,7 +190,7 @@ void TestEventReplacement()
|
||||||
|
|
||||||
void TestEventRemoval()
|
void TestEventRemoval()
|
||||||
{
|
{
|
||||||
Timeline timeline(10.0f, .1f, 20.0f);
|
Timeline timeline(10.0f);
|
||||||
|
|
||||||
ErrorResultMock rv;
|
ErrorResultMock rv;
|
||||||
|
|
||||||
|
@ -229,7 +209,7 @@ void TestEventRemoval()
|
||||||
|
|
||||||
void TestBeforeFirstEvent()
|
void TestBeforeFirstEvent()
|
||||||
{
|
{
|
||||||
Timeline timeline(10.0f, .1f, 20.0f);
|
Timeline timeline(10.0f);
|
||||||
|
|
||||||
ErrorResultMock rv;
|
ErrorResultMock rv;
|
||||||
|
|
||||||
|
@ -239,7 +219,7 @@ void TestBeforeFirstEvent()
|
||||||
|
|
||||||
void TestAfterLastValueEvent()
|
void TestAfterLastValueEvent()
|
||||||
{
|
{
|
||||||
Timeline timeline(10.0f, .1f, 20.0f);
|
Timeline timeline(10.0f);
|
||||||
|
|
||||||
ErrorResultMock rv;
|
ErrorResultMock rv;
|
||||||
|
|
||||||
|
@ -249,7 +229,7 @@ void TestAfterLastValueEvent()
|
||||||
|
|
||||||
void TestAfterLastTargetValueEvent()
|
void TestAfterLastTargetValueEvent()
|
||||||
{
|
{
|
||||||
Timeline timeline(10.0f, .1f, 20.0f);
|
Timeline timeline(10.0f);
|
||||||
|
|
||||||
ErrorResultMock rv;
|
ErrorResultMock rv;
|
||||||
|
|
||||||
|
@ -259,7 +239,7 @@ void TestAfterLastTargetValueEvent()
|
||||||
|
|
||||||
void TestAfterLastTargetValueEventWithValueSet()
|
void TestAfterLastTargetValueEventWithValueSet()
|
||||||
{
|
{
|
||||||
Timeline timeline(10.0f, .1f, 20.0f);
|
Timeline timeline(10.0f);
|
||||||
|
|
||||||
ErrorResultMock rv;
|
ErrorResultMock rv;
|
||||||
|
|
||||||
|
@ -270,7 +250,7 @@ void TestAfterLastTargetValueEventWithValueSet()
|
||||||
|
|
||||||
void TestValue()
|
void TestValue()
|
||||||
{
|
{
|
||||||
Timeline timeline(10.0f, .1f, 20.0f);
|
Timeline timeline(10.0f);
|
||||||
|
|
||||||
ErrorResultMock rv;
|
ErrorResultMock rv;
|
||||||
|
|
||||||
|
@ -286,7 +266,7 @@ void TestValue()
|
||||||
|
|
||||||
void TestLinearRampAtZero()
|
void TestLinearRampAtZero()
|
||||||
{
|
{
|
||||||
Timeline timeline(10.0f, .1f, 20.0f);
|
Timeline timeline(10.0f);
|
||||||
|
|
||||||
ErrorResultMock rv;
|
ErrorResultMock rv;
|
||||||
|
|
||||||
|
@ -296,7 +276,7 @@ void TestLinearRampAtZero()
|
||||||
|
|
||||||
void TestExponentialRampAtZero()
|
void TestExponentialRampAtZero()
|
||||||
{
|
{
|
||||||
Timeline timeline(10.0f, .1f, 20.0f);
|
Timeline timeline(10.0f);
|
||||||
|
|
||||||
ErrorResultMock rv;
|
ErrorResultMock rv;
|
||||||
|
|
||||||
|
@ -306,7 +286,7 @@ void TestExponentialRampAtZero()
|
||||||
|
|
||||||
void TestLinearRampAtSameTime()
|
void TestLinearRampAtSameTime()
|
||||||
{
|
{
|
||||||
Timeline timeline(10.0f, .1f, 20.0f);
|
Timeline timeline(10.0f);
|
||||||
|
|
||||||
ErrorResultMock rv;
|
ErrorResultMock rv;
|
||||||
|
|
||||||
|
@ -317,7 +297,7 @@ void TestLinearRampAtSameTime()
|
||||||
|
|
||||||
void TestExponentialRampAtSameTime()
|
void TestExponentialRampAtSameTime()
|
||||||
{
|
{
|
||||||
Timeline timeline(10.0f, .1f, 20.0f);
|
Timeline timeline(10.0f);
|
||||||
|
|
||||||
ErrorResultMock rv;
|
ErrorResultMock rv;
|
||||||
|
|
||||||
|
@ -328,7 +308,7 @@ void TestExponentialRampAtSameTime()
|
||||||
|
|
||||||
void TestSetTargetZeroTimeConstant()
|
void TestSetTargetZeroTimeConstant()
|
||||||
{
|
{
|
||||||
Timeline timeline(10.0f, .1f, 20.0f);
|
Timeline timeline(10.0f);
|
||||||
|
|
||||||
ErrorResultMock rv;
|
ErrorResultMock rv;
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ PRLogModuleInfo* gNesteggLog;
|
||||||
|
|
||||||
static const unsigned NS_PER_USEC = 1000;
|
static const unsigned NS_PER_USEC = 1000;
|
||||||
static const double NS_PER_S = 1e9;
|
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
|
// If a seek request is within SEEK_DECODE_MARGIN microseconds of the
|
||||||
// current time, decode ahead from the current frame rather than performing
|
// 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);
|
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)
|
nsresult WebMReader::GetBuffered(nsTimeRanges* aBuffered, int64_t aStartTime)
|
||||||
{
|
{
|
||||||
MediaResource* resource = mDecoder->GetResource();
|
MediaResource* resource = mDecoder->GetResource();
|
||||||
|
@ -955,7 +988,29 @@ nsresult WebMReader::GetBuffered(nsTimeRanges* aBuffered, int64_t aStartTime)
|
||||||
if (rv) {
|
if (rv) {
|
||||||
double startTime = start * timecodeScale / NS_PER_S - aStartTime;
|
double startTime = start * timecodeScale / NS_PER_S - aStartTime;
|
||||||
double endTime = end * 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
|
// If this range extends to the end of the file, the true end time
|
||||||
// is the file's duration.
|
// is the file's duration.
|
||||||
if (resource->IsDataCachedToEndOfResource(ranges[index].mStart)) {
|
if (resource->IsDataCachedToEndOfResource(ranges[index].mStart)) {
|
||||||
|
|
|
@ -208,6 +208,9 @@ public:
|
||||||
// Seeks to the beginning of the specified cluster. Called on the decode
|
// Seeks to the beginning of the specified cluster. Called on the decode
|
||||||
// thread.
|
// thread.
|
||||||
void SeekToCluster(uint32_t aIdx);
|
void SeekToCluster(uint32_t aIdx);
|
||||||
|
|
||||||
|
// Returns true if data at the end of the final subsegment has been cached.
|
||||||
|
bool IsDataCachedAtEndOfSubsegments() MOZ_OVERRIDE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -481,7 +481,6 @@ using mozilla::dom::workers::ResolveWorkerClasses;
|
||||||
#include "BluetoothManager.h"
|
#include "BluetoothManager.h"
|
||||||
#include "BluetoothAdapter.h"
|
#include "BluetoothAdapter.h"
|
||||||
#include "BluetoothDevice.h"
|
#include "BluetoothDevice.h"
|
||||||
#include "BluetoothPropertyEvent.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "nsIDOMNavigatorSystemMessages.h"
|
#include "nsIDOMNavigatorSystemMessages.h"
|
||||||
|
@ -1518,11 +1517,9 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||||
NS_DEFINE_CLASSINFO_DATA(BluetoothManager, nsEventTargetSH,
|
NS_DEFINE_CLASSINFO_DATA(BluetoothManager, nsEventTargetSH,
|
||||||
EVENTTARGET_SCRIPTABLE_FLAGS)
|
EVENTTARGET_SCRIPTABLE_FLAGS)
|
||||||
NS_DEFINE_CLASSINFO_DATA(BluetoothAdapter, nsEventTargetSH,
|
NS_DEFINE_CLASSINFO_DATA(BluetoothAdapter, nsEventTargetSH,
|
||||||
EVENTTARGET_SCRIPTABLE_FLAGS)
|
EVENTTARGET_SCRIPTABLE_FLAGS)
|
||||||
NS_DEFINE_CLASSINFO_DATA(BluetoothDevice, nsEventTargetSH,
|
NS_DEFINE_CLASSINFO_DATA(BluetoothDevice, nsEventTargetSH,
|
||||||
EVENTTARGET_SCRIPTABLE_FLAGS)
|
EVENTTARGET_SCRIPTABLE_FLAGS)
|
||||||
NS_DEFINE_CLASSINFO_DATA(BluetoothPropertyEvent, nsDOMGenericSH,
|
|
||||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
NS_DEFINE_CLASSINFO_DATA(CameraManager, nsDOMGenericSH,
|
NS_DEFINE_CLASSINFO_DATA(CameraManager, nsDOMGenericSH,
|
||||||
|
@ -3945,15 +3942,10 @@ nsDOMClassInfo::Init()
|
||||||
DOM_CLASSINFO_MAP_BEGIN(BluetoothAdapter, nsIDOMBluetoothAdapter)
|
DOM_CLASSINFO_MAP_BEGIN(BluetoothAdapter, nsIDOMBluetoothAdapter)
|
||||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothAdapter)
|
DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothAdapter)
|
||||||
DOM_CLASSINFO_MAP_END
|
DOM_CLASSINFO_MAP_END
|
||||||
|
|
||||||
DOM_CLASSINFO_MAP_BEGIN(BluetoothDevice, nsIDOMBluetoothDevice)
|
DOM_CLASSINFO_MAP_BEGIN(BluetoothDevice, nsIDOMBluetoothDevice)
|
||||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothDevice)
|
DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothDevice)
|
||||||
DOM_CLASSINFO_MAP_END
|
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
|
#endif
|
||||||
|
|
||||||
DOM_CLASSINFO_MAP_BEGIN(CameraManager, nsIDOMCameraManager)
|
DOM_CLASSINFO_MAP_BEGIN(CameraManager, nsIDOMCameraManager)
|
||||||
|
|
|
@ -445,7 +445,6 @@ DOMCI_CLASS(FMRadio)
|
||||||
DOMCI_CLASS(BluetoothManager)
|
DOMCI_CLASS(BluetoothManager)
|
||||||
DOMCI_CLASS(BluetoothAdapter)
|
DOMCI_CLASS(BluetoothAdapter)
|
||||||
DOMCI_CLASS(BluetoothDevice)
|
DOMCI_CLASS(BluetoothDevice)
|
||||||
DOMCI_CLASS(BluetoothPropertyEvent)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DOMCI_CLASS(CameraManager)
|
DOMCI_CLASS(CameraManager)
|
||||||
|
|
|
@ -5848,7 +5848,9 @@ class CGProxyUnwrap(CGAbstractMethod):
|
||||||
def declare(self):
|
def declare(self):
|
||||||
return ""
|
return ""
|
||||||
def definition_body(self):
|
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);
|
obj = js::UnwrapObject(obj);
|
||||||
}
|
}
|
||||||
MOZ_ASSERT(IsProxy(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.
|
// 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;
|
double toTruncate = (d < 0) ? d - 0.5 : d + 0.5;
|
||||||
|
|
||||||
T truncated(toTruncate);
|
T truncated = static_cast<T>(toTruncate);
|
||||||
|
|
||||||
if (truncated == 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))
|
if (!PrimitiveConversionTraits<T, B>::converter(cx, v, &t))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
*retval =
|
*retval = static_cast<T>(
|
||||||
static_cast<typename PrimitiveConversionTraits<T, B>::intermediateType>(t);
|
static_cast<typename PrimitiveConversionTraits<T, B>::intermediateType>(t));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#include "base/basictypes.h"
|
#include "base/basictypes.h"
|
||||||
#include "BluetoothAdapter.h"
|
#include "BluetoothAdapter.h"
|
||||||
#include "BluetoothDevice.h"
|
#include "BluetoothDevice.h"
|
||||||
#include "BluetoothPropertyEvent.h"
|
|
||||||
#include "BluetoothReplyRunnable.h"
|
#include "BluetoothReplyRunnable.h"
|
||||||
#include "BluetoothService.h"
|
#include "BluetoothService.h"
|
||||||
#include "BluetoothUtils.h"
|
#include "BluetoothUtils.h"
|
||||||
|
@ -15,13 +14,11 @@
|
||||||
|
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsDOMClassInfo.h"
|
#include "nsDOMClassInfo.h"
|
||||||
#include "nsDOMEvent.h"
|
|
||||||
#include "nsIDOMBluetoothDeviceAddressEvent.h"
|
#include "nsIDOMBluetoothDeviceAddressEvent.h"
|
||||||
#include "nsIDOMBluetoothDeviceEvent.h"
|
#include "nsIDOMBluetoothDeviceEvent.h"
|
||||||
#include "nsIDOMDOMRequest.h"
|
|
||||||
#include "nsTArrayHelpers.h"
|
#include "nsTArrayHelpers.h"
|
||||||
|
#include "DOMRequest.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
#include "nsXPCOMCIDInternal.h"
|
|
||||||
|
|
||||||
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
|
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
|
||||||
#include "mozilla/dom/ContentChild.h"
|
#include "mozilla/dom/ContentChild.h"
|
||||||
|
@ -72,24 +69,30 @@ public:
|
||||||
virtual bool ParseSuccessfulReply(jsval* aValue)
|
virtual bool ParseSuccessfulReply(jsval* aValue)
|
||||||
{
|
{
|
||||||
*aValue = JSVAL_VOID;
|
*aValue = JSVAL_VOID;
|
||||||
BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
|
|
||||||
|
const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
|
||||||
if (v.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
|
if (v.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
|
||||||
NS_WARNING("Not a BluetoothNamedValue array!");
|
NS_WARNING("Not a BluetoothNamedValue array!");
|
||||||
|
SetError(NS_LITERAL_STRING("BluetoothReplyTypeError"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const InfallibleTArray<BluetoothNamedValue>& reply =
|
const InfallibleTArray<BluetoothNamedValue>& values =
|
||||||
mReply->get_BluetoothReplySuccess().value().get_ArrayOfBluetoothNamedValue();
|
v.get_ArrayOfBluetoothNamedValue();
|
||||||
|
|
||||||
nsTArray<nsRefPtr<BluetoothDevice> > devices;
|
nsTArray<nsRefPtr<BluetoothDevice> > devices;
|
||||||
JSObject* JsDevices;
|
JSObject* JsDevices;
|
||||||
for (uint32_t i = 0; i < reply.Length(); i++) {
|
for (uint32_t i = 0; i < values.Length(); i++) {
|
||||||
if (reply[i].value().type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
|
const BluetoothValue properties = values[i].value();
|
||||||
|
if (properties.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
|
||||||
NS_WARNING("Not a BluetoothNamedValue array!");
|
NS_WARNING("Not a BluetoothNamedValue array!");
|
||||||
|
SetError(NS_LITERAL_STRING("BluetoothReplyTypeError"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
nsRefPtr<BluetoothDevice> d = BluetoothDevice::Create(mAdapterPtr->GetOwner(),
|
nsRefPtr<BluetoothDevice> d =
|
||||||
mAdapterPtr->GetPath(),
|
BluetoothDevice::Create(mAdapterPtr->GetOwner(),
|
||||||
reply[i].value());
|
mAdapterPtr->GetPath(),
|
||||||
|
properties);
|
||||||
devices.AppendElement(d);
|
devices.AppendElement(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,18 +100,18 @@ public:
|
||||||
nsIScriptContext* sc = mAdapterPtr->GetContextForEventHandlers(&rv);
|
nsIScriptContext* sc = mAdapterPtr->GetContextForEventHandlers(&rv);
|
||||||
if (!sc) {
|
if (!sc) {
|
||||||
NS_WARNING("Cannot create script context!");
|
NS_WARNING("Cannot create script context!");
|
||||||
|
SetError(NS_LITERAL_STRING("BluetoothScriptContextError"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = nsTArrayToJSArray(sc->GetNativeContext(), devices, &JsDevices);
|
rv = nsTArrayToJSArray(sc->GetNativeContext(), devices, &JsDevices);
|
||||||
|
if (!JsDevices) {
|
||||||
if (JsDevices) {
|
NS_WARNING("Cannot create JS array!");
|
||||||
aValue->setObject(*JsDevices);
|
SetError(NS_LITERAL_STRING("BluetoothError"));
|
||||||
}
|
|
||||||
else {
|
|
||||||
NS_WARNING("Paird not yet set!");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aValue->setObject(*JsDevices);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,18 +127,35 @@ private:
|
||||||
|
|
||||||
static int kCreatePairedDeviceTimeout = 50000; // unit: msec
|
static int kCreatePairedDeviceTimeout = 50000; // unit: msec
|
||||||
|
|
||||||
BluetoothAdapter::BluetoothAdapter(nsPIDOMWindow* aOwner, const BluetoothValue& aValue)
|
nsresult
|
||||||
: BluetoothPropertyContainer(BluetoothObjectType::TYPE_ADAPTER)
|
PrepareDOMRequest(nsIDOMWindow* aWindow, nsIDOMDOMRequest** aRequest)
|
||||||
, mEnabled(false)
|
|
||||||
, mDiscoverable(false)
|
|
||||||
, mDiscovering(false)
|
|
||||||
, mPairable(false)
|
|
||||||
, mPowered(false)
|
|
||||||
, mJsUuids(nullptr)
|
|
||||||
, mJsDeviceAddresses(nullptr)
|
|
||||||
, mIsRooted(false)
|
|
||||||
{
|
{
|
||||||
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 =
|
const InfallibleTArray<BluetoothNamedValue>& values =
|
||||||
aValue.get_ArrayOfBluetoothNamedValue();
|
aValue.get_ArrayOfBluetoothNamedValue();
|
||||||
for (uint32_t i = 0; i < values.Length(); ++i) {
|
for (uint32_t i = 0; i < values.Length(); ++i) {
|
||||||
|
@ -148,8 +168,6 @@ BluetoothAdapter::~BluetoothAdapter()
|
||||||
BluetoothService* bs = BluetoothService::Get();
|
BluetoothService* bs = BluetoothService::Get();
|
||||||
// We can be null on shutdown, where this might happen
|
// We can be null on shutdown, where this might happen
|
||||||
if (bs) {
|
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);
|
bs->UnregisterBluetoothSignalHandler(mPath, this);
|
||||||
}
|
}
|
||||||
Unroot();
|
Unroot();
|
||||||
|
@ -188,8 +206,6 @@ BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue)
|
||||||
mAddress = value.get_nsString();
|
mAddress = value.get_nsString();
|
||||||
} else if (name.EqualsLiteral("Path")) {
|
} else if (name.EqualsLiteral("Path")) {
|
||||||
mPath = value.get_nsString();
|
mPath = value.get_nsString();
|
||||||
} else if (name.EqualsLiteral("Enabled")) {
|
|
||||||
mEnabled = value.get_bool();
|
|
||||||
} else if (name.EqualsLiteral("Discoverable")) {
|
} else if (name.EqualsLiteral("Discoverable")) {
|
||||||
mDiscoverable = value.get_bool();
|
mDiscoverable = value.get_bool();
|
||||||
} else if (name.EqualsLiteral("Discovering")) {
|
} else if (name.EqualsLiteral("Discovering")) {
|
||||||
|
@ -208,33 +224,24 @@ BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue)
|
||||||
mUuids = value.get_ArrayOfnsString();
|
mUuids = value.get_ArrayOfnsString();
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
|
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
|
||||||
if (sc) {
|
NS_ENSURE_SUCCESS_VOID(rv);
|
||||||
rv =
|
|
||||||
nsTArrayToJSArray(sc->GetNativeContext(), mUuids, &mJsUuids);
|
if (!SetJsObject(sc->GetNativeContext(), value, mJsUuids)) {
|
||||||
if (NS_FAILED(rv)) {
|
NS_WARNING("Cannot set JS UUIDs object!");
|
||||||
NS_WARNING("Cannot set JS UUIDs object!");
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
Root();
|
|
||||||
} else {
|
|
||||||
NS_WARNING("Could not get context!");
|
|
||||||
}
|
}
|
||||||
|
Root();
|
||||||
} else if (name.EqualsLiteral("Devices")) {
|
} else if (name.EqualsLiteral("Devices")) {
|
||||||
mDeviceAddresses = value.get_ArrayOfnsString();
|
mDeviceAddresses = value.get_ArrayOfnsString();
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
|
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
|
||||||
if (sc) {
|
NS_ENSURE_SUCCESS_VOID(rv);
|
||||||
rv =
|
|
||||||
nsTArrayToJSArray(sc->GetNativeContext(), mDeviceAddresses,
|
if (!SetJsObject(sc->GetNativeContext(), value, mJsDeviceAddresses)) {
|
||||||
&mJsDeviceAddresses);
|
NS_WARNING("Cannot set JS Devices object!");
|
||||||
if (NS_FAILED(rv)) {
|
return;
|
||||||
NS_WARNING("Cannot set JS Device Addresses object!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Root();
|
|
||||||
} else {
|
|
||||||
NS_WARNING("Could not get context!");
|
|
||||||
}
|
}
|
||||||
|
Root();
|
||||||
} else {
|
} else {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
nsCString warningMsg;
|
nsCString warningMsg;
|
||||||
|
@ -247,16 +254,15 @@ BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue)
|
||||||
|
|
||||||
// static
|
// static
|
||||||
already_AddRefed<BluetoothAdapter>
|
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();
|
BluetoothService* bs = BluetoothService::Get();
|
||||||
if (!bs) {
|
NS_ENSURE_TRUE(bs, nullptr);
|
||||||
NS_WARNING("BluetoothService not available!");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsRefPtr<BluetoothAdapter> adapter = new BluetoothAdapter(aOwner, aValue);
|
|
||||||
|
|
||||||
|
nsRefPtr<BluetoothAdapter> adapter = new BluetoothAdapter(aWindow, aValue);
|
||||||
bs->RegisterBluetoothSignalHandler(adapter->GetPath(), adapter);
|
bs->RegisterBluetoothSignalHandler(adapter->GetPath(), adapter);
|
||||||
|
|
||||||
return adapter.forget();
|
return adapter.forget();
|
||||||
|
@ -267,6 +273,9 @@ BluetoothAdapter::Notify(const BluetoothSignal& aData)
|
||||||
{
|
{
|
||||||
InfallibleTArray<BluetoothNamedValue> arr;
|
InfallibleTArray<BluetoothNamedValue> arr;
|
||||||
|
|
||||||
|
BT_LOG("[A] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
|
||||||
|
|
||||||
|
BluetoothValue v = aData.value();
|
||||||
if (aData.name().EqualsLiteral("DeviceFound")) {
|
if (aData.name().EqualsLiteral("DeviceFound")) {
|
||||||
nsRefPtr<BluetoothDevice> device = BluetoothDevice::Create(GetOwner(), mPath, aData.value());
|
nsRefPtr<BluetoothDevice> device = BluetoothDevice::Create(GetOwner(), mPath, aData.value());
|
||||||
nsCOMPtr<nsIDOMEvent> event;
|
nsCOMPtr<nsIDOMEvent> event;
|
||||||
|
@ -301,16 +310,14 @@ BluetoothAdapter::Notify(const BluetoothSignal& aData)
|
||||||
false, false, device);
|
false, false, device);
|
||||||
DispatchTrustedEvent(e);
|
DispatchTrustedEvent(e);
|
||||||
} else if (aData.name().EqualsLiteral("PropertyChanged")) {
|
} else if (aData.name().EqualsLiteral("PropertyChanged")) {
|
||||||
NS_ASSERTION(aData.value().type() == BluetoothValue::TArrayOfBluetoothNamedValue,
|
NS_ASSERTION(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue,
|
||||||
"PropertyChanged: Invalid value type");
|
"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!");
|
NS_ASSERTION(arr.Length() == 1,
|
||||||
BluetoothNamedValue v = arr[0];
|
"Got more than one property in a change message!");
|
||||||
|
SetPropertyByValue(arr[0]);
|
||||||
SetPropertyByValue(v);
|
|
||||||
nsRefPtr<BluetoothPropertyEvent> e = BluetoothPropertyEvent::Create(v.name());
|
|
||||||
e->Dispatch(ToIDOMEventTarget(), NS_LITERAL_STRING("propertychanged"));
|
|
||||||
} else {
|
} else {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
nsCString warningMsg;
|
nsCString warningMsg;
|
||||||
|
@ -324,42 +331,30 @@ BluetoothAdapter::Notify(const BluetoothSignal& aData)
|
||||||
nsresult
|
nsresult
|
||||||
BluetoothAdapter::StartStopDiscovery(bool aStart, nsIDOMDOMRequest** aRequest)
|
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;
|
nsCOMPtr<nsIDOMDOMRequest> req;
|
||||||
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
|
nsresult rv;
|
||||||
if (NS_FAILED(rv)) {
|
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
|
||||||
NS_WARNING("Can't create DOMRequest!");
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
|
||||||
return 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) {
|
if (aStart) {
|
||||||
rv = bs->StartDiscoveryInternal(mPath, results);
|
rv = bs->StartDiscoveryInternal(mPath, results);
|
||||||
} else {
|
} else {
|
||||||
rv = bs->StopDiscoveryInternal(mPath, results);
|
rv = bs->StopDiscoveryInternal(mPath, results);
|
||||||
}
|
}
|
||||||
if (NS_FAILED(rv)) {
|
if(NS_FAILED(rv)) {
|
||||||
NS_WARNING("Starting discovery failed!");
|
NS_WARNING("Start/Stop Discovery failed!");
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
req.forget(aRequest);
|
|
||||||
|
|
||||||
// mDiscovering is not set here, we'll get a Property update from our external
|
// mDiscovering is not set here, we'll get a Property update from our external
|
||||||
// protocol to tell us that it's been set.
|
// protocol to tell us that it's been set.
|
||||||
|
|
||||||
|
req.forget(aRequest);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,11 +428,11 @@ BluetoothAdapter::GetDevices(JSContext* aCx, jsval* aDevices)
|
||||||
else {
|
else {
|
||||||
NS_WARNING("Devices not yet set!\n");
|
NS_WARNING("Devices not yet set!\n");
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
NS_IMETHODIMP
|
||||||
BluetoothAdapter::GetUuids(JSContext* aCx, jsval* aValue)
|
BluetoothAdapter::GetUuids(JSContext* aCx, jsval* aValue)
|
||||||
{
|
{
|
||||||
if (mJsUuids) {
|
if (mJsUuids) {
|
||||||
|
@ -490,30 +485,23 @@ BluetoothAdapter::SetDiscoverableTimeout(const uint32_t aDiscoverableTimeout,
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
BluetoothAdapter::GetPairedDevices(nsIDOMDOMRequest** aRequest)
|
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();
|
BluetoothService* bs = BluetoothService::Get();
|
||||||
if (!bs) {
|
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
|
||||||
NS_WARNING("BluetoothService not available!");
|
if (NS_FAILED(bs->GetPairedDevicePropertiesInternal(mDeviceAddresses,
|
||||||
|
results))) {
|
||||||
|
NS_WARNING("GetPairedDevices failed!");
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
|
req.forget(aRequest);
|
||||||
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);
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,30 +510,19 @@ BluetoothAdapter::PairUnpair(bool aPair,
|
||||||
nsIDOMBluetoothDevice* aDevice,
|
nsIDOMBluetoothDevice* aDevice,
|
||||||
nsIDOMDOMRequest** aRequest)
|
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;
|
nsCOMPtr<nsIDOMDOMRequest> req;
|
||||||
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
|
nsresult rv;
|
||||||
if (NS_FAILED(rv)) {
|
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
|
||||||
NS_WARNING("Can't create DOMRequest!");
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsRefPtr<BluetoothVoidReplyRunnable> results = new BluetoothVoidReplyRunnable(req);
|
nsRefPtr<BluetoothVoidReplyRunnable> results =
|
||||||
|
new BluetoothVoidReplyRunnable(req);
|
||||||
|
|
||||||
nsString addr;
|
nsString addr;
|
||||||
aDevice->GetAddress(addr);
|
aDevice->GetAddress(addr);
|
||||||
|
|
||||||
|
BluetoothService* bs = BluetoothService::Get();
|
||||||
|
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
|
||||||
if (aPair) {
|
if (aPair) {
|
||||||
rv = bs->CreatePairedDeviceInternal(mPath,
|
rv = bs->CreatePairedDeviceInternal(mPath,
|
||||||
addr,
|
addr,
|
||||||
|
@ -561,18 +538,19 @@ BluetoothAdapter::PairUnpair(bool aPair,
|
||||||
}
|
}
|
||||||
|
|
||||||
req.forget(aRequest);
|
req.forget(aRequest);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
BluetoothAdapter::Pair(nsIDOMBluetoothDevice* aDevice, nsIDOMDOMRequest** aRequest)
|
BluetoothAdapter::Pair(nsIDOMBluetoothDevice* aDevice,
|
||||||
|
nsIDOMDOMRequest** aRequest)
|
||||||
{
|
{
|
||||||
return PairUnpair(true, aDevice, aRequest);
|
return PairUnpair(true, aDevice, aRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
BluetoothAdapter::Unpair(nsIDOMBluetoothDevice* aDevice, nsIDOMDOMRequest** aRequest)
|
BluetoothAdapter::Unpair(nsIDOMBluetoothDevice* aDevice,
|
||||||
|
nsIDOMDOMRequest** aRequest)
|
||||||
{
|
{
|
||||||
return PairUnpair(false, aDevice, aRequest);
|
return PairUnpair(false, aDevice, aRequest);
|
||||||
}
|
}
|
||||||
|
@ -582,29 +560,17 @@ BluetoothAdapter::SetPinCode(const nsAString& aDeviceAddress,
|
||||||
const nsAString& aPinCode,
|
const nsAString& aPinCode,
|
||||||
nsIDOMDOMRequest** aRequest)
|
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;
|
nsCOMPtr<nsIDOMDOMRequest> req;
|
||||||
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
|
nsresult rv;
|
||||||
if (NS_FAILED(rv)) {
|
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
|
||||||
NS_WARNING("Can't create DOMRequest!");
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsRefPtr<BluetoothVoidReplyRunnable> results = new BluetoothVoidReplyRunnable(req);
|
nsRefPtr<BluetoothVoidReplyRunnable> results =
|
||||||
|
new BluetoothVoidReplyRunnable(req);
|
||||||
|
|
||||||
bool result = bs->SetPinCodeInternal(aDeviceAddress, aPinCode, results);
|
BluetoothService* bs = BluetoothService::Get();
|
||||||
if(!result) {
|
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
|
||||||
|
if(!bs->SetPinCodeInternal(aDeviceAddress, aPinCode, results)) {
|
||||||
NS_WARNING("SetPinCode failed!");
|
NS_WARNING("SetPinCode failed!");
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -617,29 +583,17 @@ nsresult
|
||||||
BluetoothAdapter::SetPasskey(const nsAString& aDeviceAddress, uint32_t aPasskey,
|
BluetoothAdapter::SetPasskey(const nsAString& aDeviceAddress, uint32_t aPasskey,
|
||||||
nsIDOMDOMRequest** aRequest)
|
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;
|
nsCOMPtr<nsIDOMDOMRequest> req;
|
||||||
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
|
nsresult rv;
|
||||||
if (NS_FAILED(rv)) {
|
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
|
||||||
NS_WARNING("Can't create DOMRequest!");
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsRefPtr<BluetoothVoidReplyRunnable> results = new BluetoothVoidReplyRunnable(req);
|
nsRefPtr<BluetoothVoidReplyRunnable> results =
|
||||||
|
new BluetoothVoidReplyRunnable(req);
|
||||||
|
|
||||||
bool result = bs->SetPasskeyInternal(aDeviceAddress, aPasskey, results);
|
BluetoothService* bs = BluetoothService::Get();
|
||||||
if(!result) {
|
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
|
||||||
|
if(bs->SetPasskeyInternal(aDeviceAddress, aPasskey, results)) {
|
||||||
NS_WARNING("SetPasskeyInternal failed!");
|
NS_WARNING("SetPasskeyInternal failed!");
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -653,29 +607,19 @@ BluetoothAdapter::SetPairingConfirmation(const nsAString& aDeviceAddress,
|
||||||
bool aConfirmation,
|
bool aConfirmation,
|
||||||
nsIDOMDOMRequest** aRequest)
|
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;
|
nsCOMPtr<nsIDOMDOMRequest> req;
|
||||||
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
|
nsresult rv;
|
||||||
if (NS_FAILED(rv)) {
|
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
|
||||||
NS_WARNING("Can't create DOMRequest!");
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsRefPtr<BluetoothVoidReplyRunnable> results = new BluetoothVoidReplyRunnable(req);
|
nsRefPtr<BluetoothVoidReplyRunnable> results =
|
||||||
|
new BluetoothVoidReplyRunnable(req);
|
||||||
|
|
||||||
bool result = bs->SetPairingConfirmationInternal(aDeviceAddress, aConfirmation, results);
|
BluetoothService* bs = BluetoothService::Get();
|
||||||
if(!result) {
|
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
|
||||||
|
if(!bs->SetPairingConfirmationInternal(aDeviceAddress,
|
||||||
|
aConfirmation,
|
||||||
|
results)) {
|
||||||
NS_WARNING("SetPairingConfirmation failed!");
|
NS_WARNING("SetPairingConfirmation failed!");
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -688,29 +632,17 @@ nsresult
|
||||||
BluetoothAdapter::SetAuthorization(const nsAString& aDeviceAddress, bool aAllow,
|
BluetoothAdapter::SetAuthorization(const nsAString& aDeviceAddress, bool aAllow,
|
||||||
nsIDOMDOMRequest** aRequest)
|
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;
|
nsCOMPtr<nsIDOMDOMRequest> req;
|
||||||
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
|
nsresult rv;
|
||||||
if (NS_FAILED(rv)) {
|
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
|
||||||
NS_WARNING("Can't create DOMRequest!");
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsRefPtr<BluetoothVoidReplyRunnable> results = new BluetoothVoidReplyRunnable(req);
|
nsRefPtr<BluetoothVoidReplyRunnable> results =
|
||||||
|
new BluetoothVoidReplyRunnable(req);
|
||||||
|
|
||||||
bool result = bs->SetAuthorizationInternal(aDeviceAddress, aAllow, results);
|
BluetoothService* bs = BluetoothService::Get();
|
||||||
if(!result) {
|
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
|
||||||
|
if(!bs->SetAuthorizationInternal(aDeviceAddress, aAllow, results)) {
|
||||||
NS_WARNING("SetAuthorization failed!");
|
NS_WARNING("SetAuthorization failed!");
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -724,24 +656,13 @@ BluetoothAdapter::Connect(const nsAString& aDeviceAddress,
|
||||||
uint16_t aProfileId,
|
uint16_t aProfileId,
|
||||||
nsIDOMDOMRequest** aRequest)
|
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;
|
nsCOMPtr<nsIDOMDOMRequest> req;
|
||||||
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
|
nsresult rv;
|
||||||
if (NS_FAILED(rv)) {
|
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
|
||||||
NS_WARNING("Can't create DOMRequest!");
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
BluetoothService* bs = BluetoothService::Get();
|
||||||
|
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
nsRefPtr<BluetoothVoidReplyRunnable> results =
|
nsRefPtr<BluetoothVoidReplyRunnable> results =
|
||||||
new BluetoothVoidReplyRunnable(req);
|
new BluetoothVoidReplyRunnable(req);
|
||||||
|
@ -755,28 +676,17 @@ NS_IMETHODIMP
|
||||||
BluetoothAdapter::Disconnect(uint16_t aProfileId,
|
BluetoothAdapter::Disconnect(uint16_t aProfileId,
|
||||||
nsIDOMDOMRequest** aRequest)
|
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;
|
nsCOMPtr<nsIDOMDOMRequest> req;
|
||||||
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
|
nsresult rv;
|
||||||
if (NS_FAILED(rv)) {
|
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
|
||||||
NS_WARNING("Can't create DOMRequest!");
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsRefPtr<BluetoothVoidReplyRunnable> result =
|
nsRefPtr<BluetoothVoidReplyRunnable> results =
|
||||||
new BluetoothVoidReplyRunnable(req);
|
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);
|
req.forget(aRequest);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -787,37 +697,26 @@ BluetoothAdapter::SendFile(const nsAString& aDeviceAddress,
|
||||||
nsIDOMBlob* aBlob,
|
nsIDOMBlob* aBlob,
|
||||||
nsIDOMDOMRequest** aRequest)
|
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;
|
nsCOMPtr<nsIDOMDOMRequest> req;
|
||||||
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
|
nsresult rv;
|
||||||
if (NS_FAILED(rv)) {
|
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
|
||||||
NS_WARNING("Can't create DOMRequest!");
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
nsRefPtr<BluetoothVoidReplyRunnable> results =
|
||||||
|
new BluetoothVoidReplyRunnable(req);
|
||||||
|
|
||||||
BlobChild* actor =
|
BlobChild* actor =
|
||||||
mozilla::dom::ContentChild::GetSingleton()->GetOrCreateActorForBlob(aBlob);
|
mozilla::dom::ContentChild::GetSingleton()->GetOrCreateActorForBlob(aBlob);
|
||||||
|
|
||||||
if (!actor) {
|
if (!actor) {
|
||||||
NS_WARNING("Can't create actor");
|
NS_WARNING("Can't create actor");
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<BluetoothVoidReplyRunnable> result = new BluetoothVoidReplyRunnable(req);
|
BluetoothService* bs = BluetoothService::Get();
|
||||||
bs->SendFile(aDeviceAddress, nullptr, actor, result);
|
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
|
||||||
req.forget(aRequest);
|
bs->SendFile(aDeviceAddress, nullptr, actor, results);
|
||||||
|
|
||||||
|
req.forget(aRequest);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -825,29 +724,19 @@ NS_IMETHODIMP
|
||||||
BluetoothAdapter::StopSendingFile(const nsAString& aDeviceAddress,
|
BluetoothAdapter::StopSendingFile(const nsAString& aDeviceAddress,
|
||||||
nsIDOMDOMRequest** aRequest)
|
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;
|
nsCOMPtr<nsIDOMDOMRequest> req;
|
||||||
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
|
nsresult rv;
|
||||||
if (NS_FAILED(rv)) {
|
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
|
||||||
NS_WARNING("Can't create DOMRequest!");
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
|
||||||
return 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);
|
req.forget(aRequest);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -856,33 +745,19 @@ BluetoothAdapter::ConfirmReceivingFile(const nsAString& aDeviceAddress,
|
||||||
bool aConfirmation,
|
bool aConfirmation,
|
||||||
nsIDOMDOMRequest** aRequest)
|
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;
|
nsCOMPtr<nsIDOMDOMRequest> req;
|
||||||
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
|
nsresult rv;
|
||||||
if (NS_FAILED(rv)) {
|
rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
|
||||||
NS_WARNING("Can't create DOMRequest!");
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsRefPtr<BluetoothVoidReplyRunnable> result =
|
nsRefPtr<BluetoothVoidReplyRunnable> results =
|
||||||
new BluetoothVoidReplyRunnable(req);
|
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);
|
req.forget(aRequest);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,34 @@
|
||||||
#include "nsStringGlue.h"
|
#include "nsStringGlue.h"
|
||||||
#include "nsTArray.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 \
|
#define BEGIN_BLUETOOTH_NAMESPACE \
|
||||||
namespace mozilla { namespace dom { namespace bluetooth {
|
namespace mozilla { namespace dom { namespace bluetooth {
|
||||||
#define END_BLUETOOTH_NAMESPACE \
|
#define END_BLUETOOTH_NAMESPACE \
|
||||||
|
|
|
@ -6,15 +6,12 @@
|
||||||
|
|
||||||
#include "base/basictypes.h"
|
#include "base/basictypes.h"
|
||||||
#include "BluetoothDevice.h"
|
#include "BluetoothDevice.h"
|
||||||
#include "BluetoothPropertyEvent.h"
|
|
||||||
#include "BluetoothReplyRunnable.h"
|
#include "BluetoothReplyRunnable.h"
|
||||||
#include "BluetoothService.h"
|
#include "BluetoothService.h"
|
||||||
#include "BluetoothUtils.h"
|
#include "BluetoothUtils.h"
|
||||||
|
|
||||||
#include "nsIDOMDOMRequest.h"
|
|
||||||
#include "nsDOMClassInfo.h"
|
#include "nsDOMClassInfo.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsTArrayHelpers.h"
|
|
||||||
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
|
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
|
||||||
|
|
||||||
USING_BLUETOOTH_NAMESPACE
|
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_JS_MEMBER_CALLBACK(mJsServices)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothDevice,
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothDevice,
|
||||||
nsDOMEventTargetHelper)
|
nsDOMEventTargetHelper)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothDevice,
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothDevice,
|
||||||
nsDOMEventTargetHelper)
|
nsDOMEventTargetHelper)
|
||||||
tmp->Unroot();
|
tmp->Unroot();
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
@ -45,7 +42,7 @@ NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
|
||||||
NS_IMPL_ADDREF_INHERITED(BluetoothDevice, nsDOMEventTargetHelper)
|
NS_IMPL_ADDREF_INHERITED(BluetoothDevice, nsDOMEventTargetHelper)
|
||||||
NS_IMPL_RELEASE_INHERITED(BluetoothDevice, nsDOMEventTargetHelper)
|
NS_IMPL_RELEASE_INHERITED(BluetoothDevice, nsDOMEventTargetHelper)
|
||||||
|
|
||||||
BluetoothDevice::BluetoothDevice(nsPIDOMWindow* aOwner,
|
BluetoothDevice::BluetoothDevice(nsPIDOMWindow* aWindow,
|
||||||
const nsAString& aAdapterPath,
|
const nsAString& aAdapterPath,
|
||||||
const BluetoothValue& aValue) :
|
const BluetoothValue& aValue) :
|
||||||
BluetoothPropertyContainer(BluetoothObjectType::TYPE_DEVICE),
|
BluetoothPropertyContainer(BluetoothObjectType::TYPE_DEVICE),
|
||||||
|
@ -54,7 +51,9 @@ BluetoothDevice::BluetoothDevice(nsPIDOMWindow* aOwner,
|
||||||
mAdapterPath(aAdapterPath),
|
mAdapterPath(aAdapterPath),
|
||||||
mIsRooted(false)
|
mIsRooted(false)
|
||||||
{
|
{
|
||||||
BindToOwner(aOwner);
|
MOZ_ASSERT(aWindow);
|
||||||
|
|
||||||
|
BindToOwner(aWindow);
|
||||||
const InfallibleTArray<BluetoothNamedValue>& values =
|
const InfallibleTArray<BluetoothNamedValue>& values =
|
||||||
aValue.get_ArrayOfBluetoothNamedValue();
|
aValue.get_ArrayOfBluetoothNamedValue();
|
||||||
for (uint32_t i = 0; i < values.Length(); ++i) {
|
for (uint32_t i = 0; i < values.Length(); ++i) {
|
||||||
|
@ -116,58 +115,46 @@ BluetoothDevice::SetPropertyByValue(const BluetoothNamedValue& aValue)
|
||||||
mUuids = value.get_ArrayOfnsString();
|
mUuids = value.get_ArrayOfnsString();
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
|
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
|
||||||
if (sc) {
|
NS_ENSURE_SUCCESS_VOID(rv);
|
||||||
rv =
|
|
||||||
nsTArrayToJSArray(sc->GetNativeContext(), mUuids, &mJsUuids);
|
if (!SetJsObject(sc->GetNativeContext(), value, mJsUuids)) {
|
||||||
if (NS_FAILED(rv)) {
|
NS_WARNING("Cannot set JS UUIDs object!");
|
||||||
NS_WARNING("Cannot set JS UUIDs object!");
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
Root();
|
|
||||||
} else {
|
|
||||||
NS_WARNING("Could not get context!");
|
|
||||||
}
|
}
|
||||||
|
Root();
|
||||||
} else if (name.EqualsLiteral("Services")) {
|
} else if (name.EqualsLiteral("Services")) {
|
||||||
mServices = value.get_ArrayOfnsString();
|
mServices = value.get_ArrayOfnsString();
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
|
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
|
||||||
if (sc) {
|
NS_ENSURE_SUCCESS_VOID(rv);
|
||||||
rv =
|
|
||||||
nsTArrayToJSArray(sc->GetNativeContext(), mServices, &mJsServices);
|
if (!SetJsObject(sc->GetNativeContext(), value, mJsServices)) {
|
||||||
if (NS_FAILED(rv)) {
|
NS_WARNING("Cannot set JS Devices object!");
|
||||||
NS_WARNING("Cannot set JS Services object!");
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
Root();
|
|
||||||
} else {
|
|
||||||
NS_WARNING("Could not get context!");
|
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
Root();
|
||||||
} else {
|
} else {
|
||||||
nsCString warningMsg;
|
nsCString warningMsg;
|
||||||
warningMsg.AssignLiteral("Not handling device property: ");
|
warningMsg.AssignLiteral("Not handling device property: ");
|
||||||
warningMsg.Append(NS_ConvertUTF16toUTF8(name));
|
warningMsg.Append(NS_ConvertUTF16toUTF8(name));
|
||||||
NS_WARNING(warningMsg.get());
|
NS_WARNING(warningMsg.get());
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
already_AddRefed<BluetoothDevice>
|
already_AddRefed<BluetoothDevice>
|
||||||
BluetoothDevice::Create(nsPIDOMWindow* aOwner,
|
BluetoothDevice::Create(nsPIDOMWindow* aWindow,
|
||||||
const nsAString& aAdapterPath,
|
const nsAString& aAdapterPath,
|
||||||
const BluetoothValue& aValue)
|
const BluetoothValue& aValue)
|
||||||
{
|
{
|
||||||
// Make sure we at least have a service
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
MOZ_ASSERT(aWindow);
|
||||||
|
|
||||||
BluetoothService* bs = BluetoothService::Get();
|
BluetoothService* bs = BluetoothService::Get();
|
||||||
if (!bs) {
|
NS_ENSURE_TRUE(bs, nullptr);
|
||||||
NS_WARNING("BluetoothService not available!");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsRefPtr<BluetoothDevice> device = new BluetoothDevice(aOwner, aAdapterPath,
|
|
||||||
aValue);
|
|
||||||
|
|
||||||
|
nsRefPtr<BluetoothDevice> device =
|
||||||
|
new BluetoothDevice(aWindow, aAdapterPath, aValue);
|
||||||
bs->RegisterBluetoothSignalHandler(device->mPath, device);
|
bs->RegisterBluetoothSignalHandler(device->mPath, device);
|
||||||
|
|
||||||
return device.forget();
|
return device.forget();
|
||||||
|
@ -176,23 +163,18 @@ BluetoothDevice::Create(nsPIDOMWindow* aOwner,
|
||||||
void
|
void
|
||||||
BluetoothDevice::Notify(const BluetoothSignal& aData)
|
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")) {
|
if (aData.name().EqualsLiteral("PropertyChanged")) {
|
||||||
NS_ASSERTION(aData.value().type() == BluetoothValue::TArrayOfBluetoothNamedValue,
|
NS_ASSERTION(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue,
|
||||||
"PropertyChanged: Invalid value type");
|
"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!");
|
NS_ASSERTION(arr.Length() == 1,
|
||||||
BluetoothNamedValue v = arr[0];
|
"Got more than one property in a change message!");
|
||||||
nsString name = v.name();
|
SetPropertyByValue(arr[0]);
|
||||||
|
|
||||||
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"));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
nsCString warningMsg;
|
nsCString warningMsg;
|
||||||
|
|
|
@ -51,8 +51,12 @@ public:
|
||||||
*aValue = JSVAL_VOID;
|
*aValue = JSVAL_VOID;
|
||||||
|
|
||||||
const 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;
|
||||||
|
}
|
||||||
|
|
||||||
MOZ_ASSERT(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
|
|
||||||
const InfallibleTArray<BluetoothNamedValue>& values =
|
const InfallibleTArray<BluetoothNamedValue>& values =
|
||||||
v.get_ArrayOfBluetoothNamedValue();
|
v.get_ArrayOfBluetoothNamedValue();
|
||||||
nsCOMPtr<nsIDOMBluetoothAdapter> adapter;
|
nsCOMPtr<nsIDOMBluetoothAdapter> adapter;
|
||||||
|
@ -204,6 +208,8 @@ NS_NewBluetoothManager(nsPIDOMWindow* aWindow,
|
||||||
void
|
void
|
||||||
BluetoothManager::Notify(const BluetoothSignal& aData)
|
BluetoothManager::Notify(const BluetoothSignal& aData)
|
||||||
{
|
{
|
||||||
|
BT_LOG("[M] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
|
||||||
|
|
||||||
if (aData.name().EqualsLiteral("AdapterAdded")) {
|
if (aData.name().EqualsLiteral("AdapterAdded")) {
|
||||||
DispatchTrustedEvent(NS_LITERAL_STRING("adapteradded"));
|
DispatchTrustedEvent(NS_LITERAL_STRING("adapteradded"));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include "base/basictypes.h"
|
#include "base/basictypes.h"
|
||||||
#include "BluetoothPropertyContainer.h"
|
#include "BluetoothPropertyContainer.h"
|
||||||
#include "BluetoothService.h"
|
#include "BluetoothService.h"
|
||||||
#include "nsIDOMDOMRequest.h"
|
#include "DOMRequest.h"
|
||||||
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
|
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
|
||||||
|
|
||||||
USING_BLUETOOTH_NAMESPACE
|
USING_BLUETOOTH_NAMESPACE
|
||||||
|
@ -16,12 +16,9 @@ nsresult
|
||||||
BluetoothPropertyContainer::FirePropertyAlreadySet(nsIDOMWindow* aOwner,
|
BluetoothPropertyContainer::FirePropertyAlreadySet(nsIDOMWindow* aOwner,
|
||||||
nsIDOMDOMRequest** aRequest)
|
nsIDOMDOMRequest** aRequest)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
|
nsCOMPtr<nsIDOMRequestService> rs =
|
||||||
|
do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
|
||||||
if (!rs) {
|
NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
|
||||||
NS_WARNING("No DOMRequest Service!");
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMDOMRequest> req;
|
nsCOMPtr<nsIDOMDOMRequest> req;
|
||||||
nsresult rv = rs->CreateRequest(aOwner, getter_AddRefs(req));
|
nsresult rv = rs->CreateRequest(aOwner, getter_AddRefs(req));
|
||||||
|
@ -45,12 +42,10 @@ BluetoothPropertyContainer::SetProperty(nsIDOMWindow* aOwner,
|
||||||
NS_WARNING("Bluetooth service not available!");
|
NS_WARNING("Bluetooth service not available!");
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
|
|
||||||
|
nsCOMPtr<nsIDOMRequestService> rs =
|
||||||
if (!rs) {
|
do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
|
||||||
NS_WARNING("No DOMRequest Service!");
|
NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMDOMRequest> req;
|
nsCOMPtr<nsIDOMDOMRequest> req;
|
||||||
nsresult rv = rs->CreateRequest(aOwner, getter_AddRefs(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 "base/basictypes.h"
|
||||||
#include "BluetoothReplyRunnable.h"
|
#include "BluetoothReplyRunnable.h"
|
||||||
#include "nsIDOMDOMRequest.h"
|
#include "DOMRequest.h"
|
||||||
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
|
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
|
||||||
|
|
||||||
USING_BLUETOOTH_NAMESPACE
|
USING_BLUETOOTH_NAMESPACE
|
||||||
|
@ -34,14 +34,9 @@ nsresult
|
||||||
BluetoothReplyRunnable::FireReply(const jsval& aVal)
|
BluetoothReplyRunnable::FireReply(const jsval& aVal)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIDOMRequestService> rs =
|
nsCOMPtr<nsIDOMRequestService> rs =
|
||||||
do_GetService("@mozilla.org/dom/dom-request-service;1");
|
do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
|
||||||
|
NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
|
||||||
if (!rs) {
|
|
||||||
NS_WARNING("No DOMRequest Service!");
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return mReply->type() == BluetoothReply::TBluetoothReplySuccess ?
|
return mReply->type() == BluetoothReply::TBluetoothReplySuccess ?
|
||||||
rs->FireSuccessAsync(mDOMRequest, aVal) :
|
rs->FireSuccessAsync(mDOMRequest, aVal) :
|
||||||
rs->FireErrorAsync(mDOMRequest, mReply->get_BluetoothReplyError().error());
|
rs->FireErrorAsync(mDOMRequest, mReply->get_BluetoothReplyError().error());
|
||||||
|
@ -52,12 +47,8 @@ BluetoothReplyRunnable::FireErrorString()
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIDOMRequestService> rs =
|
nsCOMPtr<nsIDOMRequestService> rs =
|
||||||
do_GetService("@mozilla.org/dom/dom-request-service;1");
|
do_GetService("@mozilla.org/dom/dom-request-service;1");
|
||||||
|
NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
|
||||||
if (!rs) {
|
|
||||||
NS_WARNING("No DOMRequest Service!");
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rs->FireErrorAsync(mDOMRequest, mErrorString);
|
return rs->FireErrorAsync(mDOMRequest, mErrorString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,11 +64,9 @@ BluetoothRilListener::BluetoothRilListener()
|
||||||
bool
|
bool
|
||||||
BluetoothRilListener::StartListening()
|
BluetoothRilListener::StartListening()
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIRILContentHelper> ril = do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
|
nsCOMPtr<nsIRILContentHelper> ril =
|
||||||
if (!ril) {
|
do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
|
||||||
NS_ERROR("No RIL Service!");
|
NS_ENSURE_TRUE(ril, false);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult rv = ril->RegisterTelephonyCallback(mRILTelephonyCallback);
|
nsresult rv = ril->RegisterTelephonyCallback(mRILTelephonyCallback);
|
||||||
NS_ENSURE_SUCCESS(rv, false);
|
NS_ENSURE_SUCCESS(rv, false);
|
||||||
|
@ -81,11 +79,9 @@ BluetoothRilListener::StartListening()
|
||||||
bool
|
bool
|
||||||
BluetoothRilListener::StopListening()
|
BluetoothRilListener::StopListening()
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIRILContentHelper> ril = do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
|
nsCOMPtr<nsIRILContentHelper> ril =
|
||||||
if (!ril) {
|
do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
|
||||||
NS_ERROR("No RIL Service!");
|
NS_ENSURE_TRUE(ril, false);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult rv = ril->UnregisterTelephonyCallback(mRILTelephonyCallback);
|
nsresult rv = ril->UnregisterTelephonyCallback(mRILTelephonyCallback);
|
||||||
|
|
||||||
|
|
|
@ -68,11 +68,9 @@ void
|
||||||
BluetoothScoManager::NotifyAudioManager(const nsAString& aAddress) {
|
BluetoothScoManager::NotifyAudioManager(const nsAString& aAddress) {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
nsCOMPtr<nsIObserverService> obs = do_GetService("@mozilla.org/observer-service;1");
|
nsCOMPtr<nsIObserverService> obs =
|
||||||
if (!obs) {
|
do_GetService("@mozilla.org/observer-service;1");
|
||||||
NS_WARNING("Failed to get observser service!");
|
NS_ENSURE_TRUE_VOID(obs);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aAddress.IsEmpty()) {
|
if (aAddress.IsEmpty()) {
|
||||||
if (NS_FAILED(obs->NotifyObservers(nullptr, BLUETOOTH_SCO_STATUS_CHANGED, nullptr))) {
|
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");
|
nsCOMPtr<nsIAudioManager> am =
|
||||||
if (!am) {
|
do_GetService("@mozilla.org/telephony/audiomanager;1");
|
||||||
NS_WARNING("Failed to get AudioManager service!");
|
NS_ENSURE_TRUE_VOID(am);
|
||||||
return;
|
|
||||||
}
|
|
||||||
am->SetForceForUse(am->USE_COMMUNICATION, am->FORCE_BT_SCO);
|
am->SetForceForUse(am->USE_COMMUNICATION, am->FORCE_BT_SCO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,11 +40,14 @@
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MOZSETTINGS_CHANGED_ID "mozsettings-changed"
|
#define MOZSETTINGS_CHANGED_ID "mozsettings-changed"
|
||||||
#define BLUETOOTH_ENABLED_SETTING "bluetooth.enabled"
|
#define BLUETOOTH_ENABLED_SETTING "bluetooth.enabled"
|
||||||
|
#define BLUETOOTH_DEBUGGING_SETTING "bluetooth.debugging.enabled"
|
||||||
|
|
||||||
#define DEFAULT_SHUTDOWN_TIMER_MS 5000
|
#define DEFAULT_SHUTDOWN_TIMER_MS 5000
|
||||||
|
|
||||||
|
bool gBluetoothDebugFlag = false;
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
USING_BLUETOOTH_NAMESPACE
|
USING_BLUETOOTH_NAMESPACE
|
||||||
|
@ -314,12 +317,15 @@ BluetoothService::Cleanup()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BluetoothService::RegisterBluetoothSignalHandler(const nsAString& aNodeName,
|
BluetoothService::RegisterBluetoothSignalHandler(
|
||||||
BluetoothSignalObserver* aHandler)
|
const nsAString& aNodeName,
|
||||||
|
BluetoothSignalObserver* aHandler)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
MOZ_ASSERT(aHandler);
|
MOZ_ASSERT(aHandler);
|
||||||
|
|
||||||
|
BT_LOG("[S] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aNodeName).get());
|
||||||
|
|
||||||
BluetoothSignalObserverList* ol;
|
BluetoothSignalObserverList* ol;
|
||||||
if (!mBluetoothSignalObserverTable.Get(aNodeName, &ol)) {
|
if (!mBluetoothSignalObserverTable.Get(aNodeName, &ol)) {
|
||||||
ol = new BluetoothSignalObserverList();
|
ol = new BluetoothSignalObserverList();
|
||||||
|
@ -331,12 +337,15 @@ BluetoothService::RegisterBluetoothSignalHandler(const nsAString& aNodeName,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BluetoothService::UnregisterBluetoothSignalHandler(const nsAString& aNodeName,
|
BluetoothService::UnregisterBluetoothSignalHandler(
|
||||||
BluetoothSignalObserver* aHandler)
|
const nsAString& aNodeName,
|
||||||
|
BluetoothSignalObserver* aHandler)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
MOZ_ASSERT(aHandler);
|
MOZ_ASSERT(aHandler);
|
||||||
|
|
||||||
|
BT_LOG("[S] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aNodeName).get());
|
||||||
|
|
||||||
BluetoothSignalObserverList* ol;
|
BluetoothSignalObserverList* ol;
|
||||||
if (mBluetoothSignalObserverTable.Get(aNodeName, &ol)) {
|
if (mBluetoothSignalObserverTable.Get(aNodeName, &ol)) {
|
||||||
ol->RemoveObserver(aHandler);
|
ol->RemoveObserver(aHandler);
|
||||||
|
@ -551,38 +560,59 @@ BluetoothService::HandleSettingsChanged(const nsAString& aData)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// First, check if the string equals to BLUETOOTH_DEBUGGING_SETTING
|
||||||
JSBool match;
|
JSBool match;
|
||||||
if (!JS_StringEqualsAscii(cx, key.toString(), BLUETOOTH_ENABLED_SETTING,
|
if (!JS_StringEqualsAscii(cx, key.toString(), BLUETOOTH_DEBUGGING_SETTING, &match)) {
|
||||||
&match)) {
|
|
||||||
MOZ_ASSERT(!JS_IsExceptionPending(cx));
|
MOZ_ASSERT(!JS_IsExceptionPending(cx));
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
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;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::Value value;
|
// Second, check if the string is BLUETOOTH_ENABLED_SETTING
|
||||||
if (!JS_GetProperty(cx, &obj, "value", &value)) {
|
if (!JS_StringEqualsAscii(cx, key.toString(), BLUETOOTH_ENABLED_SETTING, &match)) {
|
||||||
MOZ_ASSERT(!JS_IsExceptionPending(cx));
|
MOZ_ASSERT(!JS_IsExceptionPending(cx));
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!value.isBoolean()) {
|
if (match) {
|
||||||
MOZ_ASSERT(false, "Expecting a boolean for 'bluetooth.enabled'!");
|
JS::Value value;
|
||||||
return NS_ERROR_UNEXPECTED;
|
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;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -726,7 +756,6 @@ BluetoothService::Observe(nsISupports* aSubject, const char* aTopic,
|
||||||
void
|
void
|
||||||
BluetoothService::Notify(const BluetoothSignal& aData)
|
BluetoothService::Notify(const BluetoothSignal& aData)
|
||||||
{
|
{
|
||||||
InfallibleTArray<BluetoothNamedValue> arr(aData.value().get_ArrayOfBluetoothNamedValue());
|
|
||||||
nsString type;
|
nsString type;
|
||||||
|
|
||||||
JSContext* cx = nsContentUtils::GetSafeJSContext();
|
JSContext* cx = nsContentUtils::GetSafeJSContext();
|
||||||
|
@ -740,29 +769,36 @@ BluetoothService::Notify(const BluetoothSignal& aData)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ok = SetJsObject(cx, obj, arr);
|
if (!SetJsObject(cx, aData.value(), obj)) {
|
||||||
if (!ok) {
|
|
||||||
NS_WARNING("Failed to set properties of system message!");
|
NS_WARNING("Failed to set properties of system message!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BT_LOG("[S] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
|
||||||
|
|
||||||
if (aData.name().EqualsLiteral("RequestConfirmation")) {
|
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");
|
type.AssignLiteral("bluetooth-requestconfirmation");
|
||||||
} else if (aData.name().EqualsLiteral("RequestPinCode")) {
|
} 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");
|
type.AssignLiteral("bluetooth-requestpincode");
|
||||||
} else if (aData.name().EqualsLiteral("RequestPasskey")) {
|
} 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");
|
type.AssignLiteral("bluetooth-requestpasskey");
|
||||||
} else if (aData.name().EqualsLiteral("Authorize")) {
|
} 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");
|
type.AssignLiteral("bluetooth-authorize");
|
||||||
} else if (aData.name().EqualsLiteral("Cancel")) {
|
} 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");
|
type.AssignLiteral("bluetooth-cancel");
|
||||||
} else if (aData.name().EqualsLiteral("PairedStatusChanged")) {
|
} 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");
|
type.AssignLiteral("bluetooth-pairedstatuschanged");
|
||||||
} else {
|
} else {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
|
@ -166,20 +166,6 @@ public:
|
||||||
BluetoothReplyRunnable* aRunnable) = 0;
|
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
|
* Fetches the propertes for the specified device
|
||||||
*
|
*
|
||||||
* @param aSignal BluetoothSignal to be distrubuted after retrieving device properties
|
* @param aSignal BluetoothSignal to be distrubuted after retrieving device properties
|
||||||
|
@ -312,9 +298,6 @@ public:
|
||||||
protected:
|
protected:
|
||||||
BluetoothService()
|
BluetoothService()
|
||||||
: mEnabled(false)
|
: mEnabled(false)
|
||||||
#ifdef DEBUG
|
|
||||||
, mLastRequestedEnable(false)
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
mBluetoothSignalObserverTable.Init();
|
mBluetoothSignalObserverTable.Init();
|
||||||
}
|
}
|
||||||
|
@ -403,10 +386,6 @@ protected:
|
||||||
BluetoothManagerList mLiveManagers;
|
BluetoothManagerList mLiveManagers;
|
||||||
|
|
||||||
bool mEnabled;
|
bool mEnabled;
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
bool mLastRequestedEnable;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
END_BLUETOOTH_NAMESPACE
|
END_BLUETOOTH_NAMESPACE
|
||||||
|
|
|
@ -35,15 +35,6 @@
|
||||||
#include "BluetoothUnixSocketConnector.h"
|
#include "BluetoothUnixSocketConnector.h"
|
||||||
#include "nsThreadUtils.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
|
USING_BLUETOOTH_NAMESPACE
|
||||||
|
|
||||||
static const int RFCOMM_SO_SNDBUF = 70 * 1024; // 70 KB send buffer
|
static const int RFCOMM_SO_SNDBUF = 70 * 1024; // 70 KB send buffer
|
||||||
|
|
|
@ -12,42 +12,68 @@
|
||||||
#include "mozilla/Scoped.h"
|
#include "mozilla/Scoped.h"
|
||||||
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
|
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
|
#include "nsIScriptContext.h"
|
||||||
#include "nsISystemMessagesInternal.h"
|
#include "nsISystemMessagesInternal.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
|
#include "nsTArrayHelpers.h"
|
||||||
|
|
||||||
BEGIN_BLUETOOTH_NAMESPACE
|
BEGIN_BLUETOOTH_NAMESPACE
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SetJsObject(JSContext* aContext,
|
SetJsObject(JSContext* aContext,
|
||||||
JSObject* aObj,
|
const BluetoothValue& aValue,
|
||||||
const InfallibleTArray<BluetoothNamedValue>& aData)
|
JSObject* aObj)
|
||||||
{
|
{
|
||||||
for (uint32_t i = 0; i < aData.Length(); i++) {
|
MOZ_ASSERT(aContext && aObj);
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!JS_SetProperty(aContext, aObj,
|
if (aValue.type() == BluetoothValue::TArrayOfnsString) {
|
||||||
NS_ConvertUTF16toUTF8(aData[i].name()).get(),
|
const nsTArray<nsString>& sourceArray = aValue.get_ArrayOfnsString();
|
||||||
&v)) {
|
if (NS_FAILED(nsTArrayToJSArray(aContext, sourceArray, &aObj))) {
|
||||||
|
NS_WARNING("Cannot set JS UUIDs object!");
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,18 +123,14 @@ BroadcastSystemMessage(const nsAString& aType,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SetJsObject(cx, obj, aData)) {
|
if (!SetJsObject(cx, aData, obj)) {
|
||||||
NS_WARNING("Failed to set properties of system message!");
|
NS_WARNING("Failed to set properties of system message!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsISystemMessagesInternal> systemMessenger =
|
nsCOMPtr<nsISystemMessagesInternal> systemMessenger =
|
||||||
do_GetService("@mozilla.org/system-message-internal;1");
|
do_GetService("@mozilla.org/system-message-internal;1");
|
||||||
|
NS_ENSURE_TRUE(systemMessenger, false);
|
||||||
if (!systemMessenger) {
|
|
||||||
NS_WARNING("Failed to get SystemMessenger service!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
systemMessenger->BroadcastMessage(aType, OBJECT_TO_JSVAL(obj));
|
systemMessenger->BroadcastMessage(aType, OBJECT_TO_JSVAL(obj));
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
#define mozilla_dom_bluetooth_bluetoothutils_h__
|
#define mozilla_dom_bluetooth_bluetoothutils_h__
|
||||||
|
|
||||||
#include "BluetoothCommon.h"
|
#include "BluetoothCommon.h"
|
||||||
#include "nsTArray.h"
|
|
||||||
|
|
||||||
struct JSContext;
|
struct JSContext;
|
||||||
class JSObject;
|
class JSObject;
|
||||||
|
@ -21,8 +20,8 @@ class BluetoothReplyRunnable;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SetJsObject(JSContext* aContext,
|
SetJsObject(JSContext* aContext,
|
||||||
JSObject* aObj,
|
const BluetoothValue& aValue,
|
||||||
const InfallibleTArray<BluetoothNamedValue>& aData);
|
JSObject* aObj);
|
||||||
|
|
||||||
nsString
|
nsString
|
||||||
GetObjectPathFromAddress(const nsAString& aAdapterPath,
|
GetObjectPathFromAddress(const nsAString& aAdapterPath,
|
||||||
|
|
|
@ -44,7 +44,6 @@ CPPSRCS += \
|
||||||
BluetoothManager.cpp \
|
BluetoothManager.cpp \
|
||||||
BluetoothAdapter.cpp \
|
BluetoothAdapter.cpp \
|
||||||
BluetoothDevice.cpp \
|
BluetoothDevice.cpp \
|
||||||
BluetoothPropertyEvent.cpp \
|
|
||||||
BluetoothReplyRunnable.cpp \
|
BluetoothReplyRunnable.cpp \
|
||||||
BluetoothPropertyContainer.cpp \
|
BluetoothPropertyContainer.cpp \
|
||||||
BluetoothUtils.cpp \
|
BluetoothUtils.cpp \
|
||||||
|
@ -70,7 +69,6 @@ XPIDLSRCS = \
|
||||||
nsIDOMBluetoothDevice.idl \
|
nsIDOMBluetoothDevice.idl \
|
||||||
nsIDOMBluetoothDeviceEvent.idl \
|
nsIDOMBluetoothDeviceEvent.idl \
|
||||||
nsIDOMBluetoothDeviceAddressEvent.idl \
|
nsIDOMBluetoothDeviceAddressEvent.idl \
|
||||||
nsIDOMBluetoothPropertyEvent.idl \
|
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
|
ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
|
||||||
|
|
|
@ -189,8 +189,6 @@ BluetoothParent::RecvPBluetoothRequestConstructor(
|
||||||
return actor->DoRequest(aRequest.get_DefaultAdapterPathRequest());
|
return actor->DoRequest(aRequest.get_DefaultAdapterPathRequest());
|
||||||
case Request::TSetPropertyRequest:
|
case Request::TSetPropertyRequest:
|
||||||
return actor->DoRequest(aRequest.get_SetPropertyRequest());
|
return actor->DoRequest(aRequest.get_SetPropertyRequest());
|
||||||
case Request::TGetPropertyRequest:
|
|
||||||
return actor->DoRequest(aRequest.get_GetPropertyRequest());
|
|
||||||
case Request::TStartDiscoveryRequest:
|
case Request::TStartDiscoveryRequest:
|
||||||
return actor->DoRequest(aRequest.get_StartDiscoveryRequest());
|
return actor->DoRequest(aRequest.get_StartDiscoveryRequest());
|
||||||
case Request::TStopDiscoveryRequest:
|
case Request::TStopDiscoveryRequest:
|
||||||
|
@ -318,20 +316,6 @@ BluetoothRequestParent::DoRequest(const SetPropertyRequest& aRequest)
|
||||||
return true;
|
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
|
bool
|
||||||
BluetoothRequestParent::DoRequest(const StartDiscoveryRequest& aRequest)
|
BluetoothRequestParent::DoRequest(const StartDiscoveryRequest& aRequest)
|
||||||
{
|
{
|
||||||
|
|
|
@ -140,15 +140,6 @@ BluetoothServiceChildProcess::StartDiscoveryInternal(
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
|
||||||
BluetoothServiceChildProcess::GetProperties(BluetoothObjectType aType,
|
|
||||||
const nsAString& aPath,
|
|
||||||
BluetoothReplyRunnable* aRunnable)
|
|
||||||
{
|
|
||||||
SendRequest(aRunnable, GetPropertyRequest(aType, nsString(aPath)));
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
BluetoothServiceChildProcess::SetProperty(BluetoothObjectType aType,
|
BluetoothServiceChildProcess::SetProperty(BluetoothObjectType aType,
|
||||||
const nsAString& aPath,
|
const nsAString& aPath,
|
||||||
|
|
|
@ -59,11 +59,6 @@ public:
|
||||||
StartDiscoveryInternal(const nsAString& aAdapterPath,
|
StartDiscoveryInternal(const nsAString& aAdapterPath,
|
||||||
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||||
|
|
||||||
virtual nsresult
|
|
||||||
GetProperties(BluetoothObjectType aType,
|
|
||||||
const nsAString& aPath,
|
|
||||||
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
|
||||||
|
|
||||||
virtual nsresult
|
virtual nsresult
|
||||||
SetProperty(BluetoothObjectType aType,
|
SetProperty(BluetoothObjectType aType,
|
||||||
const nsAString& aPath,
|
const nsAString& aPath,
|
||||||
|
|
|
@ -59,15 +59,6 @@ using namespace mozilla;
|
||||||
using namespace mozilla::ipc;
|
using namespace mozilla::ipc;
|
||||||
USING_BLUETOOTH_NAMESPACE
|
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 B2G_AGENT_CAPABILITIES "DisplayYesNo"
|
||||||
#define DBUS_MANAGER_IFACE BLUEZ_DBUS_BASE_IFC ".Manager"
|
#define DBUS_MANAGER_IFACE BLUEZ_DBUS_BASE_IFC ".Manager"
|
||||||
#define DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter"
|
#define DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter"
|
||||||
|
@ -309,10 +300,7 @@ public:
|
||||||
|
|
||||||
// Get device properties and then send to BluetoothAdapter
|
// Get device properties and then send to BluetoothAdapter
|
||||||
BluetoothService* bs = BluetoothService::Get();
|
BluetoothService* bs = BluetoothService::Get();
|
||||||
if (!bs) {
|
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
|
||||||
NS_WARNING("BluetoothService not available!");
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Due to the fact that we need to queue the dbus call to the command thread
|
// 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
|
// inside the bluetoothservice, we have to route the call down to the main
|
||||||
|
@ -365,6 +353,8 @@ static void
|
||||||
UnpackIntMessage(DBusMessage* aMsg, DBusError* aErr,
|
UnpackIntMessage(DBusMessage* aMsg, DBusError* aErr,
|
||||||
BluetoothValue& aValue, nsAString& aErrorStr)
|
BluetoothValue& aValue, nsAString& aErrorStr)
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(aMsg);
|
||||||
|
|
||||||
DBusError err;
|
DBusError err;
|
||||||
dbus_error_init(&err);
|
dbus_error_init(&err);
|
||||||
if (!IsDBusMessageError(aMsg, aErr, aErrorStr)) {
|
if (!IsDBusMessageError(aMsg, aErr, aErrorStr)) {
|
||||||
|
@ -420,13 +410,17 @@ static DBusHandlerResult
|
||||||
AgentEventFilter(DBusConnection *conn, DBusMessage *msg, void *data)
|
AgentEventFilter(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||||
{
|
{
|
||||||
if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_METHOD_CALL) {
|
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;
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBusError err;
|
DBusError err;
|
||||||
dbus_error_init(&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 signalPath = NS_ConvertUTF8toUTF16(dbus_message_get_path(msg));
|
||||||
nsString signalName = NS_ConvertUTF8toUTF16(dbus_message_get_member(msg));
|
nsString signalName = NS_ConvertUTF8toUTF16(dbus_message_get_member(msg));
|
||||||
nsString errorStr;
|
nsString errorStr;
|
||||||
|
@ -460,7 +454,7 @@ AgentEventFilter(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||||
DBUS_TYPE_OBJECT_PATH, &objectPath,
|
DBUS_TYPE_OBJECT_PATH, &objectPath,
|
||||||
DBUS_TYPE_STRING, &uuid,
|
DBUS_TYPE_STRING, &uuid,
|
||||||
DBUS_TYPE_INVALID)) {
|
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");
|
errorStr.AssignLiteral("Invalid arguments for Authorize() method");
|
||||||
} else {
|
} else {
|
||||||
nsString deviceAddress =
|
nsString deviceAddress =
|
||||||
|
@ -492,11 +486,12 @@ AgentEventFilter(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||||
DBUS_TYPE_OBJECT_PATH, &objectPath,
|
DBUS_TYPE_OBJECT_PATH, &objectPath,
|
||||||
DBUS_TYPE_UINT32, &passkey,
|
DBUS_TYPE_UINT32, &passkey,
|
||||||
DBUS_TYPE_INVALID)) {
|
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");
|
errorStr.AssignLiteral("Invalid arguments for RequestConfirmation() method");
|
||||||
} else {
|
} else {
|
||||||
parameters.AppendElement(BluetoothNamedValue(
|
parameters.AppendElement(BluetoothNamedValue(
|
||||||
NS_LITERAL_STRING("address"),
|
NS_LITERAL_STRING("path"),
|
||||||
NS_ConvertUTF8toUTF16(objectPath)));
|
NS_ConvertUTF8toUTF16(objectPath)));
|
||||||
parameters.AppendElement(BluetoothNamedValue(
|
parameters.AppendElement(BluetoothNamedValue(
|
||||||
NS_LITERAL_STRING("passkey"),
|
NS_LITERAL_STRING("passkey"),
|
||||||
|
@ -524,11 +519,12 @@ AgentEventFilter(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||||
if (!dbus_message_get_args(msg, NULL,
|
if (!dbus_message_get_args(msg, NULL,
|
||||||
DBUS_TYPE_OBJECT_PATH, &objectPath,
|
DBUS_TYPE_OBJECT_PATH, &objectPath,
|
||||||
DBUS_TYPE_INVALID)) {
|
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");
|
errorStr.AssignLiteral("Invalid arguments for RequestPinCode() method");
|
||||||
} else {
|
} else {
|
||||||
parameters.AppendElement(BluetoothNamedValue(
|
parameters.AppendElement(BluetoothNamedValue(
|
||||||
NS_LITERAL_STRING("address"),
|
NS_LITERAL_STRING("path"),
|
||||||
NS_ConvertUTF8toUTF16(objectPath)));
|
NS_ConvertUTF8toUTF16(objectPath)));
|
||||||
|
|
||||||
KeepDBusPairingMessage(GetAddressFromObjectPath(
|
KeepDBusPairingMessage(GetAddressFromObjectPath(
|
||||||
|
@ -552,11 +548,12 @@ AgentEventFilter(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||||
if (!dbus_message_get_args(msg, NULL,
|
if (!dbus_message_get_args(msg, NULL,
|
||||||
DBUS_TYPE_OBJECT_PATH, &objectPath,
|
DBUS_TYPE_OBJECT_PATH, &objectPath,
|
||||||
DBUS_TYPE_INVALID)) {
|
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");
|
errorStr.AssignLiteral("Invalid arguments for RequestPasskey() method");
|
||||||
} else {
|
} else {
|
||||||
parameters.AppendElement(BluetoothNamedValue(
|
parameters.AppendElement(BluetoothNamedValue(
|
||||||
NS_LITERAL_STRING("address"),
|
NS_LITERAL_STRING("path"),
|
||||||
NS_ConvertUTF8toUTF16(objectPath)));
|
NS_ConvertUTF8toUTF16(objectPath)));
|
||||||
|
|
||||||
KeepDBusPairingMessage(GetAddressFromObjectPath(
|
KeepDBusPairingMessage(GetAddressFromObjectPath(
|
||||||
|
@ -590,7 +587,7 @@ AgentEventFilter(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
LOG("agent handler %s: Unhandled event. Ignore.", __FUNCTION__);
|
BT_WARNING("agent handler %s: Unhandled event. Ignore.", __FUNCTION__);
|
||||||
#endif
|
#endif
|
||||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||||
}
|
}
|
||||||
|
@ -631,7 +628,7 @@ RegisterLocalAgent(const char* adapterPath,
|
||||||
agentPath,
|
agentPath,
|
||||||
&agentVtable,
|
&agentVtable,
|
||||||
NULL)) {
|
NULL)) {
|
||||||
LOG("%s: Can't register object path %s for agent!",
|
BT_WARNING("%s: Can't register object path %s for agent!",
|
||||||
__FUNCTION__, agentPath);
|
__FUNCTION__, agentPath);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -640,7 +637,7 @@ RegisterLocalAgent(const char* adapterPath,
|
||||||
dbus_message_new_method_call("org.bluez", adapterPath,
|
dbus_message_new_method_call("org.bluez", adapterPath,
|
||||||
DBUS_ADAPTER_IFACE, "RegisterAgent");
|
DBUS_ADAPTER_IFACE, "RegisterAgent");
|
||||||
if (!msg) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -648,7 +645,7 @@ RegisterLocalAgent(const char* adapterPath,
|
||||||
DBUS_TYPE_OBJECT_PATH, &agentPath,
|
DBUS_TYPE_OBJECT_PATH, &agentPath,
|
||||||
DBUS_TYPE_STRING, &capabilities,
|
DBUS_TYPE_STRING, &capabilities,
|
||||||
DBUS_TYPE_INVALID)) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -665,11 +662,11 @@ RegisterLocalAgent(const char* adapterPath,
|
||||||
if (!strcmp(err.name, "org.bluez.Error.AlreadyExists")) {
|
if (!strcmp(err.name, "org.bluez.Error.AlreadyExists")) {
|
||||||
LOG_AND_FREE_DBUS_ERROR(&err);
|
LOG_AND_FREE_DBUS_ERROR(&err);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
LOG("Agent already registered, still returning true");
|
BT_WARNING("Agent already registered, still returning true");
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
LOG_AND_FREE_DBUS_ERROR(&err);
|
LOG_AND_FREE_DBUS_ERROR(&err);
|
||||||
LOG("%s: Can't register agent!", __FUNCTION__);
|
BT_WARNING("%s: Can't register agent!", __FUNCTION__);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -699,7 +696,7 @@ RegisterAgent(const nsAString& aAdapterPath)
|
||||||
REMOTE_AGENT_PATH,
|
REMOTE_AGENT_PATH,
|
||||||
&agentVtable,
|
&agentVtable,
|
||||||
NULL)) {
|
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);
|
__FUNCTION__, REMOTE_AGENT_PATH);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -721,7 +718,7 @@ ExtractHandles(DBusMessage *aReply, nsTArray<uint32_t>& aOutHandles)
|
||||||
DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &handles, &len,
|
DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &handles, &len,
|
||||||
DBUS_TYPE_INVALID)) {
|
DBUS_TYPE_INVALID)) {
|
||||||
if (!handles) {
|
if (!handles) {
|
||||||
LOG("Null array in extract_handles");
|
BT_WARNING("Null array in extract_handles");
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < len; ++i) {
|
for (int i = 0; i < len; ++i) {
|
||||||
aOutHandles.AppendElement(handles[i]);
|
aOutHandles.AppendElement(handles[i]);
|
||||||
|
@ -775,7 +772,7 @@ BluetoothDBusService::AddReservedServicesInternal(const nsAString& aAdapterPath,
|
||||||
&services, length, DBUS_TYPE_INVALID);
|
&services, length, DBUS_TYPE_INVALID);
|
||||||
|
|
||||||
if (!reply) {
|
if (!reply) {
|
||||||
LOG("Null DBus message. Couldn't extract handles.");
|
BT_WARNING("Null DBus message. Couldn't extract handles.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1307,21 +1304,27 @@ EventFilter(DBusConnection* aConn, DBusMessage* aMsg, void* aData)
|
||||||
NS_ASSERTION(!NS_IsMainThread(), "Shouldn't be called from Main Thread!");
|
NS_ASSERTION(!NS_IsMainThread(), "Shouldn't be called from Main Thread!");
|
||||||
|
|
||||||
if (dbus_message_get_type(aMsg) != DBUS_MESSAGE_TYPE_SIGNAL) {
|
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));
|
__FUNCTION__, dbus_message_get_member(aMsg));
|
||||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dbus_message_get_path(aMsg) == NULL) {
|
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));
|
dbus_message_get_member(aMsg));
|
||||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBusError err;
|
DBusError err;
|
||||||
|
dbus_error_init(&err);
|
||||||
|
|
||||||
nsString signalPath;
|
nsString signalPath;
|
||||||
nsString signalName;
|
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));
|
signalPath = NS_ConvertUTF8toUTF16(dbus_message_get_path(aMsg));
|
||||||
signalName = NS_ConvertUTF8toUTF16(dbus_message_get_member(aMsg));
|
signalName = NS_ConvertUTF8toUTF16(dbus_message_get_member(aMsg));
|
||||||
nsString errorStr;
|
nsString errorStr;
|
||||||
|
@ -1635,13 +1638,13 @@ BluetoothDBusService::StopInternal()
|
||||||
|
|
||||||
if (!dbus_connection_unregister_object_path(gThreadConnection->GetConnection(),
|
if (!dbus_connection_unregister_object_path(gThreadConnection->GetConnection(),
|
||||||
LOCAL_AGENT_PATH)) {
|
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);
|
__FUNCTION__, LOCAL_AGENT_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dbus_connection_unregister_object_path(gThreadConnection->GetConnection(),
|
if (!dbus_connection_unregister_object_path(gThreadConnection->GetConnection(),
|
||||||
REMOTE_AGENT_PATH)) {
|
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);
|
__FUNCTION__, LOCAL_AGENT_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1779,68 +1782,54 @@ public:
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
}
|
}
|
||||||
|
|
||||||
~BluetoothDevicePropertiesRunnable()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHOD Run()
|
NS_IMETHOD Run()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!NS_IsMainThread());
|
MOZ_ASSERT(!NS_IsMainThread());
|
||||||
|
|
||||||
nsString devicePath;
|
nsString devicePath;
|
||||||
BluetoothValue v = mSignal.value();
|
BluetoothValue v = mSignal.value();
|
||||||
if (v.type() == BluetoothValue::TArrayOfBluetoothNamedValue &&
|
if (v.type() != BluetoothValue::TArrayOfBluetoothNamedValue ||
|
||||||
v.get_ArrayOfBluetoothNamedValue().Length() ) {
|
v.get_ArrayOfBluetoothNamedValue().Length() == 0) {
|
||||||
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 {
|
|
||||||
NS_WARNING("Invalid value type for GetDeviceProperties() method");
|
NS_WARNING("Invalid value type for GetDeviceProperties() method");
|
||||||
return NS_ERROR_FAILURE;
|
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;
|
BluetoothValue prop;
|
||||||
if (!GetPropertiesInternal(devicePath, DBUS_DEVICE_IFACE, prop)) {
|
if (!GetPropertiesInternal(devicePath, DBUS_DEVICE_IFACE, prop)) {
|
||||||
NS_WARNING("Getting properties failed!");
|
NS_WARNING("Getting properties failed!");
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
InfallibleTArray<BluetoothNamedValue> properties(prop.get_ArrayOfBluetoothNamedValue());
|
InfallibleTArray<BluetoothNamedValue>& properties =
|
||||||
if (v.type() == BluetoothValue::TArrayOfBluetoothNamedValue) {
|
prop.get_ArrayOfBluetoothNamedValue();
|
||||||
// Return original dbus message parameters and also device name
|
|
||||||
// for agent events "RequestConfirmation", "RequestPinCode", and "RequestPasskey"
|
|
||||||
InfallibleTArray<BluetoothNamedValue> parameters(v.get_ArrayOfBluetoothNamedValue());
|
|
||||||
|
|
||||||
// For consistency, append path
|
// Return original dbus message parameters and also device name
|
||||||
nsString path = parameters[0].value();
|
// for agent events "RequestConfirmation", "RequestPinCode", and "RequestPasskey"
|
||||||
BluetoothNamedValue pathprop;
|
InfallibleTArray<BluetoothNamedValue>& parameters =
|
||||||
pathprop.name().AssignLiteral("Path");
|
v.get_ArrayOfBluetoothNamedValue();
|
||||||
pathprop.value() = path;
|
|
||||||
parameters.AppendElement(pathprop);
|
|
||||||
|
|
||||||
// Replace object path with device address
|
// Replace object path with device address
|
||||||
nsString address = GetAddressFromObjectPath(path);
|
nsString address = GetAddressFromObjectPath(devicePath);
|
||||||
parameters[0].value() = address;
|
parameters[0].name().AssignLiteral("address");
|
||||||
|
parameters[0].value() = address;
|
||||||
|
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
for (i = 0; i < properties.Length(); i++) {
|
for (i = 0; i < properties.Length(); i++) {
|
||||||
// Append device name
|
// Append device name
|
||||||
if (properties[i].name().EqualsLiteral("Name")) {
|
if (properties[i].name().EqualsLiteral("Name")) {
|
||||||
properties[i].name().AssignLiteral("name");
|
properties[i].name().AssignLiteral("name");
|
||||||
parameters.AppendElement(properties[i]);
|
parameters.AppendElement(properties[i]);
|
||||||
mSignal.value() = parameters;
|
mSignal.value() = parameters;
|
||||||
break;
|
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 =
|
nsRefPtr<DistributeBluetoothSignalTask> t =
|
||||||
new DistributeBluetoothSignalTask(mSignal);
|
new DistributeBluetoothSignalTask(mSignal);
|
||||||
|
@ -1921,36 +1910,6 @@ private:
|
||||||
nsTArray<nsString> mDeviceAddresses;
|
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
|
nsresult
|
||||||
BluetoothDBusService::GetDevicePropertiesInternal(const BluetoothSignal& aSignal)
|
BluetoothDBusService::GetDevicePropertiesInternal(const BluetoothSignal& aSignal)
|
||||||
{
|
{
|
||||||
|
@ -2229,7 +2188,7 @@ BluetoothDBusService::SetPinCodeInternal(const nsAString& aDeviceAddress,
|
||||||
BluetoothValue v = true;
|
BluetoothValue v = true;
|
||||||
DBusMessage *msg;
|
DBusMessage *msg;
|
||||||
if (!sPairingReqTable.Get(aDeviceAddress, &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.");
|
errorStr.AssignLiteral("Couldn't get original request message.");
|
||||||
DispatchBluetoothReply(aRunnable, v, errorStr);
|
DispatchBluetoothReply(aRunnable, v, errorStr);
|
||||||
return false;
|
return false;
|
||||||
|
@ -2238,7 +2197,7 @@ BluetoothDBusService::SetPinCodeInternal(const nsAString& aDeviceAddress,
|
||||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||||
|
|
||||||
if (!reply) {
|
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);
|
dbus_message_unref(msg);
|
||||||
errorStr.AssignLiteral("Memory can't be allocated for the message.");
|
errorStr.AssignLiteral("Memory can't be allocated for the message.");
|
||||||
DispatchBluetoothReply(aRunnable, v, errorStr);
|
DispatchBluetoothReply(aRunnable, v, errorStr);
|
||||||
|
@ -2253,7 +2212,7 @@ BluetoothDBusService::SetPinCodeInternal(const nsAString& aDeviceAddress,
|
||||||
if (!dbus_message_append_args(reply,
|
if (!dbus_message_append_args(reply,
|
||||||
DBUS_TYPE_STRING, &pinCode,
|
DBUS_TYPE_STRING, &pinCode,
|
||||||
DBUS_TYPE_INVALID)) {
|
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.");
|
errorStr.AssignLiteral("Couldn't append arguments to dbus message.");
|
||||||
result = false;
|
result = false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2277,7 +2236,7 @@ BluetoothDBusService::SetPasskeyInternal(const nsAString& aDeviceAddress,
|
||||||
BluetoothValue v = true;
|
BluetoothValue v = true;
|
||||||
DBusMessage *msg;
|
DBusMessage *msg;
|
||||||
if (!sPairingReqTable.Get(aDeviceAddress, &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.");
|
errorStr.AssignLiteral("Couldn't get original request message.");
|
||||||
DispatchBluetoothReply(aRunnable, v, errorStr);
|
DispatchBluetoothReply(aRunnable, v, errorStr);
|
||||||
return false;
|
return false;
|
||||||
|
@ -2286,7 +2245,7 @@ BluetoothDBusService::SetPasskeyInternal(const nsAString& aDeviceAddress,
|
||||||
DBusMessage *reply = dbus_message_new_method_return(msg);
|
DBusMessage *reply = dbus_message_new_method_return(msg);
|
||||||
|
|
||||||
if (!reply) {
|
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);
|
dbus_message_unref(msg);
|
||||||
errorStr.AssignLiteral("Memory can't be allocated for the message.");
|
errorStr.AssignLiteral("Memory can't be allocated for the message.");
|
||||||
DispatchBluetoothReply(aRunnable, v, errorStr);
|
DispatchBluetoothReply(aRunnable, v, errorStr);
|
||||||
|
@ -2299,7 +2258,7 @@ BluetoothDBusService::SetPasskeyInternal(const nsAString& aDeviceAddress,
|
||||||
if (!dbus_message_append_args(reply,
|
if (!dbus_message_append_args(reply,
|
||||||
DBUS_TYPE_UINT32, &passkey,
|
DBUS_TYPE_UINT32, &passkey,
|
||||||
DBUS_TYPE_INVALID)) {
|
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.");
|
errorStr.AssignLiteral("Couldn't append arguments to dbus message.");
|
||||||
result = false;
|
result = false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2323,7 +2282,7 @@ BluetoothDBusService::SetPairingConfirmationInternal(const nsAString& aDeviceAdd
|
||||||
BluetoothValue v = true;
|
BluetoothValue v = true;
|
||||||
DBusMessage *msg;
|
DBusMessage *msg;
|
||||||
if (!sPairingReqTable.Get(aDeviceAddress, &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.");
|
errorStr.AssignLiteral("Couldn't get original request message.");
|
||||||
DispatchBluetoothReply(aRunnable, v, errorStr);
|
DispatchBluetoothReply(aRunnable, v, errorStr);
|
||||||
return false;
|
return false;
|
||||||
|
@ -2339,7 +2298,7 @@ BluetoothDBusService::SetPairingConfirmationInternal(const nsAString& aDeviceAdd
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!reply) {
|
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);
|
dbus_message_unref(msg);
|
||||||
errorStr.AssignLiteral("Memory can't be allocated for the message.");
|
errorStr.AssignLiteral("Memory can't be allocated for the message.");
|
||||||
DispatchBluetoothReply(aRunnable, v, errorStr);
|
DispatchBluetoothReply(aRunnable, v, errorStr);
|
||||||
|
@ -2368,7 +2327,7 @@ BluetoothDBusService::SetAuthorizationInternal(const nsAString& aDeviceAddress,
|
||||||
DBusMessage *msg;
|
DBusMessage *msg;
|
||||||
|
|
||||||
if (!sAuthorizeReqTable.Get(aDeviceAddress, &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.");
|
errorStr.AssignLiteral("Couldn't get original request message.");
|
||||||
DispatchBluetoothReply(aRunnable, v, errorStr);
|
DispatchBluetoothReply(aRunnable, v, errorStr);
|
||||||
return false;
|
return false;
|
||||||
|
@ -2384,7 +2343,7 @@ BluetoothDBusService::SetAuthorizationInternal(const nsAString& aDeviceAddress,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!reply) {
|
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);
|
dbus_message_unref(msg);
|
||||||
errorStr.AssignLiteral("Memory can't be allocated for the message.");
|
errorStr.AssignLiteral("Memory can't be allocated for the message.");
|
||||||
DispatchBluetoothReply(aRunnable, v, errorStr);
|
DispatchBluetoothReply(aRunnable, v, errorStr);
|
||||||
|
|
|
@ -41,11 +41,6 @@ public:
|
||||||
virtual nsresult StopDiscoveryInternal(const nsAString& aAdapterPath,
|
virtual nsresult StopDiscoveryInternal(const nsAString& aAdapterPath,
|
||||||
BluetoothReplyRunnable* aRunnable);
|
BluetoothReplyRunnable* aRunnable);
|
||||||
|
|
||||||
virtual nsresult
|
|
||||||
GetProperties(BluetoothObjectType aType,
|
|
||||||
const nsAString& aPath,
|
|
||||||
BluetoothReplyRunnable* aRunnable);
|
|
||||||
|
|
||||||
virtual nsresult
|
virtual nsresult
|
||||||
GetDevicePropertiesInternal(const BluetoothSignal& aSignal);
|
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);
|
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.
|
* of DOMEvents.
|
||||||
* Usually |this| is returned, but for example global object returns
|
* Usually |this| is returned, but for example global object returns
|
||||||
* the outer object.
|
* the outer object.
|
||||||
|
@ -194,7 +194,7 @@ interface nsIDOMEventTarget : nsISupports
|
||||||
[notxpcom, nostdcall] nsIDOMEventTarget GetTargetForDOMEvent();
|
[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.
|
* of the event and when constructing event target chain.
|
||||||
* Usually |this| is returned, but for example global object returns
|
* Usually |this| is returned, but for example global object returns
|
||||||
* the inner object.
|
* the inner object.
|
||||||
|
@ -286,11 +286,9 @@ interface nsIDOMEventTarget : nsISupports
|
||||||
|
|
||||||
%{C++
|
%{C++
|
||||||
|
|
||||||
typedef nsIDOMEventTarget nsPIDOMEventTarget;
|
|
||||||
|
|
||||||
#define NS_IMPL_DOMTARGET_DEFAULTS(_class) \
|
#define NS_IMPL_DOMTARGET_DEFAULTS(_class) \
|
||||||
nsPIDOMEventTarget* _class::GetTargetForDOMEvent() { return this; } \
|
nsIDOMEventTarget* _class::GetTargetForDOMEvent() { return this; } \
|
||||||
nsPIDOMEventTarget* _class::GetTargetForEventTargetChain() { return this; } \
|
nsIDOMEventTarget* _class::GetTargetForEventTargetChain() { return this; } \
|
||||||
nsresult _class::WillHandleEvent(nsEventChainPostVisitor& aVisitor) { return NS_OK; } \
|
nsresult _class::WillHandleEvent(nsEventChainPostVisitor& aVisitor) { return NS_OK; } \
|
||||||
JSContext* _class::GetJSContextForEventHandlers() { return nullptr; }
|
JSContext* _class::GetJSContextForEventHandlers() { return nullptr; }
|
||||||
|
|
||||||
|
|
|
@ -85,9 +85,12 @@ TabParent::TabParent(const TabContext& aContext)
|
||||||
, mIMECompositionStart(0)
|
, mIMECompositionStart(0)
|
||||||
, mIMESeqno(0)
|
, mIMESeqno(0)
|
||||||
, mEventCaptureDepth(0)
|
, mEventCaptureDepth(0)
|
||||||
|
, mRect(0, 0, 0, 0)
|
||||||
, mDimensions(0, 0)
|
, mDimensions(0, 0)
|
||||||
|
, mOrientation(0)
|
||||||
, mDPI(0)
|
, mDPI(0)
|
||||||
, mShown(false)
|
, mShown(false)
|
||||||
|
, mUpdatedDimensions(false)
|
||||||
, mMarkedDestroying(false)
|
, mMarkedDestroying(false)
|
||||||
, mIsDestroyed(false)
|
, mIsDestroyed(false)
|
||||||
{
|
{
|
||||||
|
@ -265,12 +268,20 @@ TabParent::UpdateDimensions(const nsRect& rect, const nsIntSize& size)
|
||||||
}
|
}
|
||||||
hal::ScreenConfiguration config;
|
hal::ScreenConfiguration config;
|
||||||
hal::GetCurrentScreenConfiguration(&config);
|
hal::GetCurrentScreenConfiguration(&config);
|
||||||
|
ScreenOrientation orientation = config.orientation();
|
||||||
|
|
||||||
unused << SendUpdateDimensions(rect, size, config.orientation());
|
if (!mUpdatedDimensions || mOrientation != orientation ||
|
||||||
if (RenderFrameParent* rfp = GetRenderFrame()) {
|
mDimensions != size || !mRect.IsEqualEdges(rect)) {
|
||||||
rfp->NotifyDimensionsChanged(size.width, size.height);
|
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
|
void
|
||||||
|
|
|
@ -276,9 +276,12 @@ protected:
|
||||||
// The number of event series we're currently capturing.
|
// The number of event series we're currently capturing.
|
||||||
int32_t mEventCaptureDepth;
|
int32_t mEventCaptureDepth;
|
||||||
|
|
||||||
|
nsRect mRect;
|
||||||
nsIntSize mDimensions;
|
nsIntSize mDimensions;
|
||||||
|
ScreenOrientation mOrientation;
|
||||||
float mDPI;
|
float mDPI;
|
||||||
bool mShown;
|
bool mShown;
|
||||||
|
bool mUpdatedDimensions;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
already_AddRefed<nsFrameLoader> GetFrameLoader() const;
|
already_AddRefed<nsFrameLoader> GetFrameLoader() const;
|
||||||
|
|
|
@ -764,8 +764,9 @@ SmsDatabaseService.prototype = {
|
||||||
|
|
||||||
saveSendingMessage: function saveSendingMessage(
|
saveSendingMessage: function saveSendingMessage(
|
||||||
aReceiver, aBody, aDeliveryStatus, aDate, aCallback) {
|
aReceiver, aBody, aDeliveryStatus, aDate, aCallback) {
|
||||||
let sender = this.mRIL.rilContext.icc
|
let rilContext = this.mRIL.rilContext;
|
||||||
? this.mRIL.rilContext.icc.msisdn
|
let sender = rilContext.icc
|
||||||
|
? rilContext.icc.msisdn
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
// Workaround an xpconnect issue with undefined string objects.
|
// Workaround an xpconnect issue with undefined string objects.
|
||||||
|
@ -775,18 +776,21 @@ SmsDatabaseService.prototype = {
|
||||||
}
|
}
|
||||||
|
|
||||||
let receiver = aReceiver;
|
let receiver = aReceiver;
|
||||||
if (receiver) {
|
|
||||||
let parsedNumber = PhoneNumberUtils.parse(receiver.toString());
|
|
||||||
receiver = (parsedNumber && parsedNumber.internationalNumber)
|
|
||||||
? parsedNumber.internationalNumber
|
|
||||||
: receiver;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sender) {
|
if (rilContext.voice.network.mcc === rilContext.icc.mcc) {
|
||||||
let parsedNumber = PhoneNumberUtils.parse(sender.toString());
|
if (receiver) {
|
||||||
sender = (parsedNumber && parsedNumber.internationalNumber)
|
let parsedNumber = PhoneNumberUtils.parse(receiver.toString());
|
||||||
? parsedNumber.internationalNumber
|
receiver = (parsedNumber && parsedNumber.internationalNumber)
|
||||||
: sender;
|
? parsedNumber.internationalNumber
|
||||||
|
: receiver;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sender) {
|
||||||
|
let parsedNumber = PhoneNumberUtils.parse(sender.toString());
|
||||||
|
sender = (parsedNumber && parsedNumber.internationalNumber)
|
||||||
|
? parsedNumber.internationalNumber
|
||||||
|
: sender;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let message = {
|
let message = {
|
||||||
|
|
|
@ -101,12 +101,12 @@ nsVolume::LogState() const
|
||||||
{
|
{
|
||||||
if (mState == nsIVolume::STATE_MOUNTED) {
|
if (mState == nsIVolume::STATE_MOUNTED) {
|
||||||
LOG("nsVolume: %s state %s @ '%s' gen %d locked %d",
|
LOG("nsVolume: %s state %s @ '%s' gen %d locked %d",
|
||||||
NameStr(), StateStr(), MountPointStr(),
|
NameStr().get(), StateStr(), MountPointStr().get(),
|
||||||
MountGeneration(), (int)IsMountLocked());
|
MountGeneration(), (int)IsMountLocked());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("nsVolume: %s state %s", NameStr(), StateStr());
|
LOG("nsVolume: %s state %s", NameStr().get(), StateStr());
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsVolume::Set(const nsVolume* aVolume)
|
void nsVolume::Set(const nsVolume* aVolume)
|
||||||
|
|
|
@ -60,13 +60,13 @@ public:
|
||||||
void LogState() const;
|
void LogState() const;
|
||||||
|
|
||||||
const nsString& Name() const { return mName; }
|
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; }
|
int32_t MountGeneration() const { return mMountGeneration; }
|
||||||
bool IsMountLocked() const { return mMountLocked; }
|
bool IsMountLocked() const { return mMountLocked; }
|
||||||
|
|
||||||
const nsString& MountPoint() const { return mMountPoint; }
|
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; }
|
int32_t State() const { return mState; }
|
||||||
const char* StateStr() const { return NS_VolumeStateStr(mState); }
|
const char* StateStr() const { return NS_VolumeStateStr(mState); }
|
||||||
|
|
|
@ -129,7 +129,7 @@ NS_IMETHODIMP nsVolumeService::BroadcastVolume(const nsAString& aVolName)
|
||||||
nsCOMPtr<nsIObserverService> obs = GetObserverService();
|
nsCOMPtr<nsIObserverService> obs = GetObserverService();
|
||||||
NS_ENSURE_TRUE(obs, NS_NOINTERFACE);
|
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()));
|
nsString stateStr(NS_ConvertUTF8toUTF16(vol->StateStr()));
|
||||||
obs->NotifyObservers(vol, NS_VOLUME_STATE_CHANGED, stateStr.get());
|
obs->NotifyObservers(vol, NS_VOLUME_STATE_CHANGED, stateStr.get());
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -291,8 +291,8 @@ public:
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
DBG("UpdateVolumeRunnable::Run '%s' state %s gen %d locked %d",
|
DBG("UpdateVolumeRunnable::Run '%s' state %s gen %d locked %d",
|
||||||
mVolume->NameStr(), mVolume->StateStr(), mVolume->MountGeneration(),
|
mVolume->NameStr().get(), mVolume->StateStr(),
|
||||||
(int)mVolume->IsMountLocked());
|
mVolume->MountGeneration(), (int)mVolume->IsMountLocked());
|
||||||
|
|
||||||
mVolumeService->UpdateVolume(mVolume);
|
mVolumeService->UpdateVolume(mVolume);
|
||||||
mVolumeService = NULL;
|
mVolumeService = NULL;
|
||||||
|
|
|
@ -60,6 +60,11 @@
|
||||||
value="This button is much longer than the others">
|
value="This button is much longer than the others">
|
||||||
</p></div>
|
</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;"
|
<input id="input-displaynone" style="display: none; border: 0; padding: 0;"
|
||||||
_offsetParent="null">
|
_offsetParent="null">
|
||||||
<p id="p3" style="margin: 2px; border: 0; padding: 1px;"
|
<p id="p3" style="margin: 2px; border: 0; padding: 1px;"
|
||||||
|
|
|
@ -60,6 +60,7 @@ function testElement(element)
|
||||||
offsetParent, element.id);
|
offsetParent, element.id);
|
||||||
|
|
||||||
var scrollWidth, scrollHeight, clientWidth, clientHeight;
|
var scrollWidth, scrollHeight, clientWidth, clientHeight;
|
||||||
|
var doScrollCheck = true;
|
||||||
if (element.id == "scrollbox") {
|
if (element.id == "scrollbox") {
|
||||||
var lastchild = $("lastline");
|
var lastchild = $("lastline");
|
||||||
scrollWidth = lastchild.getBoundingClientRect().width + paddingLeft + paddingRight;
|
scrollWidth = lastchild.getBoundingClientRect().width + paddingLeft + paddingRight;
|
||||||
|
@ -69,18 +70,29 @@ function testElement(element)
|
||||||
scrollHeight = contentsHeight + paddingTop + paddingBottom;
|
scrollHeight = contentsHeight + paddingTop + paddingBottom;
|
||||||
clientWidth = paddingLeft + width + paddingRight - scrollbarWidth;
|
clientWidth = paddingLeft + width + paddingRight - scrollbarWidth;
|
||||||
clientHeight = paddingTop + height + paddingBottom - scrollbarHeight;
|
clientHeight = paddingTop + height + paddingBottom - scrollbarHeight;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
scrollWidth = paddingLeft + width + paddingRight;
|
|
||||||
scrollHeight = paddingTop + height + paddingBottom;
|
|
||||||
clientWidth = paddingLeft + width + paddingRight;
|
clientWidth = paddingLeft + width + paddingRight;
|
||||||
clientHeight = paddingTop + height + paddingBottom;
|
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)
|
if (doScrollCheck) {
|
||||||
checkScrollState(element, 0, 0, 0, 0, element.id);
|
if (element instanceof SVGElement)
|
||||||
else
|
checkScrollState(element, 0, 0, 0, 0, element.id);
|
||||||
checkScrollState(element, 0, 0, scrollWidth, scrollHeight, element.id);
|
else
|
||||||
|
checkScrollState(element, 0, 0, scrollWidth, scrollHeight, element.id);
|
||||||
|
}
|
||||||
|
|
||||||
if (element instanceof SVGElement)
|
if (element instanceof SVGElement)
|
||||||
checkClientState(element, 0, 0, 0, 0, element.id);
|
checkClientState(element, 0, 0, 0, 0, element.id);
|
||||||
|
|
|
@ -1822,7 +1822,7 @@ public:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MOZ_WIDGET_GONK
|
#ifdef MOZ_WIDGET_GONK
|
||||||
if (gUseBackingSurface) {
|
if (gUseBackingSurface && aSize.width >= 64) {
|
||||||
mGLContext->MakeCurrent(true);
|
mGLContext->MakeCurrent(true);
|
||||||
PixelFormat format = PixelFormatForImage(mUpdateFormat);
|
PixelFormat format = PixelFormatForImage(mUpdateFormat);
|
||||||
uint32_t usage = GraphicBuffer::USAGE_HW_TEXTURE |
|
uint32_t usage = GraphicBuffer::USAGE_HW_TEXTURE |
|
||||||
|
|
|
@ -13,9 +13,7 @@ MODULE = gl
|
||||||
LIBRARY_NAME = gl
|
LIBRARY_NAME = gl
|
||||||
LIBXUL_LIBRARY = 1
|
LIBXUL_LIBRARY = 1
|
||||||
EXPORT_LIBRARY = 1
|
EXPORT_LIBRARY = 1
|
||||||
ifndef _MSC_VER
|
|
||||||
FAIL_ON_WARNINGS = 1
|
FAIL_ON_WARNINGS = 1
|
||||||
endif # !_MSC_VER
|
|
||||||
|
|
||||||
EXPORTS = \
|
EXPORTS = \
|
||||||
GLDefs.h \
|
GLDefs.h \
|
||||||
|
|
|
@ -294,6 +294,13 @@ ShadowLayerForwarder::PlatformAllocBuffer(const gfxIntSize& aSize,
|
||||||
uint32_t aCaps,
|
uint32_t aCaps,
|
||||||
SurfaceDescriptor* aBuffer)
|
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");
|
SAMPLE_LABEL("ShadowLayerForwarder", "PlatformAllocBuffer");
|
||||||
// Gralloc buffers are efficiently mappable as gfxImageSurface, so
|
// Gralloc buffers are efficiently mappable as gfxImageSurface, so
|
||||||
// no need to check |aCaps & MAP_AS_IMAGE_SURFACE|.
|
// no need to check |aCaps & MAP_AS_IMAGE_SURFACE|.
|
||||||
|
|
|
@ -14,6 +14,10 @@ LIBRARY_NAME = thebes
|
||||||
LIBXUL_LIBRARY = 1
|
LIBXUL_LIBRARY = 1
|
||||||
EXPORT_LIBRARY = 1
|
EXPORT_LIBRARY = 1
|
||||||
|
|
||||||
|
ifndef _MSC_VER
|
||||||
|
FAIL_ON_WARNINGS = 1
|
||||||
|
endif # !_MSC_VER
|
||||||
|
|
||||||
EXPORTS = \
|
EXPORTS = \
|
||||||
gfx2DGlue.h \
|
gfx2DGlue.h \
|
||||||
gfx3DMatrix.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
|
gfxUserFontType
|
||||||
gfxFontUtils::DetermineFontDataType(const uint8_t *aFontData, uint32_t aFontDataLength)
|
gfxFontUtils::DetermineFontDataType(const uint8_t *aFontData, uint32_t aFontDataLength)
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,6 +12,7 @@ include $(DEPTH)/config/autoconf.mk
|
||||||
MODULE = imgicon
|
MODULE = imgicon
|
||||||
LIBRARY_NAME = imgiconandroid_s
|
LIBRARY_NAME = imgiconandroid_s
|
||||||
LIBXUL_LIBRARY = 1
|
LIBXUL_LIBRARY = 1
|
||||||
|
FAIL_ON_WARNINGS := 1
|
||||||
|
|
||||||
CPPSRCS = nsIconChannel.cpp
|
CPPSRCS = nsIconChannel.cpp
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ const size_t CellSize = size_t(1) << CellShift;
|
||||||
const size_t CellMask = CellSize - 1;
|
const size_t CellMask = CellSize - 1;
|
||||||
|
|
||||||
/* These are magic constants derived from actual offsets in gc/Heap.h. */
|
/* 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;
|
const size_t ChunkMarkBitmapBits = 129024;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -406,6 +406,9 @@ class Vector : private AllocPolicy
|
||||||
/* Clears and releases any heap-allocated storage. */
|
/* Clears and releases any heap-allocated storage. */
|
||||||
void clearAndFree();
|
void clearAndFree();
|
||||||
|
|
||||||
|
/* If true, appending |needed| elements will not call realloc(). */
|
||||||
|
bool canAppendWithoutRealloc(size_t needed) const;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Potentially fallible append operations.
|
* Potentially fallible append operations.
|
||||||
*
|
*
|
||||||
|
@ -772,6 +775,13 @@ Vector<T,N,AP>::clearAndFree()
|
||||||
#endif
|
#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 T, size_t N, class AP>
|
||||||
template <class U>
|
template <class U>
|
||||||
JS_ALWAYS_INLINE bool
|
JS_ALWAYS_INLINE bool
|
||||||
|
|
|
@ -12,10 +12,12 @@
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
#include "jsatom.h"
|
#include "jsatom.h"
|
||||||
#include "jscntxt.h"
|
#include "jscntxt.h"
|
||||||
|
#include "jsinterp.h"
|
||||||
#include "jsobj.h"
|
#include "jsobj.h"
|
||||||
|
|
||||||
#include "builtin/Intl.h"
|
#include "builtin/Intl.h"
|
||||||
#include "vm/GlobalObject.h"
|
#include "vm/GlobalObject.h"
|
||||||
|
#include "vm/Stack.h"
|
||||||
|
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
|
|
||||||
|
@ -27,8 +29,23 @@ static bool
|
||||||
IntlInitialize(JSContext *cx, HandleObject obj, Handle<PropertyName*> initializer,
|
IntlInitialize(JSContext *cx, HandleObject obj, Handle<PropertyName*> initializer,
|
||||||
HandleValue locales, HandleValue options)
|
HandleValue locales, HandleValue options)
|
||||||
{
|
{
|
||||||
// ??? stub - initializer to be implemented as self-hosted function
|
RootedValue initializerValue(cx);
|
||||||
return true;
|
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 ********************/
|
/******************** Collator ********************/
|
||||||
|
@ -55,10 +72,12 @@ collator_toSource(JSContext *cx, unsigned argc, Value *vp)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static JSFunctionSpec collator_static_methods[] = {
|
static JSFunctionSpec collator_static_methods[] = {
|
||||||
|
{"supportedLocalesOf", JSOP_NULLWRAPPER, 1, JSFunction::INTERPRETED, "Intl_Collator_supportedLocalesOf"},
|
||||||
JS_FS_END
|
JS_FS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
static JSFunctionSpec collator_methods[] = {
|
static JSFunctionSpec collator_methods[] = {
|
||||||
|
{"resolvedOptions", JSOP_NULLWRAPPER, 0, JSFunction::INTERPRETED, "Intl_Collator_resolvedOptions"},
|
||||||
#if JS_HAS_TOSOURCE
|
#if JS_HAS_TOSOURCE
|
||||||
JS_FN(js_toSource_str, collator_toSource, 0, 0),
|
JS_FN(js_toSource_str, collator_toSource, 0, 0),
|
||||||
#endif
|
#endif
|
||||||
|
@ -139,6 +158,21 @@ InitCollatorClass(JSContext *cx, HandleObject Intl, Handle<GlobalObject*> global
|
||||||
if (!JS_DefineFunctions(cx, proto, collator_methods))
|
if (!JS_DefineFunctions(cx, proto, collator_methods))
|
||||||
return NULL;
|
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
|
// 10.2.1 and 10.3
|
||||||
RootedValue locales(cx, UndefinedValue());
|
RootedValue locales(cx, UndefinedValue());
|
||||||
RootedValue options(cx, UndefinedValue());
|
RootedValue options(cx, UndefinedValue());
|
||||||
|
@ -190,10 +224,12 @@ numberFormat_toSource(JSContext *cx, unsigned argc, Value *vp)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static JSFunctionSpec numberFormat_static_methods[] = {
|
static JSFunctionSpec numberFormat_static_methods[] = {
|
||||||
|
{"supportedLocalesOf", JSOP_NULLWRAPPER, 1, JSFunction::INTERPRETED, "Intl_NumberFormat_supportedLocalesOf"},
|
||||||
JS_FS_END
|
JS_FS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
static JSFunctionSpec numberFormat_methods[] = {
|
static JSFunctionSpec numberFormat_methods[] = {
|
||||||
|
{"resolvedOptions", JSOP_NULLWRAPPER, 0, JSFunction::INTERPRETED, "Intl_NumberFormat_resolvedOptions"},
|
||||||
#if JS_HAS_TOSOURCE
|
#if JS_HAS_TOSOURCE
|
||||||
JS_FN(js_toSource_str, numberFormat_toSource, 0, 0),
|
JS_FN(js_toSource_str, numberFormat_toSource, 0, 0),
|
||||||
#endif
|
#endif
|
||||||
|
@ -274,6 +310,21 @@ InitNumberFormatClass(JSContext *cx, HandleObject Intl, Handle<GlobalObject*> gl
|
||||||
if (!JS_DefineFunctions(cx, proto, numberFormat_methods))
|
if (!JS_DefineFunctions(cx, proto, numberFormat_methods))
|
||||||
return NULL;
|
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
|
// 11.2.1 and 11.3
|
||||||
RootedValue locales(cx, UndefinedValue());
|
RootedValue locales(cx, UndefinedValue());
|
||||||
RootedValue options(cx, UndefinedValue());
|
RootedValue options(cx, UndefinedValue());
|
||||||
|
@ -325,10 +376,12 @@ dateTimeFormat_toSource(JSContext *cx, unsigned argc, Value *vp)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static JSFunctionSpec dateTimeFormat_static_methods[] = {
|
static JSFunctionSpec dateTimeFormat_static_methods[] = {
|
||||||
|
{"supportedLocalesOf", JSOP_NULLWRAPPER, 1, JSFunction::INTERPRETED, "Intl_DateTimeFormat_supportedLocalesOf"},
|
||||||
JS_FS_END
|
JS_FS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
static JSFunctionSpec dateTimeFormat_methods[] = {
|
static JSFunctionSpec dateTimeFormat_methods[] = {
|
||||||
|
{"resolvedOptions", JSOP_NULLWRAPPER, 0, JSFunction::INTERPRETED, "Intl_DateTimeFormat_resolvedOptions"},
|
||||||
#if JS_HAS_TOSOURCE
|
#if JS_HAS_TOSOURCE
|
||||||
JS_FN(js_toSource_str, dateTimeFormat_toSource, 0, 0),
|
JS_FN(js_toSource_str, dateTimeFormat_toSource, 0, 0),
|
||||||
#endif
|
#endif
|
||||||
|
@ -409,6 +462,21 @@ InitDateTimeFormatClass(JSContext *cx, HandleObject Intl, Handle<GlobalObject*>
|
||||||
if (!JS_DefineFunctions(cx, proto, dateTimeFormat_methods))
|
if (!JS_DefineFunctions(cx, proto, dateTimeFormat_methods))
|
||||||
return NULL;
|
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
|
// 12.2.1 and 12.3
|
||||||
RootedValue locales(cx, UndefinedValue());
|
RootedValue locales(cx, UndefinedValue());
|
||||||
RootedValue options(cx, UndefinedValue());
|
RootedValue options(cx, UndefinedValue());
|
||||||
|
@ -493,12 +561,17 @@ js_InitIntlClass(JSContext *cx, HandleObject obj)
|
||||||
if (!JS_DefineFunctions(cx, Intl, intl_static_methods))
|
if (!JS_DefineFunctions(cx, Intl, intl_static_methods))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!InitCollatorClass(cx, Intl, global))
|
// Skip initialization of the Intl constructors during initialization of the
|
||||||
return NULL;
|
// self-hosting global as we may get here before self-hosted code is compiled,
|
||||||
if (!InitNumberFormatClass(cx, Intl, global))
|
// and no core code refers to the Intl classes.
|
||||||
return NULL;
|
if (!cx->runtime->isSelfHostingGlobal(cx->global())) {
|
||||||
if (!InitDateTimeFormatClass(cx, Intl, global))
|
if (!InitCollatorClass(cx, Intl, global))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (!InitNumberFormatClass(cx, Intl, global))
|
||||||
|
return NULL;
|
||||||
|
if (!InitDateTimeFormatClass(cx, Intl, global))
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
MarkStandardClassInitializedNoProto(global, &IntlClass);
|
MarkStandardClassInitializedNoProto(global, &IntlClass);
|
||||||
|
|
||||||
|
@ -508,7 +581,9 @@ js_InitIntlClass(JSContext *cx, HandleObject obj)
|
||||||
bool
|
bool
|
||||||
GlobalObject::initIntlObject(JSContext *cx, Handle<GlobalObject*> global)
|
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))
|
if (!Intl || !JSObject::setSingletonType(cx, Intl))
|
||||||
return false;
|
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.
|
* will just cause the inner scripts to be repeatedly cloned.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(!bce->emittingRunOnceLambda);
|
JS_ASSERT(!bce->emittingRunOnceLambda);
|
||||||
bce->emittingRunOnceLambda = true;
|
if (bce->checkSingletonContext()) {
|
||||||
if (!EmitTree(cx, bce, pn2))
|
bce->emittingRunOnceLambda = true;
|
||||||
return false;
|
if (!EmitTree(cx, bce, pn2))
|
||||||
bce->emittingRunOnceLambda = false;
|
return false;
|
||||||
|
bce->emittingRunOnceLambda = false;
|
||||||
|
} else {
|
||||||
|
if (!EmitTree(cx, bce, pn2))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
callop = false;
|
callop = false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -85,6 +85,7 @@ struct Cell
|
||||||
MOZ_ALWAYS_INLINE bool markIfUnmarked(uint32_t color = BLACK) const;
|
MOZ_ALWAYS_INLINE bool markIfUnmarked(uint32_t color = BLACK) const;
|
||||||
MOZ_ALWAYS_INLINE void unmark(uint32_t color) const;
|
MOZ_ALWAYS_INLINE void unmark(uint32_t color) const;
|
||||||
|
|
||||||
|
inline JSRuntime *runtime() const;
|
||||||
inline JSCompartment *compartment() const;
|
inline JSCompartment *compartment() const;
|
||||||
inline Zone *zone() const;
|
inline Zone *zone() const;
|
||||||
|
|
||||||
|
@ -593,7 +594,7 @@ struct ChunkInfo
|
||||||
* Calculating sizes and offsets is simpler if sizeof(ChunkInfo) is
|
* Calculating sizes and offsets is simpler if sizeof(ChunkInfo) is
|
||||||
* architecture-independent.
|
* architecture-independent.
|
||||||
*/
|
*/
|
||||||
char padding[12];
|
char padding[16];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -611,6 +612,9 @@ struct ChunkInfo
|
||||||
|
|
||||||
/* Number of GC cycles this chunk has survived. */
|
/* Number of GC cycles this chunk has survived. */
|
||||||
uint32_t age;
|
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);
|
return reinterpret_cast<Chunk *>(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline JSRuntime *
|
||||||
|
Cell::runtime() const
|
||||||
|
{
|
||||||
|
return chunk()->info.runtime;
|
||||||
|
}
|
||||||
|
|
||||||
AllocKind
|
AllocKind
|
||||||
Cell::getAllocKind() const
|
Cell::getAllocKind() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -55,10 +55,10 @@ EdgeCaseAnalysis::AllUsesTruncate(MInstruction *m)
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
for (MUseIterator use = m->usesBegin(); use != m->usesEnd(); use++) {
|
for (MUseIterator use = m->usesBegin(); use != m->usesEnd(); use++) {
|
||||||
// See #809485 why this is allowed
|
// See #809485 why this is allowed
|
||||||
if (use->node()->isResumePoint())
|
if (use->consumer()->isResumePoint())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
MDefinition *def = use->node()->toDefinition();
|
MDefinition *def = use->consumer()->toDefinition();
|
||||||
if (def->isTruncateToInt32())
|
if (def->isTruncateToInt32())
|
||||||
continue;
|
continue;
|
||||||
if (def->isBitAnd())
|
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
|
// Walk the uses a second time, removing any in resume points after
|
||||||
// the last use in a definition.
|
// the last use in a definition.
|
||||||
for (MUseIterator uses(ins->usesBegin()); uses != ins->usesEnd(); ) {
|
for (MUseIterator uses(ins->usesBegin()); uses != ins->usesEnd(); ) {
|
||||||
if (uses->node()->isDefinition()) {
|
if (uses->consumer()->isDefinition()) {
|
||||||
uses++;
|
uses++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
MResumePoint *mrp = uses->node()->toResumePoint();
|
MResumePoint *mrp = uses->consumer()->toResumePoint();
|
||||||
if (mrp->block() != *block ||
|
if (mrp->block() != *block ||
|
||||||
!mrp->instruction() ||
|
!mrp->instruction() ||
|
||||||
mrp->instruction() == *ins ||
|
mrp->instruction() == *ins ||
|
||||||
|
@ -188,8 +188,8 @@ IsPhiObservable(MPhi *phi, Observability observe)
|
||||||
|
|
||||||
case ConservativeObservability:
|
case ConservativeObservability:
|
||||||
for (MUseIterator iter(phi->usesBegin()); iter != phi->usesEnd(); iter++) {
|
for (MUseIterator iter(phi->usesBegin()); iter != phi->usesEnd(); iter++) {
|
||||||
if (!iter->node()->isDefinition() ||
|
if (!iter->consumer()->isDefinition() ||
|
||||||
!iter->node()->toDefinition()->isPhi())
|
!iter->consumer()->toDefinition()->isPhi())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -879,16 +879,30 @@ CheckPredecessorImpliesSuccessor(MBasicBlock *A, MBasicBlock *B)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
CheckMarkedAsUse(MInstruction *ins, MDefinition *operand)
|
CheckOperandImpliesUse(MInstruction *ins, MDefinition *operand)
|
||||||
{
|
{
|
||||||
for (MUseIterator i = operand->usesBegin(); i != operand->usesEnd(); i++) {
|
for (MUseIterator i = operand->usesBegin(); i != operand->usesEnd(); i++) {
|
||||||
if (i->node()->isDefinition()) {
|
if (i->consumer()->isDefinition() && i->consumer()->toDefinition() == ins)
|
||||||
if (ins == i->node()->toDefinition())
|
return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
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
|
#endif // DEBUG
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -926,9 +940,14 @@ ion::AssertGraphCoherency(MIRGraph &graph)
|
||||||
for (size_t i = 0; i < block->numPredecessors(); i++)
|
for (size_t i = 0; i < block->numPredecessors(); i++)
|
||||||
JS_ASSERT(CheckPredecessorImpliesSuccessor(*block, block->getPredecessor(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 (MInstructionIterator ins = block->begin(); ins != block->end(); ins++) {
|
||||||
for (uint32_t i = 0; i < ins->numOperands(); i++)
|
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.
|
// would have been returned.
|
||||||
JS_ASSERT(exits.length() > 0);
|
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) {
|
if (exits.length() > 1) {
|
||||||
retDef = MPhi::New(bottom->stackDepth());
|
phi = MPhi::New(bottom->stackDepth());
|
||||||
bottom->addPhi(retDef);
|
phi->initLength(exits.length());
|
||||||
|
bottom->addPhi(phi);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (MBasicBlock **it = exits.begin(), **end = exits.end(); it != end; ++it) {
|
for (size_t i = 0; i < exits.length(); i++) {
|
||||||
MBasicBlock *exitBlock = *it;
|
MBasicBlock *exitBlock = exits[i];
|
||||||
|
|
||||||
MDefinition *rval = exitBlock->lastIns()->toReturn()->getOperand(0);
|
MDefinition *rval = exitBlock->lastIns()->toReturn()->getOperand(0);
|
||||||
exitBlock->discardLastIns();
|
exitBlock->discardLastIns();
|
||||||
|
@ -2988,10 +2990,10 @@ IonBuilder::patchInlinedReturns(CallInfo &callInfo, MIRGraphExits &exits, MBasic
|
||||||
if (exits.length() == 1)
|
if (exits.length() == 1)
|
||||||
return rval;
|
return rval;
|
||||||
|
|
||||||
retDef->addInput(rval);
|
phi->setOperand(i, rval);
|
||||||
}
|
}
|
||||||
|
|
||||||
return retDef;
|
return phi;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -3529,11 +3531,16 @@ IonBuilder::inlineScriptedCalls(AutoObjectVector &targets, AutoObjectVector &ori
|
||||||
MPhi *phi = MPhi::New(inlineBottom->stackDepth() - callInfo.argc() - 2);
|
MPhi *phi = MPhi::New(inlineBottom->stackDepth() - callInfo.argc() - 2);
|
||||||
inlineBottom->addPhi(phi);
|
inlineBottom->addPhi(phi);
|
||||||
|
|
||||||
|
if (!phi->initLength(retvalDefns.length()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
size_t index = 0;
|
||||||
MDefinition **it = retvalDefns.begin(), **end = retvalDefns.end();
|
MDefinition **it = retvalDefns.begin(), **end = retvalDefns.end();
|
||||||
for (; it != end; ++it) {
|
for (; it != end; it++, index++)
|
||||||
if (!phi->addInput(*it))
|
phi->setOperand(index, *it);
|
||||||
return false;
|
|
||||||
}
|
JS_ASSERT(index == retvalDefns.length());
|
||||||
|
|
||||||
// retvalDefns should become a singleton vector of 'phi'
|
// retvalDefns should become a singleton vector of 'phi'
|
||||||
retvalDefns.clear();
|
retvalDefns.clear();
|
||||||
if (!retvalDefns.append(phi))
|
if (!retvalDefns.append(phi))
|
||||||
|
@ -3578,10 +3585,16 @@ IonBuilder::inlineScriptedCalls(AutoObjectVector &targets, AutoObjectVector &ori
|
||||||
MPhi *phi = MPhi::New(bottom->stackDepth());
|
MPhi *phi = MPhi::New(bottom->stackDepth());
|
||||||
bottom->addPhi(phi);
|
bottom->addPhi(phi);
|
||||||
|
|
||||||
for (MDefinition **it = retvalDefns.begin(), **end = retvalDefns.end(); it != end; ++it) {
|
if (!phi->initLength(retvalDefns.length()))
|
||||||
if (!phi->addInput(*it))
|
return false;
|
||||||
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;
|
retvalDefn = phi;
|
||||||
} else {
|
} else {
|
||||||
retvalDefn = retvalDefns.back();
|
retvalDefn = retvalDefns.back();
|
||||||
|
@ -4216,10 +4229,13 @@ IonBuilder::makeCallHelper(HandleFunction target, CallInfo &callInfo,
|
||||||
return NULL;
|
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);
|
thisArg->block()->discard(thisArg);
|
||||||
|
|
||||||
|
MPassArg *newThis = MPassArg::New(create);
|
||||||
current->add(newThis);
|
current->add(newThis);
|
||||||
|
|
||||||
thisArg = newThis;
|
thisArg = newThis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -551,7 +551,7 @@ CanEmitCompareAtUses(MInstruction *ins)
|
||||||
|
|
||||||
bool foundTest = false;
|
bool foundTest = false;
|
||||||
for (MUseIterator iter(ins->usesBegin()); iter != ins->usesEnd(); iter++) {
|
for (MUseIterator iter(ins->usesBegin()); iter != ins->usesEnd(); iter++) {
|
||||||
MNode *node = iter->node();
|
MNode *node = iter->consumer();
|
||||||
if (!node->isDefinition())
|
if (!node->isDefinition())
|
||||||
return false;
|
return false;
|
||||||
if (!node->toDefinition()->isTest())
|
if (!node->toDefinition()->isTest())
|
||||||
|
|
|
@ -248,43 +248,70 @@ MDefinition::removeUse(MUseIterator use)
|
||||||
}
|
}
|
||||||
|
|
||||||
MUseIterator
|
MUseIterator
|
||||||
MNode::replaceOperand(MUseIterator use, MDefinition *ins)
|
MNode::replaceOperand(MUseIterator use, MDefinition *def)
|
||||||
{
|
{
|
||||||
MDefinition *used = getOperand(use->index());
|
JS_ASSERT(def != NULL);
|
||||||
if (used == ins)
|
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;
|
return use;
|
||||||
|
|
||||||
MUse *save = *use;
|
MUseIterator result(prev->removeUse(use));
|
||||||
MUseIterator result(used->removeUse(use));
|
setOperand(index, def);
|
||||||
if (ins) {
|
|
||||||
setOperand(save->index(), ins);
|
|
||||||
ins->linkUse(save);
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MNode::replaceOperand(size_t index, MDefinition *def)
|
MNode::replaceOperand(size_t index, MDefinition *def)
|
||||||
{
|
{
|
||||||
MDefinition *d = getOperand(index);
|
JS_ASSERT(def != NULL);
|
||||||
for (MUseIterator i(d->usesBegin()); i != d->usesEnd(); i++) {
|
MUse *use = getUseFor(index);
|
||||||
if (i->index() == index && i->node() == this) {
|
MDefinition *prev = use->producer();
|
||||||
replaceOperand(i, def);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
void
|
||||||
MDefinition::replaceAllUsesWith(MDefinition *dom)
|
MDefinition::replaceAllUsesWith(MDefinition *dom)
|
||||||
{
|
{
|
||||||
for (MUseIterator i(uses_.begin()); i != uses_.end(); ) {
|
JS_ASSERT(dom != NULL);
|
||||||
MUse *use = *i;
|
if (dom == this)
|
||||||
i = uses_.removeAt(i);
|
return;
|
||||||
use->node()->setOperand(use->index(), dom);
|
|
||||||
dom->linkUse(use);
|
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
|
void
|
||||||
MPhi::removeOperand(size_t index)
|
MPhi::removeOperand(size_t index)
|
||||||
{
|
{
|
||||||
|
MUse *use = getUseFor(index);
|
||||||
|
|
||||||
JS_ASSERT(index < inputs_.length());
|
JS_ASSERT(index < inputs_.length());
|
||||||
JS_ASSERT(inputs_.length() > 1);
|
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
|
// If we have phi(..., a, b, c, d, ..., z) and we plan
|
||||||
// on removing a, then first shift downward so that we have
|
// on removing a, then first shift downward so that we have
|
||||||
// phi(..., b, c, d, ..., z, z):
|
// phi(..., b, c, d, ..., z, z):
|
||||||
size_t length = inputs_.length();
|
size_t length = inputs_.length();
|
||||||
for (size_t i = index + 1; i < length; i++)
|
for (size_t i = index; i < length - 1; i++) {
|
||||||
replaceOperand(i - 1, getOperand(i));
|
MUse *next = MPhi::getUseFor(i + 1);
|
||||||
|
next->producer()->removeUse(next);
|
||||||
// remove the final operand that now appears twice:
|
MPhi::setOperand(i, next->producer());
|
||||||
replaceOperand(length - 1, NULL);
|
}
|
||||||
|
|
||||||
// truncate the inputs_ list:
|
// truncate the inputs_ list:
|
||||||
inputs_.shrinkBy(1);
|
inputs_.shrinkBy(1);
|
||||||
|
@ -523,17 +559,56 @@ MPhi::congruentTo(MDefinition *const &ins) const
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
MPhi::addInput(MDefinition *ins)
|
MPhi::initLength(size_t length)
|
||||||
{
|
{
|
||||||
ins->addUse(this, inputs_.length());
|
// Initializes a new MPhi to have an Operand vector of at least the given
|
||||||
return inputs_.append(ins);
|
// 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
|
uint32_t
|
||||||
MPrepareCall::argc() const
|
MPrepareCall::argc() const
|
||||||
{
|
{
|
||||||
JS_ASSERT(useCount() == 1);
|
JS_ASSERT(useCount() == 1);
|
||||||
MCall *call = usesBegin()->node()->toDefinition()->toCall();
|
MCall *call = usesBegin()->consumer()->toDefinition()->toCall();
|
||||||
return call->numStackArgs();
|
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.
|
// The operand vector is initialized in reverse order by the IonBuilder.
|
||||||
// It cannot be checked for consistency until all arguments are added.
|
// It cannot be checked for consistency until all arguments are added.
|
||||||
arg->setArgnum(argnum);
|
arg->setArgnum(argnum);
|
||||||
MNode::initOperand(argnum + NumNonArgumentOperands, arg->toDefinition());
|
setOperand(argnum + NumNonArgumentOperands, arg->toDefinition());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -647,10 +722,10 @@ NeedNegativeZeroCheck(MDefinition *def)
|
||||||
{
|
{
|
||||||
// Test if all uses have the same semantics for -0 and 0
|
// Test if all uses have the same semantics for -0 and 0
|
||||||
for (MUseIterator use = def->usesBegin(); use != def->usesEnd(); use++) {
|
for (MUseIterator use = def->usesBegin(); use != def->usesEnd(); use++) {
|
||||||
if (use->node()->isResumePoint())
|
if (use->consumer()->isResumePoint())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
MDefinition *use_def = use->node()->toDefinition();
|
MDefinition *use_def = use->consumer()->toDefinition();
|
||||||
switch (use_def->op()) {
|
switch (use_def->op()) {
|
||||||
case MDefinition::Op_Add: {
|
case MDefinition::Op_Add: {
|
||||||
// If add is truncating -0 and 0 are observed as the same.
|
// 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::New(MBasicBlock *block, jsbytecode *pc, MResumePoint *parent, Mode mode)
|
||||||
{
|
{
|
||||||
MResumePoint *resume = new MResumePoint(block, pc, parent, mode);
|
MResumePoint *resume = new MResumePoint(block, pc, parent, mode);
|
||||||
if (!resume->init(block))
|
if (!resume->init())
|
||||||
return NULL;
|
return NULL;
|
||||||
resume->inherit(block);
|
resume->inherit(block);
|
||||||
return resume;
|
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
|
void
|
||||||
MResumePoint::inherit(MBasicBlock *block)
|
MResumePoint::inherit(MBasicBlock *block)
|
||||||
{
|
{
|
||||||
|
@ -1462,7 +1528,7 @@ MResumePoint::inherit(MBasicBlock *block)
|
||||||
// and LStackArg does not define a value.
|
// and LStackArg does not define a value.
|
||||||
if (def->isPassArg())
|
if (def->isPassArg())
|
||||||
def = def->toPassArg()->getArgument();
|
def = def->toPassArg()->getArgument();
|
||||||
initOperand(i, def);
|
setOperand(i, def);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
270
js/src/ion/MIR.h
270
js/src/ion/MIR.h
|
@ -67,32 +67,51 @@ class MResumePoint;
|
||||||
static inline bool isOSRLikeValue (MDefinition *def);
|
static inline bool isOSRLikeValue (MDefinition *def);
|
||||||
|
|
||||||
// Represents a use of a node.
|
// Represents a use of a node.
|
||||||
class MUse : public TempObject, public InlineForwardListNode<MUse>
|
class MUse : public TempObject, public InlineListNode<MUse>
|
||||||
{
|
{
|
||||||
friend class MDefinition;
|
friend class MDefinition;
|
||||||
|
|
||||||
MNode *node_; // The node that is using this operand.
|
MDefinition *producer_; // MDefinition that is being used.
|
||||||
uint32_t index_; // The index of this operand in its owner.
|
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)
|
MUse(MDefinition *producer, MNode *consumer, uint32_t index)
|
||||||
: node_(owner),
|
: producer_(producer),
|
||||||
|
consumer_(consumer),
|
||||||
index_(index)
|
index_(index)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static inline MUse *New(MNode *owner, uint32_t index) {
|
// Default constructor for use in vectors.
|
||||||
return new MUse(owner, index);
|
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 {
|
// Set data inside the MUse.
|
||||||
return node_;
|
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 {
|
uint32_t index() const {
|
||||||
return index_;
|
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:
|
// A node is an entry in the MIR graph. It has two kinds:
|
||||||
// MInstruction: an instruction which appears in the IR stream.
|
// MInstruction: an instruction which appears in the IR stream.
|
||||||
|
@ -114,9 +133,12 @@ class MNode : public TempObject
|
||||||
ResumePoint
|
ResumePoint
|
||||||
};
|
};
|
||||||
|
|
||||||
MNode() : block_(NULL)
|
MNode()
|
||||||
|
: block_(NULL)
|
||||||
{ }
|
{ }
|
||||||
MNode(MBasicBlock *block) : block_(block)
|
|
||||||
|
MNode(MBasicBlock *block)
|
||||||
|
: block_(block)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual Kind kind() const = 0;
|
virtual Kind kind() const = 0;
|
||||||
|
@ -141,20 +163,25 @@ class MNode : public TempObject
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replaces an operand, taking care to update use chains. No memory is
|
// Replaces an already-set operand during iteration over a use chain.
|
||||||
// allocated; the existing data structures are re-linked.
|
|
||||||
MUseIterator replaceOperand(MUseIterator use, MDefinition *ins);
|
MUseIterator replaceOperand(MUseIterator use, MDefinition *ins);
|
||||||
|
|
||||||
|
// Replaces an already-set operand, updating use information.
|
||||||
void replaceOperand(size_t index, MDefinition *ins);
|
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 MDefinition *toDefinition();
|
||||||
inline MResumePoint *toResumePoint();
|
inline MResumePoint *toResumePoint();
|
||||||
|
|
||||||
protected:
|
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;
|
virtual void setOperand(size_t index, MDefinition *operand) = 0;
|
||||||
|
|
||||||
// Initializes an operand for the first time.
|
// Gets the MUse corresponding to given operand.
|
||||||
inline void initOperand(size_t index, MDefinition *ins);
|
virtual MUse *getUseFor(size_t index) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AliasSet {
|
class AliasSet {
|
||||||
|
@ -230,8 +257,8 @@ class MDefinition : public MNode
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
InlineForwardList<MUse> uses_; // Use chain.
|
InlineList<MUse> uses_; // Use chain.
|
||||||
uint32_t id_; // Instruction ID, which after block re-ordering
|
uint32_t id_; // Instruction ID, which after block re-ordering
|
||||||
// is sorted within a basic block.
|
// is sorted within a basic block.
|
||||||
ValueNumberData *valueNumber_; // The instruction's value number (see GVN for details in use)
|
ValueNumberData *valueNumber_; // The instruction's value number (see GVN for details in use)
|
||||||
Range *range_; // Any computed range for this def.
|
Range *range_; // Any computed range for this def.
|
||||||
|
@ -377,6 +404,9 @@ class MDefinition : public MNode
|
||||||
|
|
||||||
// Removes a use at the given position
|
// Removes a use at the given position
|
||||||
MUseIterator removeUse(MUseIterator use);
|
MUseIterator removeUse(MUseIterator use);
|
||||||
|
void removeUse(MUse *use) {
|
||||||
|
uses_.remove(use);
|
||||||
|
}
|
||||||
|
|
||||||
// Number of uses of this instruction.
|
// Number of uses of this instruction.
|
||||||
size_t useCount() const;
|
size_t useCount() const;
|
||||||
|
@ -389,8 +419,8 @@ class MDefinition : public MNode
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addUse(MNode *node, size_t index) {
|
void addUse(MUse *use) {
|
||||||
uses_.pushFront(MUse::New(node, index));
|
uses_.pushFront(use);
|
||||||
}
|
}
|
||||||
void replaceAllUsesWith(MDefinition *dom);
|
void replaceAllUsesWith(MDefinition *dom);
|
||||||
|
|
||||||
|
@ -406,13 +436,6 @@ class MDefinition : public MNode
|
||||||
return true;
|
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) {
|
void setVirtualRegister(uint32_t vreg) {
|
||||||
virtualRegister_ = vreg;
|
virtualRegister_ = vreg;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -494,7 +517,7 @@ class MUseDefIterator
|
||||||
MUseIterator search(MUseIterator start) {
|
MUseIterator search(MUseIterator start) {
|
||||||
MUseIterator i(start);
|
MUseIterator i(start);
|
||||||
for (; i != def_->usesEnd(); i++) {
|
for (; i != def_->usesEnd(); i++) {
|
||||||
if (i->node()->isDefinition())
|
if (i->consumer()->isDefinition())
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
return def_->usesEnd();
|
return def_->usesEnd();
|
||||||
|
@ -504,8 +527,7 @@ class MUseDefIterator
|
||||||
MUseDefIterator(MDefinition *def)
|
MUseDefIterator(MDefinition *def)
|
||||||
: def_(def),
|
: def_(def),
|
||||||
current_(search(def->usesBegin()))
|
current_(search(def->usesBegin()))
|
||||||
{
|
{ }
|
||||||
}
|
|
||||||
|
|
||||||
operator bool() const {
|
operator bool() const {
|
||||||
return current_ != def_->usesEnd();
|
return current_ != def_->usesEnd();
|
||||||
|
@ -521,7 +543,7 @@ class MUseDefIterator
|
||||||
return *current_;
|
return *current_;
|
||||||
}
|
}
|
||||||
MDefinition *def() const {
|
MDefinition *def() const {
|
||||||
return current_->node()->toDefinition();
|
return current_->consumer()->toDefinition();
|
||||||
}
|
}
|
||||||
size_t index() const {
|
size_t index() const {
|
||||||
return current_->index();
|
return current_->index();
|
||||||
|
@ -564,15 +586,20 @@ template <size_t Arity>
|
||||||
class MAryInstruction : public MInstruction
|
class MAryInstruction : public MInstruction
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
FixedArityList<MDefinition*, Arity> operands_;
|
FixedArityList<MUse, Arity> operands_;
|
||||||
|
|
||||||
void setOperand(size_t index, MDefinition *operand) {
|
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:
|
public:
|
||||||
MDefinition *getOperand(size_t index) const {
|
MDefinition *getOperand(size_t index) const {
|
||||||
return operands_[index];
|
return operands_[index].producer();
|
||||||
}
|
}
|
||||||
size_t numOperands() const {
|
size_t numOperands() const {
|
||||||
return Arity;
|
return Arity;
|
||||||
|
@ -758,7 +785,7 @@ class MTableSwitch
|
||||||
// Contains the blocks/cases that still need to get build
|
// Contains the blocks/cases that still need to get build
|
||||||
Vector<MBasicBlock*, 0, IonAllocPolicy> blocks_;
|
Vector<MBasicBlock*, 0, IonAllocPolicy> blocks_;
|
||||||
|
|
||||||
MDefinition *operand_;
|
MUse operand_;
|
||||||
int32_t low_;
|
int32_t low_;
|
||||||
int32_t high_;
|
int32_t high_;
|
||||||
|
|
||||||
|
@ -768,13 +795,19 @@ class MTableSwitch
|
||||||
low_(low),
|
low_(low),
|
||||||
high_(high)
|
high_(high)
|
||||||
{
|
{
|
||||||
initOperand(0, ins);
|
setOperand(0, ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setOperand(size_t index, MDefinition *operand) {
|
void setOperand(size_t index, MDefinition *operand) {
|
||||||
JS_ASSERT(index == 0);
|
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:
|
public:
|
||||||
|
@ -846,7 +879,7 @@ class MTableSwitch
|
||||||
|
|
||||||
MDefinition *getOperand(size_t index) const {
|
MDefinition *getOperand(size_t index) const {
|
||||||
JS_ASSERT(index == 0);
|
JS_ASSERT(index == 0);
|
||||||
return operand_;
|
return operand_.producer();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t numOperands() const {
|
size_t numOperands() const {
|
||||||
|
@ -857,20 +890,25 @@ class MTableSwitch
|
||||||
template <size_t Arity, size_t Successors>
|
template <size_t Arity, size_t Successors>
|
||||||
class MAryControlInstruction : public MControlInstruction
|
class MAryControlInstruction : public MControlInstruction
|
||||||
{
|
{
|
||||||
FixedArityList<MDefinition *, Arity> operands_;
|
FixedArityList<MUse, Arity> operands_;
|
||||||
FixedArityList<MBasicBlock *, Successors> successors_;
|
FixedArityList<MBasicBlock *, Successors> successors_;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setOperand(size_t index, MDefinition *operand) {
|
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) {
|
void setSuccessor(size_t index, MBasicBlock *successor) {
|
||||||
successors_[index] = successor;
|
successors_[index] = successor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MUse *getUseFor(size_t index) {
|
||||||
|
return &operands_[index];
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MDefinition *getOperand(size_t index) const {
|
MDefinition *getOperand(size_t index) const {
|
||||||
return operands_[index];
|
return operands_[index].producer();
|
||||||
}
|
}
|
||||||
size_t numOperands() const {
|
size_t numOperands() const {
|
||||||
return Arity;
|
return Arity;
|
||||||
|
@ -927,7 +965,7 @@ class MTest
|
||||||
MTest(MDefinition *ins, MBasicBlock *if_true, MBasicBlock *if_false)
|
MTest(MDefinition *ins, MBasicBlock *if_true, MBasicBlock *if_false)
|
||||||
: operandMightEmulateUndefined_(true)
|
: operandMightEmulateUndefined_(true)
|
||||||
{
|
{
|
||||||
initOperand(0, ins);
|
setOperand(0, ins);
|
||||||
setSuccessor(0, if_true);
|
setSuccessor(0, if_true);
|
||||||
setSuccessor(1, if_false);
|
setSuccessor(1, if_false);
|
||||||
}
|
}
|
||||||
|
@ -970,7 +1008,7 @@ class MReturn
|
||||||
public BoxInputsPolicy
|
public BoxInputsPolicy
|
||||||
{
|
{
|
||||||
MReturn(MDefinition *ins) {
|
MReturn(MDefinition *ins) {
|
||||||
initOperand(0, ins);
|
setOperand(0, ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -992,7 +1030,7 @@ class MThrow
|
||||||
public BoxInputsPolicy
|
public BoxInputsPolicy
|
||||||
{
|
{
|
||||||
MThrow(MDefinition *ins) {
|
MThrow(MDefinition *ins) {
|
||||||
initOperand(0, ins);
|
setOperand(0, ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -1093,8 +1131,8 @@ class MInitProp
|
||||||
MInitProp(MDefinition *obj, HandlePropertyName name, MDefinition *value)
|
MInitProp(MDefinition *obj, HandlePropertyName name, MDefinition *value)
|
||||||
: name_(name)
|
: name_(name)
|
||||||
{
|
{
|
||||||
initOperand(0, obj);
|
setOperand(0, obj);
|
||||||
initOperand(1, value);
|
setOperand(1, value);
|
||||||
setResultType(MIRType_None);
|
setResultType(MIRType_None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1141,7 +1179,7 @@ class MPrepareCall : public MNullaryInstruction
|
||||||
|
|
||||||
class MVariadicInstruction : public MInstruction
|
class MVariadicInstruction : public MInstruction
|
||||||
{
|
{
|
||||||
FixedList<MDefinition *> operands_;
|
FixedList<MUse> operands_;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool init(size_t length) {
|
bool init(size_t length) {
|
||||||
|
@ -1151,13 +1189,18 @@ class MVariadicInstruction : public MInstruction
|
||||||
public:
|
public:
|
||||||
// Will assert if called before initialization.
|
// Will assert if called before initialization.
|
||||||
MDefinition *getOperand(size_t index) const {
|
MDefinition *getOperand(size_t index) const {
|
||||||
return operands_[index];
|
return operands_[index].producer();
|
||||||
}
|
}
|
||||||
size_t numOperands() const {
|
size_t numOperands() const {
|
||||||
return operands_.length();
|
return operands_.length();
|
||||||
}
|
}
|
||||||
void setOperand(size_t index, MDefinition *operand) {
|
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) {
|
void initPrepareCall(MDefinition *start) {
|
||||||
JS_ASSERT(start->isPrepareCall());
|
JS_ASSERT(start->isPrepareCall());
|
||||||
return initOperand(PrepareCallOperandIndex, start);
|
return setOperand(PrepareCallOperandIndex, start);
|
||||||
}
|
}
|
||||||
void initFunction(MDefinition *func) {
|
void initFunction(MDefinition *func) {
|
||||||
JS_ASSERT(!func->isPassArg());
|
JS_ASSERT(!func->isPassArg());
|
||||||
return initOperand(FunctionOperandIndex, func);
|
return setOperand(FunctionOperandIndex, func);
|
||||||
}
|
}
|
||||||
|
|
||||||
MDefinition *getFunction() const {
|
MDefinition *getFunction() const {
|
||||||
|
@ -1264,9 +1307,9 @@ class MApplyArgs
|
||||||
MApplyArgs(JSFunction *target, MDefinition *fun, MDefinition *argc, MDefinition *self)
|
MApplyArgs(JSFunction *target, MDefinition *fun, MDefinition *argc, MDefinition *self)
|
||||||
: target_(target)
|
: target_(target)
|
||||||
{
|
{
|
||||||
initOperand(0, fun);
|
setOperand(0, fun);
|
||||||
initOperand(1, argc);
|
setOperand(1, argc);
|
||||||
initOperand(2, self);
|
setOperand(2, self);
|
||||||
setResultType(MIRType_Value);
|
setResultType(MIRType_Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1301,7 +1344,7 @@ class MUnaryInstruction : public MAryInstruction<1>
|
||||||
protected:
|
protected:
|
||||||
MUnaryInstruction(MDefinition *ins)
|
MUnaryInstruction(MDefinition *ins)
|
||||||
{
|
{
|
||||||
initOperand(0, ins);
|
setOperand(0, ins);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1310,8 +1353,8 @@ class MBinaryInstruction : public MAryInstruction<2>
|
||||||
protected:
|
protected:
|
||||||
MBinaryInstruction(MDefinition *left, MDefinition *right)
|
MBinaryInstruction(MDefinition *left, MDefinition *right)
|
||||||
{
|
{
|
||||||
initOperand(0, left);
|
setOperand(0, left);
|
||||||
initOperand(1, right);
|
setOperand(1, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -1375,9 +1418,9 @@ class MTernaryInstruction : public MAryInstruction<3>
|
||||||
protected:
|
protected:
|
||||||
MTernaryInstruction(MDefinition *first, MDefinition *second, MDefinition *third)
|
MTernaryInstruction(MDefinition *first, MDefinition *second, MDefinition *third)
|
||||||
{
|
{
|
||||||
initOperand(0, first);
|
setOperand(0, first);
|
||||||
initOperand(1, second);
|
setOperand(1, second);
|
||||||
initOperand(2, third);
|
setOperand(2, third);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -1778,8 +1821,8 @@ class MReturnFromCtor
|
||||||
public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >
|
public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >
|
||||||
{
|
{
|
||||||
MReturnFromCtor(MDefinition *value, MDefinition *object) {
|
MReturnFromCtor(MDefinition *value, MDefinition *object) {
|
||||||
initOperand(0, value);
|
setOperand(0, value);
|
||||||
initOperand(1, object);
|
setOperand(1, object);
|
||||||
setResultType(MIRType_Object);
|
setResultType(MIRType_Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2932,10 +2975,12 @@ class MFromCharCode
|
||||||
|
|
||||||
class MPhi : public MDefinition, public InlineForwardListNode<MPhi>
|
class MPhi : public MDefinition, public InlineForwardListNode<MPhi>
|
||||||
{
|
{
|
||||||
js::Vector<MDefinition *, 2, IonAllocPolicy> inputs_;
|
js::Vector<MUse, 2, IonAllocPolicy> inputs_;
|
||||||
|
|
||||||
uint32_t slot_;
|
uint32_t slot_;
|
||||||
bool triedToSpecialize_;
|
bool triedToSpecialize_;
|
||||||
bool isIterator_;
|
bool isIterator_;
|
||||||
|
|
||||||
MPhi(uint32_t slot)
|
MPhi(uint32_t slot)
|
||||||
: slot_(slot),
|
: slot_(slot),
|
||||||
triedToSpecialize_(false),
|
triedToSpecialize_(false),
|
||||||
|
@ -2945,18 +2990,25 @@ class MPhi : public MDefinition, public InlineForwardListNode<MPhi>
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setOperand(size_t index, MDefinition *operand) {
|
MUse *getUseFor(size_t index) {
|
||||||
inputs_[index] = operand;
|
return &inputs_[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
INSTRUCTION_HEADER(Phi)
|
INSTRUCTION_HEADER(Phi)
|
||||||
static MPhi *New(uint32_t slot);
|
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);
|
void removeOperand(size_t index);
|
||||||
|
|
||||||
MDefinition *getOperand(size_t index) const {
|
MDefinition *getOperand(size_t index) const {
|
||||||
return inputs_[index];
|
return inputs_[index].producer();
|
||||||
}
|
}
|
||||||
size_t numOperands() const {
|
size_t numOperands() const {
|
||||||
return inputs_.length();
|
return inputs_.length();
|
||||||
|
@ -2971,7 +3023,14 @@ class MPhi : public MDefinition, public InlineForwardListNode<MPhi>
|
||||||
triedToSpecialize_ = true;
|
triedToSpecialize_ = true;
|
||||||
setResultType(type);
|
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);
|
MDefinition *foldsTo(bool useValueNumbers);
|
||||||
|
|
||||||
|
@ -3476,8 +3535,8 @@ class MSetInitializedLength
|
||||||
{
|
{
|
||||||
MSetInitializedLength(MDefinition *elements, MDefinition *index)
|
MSetInitializedLength(MDefinition *elements, MDefinition *index)
|
||||||
{
|
{
|
||||||
initOperand(0, elements);
|
setOperand(0, elements);
|
||||||
initOperand(1, index);
|
setOperand(1, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -3855,9 +3914,9 @@ class MStoreElement
|
||||||
bool needsHoleCheck_;
|
bool needsHoleCheck_;
|
||||||
|
|
||||||
MStoreElement(MDefinition *elements, MDefinition *index, MDefinition *value, bool needsHoleCheck) {
|
MStoreElement(MDefinition *elements, MDefinition *index, MDefinition *value, bool needsHoleCheck) {
|
||||||
initOperand(0, elements);
|
setOperand(0, elements);
|
||||||
initOperand(1, index);
|
setOperand(1, index);
|
||||||
initOperand(2, value);
|
setOperand(2, value);
|
||||||
needsHoleCheck_ = needsHoleCheck;
|
needsHoleCheck_ = needsHoleCheck;
|
||||||
JS_ASSERT(elements->type() == MIRType_Elements);
|
JS_ASSERT(elements->type() == MIRType_Elements);
|
||||||
JS_ASSERT(index->type() == MIRType_Int32);
|
JS_ASSERT(index->type() == MIRType_Int32);
|
||||||
|
@ -3904,10 +3963,10 @@ class MStoreElementHole
|
||||||
{
|
{
|
||||||
MStoreElementHole(MDefinition *object, MDefinition *elements,
|
MStoreElementHole(MDefinition *object, MDefinition *elements,
|
||||||
MDefinition *index, MDefinition *value) {
|
MDefinition *index, MDefinition *value) {
|
||||||
initOperand(0, object);
|
setOperand(0, object);
|
||||||
initOperand(1, elements);
|
setOperand(1, elements);
|
||||||
initOperand(2, index);
|
setOperand(2, index);
|
||||||
initOperand(3, value);
|
setOperand(3, value);
|
||||||
JS_ASSERT(elements->type() == MIRType_Elements);
|
JS_ASSERT(elements->type() == MIRType_Elements);
|
||||||
JS_ASSERT(index->type() == MIRType_Int32);
|
JS_ASSERT(index->type() == MIRType_Int32);
|
||||||
}
|
}
|
||||||
|
@ -4517,39 +4576,45 @@ class MPolyInlineDispatch : public MControlInstruction, public SingleObjectPolic
|
||||||
};
|
};
|
||||||
Vector<Entry, 4, IonAllocPolicy> dispatchTable_;
|
Vector<Entry, 4, IonAllocPolicy> dispatchTable_;
|
||||||
|
|
||||||
MDefinition *operand_;
|
MUse operand_;
|
||||||
InlinePropertyTable *inlinePropertyTable_;
|
InlinePropertyTable *inlinePropertyTable_;
|
||||||
MBasicBlock *fallbackPrepBlock_;
|
MBasicBlock *fallbackPrepBlock_;
|
||||||
MBasicBlock *fallbackMidBlock_;
|
MBasicBlock *fallbackMidBlock_;
|
||||||
MBasicBlock *fallbackEndBlock_;
|
MBasicBlock *fallbackEndBlock_;
|
||||||
|
|
||||||
MPolyInlineDispatch(MDefinition *ins)
|
MPolyInlineDispatch(MDefinition *ins)
|
||||||
: dispatchTable_(), operand_(NULL),
|
: dispatchTable_(),
|
||||||
inlinePropertyTable_(NULL),
|
inlinePropertyTable_(NULL),
|
||||||
fallbackPrepBlock_(NULL),
|
fallbackPrepBlock_(NULL),
|
||||||
fallbackMidBlock_(NULL),
|
fallbackMidBlock_(NULL),
|
||||||
fallbackEndBlock_(NULL)
|
fallbackEndBlock_(NULL)
|
||||||
{
|
{
|
||||||
initOperand(0, ins);
|
setOperand(0, ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
MPolyInlineDispatch(MDefinition *ins, InlinePropertyTable *inlinePropertyTable,
|
MPolyInlineDispatch(MDefinition *ins, InlinePropertyTable *inlinePropertyTable,
|
||||||
MBasicBlock *fallbackPrepBlock,
|
MBasicBlock *fallbackPrepBlock,
|
||||||
MBasicBlock *fallbackMidBlock,
|
MBasicBlock *fallbackMidBlock,
|
||||||
MBasicBlock *fallbackEndBlock)
|
MBasicBlock *fallbackEndBlock)
|
||||||
: dispatchTable_(), operand_(NULL),
|
: dispatchTable_(),
|
||||||
inlinePropertyTable_(inlinePropertyTable),
|
inlinePropertyTable_(inlinePropertyTable),
|
||||||
fallbackPrepBlock_(fallbackPrepBlock),
|
fallbackPrepBlock_(fallbackPrepBlock),
|
||||||
fallbackMidBlock_(fallbackMidBlock),
|
fallbackMidBlock_(fallbackMidBlock),
|
||||||
fallbackEndBlock_(fallbackEndBlock)
|
fallbackEndBlock_(fallbackEndBlock)
|
||||||
{
|
{
|
||||||
initOperand(0, ins);
|
setOperand(0, ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void setOperand(size_t index, MDefinition *operand) {
|
virtual void setOperand(size_t index, MDefinition *operand) {
|
||||||
JS_ASSERT(index == 0);
|
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) {
|
void setSuccessor(size_t i, MBasicBlock *successor) {
|
||||||
|
@ -4565,7 +4630,7 @@ class MPolyInlineDispatch : public MControlInstruction, public SingleObjectPolic
|
||||||
|
|
||||||
virtual MDefinition *getOperand(size_t index) const {
|
virtual MDefinition *getOperand(size_t index) const {
|
||||||
JS_ASSERT(index == 0);
|
JS_ASSERT(index == 0);
|
||||||
return operand_;
|
return operand_.producer();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual size_t numOperands() const {
|
virtual size_t numOperands() const {
|
||||||
|
@ -5247,9 +5312,9 @@ class MCallSetElement
|
||||||
public CallSetElementPolicy
|
public CallSetElementPolicy
|
||||||
{
|
{
|
||||||
MCallSetElement(MDefinition *object, MDefinition *index, MDefinition *value) {
|
MCallSetElement(MDefinition *object, MDefinition *index, MDefinition *value) {
|
||||||
initOperand(0, object);
|
setOperand(0, object);
|
||||||
initOperand(1, index);
|
setOperand(1, index);
|
||||||
initOperand(2, value);
|
setOperand(2, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -5282,8 +5347,8 @@ class MSetDOMProperty
|
||||||
MSetDOMProperty(const JSJitPropertyOp func, MDefinition *obj, MDefinition *val)
|
MSetDOMProperty(const JSJitPropertyOp func, MDefinition *obj, MDefinition *val)
|
||||||
: func_(func)
|
: func_(func)
|
||||||
{
|
{
|
||||||
initOperand(0, obj);
|
setOperand(0, obj);
|
||||||
initOperand(1, val);
|
setOperand(1, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -5323,10 +5388,10 @@ class MGetDOMProperty
|
||||||
{
|
{
|
||||||
JS_ASSERT(jitinfo);
|
JS_ASSERT(jitinfo);
|
||||||
|
|
||||||
initOperand(0, obj);
|
setOperand(0, obj);
|
||||||
|
|
||||||
// Pin the guard as an operand if we want to hoist later
|
// 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.
|
// We are movable iff the jitinfo says we can be.
|
||||||
if (jitinfo->isConstant)
|
if (jitinfo->isConstant)
|
||||||
|
@ -6023,7 +6088,7 @@ class MResumePoint : public MNode
|
||||||
private:
|
private:
|
||||||
friend class MBasicBlock;
|
friend class MBasicBlock;
|
||||||
|
|
||||||
MDefinition **operands_;
|
FixedList<MUse> operands_;
|
||||||
uint32_t stackDepth_;
|
uint32_t stackDepth_;
|
||||||
jsbytecode *pc_;
|
jsbytecode *pc_;
|
||||||
MResumePoint *caller_;
|
MResumePoint *caller_;
|
||||||
|
@ -6031,14 +6096,24 @@ class MResumePoint : public MNode
|
||||||
Mode mode_;
|
Mode mode_;
|
||||||
|
|
||||||
MResumePoint(MBasicBlock *block, jsbytecode *pc, MResumePoint *parent, Mode mode);
|
MResumePoint(MBasicBlock *block, jsbytecode *pc, MResumePoint *parent, Mode mode);
|
||||||
bool init(MBasicBlock *state);
|
|
||||||
void inherit(MBasicBlock *state);
|
void inherit(MBasicBlock *state);
|
||||||
|
|
||||||
protected:
|
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.
|
// Overwrites an operand without updating its Uses.
|
||||||
void setOperand(size_t index, MDefinition *operand) {
|
void setOperand(size_t index, MDefinition *operand) {
|
||||||
JS_ASSERT(index < stackDepth_);
|
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:
|
public:
|
||||||
|
@ -6052,7 +6127,7 @@ class MResumePoint : public MNode
|
||||||
}
|
}
|
||||||
MDefinition *getOperand(size_t index) const {
|
MDefinition *getOperand(size_t index) const {
|
||||||
JS_ASSERT(index < stackDepth_);
|
JS_ASSERT(index < stackDepth_);
|
||||||
return operands_[index];
|
return operands_[index].producer();
|
||||||
}
|
}
|
||||||
jsbytecode *pc() const {
|
jsbytecode *pc() const {
|
||||||
return pc_;
|
return pc_;
|
||||||
|
@ -6151,11 +6226,6 @@ MInstruction *MDefinition::toInstruction()
|
||||||
return (MInstruction *)this;
|
return (MInstruction *)this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MNode::initOperand(size_t index, MDefinition *ins)
|
|
||||||
{
|
|
||||||
setOperand(index, ins);
|
|
||||||
ins->addUse(this, index);
|
|
||||||
}
|
|
||||||
static inline bool isOSRLikeValue (MDefinition *def) {
|
static inline bool isOSRLikeValue (MDefinition *def) {
|
||||||
if (def->isOsrValue())
|
if (def->isOsrValue())
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -194,7 +194,7 @@ MBasicBlock::inherit(MBasicBlock *pred, uint32_t popped)
|
||||||
|
|
||||||
// Create a resume point using our initial stack state.
|
// Create a resume point using our initial stack state.
|
||||||
entryResumePoint_ = new MResumePoint(this, pc(), callerResumePoint, MResumePoint::ResumeAt);
|
entryResumePoint_ = new MResumePoint(this, pc(), callerResumePoint, MResumePoint::ResumeAt);
|
||||||
if (!entryResumePoint_->init(this))
|
if (!entryResumePoint_->init())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (pred) {
|
if (pred) {
|
||||||
|
@ -204,15 +204,16 @@ MBasicBlock::inherit(MBasicBlock *pred, uint32_t popped)
|
||||||
if (kind_ == PENDING_LOOP_HEADER) {
|
if (kind_ == PENDING_LOOP_HEADER) {
|
||||||
for (size_t i = 0; i < stackDepth(); i++) {
|
for (size_t i = 0; i < stackDepth(); i++) {
|
||||||
MPhi *phi = MPhi::New(i);
|
MPhi *phi = MPhi::New(i);
|
||||||
if (!phi->addInput(pred->getSlot(i)))
|
if (!phi->initLength(1))
|
||||||
return false;
|
return false;
|
||||||
|
phi->setOperand(0, pred->getSlot(i));
|
||||||
addPhi(phi);
|
addPhi(phi);
|
||||||
setSlot(i, phi);
|
setSlot(i, phi);
|
||||||
entryResumePoint()->initOperand(i, phi);
|
entryResumePoint()->setOperand(i, phi);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (size_t i = 0; i < stackDepth(); i++)
|
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)
|
MBasicBlock::initSlot(uint32_t slot, MDefinition *ins)
|
||||||
{
|
{
|
||||||
slots_[slot] = ins;
|
slots_[slot] = ins;
|
||||||
entryResumePoint()->initOperand(slot, ins);
|
entryResumePoint()->setOperand(slot, ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -464,11 +465,22 @@ MBasicBlock::moveBefore(MInstruction *at, MInstruction *ins)
|
||||||
at->block()->insertBefore(at, 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
|
void
|
||||||
MBasicBlock::discard(MInstruction *ins)
|
MBasicBlock::discard(MInstruction *ins)
|
||||||
{
|
{
|
||||||
|
AssertSafelyDiscardable(ins);
|
||||||
for (size_t i = 0; i < ins->numOperands(); i++)
|
for (size_t i = 0; i < ins->numOperands(); i++)
|
||||||
ins->replaceOperand(i, NULL);
|
ins->discardOperand(i);
|
||||||
|
|
||||||
instructions_.remove(ins);
|
instructions_.remove(ins);
|
||||||
}
|
}
|
||||||
|
@ -476,8 +488,9 @@ MBasicBlock::discard(MInstruction *ins)
|
||||||
MInstructionIterator
|
MInstructionIterator
|
||||||
MBasicBlock::discardAt(MInstructionIterator &iter)
|
MBasicBlock::discardAt(MInstructionIterator &iter)
|
||||||
{
|
{
|
||||||
|
AssertSafelyDiscardable(*iter);
|
||||||
for (size_t i = 0; i < iter->numOperands(); i++)
|
for (size_t i = 0; i < iter->numOperands(); i++)
|
||||||
iter->replaceOperand(i, NULL);
|
iter->discardOperand(i);
|
||||||
|
|
||||||
return instructions_.removeAt(iter);
|
return instructions_.removeAt(iter);
|
||||||
}
|
}
|
||||||
|
@ -485,8 +498,9 @@ MBasicBlock::discardAt(MInstructionIterator &iter)
|
||||||
MInstructionReverseIterator
|
MInstructionReverseIterator
|
||||||
MBasicBlock::discardAt(MInstructionReverseIterator &iter)
|
MBasicBlock::discardAt(MInstructionReverseIterator &iter)
|
||||||
{
|
{
|
||||||
|
AssertSafelyDiscardable(*iter);
|
||||||
for (size_t i = 0; i < iter->numOperands(); i++)
|
for (size_t i = 0; i < iter->numOperands(); i++)
|
||||||
iter->replaceOperand(i, NULL);
|
iter->discardOperand(i);
|
||||||
|
|
||||||
return instructions_.removeAt(iter);
|
return instructions_.removeAt(iter);
|
||||||
}
|
}
|
||||||
|
@ -555,7 +569,7 @@ MBasicBlock::discardPhiAt(MPhiIterator &at)
|
||||||
JS_ASSERT(!phis_.empty());
|
JS_ASSERT(!phis_.empty());
|
||||||
|
|
||||||
for (size_t i = 0; i < at->numOperands(); i++)
|
for (size_t i = 0; i < at->numOperands(); i++)
|
||||||
at->replaceOperand(i, NULL);
|
at->discardOperand(i);
|
||||||
|
|
||||||
MPhiIterator result = phis_.removeAt(at);
|
MPhiIterator result = phis_.removeAt(at);
|
||||||
|
|
||||||
|
@ -587,33 +601,32 @@ MBasicBlock::addPredecessorPopN(MBasicBlock *pred, uint32_t popped)
|
||||||
MDefinition *other = pred->getSlot(i);
|
MDefinition *other = pred->getSlot(i);
|
||||||
|
|
||||||
if (mine != other) {
|
if (mine != other) {
|
||||||
MPhi *phi;
|
|
||||||
|
|
||||||
// If the current instruction is a phi, and it was created in this
|
// If the current instruction is a phi, and it was created in this
|
||||||
// basic block, then we have already placed this phi and should
|
// basic block, then we have already placed this phi and should
|
||||||
// instead append to its operands.
|
// instead append to its operands.
|
||||||
if (mine->isPhi() && mine->block() == this) {
|
if (mine->isPhi() && mine->block() == this) {
|
||||||
JS_ASSERT(predecessors_.length());
|
JS_ASSERT(predecessors_.length());
|
||||||
phi = mine->toPhi();
|
if (!mine->toPhi()->addInputSlow(other))
|
||||||
|
return false;
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, create a new phi node.
|
// Otherwise, create a new phi node.
|
||||||
phi = MPhi::New(i);
|
MPhi *phi = MPhi::New(i);
|
||||||
addPhi(phi);
|
addPhi(phi);
|
||||||
|
|
||||||
// Prime the phi for each predecessor, so input(x) comes from
|
// Prime the phi for each predecessor, so input(x) comes from
|
||||||
// predecessor(x).
|
// predecessor(x).
|
||||||
|
if (!phi->initLength(predecessors_.length() + 1))
|
||||||
|
return false;
|
||||||
|
|
||||||
for (size_t j = 0; j < predecessors_.length(); j++) {
|
for (size_t j = 0; j < predecessors_.length(); j++) {
|
||||||
JS_ASSERT(predecessors_[j]->getSlot(i) == mine);
|
JS_ASSERT(predecessors_[j]->getSlot(i) == mine);
|
||||||
if (!phi->addInput(mine))
|
phi->setOperand(j, mine);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
phi->setOperand(predecessors_.length(), other);
|
||||||
|
|
||||||
setSlot(i, phi);
|
setSlot(i, phi);
|
||||||
entryResumePoint()->replaceOperand(i, phi);
|
entryResumePoint()->replaceOperand(i, phi);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!phi->addInput(other))
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -639,8 +652,8 @@ MBasicBlock::assertUsesAreNotWithin(MUseIterator use, MUseIterator end)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
for (; use != end; use++) {
|
for (; use != end; use++) {
|
||||||
JS_ASSERT_IF(use->node()->isDefinition(),
|
JS_ASSERT_IF(use->consumer()->isDefinition(),
|
||||||
use->node()->toDefinition()->block()->id() < id());
|
use->consumer()->toDefinition()->block()->id() < id());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -683,7 +696,7 @@ MBasicBlock::setBackedge(MBasicBlock *pred)
|
||||||
exitDef = entryDef->getOperand(0);
|
exitDef = entryDef->getOperand(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!entryDef->addInput(exitDef))
|
if (!entryDef->addInputSlow(exitDef))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
JS_ASSERT(entryDef->slot() < pred->stackDepth());
|
JS_ASSERT(entryDef->slot() < pred->stackDepth());
|
||||||
|
|
|
@ -83,7 +83,7 @@ RangeAnalysis::RangeAnalysis(MIRGraph &graph)
|
||||||
static bool
|
static bool
|
||||||
IsDominatedUse(MBasicBlock *block, MUse *use)
|
IsDominatedUse(MBasicBlock *block, MUse *use)
|
||||||
{
|
{
|
||||||
MNode *n = use->node();
|
MNode *n = use->consumer();
|
||||||
bool isPhi = n->isDefinition() && n->toDefinition()->isPhi();
|
bool isPhi = n->isDefinition() && n->toDefinition()->isPhi();
|
||||||
|
|
||||||
if (isPhi)
|
if (isPhi)
|
||||||
|
@ -110,8 +110,8 @@ RangeAnalysis::replaceDominatedUsesWith(MDefinition *orig, MDefinition *dom,
|
||||||
MBasicBlock *block)
|
MBasicBlock *block)
|
||||||
{
|
{
|
||||||
for (MUseIterator i(orig->usesBegin()); i != orig->usesEnd(); ) {
|
for (MUseIterator i(orig->usesBegin()); i != orig->usesEnd(); ) {
|
||||||
if (i->node() != dom && IsDominatedUse(block, *i))
|
if (i->consumer() != dom && IsDominatedUse(block, *i))
|
||||||
i = i->node()->replaceOperand(i, dom);
|
i = i->consumer()->replaceOperand(i, dom);
|
||||||
else
|
else
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,7 +112,7 @@ void
|
||||||
UnreachableCodeElimination::removeUsesFromUnmarkedBlocks(MDefinition *instr)
|
UnreachableCodeElimination::removeUsesFromUnmarkedBlocks(MDefinition *instr)
|
||||||
{
|
{
|
||||||
for (MUseIterator iter(instr->usesBegin()); iter != instr->usesEnd(); ) {
|
for (MUseIterator iter(instr->usesBegin()); iter != instr->usesEnd(); ) {
|
||||||
if (!iter->node()->block()->isMarked())
|
if (!iter->consumer()->block()->isMarked())
|
||||||
iter = instr->removeUse(iter);
|
iter = instr->removeUse(iter);
|
||||||
else
|
else
|
||||||
iter++;
|
iter++;
|
||||||
|
|
|
@ -19,5 +19,5 @@ function doParseIntTests() {
|
||||||
}
|
}
|
||||||
doParseIntTests();
|
doParseIntTests();
|
||||||
|
|
||||||
assertEq(parseInt("08"), 0);
|
assertEq(parseInt("08"), 8);
|
||||||
assertEq(parseInt("09"), 0);
|
assertEq(parseInt("09"), 9);
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
assertEq(parseInt("08"), 0);
|
assertEq(parseInt("08"), 8);
|
||||||
assertEq(parseInt("09"), 0);
|
assertEq(parseInt("09"), 9);
|
||||||
assertEq(parseInt("014"), 12);
|
assertEq(parseInt("014"), 14);
|
||||||
assertEq(parseInt("0xA"), 10);
|
assertEq(parseInt("0xA"), 10);
|
||||||
assertEq(parseInt("00123"), 83);
|
assertEq(parseInt("00123"), 123);
|
||||||
|
|
||||||
for (var i = 0; i < 5; i++)
|
for (var i = 0; i < 5; i++)
|
||||||
{
|
{
|
||||||
assertEq(parseInt("08"), 0);
|
assertEq(parseInt("08"), 8);
|
||||||
assertEq(parseInt("09"), 0);
|
assertEq(parseInt("09"), 9);
|
||||||
assertEq(parseInt("014"), 12);
|
assertEq(parseInt("014"), 14);
|
||||||
assertEq(parseInt("0xA"), 10);
|
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));
|
t = MakeDate(day, TimeWithinDay(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t timeMilliseconds = static_cast<int64_t>(t);
|
int64_t utcMilliseconds = static_cast<int64_t>(t);
|
||||||
int64_t offsetMilliseconds = dtInfo->getDSTOffsetMilliseconds(timeMilliseconds);
|
int64_t offsetMilliseconds = dtInfo->getDSTOffsetMilliseconds(utcMilliseconds);
|
||||||
return static_cast<double>(offsetMilliseconds);
|
return static_cast<double>(offsetMilliseconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
112
js/src/jsnum.cpp
112
js/src/jsnum.cpp
|
@ -281,60 +281,7 @@ num_parseFloat(JSContext *cx, unsigned argc, Value *vp)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
/* ES5 15.1.2.2. */
|
||||||
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. */
|
|
||||||
JSBool
|
JSBool
|
||||||
js::num_parseInt(JSContext *cx, unsigned argc, Value *vp)
|
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]);
|
args.rval().set(args[0]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Step 1 is |inputString = ToString(string)|. When string >=
|
* Step 1 is |inputString = ToString(string)|. When string >=
|
||||||
* 1e21, ToString(string) is in the form "NeM". 'e' marks the end of
|
* 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;
|
return false;
|
||||||
args[0].setString(inputString);
|
args[0].setString(inputString);
|
||||||
|
|
||||||
/* 15.1.2.2 steps 6-8. */
|
/* Steps 6-9. */
|
||||||
bool stripPrefix = true;
|
bool stripPrefix = true;
|
||||||
int32_t radix = 0;
|
int32_t radix;
|
||||||
if (args.length() > 1) {
|
if (!args.hasDefined(1)) {
|
||||||
|
radix = 10;
|
||||||
|
} else {
|
||||||
if (!ToInt32(cx, args[1], &radix))
|
if (!ToInt32(cx, args[1], &radix))
|
||||||
return false;
|
return false;
|
||||||
if (radix != 0) {
|
if (radix == 0) {
|
||||||
|
radix = 10;
|
||||||
|
} else {
|
||||||
if (radix < 2 || radix > 36) {
|
if (radix < 2 || radix > 36) {
|
||||||
args.rval().setDouble(js_NaN);
|
args.rval().setDouble(js_NaN);
|
||||||
return true;
|
return true;
|
||||||
|
@ -402,18 +354,44 @@ js::num_parseInt(JSContext *cx, unsigned argc, Value *vp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Steps 2-5, 9-14. */
|
/* Step 2. */
|
||||||
const jschar *ws = inputString->getChars(cx);
|
const jschar *s;
|
||||||
if (!ws)
|
const jschar *end;
|
||||||
return false;
|
{
|
||||||
const jschar *end = ws + inputString->length();
|
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;
|
double number;
|
||||||
if (!ParseIntStringHelper(cx, ws, end, radix, stripPrefix, &number))
|
if (!GetPrefixInteger(cx, s, end, radix, &actualEnd, &number))
|
||||||
return false;
|
return false;
|
||||||
|
if (s == actualEnd)
|
||||||
/* Step 15. */
|
args.rval().setNumber(js_NaN);
|
||||||
args.rval().setNumber(number);
|
else
|
||||||
|
args.rval().setNumber(negative ? -number : number);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче