mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Merge mozilla-central to fx-team
This commit is contained in:
commit
e48928a775
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="93daa354671a698634a3dc661c8c9dcb7d824c31"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="99f56d9db3cd37c684b01de6fed786421f47e2b7"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="93daa354671a698634a3dc661c8c9dcb7d824c31"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="99f56d9db3cd37c684b01de6fed786421f47e2b7"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="96cdde4b5b5d8d3785b36c3c68cd746aff3005cc"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7f9ec13a30f1b2cc8bdb1a199b7da54b9ab8860f"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="276ce45e78b09c4a4ee643646f691d22804754c1">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="93daa354671a698634a3dc661c8c9dcb7d824c31"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="99f56d9db3cd37c684b01de6fed786421f47e2b7"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="93daa354671a698634a3dc661c8c9dcb7d824c31"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="99f56d9db3cd37c684b01de6fed786421f47e2b7"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="93daa354671a698634a3dc661c8c9dcb7d824c31"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="99f56d9db3cd37c684b01de6fed786421f47e2b7"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="96cdde4b5b5d8d3785b36c3c68cd746aff3005cc"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7f9ec13a30f1b2cc8bdb1a199b7da54b9ab8860f"/>
|
||||
|
@ -4,6 +4,6 @@
|
||||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "333f877ae4029d7cb1a0893f89da484d8e3cc14f",
|
||||
"revision": "278dd1b102a39cf2c48f11fe3038eaf8f0779d7d",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="93daa354671a698634a3dc661c8c9dcb7d824c31"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="99f56d9db3cd37c684b01de6fed786421f47e2b7"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="93daa354671a698634a3dc661c8c9dcb7d824c31"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="99f56d9db3cd37c684b01de6fed786421f47e2b7"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="93daa354671a698634a3dc661c8c9dcb7d824c31"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="99f56d9db3cd37c684b01de6fed786421f47e2b7"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="96cdde4b5b5d8d3785b36c3c68cd746aff3005cc"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7f9ec13a30f1b2cc8bdb1a199b7da54b9ab8860f"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="93daa354671a698634a3dc661c8c9dcb7d824c31"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="99f56d9db3cd37c684b01de6fed786421f47e2b7"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -405,6 +405,8 @@
|
||||
@BINPATH@/components/DOMWifiManager.manifest
|
||||
@BINPATH@/components/DOMWifiP2pManager.js
|
||||
@BINPATH@/components/DOMWifiP2pManager.manifest
|
||||
@BINPATH@/components/EthernetManager.js
|
||||
@BINPATH@/components/EthernetManager.manifest
|
||||
@BINPATH@/components/NetworkInterfaceListService.js
|
||||
@BINPATH@/components/NetworkInterfaceListService.manifest
|
||||
@BINPATH@/components/NetworkManager.js
|
||||
|
@ -16,7 +16,6 @@ class nsMacShellService : public nsIMacShellService,
|
||||
{
|
||||
public:
|
||||
nsMacShellService() : mCheckedThisSession(false) {};
|
||||
virtual ~nsMacShellService() {};
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISHELLSERVICE
|
||||
@ -24,6 +23,7 @@ public:
|
||||
NS_DECL_NSIWEBPROGRESSLISTENER
|
||||
|
||||
protected:
|
||||
virtual ~nsMacShellService() {};
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIFile> mBackgroundFile;
|
||||
|
@ -43,10 +43,6 @@ public:
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
~DOMMatrixReadOnly()
|
||||
{
|
||||
}
|
||||
|
||||
#define GetMatrixMember(entry2D, entry3D, default) \
|
||||
{ \
|
||||
if (mMatrix3D) { \
|
||||
@ -135,6 +131,10 @@ protected:
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
nsAutoPtr<gfx::Matrix> mMatrix2D;
|
||||
nsAutoPtr<gfx::Matrix4x4> mMatrix3D;
|
||||
|
||||
~DOMMatrixReadOnly()
|
||||
{
|
||||
}
|
||||
private:
|
||||
DOMMatrixReadOnly() MOZ_DELETE;
|
||||
DOMMatrixReadOnly(const DOMMatrixReadOnly&) MOZ_DELETE;
|
||||
@ -248,6 +248,8 @@ public:
|
||||
DOMMatrix* SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv);
|
||||
private:
|
||||
void Ensure3DMatrix();
|
||||
|
||||
~DOMMatrix() {}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1385,7 +1385,6 @@ public:
|
||||
NS_DECL_NSIDOMEVENTLISTENER
|
||||
|
||||
WebGLObserver(WebGLContext* aContext);
|
||||
~WebGLObserver();
|
||||
|
||||
void Destroy();
|
||||
|
||||
@ -1396,6 +1395,8 @@ public:
|
||||
void UnregisterMemoryPressureEvent();
|
||||
|
||||
private:
|
||||
~WebGLObserver();
|
||||
|
||||
WebGLContext* mContext;
|
||||
};
|
||||
|
||||
|
@ -94,7 +94,7 @@ SVGCircleElement::ConstructPath(gfxContext *aCtx)
|
||||
}
|
||||
|
||||
TemporaryRef<Path>
|
||||
SVGCircleElement::BuildPath()
|
||||
SVGCircleElement::BuildPath(PathBuilder* aBuilder)
|
||||
{
|
||||
float x, y, r;
|
||||
GetAnimatedLengthValues(&x, &y, &r, nullptr);
|
||||
@ -103,7 +103,7 @@ SVGCircleElement::BuildPath()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
|
||||
RefPtr<PathBuilder> pathBuilder = aBuilder ? aBuilder : CreatePathBuilder();
|
||||
|
||||
pathBuilder->Arc(Point(x, y), r, 0, Float(2*M_PI));
|
||||
|
||||
|
@ -31,7 +31,7 @@ public:
|
||||
|
||||
// nsSVGPathGeometryElement methods:
|
||||
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
|
||||
|
||||
|
@ -8,8 +8,13 @@
|
||||
#include "SVGContentUtils.h"
|
||||
|
||||
// Keep others in (case-insensitive) order:
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxMatrix.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "gfxSVGGlyphs.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/dom/SVGSVGElement.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsComputedDOMStyle.h"
|
||||
#include "nsFontMetrics.h"
|
||||
#include "nsIFrame.h"
|
||||
@ -20,12 +25,14 @@
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/Types.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsSVGPathDataParser.h"
|
||||
#include "SVGPathData.h"
|
||||
#include "SVGPathElement.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
SVGSVGElement*
|
||||
SVGContentUtils::GetOuterSVGElement(nsSVGElement *aSVGElement)
|
||||
@ -54,6 +61,179 @@ SVGContentUtils::ActivateByHyperlink(nsIContent *aContent)
|
||||
static_cast<SVGAnimationElement*>(aContent)->ActivateByHyperlink();
|
||||
}
|
||||
|
||||
enum DashState {
|
||||
eDashedStroke,
|
||||
eContinuousStroke, //< all dashes, no gaps
|
||||
eNoStroke //< all gaps, no dashes
|
||||
};
|
||||
|
||||
static DashState
|
||||
GetStrokeDashData(SVGContentUtils::AutoStrokeOptions* aStrokeOptions,
|
||||
nsSVGElement* aElement,
|
||||
const nsStyleSVG* aStyleSVG,
|
||||
gfxTextContextPaint *aContextPaint)
|
||||
{
|
||||
size_t dashArrayLength;
|
||||
Float totalLengthOfDashes = 0.0, totalLengthOfGaps = 0.0;
|
||||
|
||||
if (aContextPaint && aStyleSVG->mStrokeDasharrayFromObject) {
|
||||
const FallibleTArray<gfxFloat>& dashSrc = aContextPaint->GetStrokeDashArray();
|
||||
dashArrayLength = dashSrc.Length();
|
||||
if (dashArrayLength <= 0) {
|
||||
return eContinuousStroke;
|
||||
}
|
||||
Float* dashPattern = aStrokeOptions->InitDashPattern(dashArrayLength);
|
||||
if (!dashPattern) {
|
||||
return eContinuousStroke;
|
||||
}
|
||||
for (size_t i = 0; i < dashArrayLength; i++) {
|
||||
if (dashSrc[i] < 0.0) {
|
||||
return eContinuousStroke; // invalid
|
||||
}
|
||||
dashPattern[i] = Float(dashSrc[i]);
|
||||
(i % 2 ? totalLengthOfGaps : totalLengthOfDashes) += dashSrc[i];
|
||||
}
|
||||
} else {
|
||||
const nsStyleCoord *dasharray = aStyleSVG->mStrokeDasharray;
|
||||
dashArrayLength = aStyleSVG->mStrokeDasharrayLength;
|
||||
if (dashArrayLength <= 0) {
|
||||
return eContinuousStroke;
|
||||
}
|
||||
Float pathScale = 1.0;
|
||||
if (aElement->Tag() == nsGkAtoms::path) {
|
||||
pathScale = static_cast<SVGPathElement*>(aElement)->
|
||||
GetPathLengthScale(SVGPathElement::eForStroking);
|
||||
if (pathScale <= 0) {
|
||||
return eContinuousStroke;
|
||||
}
|
||||
}
|
||||
Float* dashPattern = aStrokeOptions->InitDashPattern(dashArrayLength);
|
||||
if (!dashPattern) {
|
||||
return eContinuousStroke;
|
||||
}
|
||||
for (uint32_t i = 0; i < dashArrayLength; i++) {
|
||||
Float dashLength =
|
||||
SVGContentUtils::CoordToFloat(aElement, dasharray[i]) * pathScale;
|
||||
if (dashLength < 0.0) {
|
||||
return eContinuousStroke; // invalid
|
||||
}
|
||||
dashPattern[i] = dashLength;
|
||||
(i % 2 ? totalLengthOfGaps : totalLengthOfDashes) += dashLength;
|
||||
}
|
||||
}
|
||||
|
||||
// Now that aStrokeOptions.mDashPattern is fully initialized we can safely
|
||||
// set mDashLength:
|
||||
aStrokeOptions->mDashLength = dashArrayLength;
|
||||
|
||||
if (totalLengthOfDashes <= 0 || totalLengthOfGaps <= 0) {
|
||||
if (totalLengthOfGaps > 0 && totalLengthOfDashes <= 0) {
|
||||
return eNoStroke;
|
||||
}
|
||||
return eContinuousStroke;
|
||||
}
|
||||
|
||||
if (aContextPaint && aStyleSVG->mStrokeDashoffsetFromObject) {
|
||||
aStrokeOptions->mDashOffset = Float(aContextPaint->GetStrokeDashOffset());
|
||||
} else {
|
||||
aStrokeOptions->mDashOffset =
|
||||
SVGContentUtils::CoordToFloat(aElement, aStyleSVG->mStrokeDashoffset);
|
||||
}
|
||||
|
||||
return eDashedStroke;
|
||||
}
|
||||
|
||||
void
|
||||
SVGContentUtils::GetStrokeOptions(AutoStrokeOptions* aStrokeOptions,
|
||||
nsSVGElement* aElement,
|
||||
nsStyleContext* aStyleContext,
|
||||
gfxTextContextPaint *aContextPaint)
|
||||
{
|
||||
nsRefPtr<nsStyleContext> styleContext;
|
||||
if (aStyleContext) {
|
||||
styleContext = aStyleContext;
|
||||
} else {
|
||||
styleContext =
|
||||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement, nullptr,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
if (!styleContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nsStyleSVG* styleSVG = styleContext->StyleSVG();
|
||||
|
||||
DashState dashState =
|
||||
GetStrokeDashData(aStrokeOptions, aElement, styleSVG, aContextPaint);
|
||||
|
||||
if (dashState == eNoStroke) {
|
||||
// Hopefully this will shortcircuit any stroke operations:
|
||||
aStrokeOptions->mLineWidth = 0;
|
||||
return;
|
||||
}
|
||||
if (dashState == eContinuousStroke) {
|
||||
// Prevent our caller from wasting time looking at the dash array:
|
||||
aStrokeOptions->mDashLength = 0;
|
||||
}
|
||||
|
||||
aStrokeOptions->mLineWidth =
|
||||
GetStrokeWidth(aElement, styleContext, aContextPaint);
|
||||
|
||||
aStrokeOptions->mMiterLimit = Float(styleSVG->mStrokeMiterlimit);
|
||||
|
||||
switch (styleSVG->mStrokeLinejoin) {
|
||||
case NS_STYLE_STROKE_LINEJOIN_MITER:
|
||||
aStrokeOptions->mLineJoin = JoinStyle::MITER;
|
||||
break;
|
||||
case NS_STYLE_STROKE_LINEJOIN_ROUND:
|
||||
aStrokeOptions->mLineJoin = JoinStyle::ROUND;
|
||||
break;
|
||||
case NS_STYLE_STROKE_LINEJOIN_BEVEL:
|
||||
aStrokeOptions->mLineJoin = JoinStyle::BEVEL;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (styleSVG->mStrokeLinecap) {
|
||||
case NS_STYLE_STROKE_LINECAP_BUTT:
|
||||
aStrokeOptions->mLineCap = CapStyle::BUTT;
|
||||
break;
|
||||
case NS_STYLE_STROKE_LINECAP_ROUND:
|
||||
aStrokeOptions->mLineCap = CapStyle::ROUND;
|
||||
break;
|
||||
case NS_STYLE_STROKE_LINECAP_SQUARE:
|
||||
aStrokeOptions->mLineCap = CapStyle::SQUARE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Float
|
||||
SVGContentUtils::GetStrokeWidth(nsSVGElement* aElement,
|
||||
nsStyleContext* aStyleContext,
|
||||
gfxTextContextPaint *aContextPaint)
|
||||
{
|
||||
nsRefPtr<nsStyleContext> styleContext;
|
||||
if (aStyleContext) {
|
||||
styleContext = aStyleContext;
|
||||
} else {
|
||||
styleContext =
|
||||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement, nullptr,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
if (!styleContext) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
const nsStyleSVG* styleSVG = styleContext->StyleSVG();
|
||||
|
||||
if (aContextPaint && styleSVG->mStrokeWidthFromObject) {
|
||||
return aContextPaint->GetStrokeWidth();
|
||||
}
|
||||
|
||||
return SVGContentUtils::CoordToFloat(aElement, styleSVG->mStrokeWidth);
|
||||
}
|
||||
|
||||
float
|
||||
SVGContentUtils::GetFontSize(Element *aElement)
|
||||
{
|
||||
@ -596,5 +776,10 @@ SVGContentUtils::GetPath(const nsAString& aPathString)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pathData.BuildPath(mozilla::gfx::FillRule::FILL_WINDING, NS_STYLE_STROKE_LINECAP_BUTT, 1);
|
||||
RefPtr<DrawTarget> drawTarget =
|
||||
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
|
||||
RefPtr<PathBuilder> builder =
|
||||
drawTarget->CreatePathBuilder(FillRule::FILL_WINDING);
|
||||
|
||||
return pathData.BuildPath(builder, NS_STYLE_STROKE_LINECAP_BUTT, 1);
|
||||
}
|
||||
|
@ -10,12 +10,15 @@
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
|
||||
#include "mozilla/fallible.h"
|
||||
#include "mozilla/gfx/2D.h" // for StrokeOptions
|
||||
#include "mozilla/gfx/Matrix.h"
|
||||
#include "mozilla/RangedPtr.h"
|
||||
#include "nsError.h"
|
||||
#include "nsStringFwd.h"
|
||||
#include "gfx2DGlue.h"
|
||||
|
||||
class gfxTextContextPaint;
|
||||
class nsIContent;
|
||||
class nsIDocument;
|
||||
class nsIFrame;
|
||||
@ -58,6 +61,8 @@ IsSVGWhitespace(char16_t aChar)
|
||||
class SVGContentUtils
|
||||
{
|
||||
public:
|
||||
typedef mozilla::gfx::Float Float;
|
||||
typedef mozilla::gfx::StrokeOptions StrokeOptions;
|
||||
typedef mozilla::SVGAnimatedPreserveAspectRatio SVGAnimatedPreserveAspectRatio;
|
||||
typedef mozilla::SVGPreserveAspectRatio SVGPreserveAspectRatio;
|
||||
|
||||
@ -76,6 +81,64 @@ public:
|
||||
*/
|
||||
static void ActivateByHyperlink(nsIContent *aContent);
|
||||
|
||||
/**
|
||||
* Moz2D's StrokeOptions requires someone else to own its mDashPattern
|
||||
* buffer, which is a pain when you want to initialize a StrokeOptions object
|
||||
* in a helper function and pass it out. This sub-class owns the mDashPattern
|
||||
* buffer so that consumers of such a helper function don't need to worry
|
||||
* about creating it, passing it in, or deleting it. (An added benefit is
|
||||
* that in the typical case when stroke-dasharray is short it will avoid
|
||||
* allocating.)
|
||||
*/
|
||||
struct AutoStrokeOptions : public StrokeOptions {
|
||||
AutoStrokeOptions()
|
||||
{
|
||||
MOZ_ASSERT(mDashLength == 0, "InitDashPattern() depends on this");
|
||||
}
|
||||
~AutoStrokeOptions() {
|
||||
if (mDashPattern && mDashPattern != mSmallArray) {
|
||||
delete [] mDashPattern;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Creates the buffer to store the stroke-dasharray, assuming out-of-memory
|
||||
* does not occur. The buffer's address is assigned to mDashPattern and
|
||||
* returned to the caller as a non-const pointer (so that the caller can
|
||||
* initialize the values in the buffer, since mDashPattern is const).
|
||||
*/
|
||||
Float* InitDashPattern(size_t aDashCount) {
|
||||
if (aDashCount <= MOZ_ARRAY_LENGTH(mSmallArray)) {
|
||||
mDashPattern = mSmallArray;
|
||||
return mSmallArray;
|
||||
}
|
||||
static const mozilla::fallible_t fallible = mozilla::fallible_t();
|
||||
Float* nonConstArray = new (fallible) Float[aDashCount];
|
||||
mDashPattern = nonConstArray;
|
||||
return nonConstArray;
|
||||
}
|
||||
private:
|
||||
// Most dasharrays will fit in this and save us allocating
|
||||
Float mSmallArray[16];
|
||||
};
|
||||
|
||||
static void GetStrokeOptions(AutoStrokeOptions* aStrokeOptions,
|
||||
nsSVGElement* aElement,
|
||||
nsStyleContext* aStyleContext,
|
||||
gfxTextContextPaint *aContextPaint);
|
||||
|
||||
/**
|
||||
* Returns the current computed value of the CSS property 'stroke-width' for
|
||||
* the given element. aStyleContext may be provided as an optimization.
|
||||
* aContextPaint is also optional.
|
||||
*
|
||||
* Note that this function does NOT take account of the value of the 'stroke'
|
||||
* and 'stroke-opacity' properties to, say, return zero if they are "none" or
|
||||
* "0", respectively.
|
||||
*/
|
||||
static Float GetStrokeWidth(nsSVGElement* aElement,
|
||||
nsStyleContext* aStyleContext,
|
||||
gfxTextContextPaint *aContextPaint);
|
||||
|
||||
/*
|
||||
* Get the number of CSS px (user units) per em (i.e. the em-height in user
|
||||
* units) for an nsIContent
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "mozilla/dom/SVGEllipseElementBinding.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/PathHelpers.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "gfxContext.h"
|
||||
|
||||
NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Ellipse)
|
||||
@ -96,7 +97,12 @@ void
|
||||
SVGEllipseElement::ConstructPath(gfxContext *aCtx)
|
||||
{
|
||||
if (!aCtx->IsCairo()) {
|
||||
RefPtr<Path> path = BuildPath();
|
||||
RefPtr<DrawTarget> dt = aCtx->GetDrawTarget();
|
||||
FillRule fillRule =
|
||||
aCtx->CurrentFillRule() == gfxContext::FILL_RULE_WINDING ?
|
||||
FillRule::FILL_WINDING : FillRule::FILL_EVEN_ODD;
|
||||
RefPtr<PathBuilder> builder = dt->CreatePathBuilder(fillRule);
|
||||
RefPtr<Path> path = BuildPath(builder);
|
||||
if (path) {
|
||||
nsRefPtr<gfxPath> gfxpath = new gfxPath(path);
|
||||
aCtx->SetPath(gfxpath);
|
||||
@ -114,7 +120,7 @@ SVGEllipseElement::ConstructPath(gfxContext *aCtx)
|
||||
}
|
||||
|
||||
TemporaryRef<Path>
|
||||
SVGEllipseElement::BuildPath()
|
||||
SVGEllipseElement::BuildPath(PathBuilder* aBuilder)
|
||||
{
|
||||
float x, y, rx, ry;
|
||||
GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
|
||||
@ -123,7 +129,7 @@ SVGEllipseElement::BuildPath()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
|
||||
RefPtr<PathBuilder> pathBuilder = aBuilder ? aBuilder : CreatePathBuilder();
|
||||
|
||||
EllipseToBezier(pathBuilder.get(), Point(x, y), Size(rx, ry));
|
||||
|
||||
|
@ -31,7 +31,7 @@ public:
|
||||
|
||||
// nsSVGPathGeometryElement methods:
|
||||
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
|
||||
|
||||
|
@ -241,7 +241,7 @@ SVGImageElement::ConstructPath(gfxContext *aCtx)
|
||||
}
|
||||
|
||||
TemporaryRef<Path>
|
||||
SVGImageElement::BuildPath()
|
||||
SVGImageElement::BuildPath(PathBuilder* aBuilder)
|
||||
{
|
||||
// We get called in order to get bounds for this element, and for
|
||||
// hit-testing against it. For that we just pretend to be a rectangle.
|
||||
@ -253,7 +253,7 @@ SVGImageElement::BuildPath()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
|
||||
RefPtr<PathBuilder> pathBuilder = aBuilder ? aBuilder : CreatePathBuilder();
|
||||
|
||||
Rect r(x, y, width, height);
|
||||
pathBuilder->MoveTo(r.TopLeft());
|
||||
|
@ -54,7 +54,7 @@ public:
|
||||
|
||||
// nsSVGPathGeometryElement methods:
|
||||
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
|
||||
|
||||
// nsSVGSVGElement methods:
|
||||
virtual bool HasValidDimensions() const MOZ_OVERRIDE;
|
||||
|
@ -119,9 +119,9 @@ SVGLineElement::ConstructPath(gfxContext *aCtx)
|
||||
}
|
||||
|
||||
TemporaryRef<Path>
|
||||
SVGLineElement::BuildPath()
|
||||
SVGLineElement::BuildPath(PathBuilder* aBuilder)
|
||||
{
|
||||
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
|
||||
RefPtr<PathBuilder> pathBuilder = aBuilder ? aBuilder : CreatePathBuilder();
|
||||
|
||||
float x1, y1, x2, y2;
|
||||
GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr);
|
||||
|
@ -33,7 +33,7 @@ public:
|
||||
virtual bool IsMarkable() MOZ_OVERRIDE { return true; }
|
||||
virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) MOZ_OVERRIDE;
|
||||
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const;
|
||||
|
||||
|
@ -302,7 +302,7 @@ ApproximateZeroLengthSubpathSquareCaps(const gfxPoint &aPoint, gfxContext *aCtx)
|
||||
} while(0)
|
||||
|
||||
TemporaryRef<Path>
|
||||
SVGPathData::BuildPath(FillRule aFillRule,
|
||||
SVGPathData::BuildPath(PathBuilder* builder,
|
||||
uint8_t aStrokeLineCap,
|
||||
Float aStrokeWidth) const
|
||||
{
|
||||
@ -310,14 +310,6 @@ SVGPathData::BuildPath(FillRule aFillRule,
|
||||
return nullptr; // paths without an initial moveto are invalid
|
||||
}
|
||||
|
||||
RefPtr<DrawTarget> drawTarget =
|
||||
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
|
||||
NS_ASSERTION(gfxPlatform::GetPlatform()->
|
||||
SupportsAzureContentForDrawTarget(drawTarget),
|
||||
"Should support Moz2D content drawing");
|
||||
|
||||
RefPtr<PathBuilder> builder = drawTarget->CreatePathBuilder(aFillRule);
|
||||
|
||||
bool capsAreSquare = aStrokeLineCap == NS_STYLE_STROKE_LINECAP_SQUARE;
|
||||
bool subpathHasLength = false; // visual length
|
||||
bool subpathContainsNonArc = false;
|
||||
@ -814,15 +806,19 @@ TemporaryRef<Path>
|
||||
SVGPathData::ToPathForLengthOrPositionMeasuring() const
|
||||
{
|
||||
// Since the path that we return will not be used for painting it doesn't
|
||||
// matter what we pass to BuildPath as aFillRule. Hawever, we do want to
|
||||
// pass something other than NS_STYLE_STROKE_LINECAP_SQUARE as aStrokeLineCap
|
||||
// to avoid the insertion of extra little lines (by
|
||||
// matter what we pass to CreatePathBuilder as aFillRule. Hawever, we do want
|
||||
// to pass something other than NS_STYLE_STROKE_LINECAP_SQUARE as
|
||||
// aStrokeLineCap to avoid the insertion of extra little lines (by
|
||||
// ApproximateZeroLengthSubpathSquareCaps), in which case the value that we
|
||||
// pass as aStrokeWidth doesn't matter (since it's only used to determine the
|
||||
// length of those extra little lines).
|
||||
|
||||
if (!mCachedPath) {
|
||||
mCachedPath = BuildPath(FillRule::FILL_WINDING, NS_STYLE_STROKE_LINECAP_BUTT, 0);
|
||||
RefPtr<DrawTarget> drawTarget =
|
||||
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
|
||||
RefPtr<PathBuilder> builder =
|
||||
drawTarget->CreatePathBuilder(FillRule::FILL_WINDING);
|
||||
mCachedPath = BuildPath(builder, NS_STYLE_STROKE_LINECAP_BUTT, 0);
|
||||
}
|
||||
|
||||
return mCachedPath;
|
||||
|
@ -84,6 +84,7 @@ class SVGPathData
|
||||
|
||||
typedef gfx::DrawTarget DrawTarget;
|
||||
typedef gfx::Path Path;
|
||||
typedef gfx::PathBuilder PathBuilder;
|
||||
typedef gfx::FillRule FillRule;
|
||||
typedef gfx::Float Float;
|
||||
typedef gfx::CapStyle CapStyle;
|
||||
@ -166,7 +167,7 @@ public:
|
||||
TemporaryRef<Path> ToPathForLengthOrPositionMeasuring() const;
|
||||
|
||||
void ConstructPath(gfxContext *aCtx) const;
|
||||
TemporaryRef<Path> BuildPath(FillRule aFillRule,
|
||||
TemporaryRef<Path> BuildPath(PathBuilder* aBuilder,
|
||||
uint8_t aCapStyle,
|
||||
Float aStrokeWidth) const;
|
||||
|
||||
|
@ -11,8 +11,10 @@
|
||||
#include "DOMSVGPathSegList.h"
|
||||
#include "DOMSVGPoint.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "mozilla/dom/SVGPathElementBinding.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsComputedDOMStyle.h"
|
||||
#include "nsGkAtoms.h"
|
||||
@ -370,7 +372,7 @@ SVGPathElement::GetPathLengthScale(PathLengthScaleForType aFor)
|
||||
}
|
||||
|
||||
TemporaryRef<Path>
|
||||
SVGPathElement::BuildPath()
|
||||
SVGPathElement::BuildPath(PathBuilder* aBuilder)
|
||||
{
|
||||
// The Moz2D PathBuilder that our SVGPathData will be using only cares about
|
||||
// the fill rule. However, in order to fulfill the requirements of the SVG
|
||||
@ -392,19 +394,28 @@ SVGPathElement::BuildPath()
|
||||
// opacity here.
|
||||
if (style->mStrokeLinecap == NS_STYLE_STROKE_LINECAP_SQUARE) {
|
||||
strokeLineCap = style->mStrokeLinecap;
|
||||
strokeWidth = GetStrokeWidth();
|
||||
strokeWidth = SVGContentUtils::GetStrokeWidth(this, styleContext, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// The fill rule that we pass must be the current
|
||||
// computed value of our CSS 'fill-rule' property if the path that we return
|
||||
// will be used for painting or hit-testing. For all other uses (bounds
|
||||
// calculatons, length measurement, position-at-offset calculations) the fill
|
||||
// rule that we pass doesn't matter. As a result we can just pass the current
|
||||
// computed value regardless of who's calling us, or what they're going to do
|
||||
// with the path that we return.
|
||||
RefPtr<PathBuilder> builder;
|
||||
if (aBuilder) {
|
||||
builder = aBuilder;
|
||||
} else {
|
||||
RefPtr<DrawTarget> drawTarget =
|
||||
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
|
||||
// The fill rule that we pass must be the current computed value of our
|
||||
// CSS 'fill-rule' property if the path that we return will be used for
|
||||
// painting or hit-testing. For all other uses (bounds calculatons, length
|
||||
// measurement, position-at-offset calculations) the fill rule that we pass
|
||||
// doesn't matter. As a result we can just pass the current computed value
|
||||
// regardless of who's calling us, or what they're going to do with the
|
||||
// path that we return.
|
||||
RefPtr<PathBuilder> builder =
|
||||
drawTarget->CreatePathBuilder(GetFillRule());
|
||||
}
|
||||
|
||||
return mD.GetAnimValue().BuildPath(GetFillRule(), strokeLineCap, strokeWidth);
|
||||
return mD.GetAnimValue().BuildPath(builder, strokeLineCap, strokeWidth);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
@ -53,7 +53,7 @@ public:
|
||||
virtual bool IsMarkable() MOZ_OVERRIDE;
|
||||
virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) MOZ_OVERRIDE;
|
||||
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
|
||||
|
||||
/**
|
||||
* This returns a path without the extra little line segments that
|
||||
|
@ -153,7 +153,7 @@ SVGRectElement::ConstructPath(gfxContext *aCtx)
|
||||
}
|
||||
|
||||
TemporaryRef<Path>
|
||||
SVGRectElement::BuildPath()
|
||||
SVGRectElement::BuildPath(PathBuilder* aBuilder)
|
||||
{
|
||||
float x, y, width, height, rx, ry;
|
||||
GetAnimatedLengthValues(&x, &y, &width, &height, &rx, &ry, nullptr);
|
||||
@ -162,7 +162,7 @@ SVGRectElement::BuildPath()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
|
||||
RefPtr<PathBuilder> pathBuilder = aBuilder ? aBuilder : CreatePathBuilder();
|
||||
|
||||
rx = std::max(rx, 0.0f);
|
||||
ry = std::max(ry, 0.0f);
|
||||
|
@ -31,7 +31,7 @@ public:
|
||||
|
||||
// nsSVGPathGeometryElement methods:
|
||||
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
|
||||
|
||||
|
@ -111,15 +111,3 @@ nsSVGPathGeometryElement::GetFillRule()
|
||||
|
||||
return fillRule;
|
||||
}
|
||||
|
||||
Float
|
||||
nsSVGPathGeometryElement::GetStrokeWidth()
|
||||
{
|
||||
nsRefPtr<nsStyleContext> styleContext =
|
||||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(this, nullptr,
|
||||
nullptr);
|
||||
return styleContext ?
|
||||
SVGContentUtils::CoordToFloat(this,
|
||||
styleContext->StyleSVG()->mStrokeWidth) :
|
||||
0.0f;
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ public:
|
||||
* Returns a Path that can be used to paint, hit-test or calculate bounds for
|
||||
* this element. May return nullptr if there is no [valid] path.
|
||||
*/
|
||||
virtual mozilla::TemporaryRef<Path> BuildPath() = 0;
|
||||
virtual mozilla::TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) = 0;
|
||||
|
||||
virtual mozilla::TemporaryRef<Path> GetPathForLengthOrPositionMeasuring();
|
||||
|
||||
@ -77,14 +77,6 @@ public:
|
||||
* this element.
|
||||
*/
|
||||
FillRule GetFillRule();
|
||||
|
||||
/**
|
||||
* Returns the current computed value of the CSS property 'stroke-width' for
|
||||
* this element. (I.e. this does NOT take account of the value of the
|
||||
* 'stroke' and 'stroke-opacity' properties to, say, return zero if they are
|
||||
* "none" or "0", respectively.)
|
||||
*/
|
||||
Float GetStrokeWidth();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -132,7 +132,7 @@ nsSVGPolyElement::ConstructPath(gfxContext *aCtx)
|
||||
}
|
||||
|
||||
TemporaryRef<Path>
|
||||
nsSVGPolyElement::BuildPath()
|
||||
nsSVGPolyElement::BuildPath(PathBuilder* aBuilder)
|
||||
{
|
||||
const SVGPointList &points = mPoints.GetAnimValue();
|
||||
|
||||
@ -140,7 +140,7 @@ nsSVGPolyElement::BuildPath()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
|
||||
RefPtr<PathBuilder> pathBuilder = aBuilder ? aBuilder : CreatePathBuilder();
|
||||
|
||||
pathBuilder->MoveTo(points[0]);
|
||||
for (uint32_t i = 1; i < points.Length(); ++i) {
|
||||
|
@ -46,7 +46,7 @@ public:
|
||||
virtual bool IsMarkable() MOZ_OVERRIDE { return true; }
|
||||
virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) MOZ_OVERRIDE;
|
||||
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
|
||||
virtual mozilla::TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
|
||||
virtual mozilla::TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
|
||||
|
||||
// WebIDL
|
||||
already_AddRefed<mozilla::DOMSVGPointList> Points();
|
||||
|
@ -6,6 +6,13 @@ text { font: 20px monospace; }
|
||||
</style>
|
||||
|
||||
<g id="g">
|
||||
<svg id="svg1" x="10" y="10" width="25" height="30"/>
|
||||
<svg id="svg2" width="1" height="1" overflow="visible">
|
||||
<rect width="2" height="2" fill="yellow"/>
|
||||
</svg>
|
||||
<svg id="svg3" width="1" height="1" overflow="hidden">
|
||||
<rect width="2" height="2" fill="yellow"/>
|
||||
</svg>
|
||||
<text id="text1" x="25" y="25">abc</text>
|
||||
<text id="text1a" x="85" y="25" stroke="black" stroke-width="4">abc</text>
|
||||
<rect id="rect1" x="50" y="50" width="50" height="50" fill="green"/>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.0 KiB |
@ -44,6 +44,24 @@ function runTest()
|
||||
{
|
||||
var doc = $("svg").contentWindow.document;
|
||||
|
||||
var svg1Bounds = doc.getElementById("svg1").getBoundingClientRect();
|
||||
is(svg1Bounds.left, 10, "svg1.getBoundingClientRect().left");
|
||||
is(svg1Bounds.top, 10, "svg1.getBoundingClientRect().top");
|
||||
is(svg1Bounds.width, 25, "svg1.getBoundingClientRect().width");
|
||||
is(svg1Bounds.height, 30, "svg1.getBoundingClientRect().height");
|
||||
|
||||
var svg2Bounds = doc.getElementById("svg2").getBoundingClientRect();
|
||||
is(svg2Bounds.left, 0, "svg2.getBoundingClientRect().left");
|
||||
is(svg2Bounds.top, 0, "svg2.getBoundingClientRect().top");
|
||||
is(svg2Bounds.width, 2, "svg2.getBoundingClientRect().width");
|
||||
is(svg2Bounds.height, 2, "svg2.getBoundingClientRect().height");
|
||||
|
||||
var svg3Bounds = doc.getElementById("svg3").getBoundingClientRect();
|
||||
is(svg3Bounds.left, 0, "svg3.getBoundingClientRect().left");
|
||||
is(svg3Bounds.top, 0, "svg3.getBoundingClientRect().top");
|
||||
is(svg3Bounds.width, 1, "svg3.getBoundingClientRect().width");
|
||||
is(svg3Bounds.height, 1, "svg3.getBoundingClientRect().height");
|
||||
|
||||
var text1 = doc.getElementById("text1");
|
||||
|
||||
var text1Bounds = text1.getBoundingClientRect();
|
||||
|
@ -22,7 +22,7 @@ function run()
|
||||
var originY = div.offsetTop;
|
||||
var circle = document.getElementById("circle");
|
||||
|
||||
var elementFromPoint = document.elementFromPoint(originX + 150, originY + 51);
|
||||
var elementFromPoint = document.elementFromPoint(originX + 150, originY + 52);
|
||||
is(elementFromPoint, circle, "Top of circle should hit");
|
||||
|
||||
var elementFromPoint = document.elementFromPoint(originX + 249, originY + 150);
|
||||
@ -44,10 +44,10 @@ function run()
|
||||
<div id="content">
|
||||
|
||||
<div width="100%" height="1" id="div">
|
||||
</div>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="400" id="svg">
|
||||
<circle id="circle" cx="1.5" cy="1.5" r="1" transform="scale(100, 100)"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
|
@ -8,10 +8,10 @@ const Cu = Components.utils;
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
// This module exposes a subset of the functionnalities of the parent DOM
|
||||
// Registry to content processes, to be be used from the AppsService component.
|
||||
// This module exposes a subset of the functionalities of the parent DOM
|
||||
// Registry to content processes, to be used from the AppsService component.
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["DOMApplicationRegistry"];
|
||||
this.EXPORTED_SYMBOLS = ["DOMApplicationRegistry", "WrappedManifestCache"];
|
||||
|
||||
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
@ -20,54 +20,323 @@ function debug(s) {
|
||||
//dump("-*- AppsServiceChild.jsm: " + s + "\n");
|
||||
}
|
||||
|
||||
const APPS_IPC_MSG_NAMES = [
|
||||
"Webapps:AddApp",
|
||||
"Webapps:RemoveApp",
|
||||
"Webapps:UpdateApp",
|
||||
"Webapps:CheckForUpdate:Return:KO",
|
||||
"Webapps:FireEvent",
|
||||
"Webapps:UpdateState"
|
||||
];
|
||||
|
||||
// A simple cache for the wrapped manifests.
|
||||
this.WrappedManifestCache = {
|
||||
_cache: { },
|
||||
|
||||
// Gets an entry from the cache, and populates the cache if needed.
|
||||
get: function mcache_get(aManifestURL, aManifest, aWindow, aInnerWindowID) {
|
||||
if (!aManifest) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(aManifestURL in this._cache)) {
|
||||
this._cache[aManifestURL] = { };
|
||||
}
|
||||
|
||||
let winObjs = this._cache[aManifestURL];
|
||||
if (!(aInnerWindowID in winObjs)) {
|
||||
winObjs[aInnerWindowID] = Cu.cloneInto(aManifest, aWindow);
|
||||
}
|
||||
|
||||
return winObjs[aInnerWindowID];
|
||||
},
|
||||
|
||||
// Invalidates an entry in the cache.
|
||||
evict: function mcache_evict(aManifestURL, aInnerWindowID) {
|
||||
debug("Evicting manifest " + aManifestURL + " window ID " +
|
||||
aInnerWindowID);
|
||||
if (aManifestURL in this._cache) {
|
||||
let winObjs = this._cache[aManifestURL];
|
||||
if (aInnerWindowID in winObjs) {
|
||||
delete winObjs[aInnerWindowID];
|
||||
}
|
||||
|
||||
if (Object.keys(winObjs).length == 0) {
|
||||
delete this._cache[aManifestURL];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
// Clear the cache on memory pressure.
|
||||
this._cache = { };
|
||||
Cu.forceGC();
|
||||
},
|
||||
|
||||
init: function() {
|
||||
Services.obs.addObserver(this, "memory-pressure", false);
|
||||
}
|
||||
};
|
||||
|
||||
this.WrappedManifestCache.init();
|
||||
|
||||
|
||||
// DOMApplicationRegistry keeps a cache containing a list of apps in the device.
|
||||
// This information is updated with the data received from the main process and
|
||||
// it is queried by the DOM objects to set their state.
|
||||
// This module handle all the messages broadcasted from the parent process,
|
||||
// including DOM events, which are dispatched to the corresponding DOM objects.
|
||||
|
||||
this.DOMApplicationRegistry = {
|
||||
// DOMApps will hold a list of arrays of weak references to
|
||||
// mozIDOMApplication objects indexed by manifest URL.
|
||||
DOMApps: {},
|
||||
|
||||
ready: false,
|
||||
webapps: null,
|
||||
|
||||
init: function init() {
|
||||
debug("init");
|
||||
this.cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
|
||||
.getService(Ci.nsISyncMessageSender);
|
||||
|
||||
["Webapps:AddApp", "Webapps:RemoveApp"].forEach((function(aMsgName) {
|
||||
APPS_IPC_MSG_NAMES.forEach((function(aMsgName) {
|
||||
this.cpmm.addMessageListener(aMsgName, this);
|
||||
}).bind(this));
|
||||
|
||||
// We need to prime the cache with the list of apps.
|
||||
// XXX shoud we do this async and block callers if it's not yet there?
|
||||
this.webapps = this.cpmm.sendSyncMessage("Webapps:GetList", { })[0];
|
||||
this.cpmm.sendAsyncMessage("Webapps:RegisterForMessages", {
|
||||
messages: APPS_IPC_MSG_NAMES
|
||||
});
|
||||
|
||||
// We need to prime the cache with the list of apps.
|
||||
let list = this.cpmm.sendSyncMessage("Webapps:GetList", { })[0];
|
||||
this.webapps = list.webapps;
|
||||
// We need a fast mapping from localId -> app, so we add an index.
|
||||
// We also add the manifest to the app object.
|
||||
this.localIdIndex = { };
|
||||
for (let id in this.webapps) {
|
||||
let app = this.webapps[id];
|
||||
this.localIdIndex[app.localId] = app;
|
||||
app.manifest = list.manifests[id];
|
||||
}
|
||||
|
||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
// cpmm.addMessageListener causes the DOMApplicationRegistry object to live
|
||||
// forever if we don't clean up properly.
|
||||
// cpmm.addMessageListener causes the DOMApplicationRegistry object to
|
||||
// live forever if we don't clean up properly.
|
||||
this.webapps = null;
|
||||
["Webapps:AddApp", "Webapps:RemoveApp"].forEach((function(aMsgName) {
|
||||
this.DOMApps = null;
|
||||
|
||||
APPS_IPC_MSG_NAMES.forEach((aMsgName) => {
|
||||
this.cpmm.removeMessageListener(aMsgName, this);
|
||||
}).bind(this));
|
||||
});
|
||||
|
||||
this.cpmm.sendAsyncMessage("Webapps:UnregisterForMessages",
|
||||
APPS_IPC_MSG_NAMES)
|
||||
},
|
||||
|
||||
receiveMessage: function receiveMessage(aMessage) {
|
||||
debug("Received " + aMessage.name + " message.");
|
||||
let msg = aMessage.json;
|
||||
let msg = aMessage.data;
|
||||
switch (aMessage.name) {
|
||||
case "Webapps:AddApp":
|
||||
this.webapps[msg.id] = msg.app;
|
||||
this.localIdIndex[msg.app.localId] = msg.app;
|
||||
if (msg.manifest) {
|
||||
this.webapps[msg.id].manifest = msg.manifest;
|
||||
}
|
||||
break;
|
||||
case "Webapps:RemoveApp":
|
||||
delete this.DOMApps[this.webapps[msg.id].manifestURL];
|
||||
delete this.localIdIndex[this.webapps[msg.id].localId];
|
||||
delete this.webapps[msg.id];
|
||||
break;
|
||||
case "Webapps:UpdateApp":
|
||||
let app = this.webapps[msg.oldId];
|
||||
if (!app) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg.app) {
|
||||
for (let prop in msg.app) {
|
||||
app[prop] = msg.app[prop];
|
||||
}
|
||||
}
|
||||
|
||||
this.webapps[msg.newId] = app;
|
||||
this.localIdIndex[app.localId] = app;
|
||||
delete this.webapps[msg.oldId];
|
||||
|
||||
let apps = this.DOMApps[msg.app.manifestURL];
|
||||
if (!apps) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < apps.length; i++) {
|
||||
let domApp = apps[i].get();
|
||||
if (!domApp) {
|
||||
apps.splice(i);
|
||||
continue;
|
||||
}
|
||||
domApp._proxy = new Proxy(domApp, {
|
||||
get: function(target, prop) {
|
||||
if (!DOMApplicationRegistry.webapps[msg.newId]) {
|
||||
return;
|
||||
}
|
||||
return DOMApplicationRegistry.webapps[msg.newId][prop];
|
||||
},
|
||||
set: function(target, prop, val) {
|
||||
if (!DOMApplicationRegistry.webapps[msg.newId]) {
|
||||
return;
|
||||
}
|
||||
DOMApplicationRegistry.webapps[msg.newId][prop] = val;
|
||||
return;
|
||||
},
|
||||
});
|
||||
}
|
||||
break;
|
||||
case "Webapps:FireEvent":
|
||||
this._fireEvent(aMessage);
|
||||
break;
|
||||
case "Webapps:UpdateState":
|
||||
this._updateState(msg);
|
||||
break;
|
||||
case "Webapps:CheckForUpdate:Return:KO":
|
||||
let DOMApps = this.DOMApps[msg.manifestURL];
|
||||
if (!DOMApps || !msg.requestID) {
|
||||
return;
|
||||
}
|
||||
DOMApps.forEach((DOMApp) => {
|
||||
let domApp = DOMApp.get();
|
||||
if (domApp && msg.requestID) {
|
||||
domApp._fireRequestResult(aMessage, true /* aIsError */);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* mozIDOMApplication management
|
||||
*/
|
||||
|
||||
// Every time a DOM app is created, we save a weak reference to it that will
|
||||
// be used to dispatch events and fire request results.
|
||||
addDOMApp: function(aApp, aManifestURL, aId) {
|
||||
let weakRef = Cu.getWeakReference(aApp);
|
||||
|
||||
if (!this.DOMApps[aManifestURL]) {
|
||||
this.DOMApps[aManifestURL] = [];
|
||||
}
|
||||
|
||||
let apps = this.DOMApps[aManifestURL];
|
||||
|
||||
// Get rid of dead weak references.
|
||||
for (let i = 0; i < apps.length; i++) {
|
||||
if (!apps[i].get()) {
|
||||
apps.splice(i);
|
||||
}
|
||||
}
|
||||
|
||||
apps.push(weakRef);
|
||||
|
||||
// Each DOM app contains a proxy object used to build their state. We
|
||||
// return the handler for this proxy object with traps to get and set
|
||||
// app properties kept in the DOMApplicationRegistry app cache.
|
||||
return {
|
||||
get: function(target, prop) {
|
||||
if (!DOMApplicationRegistry.webapps[aId]) {
|
||||
return;
|
||||
}
|
||||
return DOMApplicationRegistry.webapps[aId][prop];
|
||||
},
|
||||
set: function(target, prop, val) {
|
||||
if (!DOMApplicationRegistry.webapps[aId]) {
|
||||
return;
|
||||
}
|
||||
DOMApplicationRegistry.webapps[aId][prop] = val;
|
||||
return;
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
_fireEvent: function(aMessage) {
|
||||
let msg = aMessage.data;
|
||||
debug("_fireEvent " + JSON.stringify(msg));
|
||||
if (!this.DOMApps || !msg.manifestURL || !msg.eventType) {
|
||||
return;
|
||||
}
|
||||
|
||||
let DOMApps = this.DOMApps[msg.manifestURL];
|
||||
if (!DOMApps) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The parent might ask childs to trigger more than one event in one
|
||||
// shot, so in order to avoid needless IPC we allow an array for the
|
||||
// 'eventType' IPC message field.
|
||||
if (!Array.isArray(msg.eventType)) {
|
||||
msg.eventType = [msg.eventType];
|
||||
}
|
||||
|
||||
DOMApps.forEach((DOMApp) => {
|
||||
let domApp = DOMApp.get();
|
||||
if (!domApp) {
|
||||
return;
|
||||
}
|
||||
msg.eventType.forEach((aEventType) => {
|
||||
if ('on' + aEventType in domApp) {
|
||||
domApp._fireEvent(aEventType);
|
||||
}
|
||||
});
|
||||
|
||||
if (msg.requestID) {
|
||||
aMessage.data.result = msg.manifestURL;
|
||||
domApp._fireRequestResult(aMessage);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_updateState: function(aMessage) {
|
||||
if (!this.DOMApps || !aMessage.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
let app = this.webapps[aMessage.id];
|
||||
if (!app) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aMessage.app) {
|
||||
for (let prop in aMessage.app) {
|
||||
app[prop] = aMessage.app[prop];
|
||||
}
|
||||
}
|
||||
|
||||
if ("error" in aMessage) {
|
||||
app.downloadError = aMessage.error;
|
||||
}
|
||||
|
||||
if (aMessage.manifest) {
|
||||
app.manifest = aMessage.manifest;
|
||||
// Evict the wrapped manifest cache for all the affected DOM objects.
|
||||
let DOMApps = this.DOMApps[app.manifestURL];
|
||||
if (!DOMApps) {
|
||||
return;
|
||||
}
|
||||
DOMApps.forEach((DOMApp) => {
|
||||
let domApp = DOMApp.get();
|
||||
if (!domApp) {
|
||||
return;
|
||||
}
|
||||
WrappedManifestCache.evict(app.manifestURL, domApp.innerWindowID);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* nsIAppsService API
|
||||
*/
|
||||
getAppByManifestURL: function getAppByManifestURL(aManifestURL) {
|
||||
debug("getAppByManifestURL " + aManifestURL);
|
||||
return AppsUtils.getAppByManifestURL(this.webapps, aManifestURL);
|
||||
@ -89,7 +358,7 @@ this.DOMApplicationRegistry = {
|
||||
},
|
||||
|
||||
getAppByLocalId: function getAppByLocalId(aLocalId) {
|
||||
debug("getAppByLocalId " + aLocalId);
|
||||
debug("getAppByLocalId " + aLocalId + " - ready: " + this.ready);
|
||||
let app = this.localIdIndex[aLocalId];
|
||||
if (!app) {
|
||||
debug("Ouch, No app!");
|
||||
|
@ -12,6 +12,7 @@ Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
||||
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||
Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
|
||||
Cu.import("resource://gre/modules/AppsServiceChild.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
@ -278,50 +279,9 @@ WebappsRegistry.prototype = {
|
||||
* mozIDOMApplication object
|
||||
*/
|
||||
|
||||
// A simple cache for the wrapped manifests.
|
||||
let manifestCache = {
|
||||
_cache: { },
|
||||
|
||||
// Gets an entry from the cache, and populates the cache if needed.
|
||||
get: function mcache_get(aManifestURL, aManifest, aWindow, aInnerWindowID) {
|
||||
if (!(aManifestURL in this._cache)) {
|
||||
this._cache[aManifestURL] = { };
|
||||
}
|
||||
|
||||
let winObjs = this._cache[aManifestURL];
|
||||
if (!(aInnerWindowID in winObjs)) {
|
||||
winObjs[aInnerWindowID] = Cu.cloneInto(aManifest, aWindow);
|
||||
}
|
||||
|
||||
return winObjs[aInnerWindowID];
|
||||
},
|
||||
|
||||
// Invalidates an entry in the cache.
|
||||
evict: function mcache_evict(aManifestURL, aInnerWindowID) {
|
||||
if (aManifestURL in this._cache) {
|
||||
let winObjs = this._cache[aManifestURL];
|
||||
if (aInnerWindowID in winObjs) {
|
||||
delete winObjs[aInnerWindowID];
|
||||
}
|
||||
|
||||
if (Object.keys(winObjs).length == 0) {
|
||||
delete this._cache[aManifestURL];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
// Clear the cache on memory pressure.
|
||||
this._cache = { };
|
||||
},
|
||||
|
||||
init: function() {
|
||||
Services.obs.addObserver(this, "memory-pressure", false);
|
||||
}
|
||||
};
|
||||
|
||||
function createApplicationObject(aWindow, aApp) {
|
||||
let app = Cc["@mozilla.org/webapps/application;1"].createInstance(Ci.mozIDOMApplication);
|
||||
let app = Cc["@mozilla.org/webapps/application;1"]
|
||||
.createInstance(Ci.mozIDOMApplication);
|
||||
app.wrappedJSObject.init(aWindow, aApp);
|
||||
return app;
|
||||
}
|
||||
@ -334,27 +294,12 @@ WebappsApplication.prototype = {
|
||||
__proto__: DOMRequestIpcHelper.prototype,
|
||||
|
||||
init: function(aWindow, aApp) {
|
||||
let proxyHandler = DOMApplicationRegistry.addDOMApp(this,
|
||||
aApp.manifestURL,
|
||||
aApp.id);
|
||||
this._proxy = new Proxy(this, proxyHandler);
|
||||
|
||||
this._window = aWindow;
|
||||
let principal = this._window.document.nodePrincipal;
|
||||
this._appStatus = principal.appStatus;
|
||||
this.origin = aApp.origin;
|
||||
this._manifest = aApp.manifest;
|
||||
this._updateManifest = aApp.updateManifest;
|
||||
this.manifestURL = aApp.manifestURL;
|
||||
this.receipts = aApp.receipts;
|
||||
this.installOrigin = aApp.installOrigin;
|
||||
this.installTime = aApp.installTime;
|
||||
this.installState = aApp.installState || "installed";
|
||||
this.removable = aApp.removable;
|
||||
this.lastUpdateCheck = aApp.lastUpdateCheck ? aApp.lastUpdateCheck
|
||||
: Date.now();
|
||||
this.updateTime = aApp.updateTime ? aApp.updateTime
|
||||
: aApp.installTime;
|
||||
this.progress = NaN;
|
||||
this.downloadAvailable = aApp.downloadAvailable;
|
||||
this.downloading = aApp.downloading;
|
||||
this.readyToApplyDownload = aApp.readyToApplyDownload;
|
||||
this.downloadSize = aApp.downloadSize || 0;
|
||||
|
||||
this._onprogress = null;
|
||||
this._ondownloadsuccess = null;
|
||||
@ -362,40 +307,83 @@ WebappsApplication.prototype = {
|
||||
this._ondownloadavailable = null;
|
||||
this._ondownloadapplied = null;
|
||||
|
||||
this._downloadError = null;
|
||||
this.initDOMRequestHelper(aWindow);
|
||||
},
|
||||
|
||||
this.initDOMRequestHelper(aWindow, [
|
||||
{ name: "Webapps:CheckForUpdate:Return:KO", weakRef: true },
|
||||
{ name: "Webapps:Connect:Return:OK", weakRef: true },
|
||||
{ name: "Webapps:Connect:Return:KO", weakRef: true },
|
||||
{ name: "Webapps:FireEvent", weakRef: true },
|
||||
{ name: "Webapps:GetConnections:Return:OK", weakRef: true },
|
||||
{ name: "Webapps:UpdateState", weakRef: true }
|
||||
]);
|
||||
get _appStatus() {
|
||||
return this._proxy.appStatus;
|
||||
},
|
||||
|
||||
cpmm.sendAsyncMessage("Webapps:RegisterForMessages", {
|
||||
messages: ["Webapps:FireEvent",
|
||||
"Webapps:UpdateState"],
|
||||
app: {
|
||||
id: this.id,
|
||||
manifestURL: this.manifestURL,
|
||||
installState: this.installState,
|
||||
downloading: this.downloading
|
||||
}
|
||||
});
|
||||
get downloadAvailable() {
|
||||
return this._proxy.downloadAvailable;
|
||||
},
|
||||
|
||||
get downloading() {
|
||||
return this._proxy.downloading;
|
||||
},
|
||||
|
||||
get downloadSize() {
|
||||
return this._proxy.downloadSize;
|
||||
},
|
||||
|
||||
get installOrigin() {
|
||||
return this._proxy.installOrigin;
|
||||
},
|
||||
|
||||
get installState() {
|
||||
return this._proxy.installState;
|
||||
},
|
||||
|
||||
get installTime() {
|
||||
return this._proxy.installTime;
|
||||
},
|
||||
|
||||
get lastUpdateCheck() {
|
||||
return this._proxy.lastUpdateCheck;
|
||||
},
|
||||
|
||||
get manifestURL() {
|
||||
return this._proxy.manifestURL;
|
||||
},
|
||||
|
||||
get origin() {
|
||||
return this._proxy.origin;
|
||||
},
|
||||
|
||||
get progress() {
|
||||
return this._proxy.progress;
|
||||
},
|
||||
|
||||
get readyToApplyDownload() {
|
||||
return this._proxy.readyToApplyDownload;
|
||||
},
|
||||
|
||||
get receipts() {
|
||||
return this._proxy.receipts;
|
||||
},
|
||||
|
||||
set receipts(aReceipts) {
|
||||
this._proxy.receipts = aReceipts;
|
||||
},
|
||||
|
||||
get removable() {
|
||||
return this._proxy.removable;
|
||||
},
|
||||
|
||||
get updateTime() {
|
||||
return this._proxy.updateTime;
|
||||
},
|
||||
|
||||
get manifest() {
|
||||
return manifestCache.get(this.manifestURL,
|
||||
this._manifest,
|
||||
this._window,
|
||||
this.innerWindowID);
|
||||
return WrappedManifestCache.get(this.manifestURL,
|
||||
this._proxy.manifest,
|
||||
this._window,
|
||||
this.innerWindowID);
|
||||
},
|
||||
|
||||
get updateManifest() {
|
||||
return this.updateManifest =
|
||||
this._updateManifest ? Cu.cloneInto(this._updateManifest, this._window)
|
||||
: null;
|
||||
return this._proxy.updateManifest ?
|
||||
Cu.cloneInto(this._proxy.updateManifest, this._window) : null;
|
||||
},
|
||||
|
||||
set onprogress(aCallback) {
|
||||
@ -440,10 +428,10 @@ WebappsApplication.prototype = {
|
||||
|
||||
get downloadError() {
|
||||
// Only return DOMError when we have an error.
|
||||
if (!this._downloadError) {
|
||||
if (!this._proxy.downloadError) {
|
||||
return null;
|
||||
}
|
||||
return new this._window.DOMError(this._downloadError);
|
||||
return new this._window.DOMError(this._proxy.downloadError);
|
||||
},
|
||||
|
||||
download: function() {
|
||||
@ -485,12 +473,11 @@ WebappsApplication.prototype = {
|
||||
BrowserElementPromptService.getBrowserElementChildForWindow(this._window);
|
||||
if (browserChild) {
|
||||
this.addMessageListeners("Webapps:ClearBrowserData:Return");
|
||||
browserChild.messageManager.sendAsyncMessage(
|
||||
"Webapps:ClearBrowserData",
|
||||
{ manifestURL: this.manifestURL,
|
||||
oid: this._id,
|
||||
requestID: this.getRequestId(request) }
|
||||
);
|
||||
browserChild.messageManager.sendAsyncMessage("Webapps:ClearBrowserData", {
|
||||
manifestURL: this.manifestURL,
|
||||
oid: this._id,
|
||||
requestID: this.getRequestId(request)
|
||||
});
|
||||
} else {
|
||||
Services.DOMRequest.fireErrorAsync(request, "NO_CLEARABLE_BROWSER");
|
||||
}
|
||||
@ -498,28 +485,33 @@ WebappsApplication.prototype = {
|
||||
},
|
||||
|
||||
connect: function(aKeyword, aRules) {
|
||||
this.addMessageListeners(["Webapps:Connect:Return:OK",
|
||||
"Webapps:Connect:Return:KO"]);
|
||||
return this.createPromise(function (aResolve, aReject) {
|
||||
cpmm.sendAsyncMessage("Webapps:Connect",
|
||||
{ keyword: aKeyword,
|
||||
rules: aRules,
|
||||
manifestURL: this.manifestURL,
|
||||
outerWindowID: this._id,
|
||||
requestID: this.getPromiseResolverId({
|
||||
resolve: aResolve,
|
||||
reject: aReject
|
||||
})});
|
||||
cpmm.sendAsyncMessage("Webapps:Connect", {
|
||||
keyword: aKeyword,
|
||||
rules: aRules,
|
||||
manifestURL: this.manifestURL,
|
||||
outerWindowID: this._id,
|
||||
requestID: this.getPromiseResolverId({
|
||||
resolve: aResolve,
|
||||
reject: aReject
|
||||
})
|
||||
});
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
getConnections: function() {
|
||||
this.addMessageListeners("Webapps:GetConnections:Return:OK");
|
||||
return this.createPromise(function (aResolve, aReject) {
|
||||
cpmm.sendAsyncMessage("Webapps:GetConnections",
|
||||
{ manifestURL: this.manifestURL,
|
||||
outerWindowID: this._id,
|
||||
requestID: this.getPromiseResolverId({
|
||||
resolve: aResolve,
|
||||
reject: aReject
|
||||
})});
|
||||
cpmm.sendAsyncMessage("Webapps:GetConnections", {
|
||||
manifestURL: this.manifestURL,
|
||||
outerWindowID: this._id,
|
||||
requestID: this.getPromiseResolverId({
|
||||
resolve: aResolve,
|
||||
reject: aReject
|
||||
})
|
||||
});
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
@ -568,12 +560,7 @@ WebappsApplication.prototype = {
|
||||
|
||||
uninit: function() {
|
||||
this._onprogress = null;
|
||||
cpmm.sendAsyncMessage("Webapps:UnregisterForMessages", [
|
||||
"Webapps:FireEvent",
|
||||
"Webapps:UpdateState"
|
||||
]);
|
||||
|
||||
manifestCache.evict(this.manifestURL, this.innerWindowID);
|
||||
WrappedManifestCache.evict(this.manifestURL, this.innerWindowID);
|
||||
},
|
||||
|
||||
_fireEvent: function(aName) {
|
||||
@ -590,22 +577,16 @@ WebappsApplication.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_updateState: function(aMsg) {
|
||||
if (aMsg.app) {
|
||||
for (let prop in aMsg.app) {
|
||||
this[prop] = aMsg.app[prop];
|
||||
}
|
||||
_fireRequestResult: function(aMessage, aIsError) {
|
||||
let req;
|
||||
let msg = aMessage.data;
|
||||
req = this.takeRequest(msg.requestID);
|
||||
if (!req) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Intentional use of 'in' so we unset the error if this is explicitly null.
|
||||
if ('error' in aMsg) {
|
||||
this._downloadError = aMsg.error;
|
||||
}
|
||||
|
||||
if (aMsg.manifest) {
|
||||
this._manifest = aMsg.manifest;
|
||||
manifestCache.evict(this.manifestURL, this.innerWindowID);
|
||||
}
|
||||
aIsError ? Services.DOMRequest.fireError(req, msg.error)
|
||||
: Services.DOMRequest.fireSuccess(req, msg.result);
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
@ -619,10 +600,7 @@ WebappsApplication.prototype = {
|
||||
req = this.takeRequest(msg.requestID);
|
||||
}
|
||||
|
||||
// ondownload* callbacks should be triggered on all app instances
|
||||
if ((msg.oid != this._id || !req) &&
|
||||
aMessage.name !== "Webapps:FireEvent" &&
|
||||
aMessage.name !== "Webapps:UpdateState") {
|
||||
if (msg.oid !== this._id || !req) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -637,51 +615,13 @@ WebappsApplication.prototype = {
|
||||
"Webapps:Launch:Return:KO"]);
|
||||
Services.DOMRequest.fireSuccess(req, null);
|
||||
break;
|
||||
case "Webapps:CheckForUpdate:Return:KO":
|
||||
Services.DOMRequest.fireError(req, msg.error);
|
||||
break;
|
||||
case "Webapps:FireEvent":
|
||||
if (msg.manifestURL != this.manifestURL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The parent might ask childs to trigger more than one event in one
|
||||
// shot, so in order to avoid needless IPC we allow an array for the
|
||||
// 'eventType' IPC message field.
|
||||
if (!Array.isArray(msg.eventType)) {
|
||||
msg.eventType = [msg.eventType];
|
||||
}
|
||||
|
||||
msg.eventType.forEach((aEventType) => {
|
||||
// If we are in a successful state clear any past errors.
|
||||
if (aEventType === 'downloadapplied' ||
|
||||
aEventType === 'downloadsuccess') {
|
||||
this._downloadError = null;
|
||||
}
|
||||
|
||||
if ("_on" + aEventType in this) {
|
||||
this._fireEvent(aEventType);
|
||||
} else {
|
||||
dump("Unsupported event type " + aEventType + "\n");
|
||||
}
|
||||
});
|
||||
|
||||
if (req) {
|
||||
Services.DOMRequest.fireSuccess(req, this.manifestURL);
|
||||
}
|
||||
break;
|
||||
case "Webapps:UpdateState":
|
||||
if (msg.manifestURL != this.manifestURL) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._updateState(msg);
|
||||
break;
|
||||
case "Webapps:ClearBrowserData:Return":
|
||||
this.removeMessageListeners(aMessage.name);
|
||||
Services.DOMRequest.fireSuccess(req, null);
|
||||
break;
|
||||
case "Webapps:Connect:Return:OK":
|
||||
this.removeMessageListeners(["Webapps:Connect:Return:OK",
|
||||
"Webapps:Connect:Return:KO"]);
|
||||
let messagePorts = [];
|
||||
msg.messagePortIDs.forEach((aPortID) => {
|
||||
let port = new this._window.MozInterAppMessagePort(aPortID);
|
||||
@ -690,9 +630,12 @@ WebappsApplication.prototype = {
|
||||
req.resolve(messagePorts);
|
||||
break;
|
||||
case "Webapps:Connect:Return:KO":
|
||||
this.removeMessageListeners(["Webapps:Connect:Return:OK",
|
||||
"Webapps:Connect:Return:KO"]);
|
||||
req.reject("No connections registered");
|
||||
break;
|
||||
case "Webapps:GetConnections:Return:OK":
|
||||
this.removeMessageListeners(aMessage.name);
|
||||
let connections = [];
|
||||
msg.connections.forEach((aConnection) => {
|
||||
let connection =
|
||||
@ -874,12 +817,8 @@ WebappsApplicationMgmt.prototype = {
|
||||
break;
|
||||
case "Webapps:Uninstall:Broadcast:Return:OK":
|
||||
if (this._onuninstall) {
|
||||
let detail = {
|
||||
manifestURL: msg.manifestURL,
|
||||
origin: msg.origin
|
||||
};
|
||||
let event = new this._window.MozApplicationEvent("applicationuninstall",
|
||||
{ application : createApplicationObject(this._window, detail) });
|
||||
{ application : createApplicationObject(this._window, msg) });
|
||||
this._onuninstall.handleEvent(event);
|
||||
}
|
||||
break;
|
||||
@ -908,7 +847,5 @@ WebappsApplicationMgmt.prototype = {
|
||||
classDescription: "Webapps Application Mgmt"})
|
||||
}
|
||||
|
||||
manifestCache.init();
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([WebappsRegistry,
|
||||
WebappsApplication]);
|
||||
|
@ -1141,8 +1141,8 @@ this.DOMApplicationRegistry = {
|
||||
this.removeMessageListener(["Webapps:Internal:AllMessages"], mm);
|
||||
break;
|
||||
case "Webapps:GetList":
|
||||
this.addMessageListener(["Webapps:AddApp", "Webapps:RemoveApp"], null, mm);
|
||||
return this.webapps;
|
||||
return this.doGetList();
|
||||
break;
|
||||
case "Webapps:Download":
|
||||
this.startDownload(msg.manifestURL);
|
||||
break;
|
||||
@ -1245,6 +1245,38 @@ this.DOMApplicationRegistry = {
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the full list of apps and manifests.
|
||||
*/
|
||||
doGetList: function() {
|
||||
let tmp = [];
|
||||
|
||||
for (let id in this.webapps) {
|
||||
tmp.push({ id: id });
|
||||
}
|
||||
|
||||
let res = {};
|
||||
let done = false;
|
||||
|
||||
this._readManifests(tmp).then(
|
||||
function(manifests) {
|
||||
manifests.forEach((item) => {
|
||||
res[item.id] = item.manifest;
|
||||
});
|
||||
done = true;
|
||||
}
|
||||
);
|
||||
|
||||
let thread = Services.tm.currentThread;
|
||||
while (!done) {
|
||||
//debug("before processNextEvent");
|
||||
thread.processNextEvent(/* mayWait */ true);
|
||||
//after("before processNextEvent");
|
||||
}
|
||||
return { webapps: this.webapps, manifests: res };
|
||||
},
|
||||
|
||||
|
||||
doLaunch: function (aData, aMm) {
|
||||
this.launch(
|
||||
aData.manifestURL,
|
||||
@ -1330,7 +1362,7 @@ this.DOMApplicationRegistry = {
|
||||
downloading: false
|
||||
},
|
||||
error: error,
|
||||
manifestURL: app.manifestURL,
|
||||
id: app.id
|
||||
})
|
||||
this.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "downloaderror",
|
||||
@ -1361,7 +1393,7 @@ this.DOMApplicationRegistry = {
|
||||
if (!app.downloadAvailable) {
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
error: "NO_DOWNLOAD_AVAILABLE",
|
||||
manifestURL: app.manifestURL
|
||||
id: app.id
|
||||
});
|
||||
this.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "downloaderror",
|
||||
@ -1409,7 +1441,7 @@ this.DOMApplicationRegistry = {
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifest: jsonManifest,
|
||||
manifestURL: aManifestURL
|
||||
id: app.id
|
||||
});
|
||||
this.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "downloadsuccess",
|
||||
@ -1453,7 +1485,7 @@ this.DOMApplicationRegistry = {
|
||||
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifestURL: aManifestURL
|
||||
id: app.id
|
||||
});
|
||||
this.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "downloadsuccess",
|
||||
@ -1555,7 +1587,7 @@ this.DOMApplicationRegistry = {
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifest: newManifest,
|
||||
manifestURL: app.manifestURL
|
||||
id: app.id
|
||||
});
|
||||
this.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "downloadapplied",
|
||||
@ -1594,7 +1626,7 @@ this.DOMApplicationRegistry = {
|
||||
installState: aApp.installState,
|
||||
progress: 0
|
||||
},
|
||||
manifestURL: aApp.manifestURL
|
||||
id: aApp.id
|
||||
});
|
||||
let cacheUpdate = updateSvc.scheduleAppUpdate(
|
||||
appcacheURI, docURI, aApp.localId, false, aProfileDir);
|
||||
@ -1644,6 +1676,7 @@ this.DOMApplicationRegistry = {
|
||||
debug("checkForUpdate for " + aData.manifestURL);
|
||||
|
||||
function sendError(aError) {
|
||||
debug("checkForUpdate error " + aError);
|
||||
aData.error = aError;
|
||||
aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
|
||||
}
|
||||
@ -1673,8 +1706,7 @@ this.DOMApplicationRegistry = {
|
||||
// then we can't have an update.
|
||||
if (app.origin.startsWith("app://") &&
|
||||
app.manifestURL.startsWith("app://")) {
|
||||
aData.error = "NOT_UPDATABLE";
|
||||
aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
|
||||
sendError("NOT_UPDATABLE");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1691,8 +1723,7 @@ this.DOMApplicationRegistry = {
|
||||
if (onlyCheckAppCache) {
|
||||
// Bail out for packaged apps.
|
||||
if (app.origin.startsWith("app://")) {
|
||||
aData.error = "NOT_UPDATABLE";
|
||||
aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
|
||||
sendError("NOT_UPDATABLE");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1700,8 +1731,7 @@ this.DOMApplicationRegistry = {
|
||||
this._readManifests([{ id: id }]).then((aResult) => {
|
||||
let manifest = aResult[0].manifest;
|
||||
if (!manifest.appcache_path) {
|
||||
aData.error = "NOT_UPDATABLE";
|
||||
aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
|
||||
sendError("NOT_UPDATABLE");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1717,7 +1747,7 @@ this.DOMApplicationRegistry = {
|
||||
this._saveApps().then(() => {
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifestURL: app.manifestURL
|
||||
id: app.id
|
||||
});
|
||||
this.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "downloadavailable",
|
||||
@ -1726,8 +1756,7 @@ this.DOMApplicationRegistry = {
|
||||
});
|
||||
});
|
||||
} else {
|
||||
aData.error = "NOT_UPDATABLE";
|
||||
aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
|
||||
sendError("NOT_UPDATABLE");
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -1787,7 +1816,7 @@ this.DOMApplicationRegistry = {
|
||||
: "downloadapplied";
|
||||
aMm.sendAsyncMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifestURL: app.manifestURL
|
||||
id: app.id
|
||||
});
|
||||
aMm.sendAsyncMessage("Webapps:FireEvent", {
|
||||
eventType: eventType,
|
||||
@ -1814,7 +1843,7 @@ this.DOMApplicationRegistry = {
|
||||
: "downloadapplied";
|
||||
aMm.sendAsyncMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifestURL: app.manifestURL
|
||||
id: app.id
|
||||
});
|
||||
aMm.sendAsyncMessage("Webapps:FireEvent", {
|
||||
eventType: eventType,
|
||||
@ -1923,7 +1952,7 @@ this.DOMApplicationRegistry = {
|
||||
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
app: aApp,
|
||||
manifestURL: aApp.manifestURL
|
||||
id: aApp.id
|
||||
});
|
||||
this.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "downloadavailable",
|
||||
@ -1989,7 +2018,7 @@ this.DOMApplicationRegistry = {
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
app: aApp,
|
||||
manifest: aApp.manifest,
|
||||
manifestURL: aApp.manifestURL
|
||||
id: aApp.id
|
||||
});
|
||||
this.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "downloadapplied",
|
||||
@ -2023,7 +2052,7 @@ this.DOMApplicationRegistry = {
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
app: aApp,
|
||||
manifest: aApp.manifest,
|
||||
manifestURL: aApp.manifestURL
|
||||
id: aApp.id
|
||||
});
|
||||
this.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: eventType,
|
||||
@ -2135,7 +2164,7 @@ this.DOMApplicationRegistry = {
|
||||
if (xhr.status == 200) {
|
||||
if (!AppsUtils.checkManifestContentType(app.installOrigin, app.origin,
|
||||
xhr.getResponseHeader("content-type"))) {
|
||||
sendError("INVALID_MANIFEST");
|
||||
sendError("INVALID_MANIFEST_CONTENT_TYPE");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2235,7 +2264,7 @@ this.DOMApplicationRegistry = {
|
||||
if (xhr.status == 200) {
|
||||
if (!AppsUtils.checkManifestContentType(app.installOrigin, app.origin,
|
||||
xhr.getResponseHeader("content-type"))) {
|
||||
sendError("INVALID_MANIFEST");
|
||||
sendError("INVALID_MANIFEST_CONTENT_TYPE");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2450,7 +2479,8 @@ this.DOMApplicationRegistry = {
|
||||
}
|
||||
|
||||
this._saveApps().then(() => {
|
||||
this.broadcastMessage("Webapps:AddApp", { id: app.id, app: app });
|
||||
this.broadcastMessage("Webapps:AddApp",
|
||||
{ id: app.id, app: app, manifest: aManifest });
|
||||
});
|
||||
}),
|
||||
|
||||
@ -2550,6 +2580,8 @@ this.DOMApplicationRegistry = {
|
||||
// saved in the registry.
|
||||
yield this._saveApps();
|
||||
|
||||
aData.isPackage ? appObject.updateManifest = jsonManifest :
|
||||
appObject.manifest = jsonManifest;
|
||||
this.broadcastMessage("Webapps:AddApp", { id: id, app: appObject });
|
||||
|
||||
// The presence of a requestID means that we have a page to update.
|
||||
@ -2626,7 +2658,8 @@ this.DOMApplicationRegistry = {
|
||||
delete this._manifestCache[aId];
|
||||
}
|
||||
|
||||
this.broadcastMessage("Webapps:AddApp", { id: aId, app: aNewApp });
|
||||
this.broadcastMessage("Webapps:AddApp",
|
||||
{ id: aId, app: aNewApp, manifest: aManifest });
|
||||
Services.obs.notifyObservers(null, "webapps-installed",
|
||||
JSON.stringify({ manifestURL: aNewApp.manifestURL }));
|
||||
|
||||
@ -2760,14 +2793,11 @@ this.DOMApplicationRegistry = {
|
||||
oldApp,
|
||||
aNewApp);
|
||||
|
||||
AppDownloadManager.add(
|
||||
aNewApp.manifestURL,
|
||||
{
|
||||
channel: requestChannel,
|
||||
appId: id,
|
||||
previousState: aIsUpdate ? "installed" : "pending"
|
||||
}
|
||||
);
|
||||
AppDownloadManager.add(aNewApp.manifestURL, {
|
||||
channel: requestChannel,
|
||||
appId: id,
|
||||
previousState: aIsUpdate ? "installed" : "pending"
|
||||
});
|
||||
|
||||
// We set the 'downloading' flag to true right before starting the fetch.
|
||||
oldApp.downloading = true;
|
||||
@ -2787,7 +2817,7 @@ this.DOMApplicationRegistry = {
|
||||
// Clear any previous download errors.
|
||||
error: null,
|
||||
app: oldApp,
|
||||
manifestURL: aNewApp.manifestURL
|
||||
id: id
|
||||
});
|
||||
|
||||
let zipFile = yield this._getPackage(requestChannel, id, oldApp, aNewApp);
|
||||
@ -2802,7 +2832,7 @@ this.DOMApplicationRegistry = {
|
||||
// We send an "applied" event right away so code awaiting that event
|
||||
// can proceed to access the app. We also throw an error to alert
|
||||
// the caller that the package wasn't downloaded.
|
||||
this._sendAppliedEvent(aNewApp, oldApp, id);
|
||||
this._sendAppliedEvent(oldApp);
|
||||
throw new Error("PACKAGE_UNCHANGED");
|
||||
}
|
||||
|
||||
@ -2942,7 +2972,7 @@ this.DOMApplicationRegistry = {
|
||||
app: {
|
||||
progress: aProgress
|
||||
},
|
||||
manifestURL: aNewApp.manifestURL
|
||||
id: aNewApp.id
|
||||
});
|
||||
this.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "progress",
|
||||
@ -3059,27 +3089,24 @@ this.DOMApplicationRegistry = {
|
||||
* something similar after updating the app, and we could refactor both cases
|
||||
* to use the same code to send the "applied" event.
|
||||
*
|
||||
* @param aNewApp {Object} the new app data
|
||||
* @param aOldApp {Object} the currently stored app data
|
||||
* @param aId {String} the unique id of the app
|
||||
* @param aApp {Object} app data
|
||||
*/
|
||||
_sendAppliedEvent: function(aNewApp, aOldApp, aId) {
|
||||
aOldApp.downloading = false;
|
||||
aOldApp.downloadAvailable = false;
|
||||
aOldApp.downloadSize = 0;
|
||||
aOldApp.installState = "installed";
|
||||
aOldApp.readyToApplyDownload = false;
|
||||
if (aOldApp.staged && aOldApp.staged.manifestHash) {
|
||||
_sendAppliedEvent: function(aApp) {
|
||||
aApp.downloading = false;
|
||||
aApp.downloadAvailable = false;
|
||||
aApp.downloadSize = 0;
|
||||
aApp.installState = "installed";
|
||||
aApp.readyToApplyDownload = false;
|
||||
if (aApp.staged && aApp.staged.manifestHash) {
|
||||
// If we're here then the manifest has changed but the package
|
||||
// hasn't. Let's clear this, so we don't keep offering
|
||||
// a bogus update to the user
|
||||
aOldApp.manifestHash = aOldApp.staged.manifestHash;
|
||||
aOldApp.etag = aOldApp.staged.etag || aOldApp.etag;
|
||||
aOldApp.staged = {};
|
||||
|
||||
// Move the staged update manifest to a non staged one.
|
||||
aApp.manifestHash = aApp.staged.manifestHash;
|
||||
aApp.etag = aApp.staged.etag || aApp.etag;
|
||||
aApp.staged = {};
|
||||
// Move the staged update manifest to a non staged one.
|
||||
try {
|
||||
let staged = this._getAppDir(aId);
|
||||
let staged = this._getAppDir(aApp.id);
|
||||
staged.append("staged-update.webapp");
|
||||
staged.moveTo(staged.parent, "update.webapp");
|
||||
} catch (ex) {
|
||||
@ -3090,15 +3117,15 @@ this.DOMApplicationRegistry = {
|
||||
// Save the updated registry, and cleanup the tmp directory.
|
||||
this._saveApps().then(() => {
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
app: aOldApp,
|
||||
manifestURL: aNewApp.manifestURL
|
||||
app: aApp,
|
||||
id: aApp.id
|
||||
});
|
||||
this.broadcastMessage("Webapps:FireEvent", {
|
||||
manifestURL: aNewApp.manifestURL,
|
||||
manifestURL: aApp.manifestURL,
|
||||
eventType: ["downloadsuccess", "downloadapplied"]
|
||||
});
|
||||
});
|
||||
let file = FileUtils.getFile("TmpD", ["webapps", aId], false);
|
||||
let file = FileUtils.getFile("TmpD", ["webapps", aApp.id], false);
|
||||
if (file && file.exists()) {
|
||||
file.remove(true);
|
||||
}
|
||||
@ -3403,9 +3430,10 @@ this.DOMApplicationRegistry = {
|
||||
dir.moveTo(parent, newId);
|
||||
});
|
||||
// Signals that we need to swap the old id with the new app.
|
||||
this.broadcastMessage("Webapps:RemoveApp", { id: oldId });
|
||||
this.broadcastMessage("Webapps:AddApp", { id: newId,
|
||||
app: aOldApp });
|
||||
this.broadcastMessage("Webapps:UpdateApp", { oldId: oldId,
|
||||
newId: newId,
|
||||
app: aOldApp });
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -3508,7 +3536,7 @@ this.DOMApplicationRegistry = {
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
app: aOldApp,
|
||||
error: aError,
|
||||
manifestURL: aNewApp.manifestURL
|
||||
id: aNewApp.id
|
||||
});
|
||||
this.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "downloaderror",
|
||||
@ -4060,7 +4088,7 @@ AppcacheObserver.prototype = {
|
||||
let app = this.app;
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifestURL: app.manifestURL
|
||||
id: app.id
|
||||
});
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "progress",
|
||||
@ -4092,7 +4120,7 @@ AppcacheObserver.prototype = {
|
||||
app.downloadAvailable = false;
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifestURL: app.manifestURL
|
||||
id: app.id
|
||||
});
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: ["downloadsuccess", "downloadapplied"],
|
||||
@ -4115,7 +4143,7 @@ AppcacheObserver.prototype = {
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
error: aError,
|
||||
manifestURL: app.manifestURL
|
||||
id: app.id
|
||||
});
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "downloaderror",
|
||||
|
@ -98,6 +98,7 @@ var PackagedTestHelper = (function PackagedTestHelper() {
|
||||
var aApp = evt.application;
|
||||
aApp.ondownloaderror = function(evt) {
|
||||
var error = aApp.downloadError.name;
|
||||
ok(true, "Got downloaderror " + error);
|
||||
if (error == aExpectedError) {
|
||||
ok(true, "Got expected " + aExpectedError);
|
||||
var expected = {
|
||||
|
@ -110,7 +110,7 @@ var steps = [
|
||||
var miniManifestURL = PackagedTestHelper.gSJS +
|
||||
"?getManifest=true" +
|
||||
"&noManifestContentType=true";
|
||||
checkAppInstallError(miniManifestURL, "INVALID_MANIFEST");
|
||||
checkAppInstallError(miniManifestURL, "INVALID_MANIFEST_CONTENT_TYPE");
|
||||
},
|
||||
function() {
|
||||
// Test mini-manifest 'size' value is not number. Bug 839435.
|
||||
|
@ -79,15 +79,15 @@ function updateApp(aExpectedReady, aPreviousVersion, aNextVersion) {
|
||||
checkLastAppState.bind(PackagedTestHelper, miniManifestURL, false, false,
|
||||
aNextVersion, PackagedTestHelper.next);
|
||||
|
||||
var ondownloadsuccesshandler =
|
||||
checkLastAppState.bind(undefined, miniManifestURL,
|
||||
aExpectedReady, false, aPreviousVersion,
|
||||
function() {
|
||||
navigator.mozApps.mgmt.applyDownload(lApp);
|
||||
});
|
||||
var ondownloadsuccesshandler =
|
||||
checkLastAppState.bind(undefined, miniManifestURL,
|
||||
aExpectedReady, false, aPreviousVersion,
|
||||
function() {
|
||||
navigator.mozApps.mgmt.applyDownload(lApp);
|
||||
});
|
||||
|
||||
checkForUpdate(true, ondownloadsuccesshandler, ondownloadappliedhandler, null,
|
||||
true);
|
||||
checkForUpdate(true, ondownloadsuccesshandler, ondownloadappliedhandler,
|
||||
null, true);
|
||||
|
||||
}
|
||||
|
||||
@ -251,7 +251,7 @@ var steps = [
|
||||
"&appName=arandomname" +
|
||||
"&appToFail1";
|
||||
PackagedTestHelper.checkAppDownloadError(miniManifestURL,
|
||||
"MANIFEST_MISMATCH", 2, false, true,
|
||||
"MANIFEST_MISMATCH", 1, false, true,
|
||||
"arandomname",
|
||||
function () {
|
||||
checkForUpdate(false, null, null, null, false,
|
||||
|
@ -243,4 +243,4 @@ addLoadEvent(go);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
@ -1,6 +1,4 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
||||
* vim: sw=2 ts=2 sts=2 et filetype=javascript
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/* 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/. */
|
||||
|
||||
@ -36,7 +34,7 @@ const BDADDR_ALL = "ff:ff:ff:ff:ff:ff";
|
||||
const BDADDR_LOCAL = "ff:ff:ff:00:00:00";
|
||||
|
||||
// A user friendly name for remote BT device.
|
||||
const REMOTE_DEVICE_NAME = "Remote BT Device";
|
||||
const REMOTE_DEVICE_NAME = "Remote_BT_Device";
|
||||
|
||||
let Promise =
|
||||
SpecialPowers.Cu.import("resource://gre/modules/Promise.jsm").Promise;
|
||||
@ -45,6 +43,58 @@ let bluetoothManager;
|
||||
|
||||
let pendingEmulatorCmdCount = 0;
|
||||
|
||||
/**
|
||||
* Push required permissions and test if |navigator.mozBluetooth| exists.
|
||||
* Resolve if it does, reject otherwise.
|
||||
*
|
||||
* Fulfill params:
|
||||
* bluetoothManager -- an reference to navigator.mozBluetooth.
|
||||
* Reject params: (none)
|
||||
*
|
||||
* @param aPermissions
|
||||
* Additional permissions to push before any test cases. Could be either
|
||||
* a string or an array of strings.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function ensureBluetoothManager(aPermissions) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let permissions = ["bluetooth"];
|
||||
if (aPermissions) {
|
||||
if (Array.isArray(aPermissions)) {
|
||||
permissions = permissions.concat(aPermissions);
|
||||
} else if (typeof aPermissions == "string") {
|
||||
permissions.push(aPermissions);
|
||||
}
|
||||
}
|
||||
|
||||
let obj = [];
|
||||
for (let perm of permissions) {
|
||||
obj.push({
|
||||
"type": perm,
|
||||
"allow": 1,
|
||||
"context": document,
|
||||
});
|
||||
}
|
||||
|
||||
SpecialPowers.pushPermissions(obj, function() {
|
||||
ok(true, "permissions pushed: " + JSON.stringify(permissions));
|
||||
|
||||
bluetoothManager = window.navigator.mozBluetooth;
|
||||
log("navigator.mozBluetooth is " +
|
||||
(bluetoothManager ? "available" : "unavailable"));
|
||||
|
||||
if (bluetoothManager instanceof BluetoothManager) {
|
||||
deferred.resolve(bluetoothManager);
|
||||
} else {
|
||||
deferred.reject();
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send emulator command with safe guard.
|
||||
*
|
||||
@ -193,71 +243,6 @@ function getEmulatorDeviceProperty(aAddress, aPropertyName) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Start dicovering Bluetooth devices.
|
||||
*
|
||||
* Allows the device's adapter to start seeking for remote devices.
|
||||
*
|
||||
* Fulfill params: (none)
|
||||
* Reject params: a DOMError
|
||||
*
|
||||
* @param aAdapter
|
||||
* A BluetoothAdapter which is used to interact with local BT dev
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function startDiscovery(aAdapter) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let request = aAdapter.startDiscovery();
|
||||
request.onsuccess = function () {
|
||||
log(" Start discovery - Success");
|
||||
// TODO (bug 892207): Make Bluetooth APIs available for 3rd party apps.
|
||||
// Currently, discovering state wouldn't change immediately here.
|
||||
// We would turn on this check when the redesigned API are landed.
|
||||
// is(aAdapter.discovering, true, "BluetoothAdapter.discovering");
|
||||
deferred.resolve();
|
||||
}
|
||||
request.onerror = function (aEvent) {
|
||||
ok(false, "Start discovery - Fail");
|
||||
deferred.reject(aEvent.target.error);
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop dicovering Bluetooth devices.
|
||||
*
|
||||
* Allows the device's adapter to stop seeking for remote devices.
|
||||
*
|
||||
* Fulfill params: (none)
|
||||
* Reject params: a DOMError
|
||||
*
|
||||
* @param aAdapter
|
||||
* A BluetoothAdapter which is used to interact with local BT device.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function stopDiscovery(aAdapter) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let request = aAdapter.stopDiscovery();
|
||||
request.onsuccess = function () {
|
||||
log(" Stop discovery - Success");
|
||||
// TODO (bug 892207): Make Bluetooth APIs available for 3rd party apps.
|
||||
// Currently, discovering state wouldn't change immediately here.
|
||||
// We would turn on this check when the redesigned API are landed.
|
||||
// is(aAdapter.discovering, false, "BluetoothAdapter.discovering");
|
||||
deferred.resolve();
|
||||
}
|
||||
request.onerror = function (aEvent) {
|
||||
ok(false, "Stop discovery - Fail");
|
||||
deferred.reject(aEvent.target.error);
|
||||
}
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get mozSettings value specified by @aKey.
|
||||
*
|
||||
@ -319,10 +304,9 @@ function setSettings(aSettings) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get mozSettings value of 'bluetooth.enabled'.
|
||||
* Get the boolean value which indicates defaultAdapter of bluetooth is enabled.
|
||||
*
|
||||
* Resolve if that mozSettings value is retrieved successfully, reject
|
||||
* otherwise.
|
||||
* Resolve if that defaultAdapter is enabled
|
||||
*
|
||||
* Fulfill params:
|
||||
* A boolean value.
|
||||
@ -331,7 +315,9 @@ function setSettings(aSettings) {
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function getBluetoothEnabled() {
|
||||
return getSettings("bluetooth.enabled");
|
||||
log("bluetoothManager.defaultAdapter.state: " + bluetoothManager.defaultAdapter.state);
|
||||
|
||||
return (bluetoothManager.defaultAdapter.state == "enabled");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -353,58 +339,6 @@ function setBluetoothEnabled(aEnabled) {
|
||||
return setSettings(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Push required permissions and test if |navigator.mozBluetooth| exists.
|
||||
* Resolve if it does, reject otherwise.
|
||||
*
|
||||
* Fulfill params:
|
||||
* bluetoothManager -- an reference to navigator.mozBluetooth.
|
||||
* Reject params: (none)
|
||||
*
|
||||
* @param aPermissions
|
||||
* Additional permissions to push before any test cases. Could be either
|
||||
* a string or an array of strings.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function ensureBluetoothManager(aPermissions) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let permissions = ["bluetooth"];
|
||||
if (aPermissions) {
|
||||
if (Array.isArray(aPermissions)) {
|
||||
permissions = permissions.concat(aPermissions);
|
||||
} else if (typeof aPermissions == "string") {
|
||||
permissions.push(aPermissions);
|
||||
}
|
||||
}
|
||||
|
||||
let obj = [];
|
||||
for (let perm of permissions) {
|
||||
obj.push({
|
||||
"type": perm,
|
||||
"allow": 1,
|
||||
"context": document,
|
||||
});
|
||||
}
|
||||
|
||||
SpecialPowers.pushPermissions(obj, function() {
|
||||
ok(true, "permissions pushed: " + JSON.stringify(permissions));
|
||||
|
||||
bluetoothManager = window.navigator.mozBluetooth;
|
||||
log("navigator.mozBluetooth is " +
|
||||
(bluetoothManager ? "available" : "unavailable"));
|
||||
|
||||
if (bluetoothManager instanceof BluetoothManager) {
|
||||
deferred.resolve(bluetoothManager);
|
||||
} else {
|
||||
deferred.reject();
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for one named BluetoothManager event.
|
||||
*
|
||||
@ -457,73 +391,6 @@ function waitForAdapterEvent(aAdapter, aEventName) {
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient function for setBluetoothEnabled and waitForManagerEvent
|
||||
* combined.
|
||||
*
|
||||
* Resolve if that named event occurs. Reject if we can't set settings.
|
||||
*
|
||||
* Fulfill params: the DOMEvent passed.
|
||||
* Reject params: (none)
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function setBluetoothEnabledAndWait(aEnabled) {
|
||||
let promises = [];
|
||||
|
||||
// Bug 969109 - Intermittent test_dom_BluetoothManager_adapteradded.js
|
||||
//
|
||||
// Here we want to wait for two events coming up -- Bluetooth "settings-set"
|
||||
// event and one of "enabled"/"disabled" events. Special care is taken here
|
||||
// to ensure that we can always receive that "enabled"/"disabled" event by
|
||||
// installing the event handler *before* we ever enable/disable Bluetooth. Or
|
||||
// we might just miss those events and get a timeout error.
|
||||
promises.push(waitForManagerEvent(aEnabled ? "enabled" : "disabled"));
|
||||
promises.push(setBluetoothEnabled(aEnabled));
|
||||
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default adapter.
|
||||
*
|
||||
* Resolve if that default adapter is got, reject otherwise.
|
||||
*
|
||||
* Fulfill params: a BluetoothAdapter instance.
|
||||
* Reject params: a DOMError, or null if if there is no adapter ready yet.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function getDefaultAdapter() {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let request = bluetoothManager.getDefaultAdapter();
|
||||
request.onsuccess = function(aEvent) {
|
||||
let adapter = aEvent.target.result;
|
||||
if (!(adapter instanceof BluetoothAdapter)) {
|
||||
ok(false, "no BluetoothAdapter ready yet.");
|
||||
deferred.reject(null);
|
||||
return;
|
||||
}
|
||||
|
||||
ok(true, "BluetoothAdapter got.");
|
||||
// TODO: We have an adapter instance now, but some of its attributes may
|
||||
// still remain unassigned/out-dated. Here we waste a few seconds to
|
||||
// wait for the property changed events.
|
||||
//
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=932914
|
||||
window.setTimeout(function() {
|
||||
deferred.resolve(adapter);
|
||||
}, 3000);
|
||||
};
|
||||
request.onerror = function(aEvent) {
|
||||
ok(false, "Failed to get default adapter.");
|
||||
deferred.reject(aEvent.target.error);
|
||||
};
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush permission settings and call |finish()|.
|
||||
*/
|
||||
@ -552,36 +419,40 @@ function startBluetoothTestBase(aPermissions, aTestCaseMain) {
|
||||
function startBluetoothTest(aReenable, aTestCaseMain) {
|
||||
startBluetoothTestBase(["settings-read", "settings-write"], function() {
|
||||
let origEnabled, needEnable;
|
||||
return Promise.resolve()
|
||||
.then(function() {
|
||||
origEnabled = getBluetoothEnabled();
|
||||
|
||||
return getBluetoothEnabled()
|
||||
.then(function(aEnabled) {
|
||||
origEnabled = aEnabled;
|
||||
needEnable = !aEnabled;
|
||||
log("Original 'bluetooth.enabled' is " + origEnabled);
|
||||
needEnable = !origEnabled;
|
||||
log("Original state of bluetooth is " + bluetoothManager.defaultAdapter.state);
|
||||
|
||||
if (aEnabled && aReenable) {
|
||||
log(" Disable 'bluetooth.enabled' ...");
|
||||
if (origEnabled && aReenable) {
|
||||
log("Disable Bluetooth ...");
|
||||
needEnable = true;
|
||||
return setBluetoothEnabledAndWait(false);
|
||||
|
||||
isnot(bluetoothManager.defaultAdapter, null,
|
||||
"bluetoothManager.defaultAdapter")
|
||||
|
||||
return bluetoothManager.defaultAdapter.disable();
|
||||
}
|
||||
})
|
||||
.then(function() {
|
||||
if (needEnable) {
|
||||
log(" Enable 'bluetooth.enabled' ...");
|
||||
log("Enable Bluetooth ...");
|
||||
|
||||
// See setBluetoothEnabledAndWait(). We must install all event
|
||||
// handlers *before* enabling Bluetooth.
|
||||
let promises = [];
|
||||
promises.push(waitForManagerEvent("adapteradded"));
|
||||
promises.push(setBluetoothEnabledAndWait(true));
|
||||
return Promise.all(promises);
|
||||
isnot(bluetoothManager.defaultAdapter, null,
|
||||
"bluetoothManager.defaultAdapter")
|
||||
|
||||
return bluetoothManager.defaultAdapter.enable();
|
||||
}
|
||||
})
|
||||
.then(getDefaultAdapter)
|
||||
.then(() => bluetoothManager.defaultAdapter)
|
||||
.then(aTestCaseMain)
|
||||
.then(function() {
|
||||
if (!origEnabled) {
|
||||
return setBluetoothEnabledAndWait(false);
|
||||
log("Disable Bluetooth ...");
|
||||
|
||||
return bluetoothManager.defaultAdapter.disable();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -1,10 +1,6 @@
|
||||
[DEFAULT]
|
||||
b2g = true
|
||||
browser = false
|
||||
qemu = true
|
||||
qemu = false
|
||||
|
||||
[test_dom_BluetoothManager_enabled.js]
|
||||
[test_dom_BluetoothManager_adapteradded.js]
|
||||
[test_dom_BluetoothAdapter_setters.js]
|
||||
[test_dom_BluetoothAdapter_getters.js]
|
||||
[test_dom_BluetoothAdapter_discovery.js]
|
||||
[test_dom_BluetoothManager_API2.js]
|
||||
|
@ -1,47 +0,0 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
||||
* vim: sw=2 ts=2 sts=2 et filetype=javascript
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Test Purpose:
|
||||
// To verify that discovery process of BluetoothAdapter is correct.
|
||||
// Use B2G emulator commands to add/remote remote devices to simulate
|
||||
// discovering behavior.
|
||||
//
|
||||
// Test Coverage:
|
||||
// - BluetoothAdapter.startDiscovery()
|
||||
// - BluetoothAdapter.stopDiscovery()
|
||||
// - BluetoothAdapter.ondevicefound()
|
||||
// - BluetoothAdapter.discovering [Temporarily turned off until BT API update]
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
startBluetoothTest(true, function testCaseMain(aAdapter) {
|
||||
log("Testing the discovery process of BluetoothAdapter ...");
|
||||
|
||||
// The properties of remote device.
|
||||
let theProperties = {
|
||||
"name": REMOTE_DEVICE_NAME,
|
||||
"discoverable": true
|
||||
};
|
||||
|
||||
return Promise.resolve()
|
||||
.then(() => removeEmulatorRemoteDevice(BDADDR_ALL))
|
||||
.then(() => addEmulatorRemoteDevice(/*theProperties*/ null))
|
||||
.then(function(aRemoteAddress) {
|
||||
let promises = [];
|
||||
promises.push(waitForAdapterEvent(aAdapter, "devicefound"));
|
||||
promises.push(startDiscovery(aAdapter));
|
||||
return Promise.all(promises)
|
||||
.then(function(aResults) {
|
||||
is(aResults[0].device.address, aRemoteAddress, "BluetoothDevice.address");
|
||||
});
|
||||
})
|
||||
.then(() => stopDiscovery(aAdapter))
|
||||
.then(() => removeEmulatorRemoteDevice(BDADDR_ALL));
|
||||
});
|
@ -1,45 +0,0 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
||||
* vim: sw=2 ts=2 sts=2 et filetype=javascript
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Test Purpose:
|
||||
// To verify that the properties of BluetoothAdapter can be updated and
|
||||
// retrieved correctly. Use B2G emulator commands to set properties for this
|
||||
// test case.
|
||||
//
|
||||
// Test Coverage:
|
||||
// - BluetoothAdapter.name
|
||||
// - BluetoothAdapter.address
|
||||
// - BluetoothAdapter.class
|
||||
// - BluetoothAdapter.discoverable
|
||||
// - BluetoothAdapter.discovering
|
||||
// ( P.S. Don't include [BluetoothAdapter.uuids], [BluetoothAdapter.devices] )
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
function testAdapterGetter(aAdapter, aPropertyName, aParamName, aExpected) {
|
||||
let cmd = "bt property " + BDADDR_LOCAL + " " + aParamName;
|
||||
return runEmulatorCmdSafe(cmd)
|
||||
.then(function(aResults) {
|
||||
is(aResults[1], "OK", "The status report from emulator command.");
|
||||
log(" Got adapter " + aResults[0]);
|
||||
is(aResults[0], aParamName + ": " + aExpected, "BluetoothAdapter." + aPropertyName);
|
||||
});
|
||||
}
|
||||
|
||||
startBluetoothTest(true, function testCaseMain(aAdapter) {
|
||||
log("Checking the correctness of BluetoothAdapter properties ...");
|
||||
|
||||
return Promise.resolve()
|
||||
.then(() => testAdapterGetter(aAdapter, "name", "name", aAdapter.name))
|
||||
.then(() => testAdapterGetter(aAdapter, "address", "address", aAdapter.address))
|
||||
.then(() => testAdapterGetter(aAdapter, "class", "cod", "0x" + aAdapter.class.toString(16)))
|
||||
.then(() => testAdapterGetter(aAdapter, "discoverable", "discoverable", aAdapter.discoverable.toString()))
|
||||
.then(() => testAdapterGetter(aAdapter, "discovering", "discovering", aAdapter.discovering.toString()));
|
||||
});
|
@ -1,85 +0,0 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
||||
* vim: sw=2 ts=2 sts=2 et filetype=javascript
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Test Purpose:
|
||||
// To verify that all setters of BluetoothAdapter (except for pairing related
|
||||
// APIs) can change properties correctly.
|
||||
//
|
||||
// Test Coverage:
|
||||
// - BluetoothAdapter.setName()
|
||||
// - BluetoothAdapter.setDiscoverable()
|
||||
// - BluetoothAdapter.setDiscoverableTimeout()
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
const BT_DEVICE_NAME = "User friendly name of local BT device";
|
||||
|
||||
function setName(aAdapter, aName) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let request = aAdapter.setName(aName);
|
||||
request.onsuccess = function () {
|
||||
log(" setName succeed: " + aName);
|
||||
is(aAdapter.name, aName, "aAdapter.name");
|
||||
deferred.resolve();
|
||||
}
|
||||
request.onerror = function () {
|
||||
ok(false, "setName failed")
|
||||
deferred.reject();
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function setDiscoverable(aAdapter, aIsDiscoverable) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let request = aAdapter.setDiscoverable(aIsDiscoverable);
|
||||
request.onsuccess = function () {
|
||||
log(" setDiscoverable succeed: " + aIsDiscoverable);
|
||||
is(aAdapter.discoverable, aIsDiscoverable, "aAdapter.discoverable");
|
||||
deferred.resolve();
|
||||
}
|
||||
request.onerror = function () {
|
||||
ok(false, "setDiscoverable failed")
|
||||
deferred.reject();
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function setDiscoverableTimeout(aAdapter, aTimeout) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let request = aAdapter.setDiscoverableTimeout(aTimeout);
|
||||
request.onsuccess = function () {
|
||||
log(" setDiscoverableTimeout succeed: " + aTimeout);
|
||||
is(aAdapter.discoverableTimeout, aTimeout, "aAdapter.discoverableTimeout");
|
||||
deferred.resolve();
|
||||
}
|
||||
request.onerror = function () {
|
||||
ok(false, "setDiscoverableTimeout failed")
|
||||
deferred.reject();
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
startBluetoothTest(true, function testCaseMain(aAdapter) {
|
||||
log("Testing BluetoothAdapter setters ...");
|
||||
|
||||
return Promise.resolve()
|
||||
.then( () => setName(aAdapter, BT_DEVICE_NAME) )
|
||||
.then( () => setDiscoverableTimeout(aAdapter, 180) )
|
||||
.then( () => setDiscoverable(aAdapter, true) )
|
||||
.then( () => setName(aAdapter, EMULATOR_NAME) )
|
||||
.then( () => setDiscoverable(aAdapter, false) )
|
||||
.then( () => setDiscoverableTimeout(aAdapter, 120) );
|
||||
});
|
@ -0,0 +1,48 @@
|
||||
/* 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/. */
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Test Purpose:
|
||||
// To verify the basic functionality of BluetoothManager.
|
||||
//
|
||||
// Test Coverage:
|
||||
// - BluetoothManager.defaultAdapter
|
||||
// - BluetoothManager.getAdapters()
|
||||
// TODO:
|
||||
// - BluetoothManager.onattributechanged()
|
||||
// - BluetoothManager.onadapteradded()
|
||||
// - BluetoothManager.onadapterremoved()
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
// TODO: Listens to 'onattributechanged' when B2G supports the feature that
|
||||
// allows user to add/remove Bluetooth adapter.
|
||||
// Currently, B2G recognizes build-in Bluetooth chip as default adapter and
|
||||
// don't support adding additional Bluetooth dongles in gonk layer.
|
||||
// Therefore, the 'onattributechanged' would be triggered *only* when the
|
||||
// instance of BluetoothManager is created.
|
||||
function waitForManagerAttributeChanged() {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
bluetoothManager.onattributechanged = function(aEvent) {
|
||||
if(aEvent.attrs.indexOf("defaultAdapter")) {
|
||||
bluetoothManager.onattributechanged = null;
|
||||
ok(true, "BluetoothManager event 'onattributechanged' got.");
|
||||
deferred.resolve(aEvent);
|
||||
}
|
||||
};
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
startBluetoothTestBase(["settings-read", "settings-write"],
|
||||
function testCaseMain() {
|
||||
let adapters = bluetoothManager.getAdapters();
|
||||
ok(Array.isArray(adapters), "Can not got the array of adapters");
|
||||
ok(adapters.length, "The number of adapters should not be zero");
|
||||
ok(bluetoothManager.defaultAdapter, "defaultAdapter should not be null.");
|
||||
});
|
@ -1,19 +0,0 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
||||
* vim: sw=2 ts=2 sts=2 et filetype=javascript
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
startBluetoothTest(true, function testCaseMain(aAdapter) {
|
||||
log("Checking adapter attributes ...");
|
||||
|
||||
is(aAdapter.name, EMULATOR_NAME, "adapter.name");
|
||||
is(aAdapter.class, EMULATOR_CLASS, "adapter.class");
|
||||
is(aAdapter.address, EMULATOR_ADDRESS, "adapter.address");
|
||||
is(aAdapter.discovering, false, "adapter.discovering");
|
||||
is(aAdapter.discoverable, false, "adapter.discoverable");
|
||||
is(aAdapter.discoverableTimeout, 120, "adapter.discoverableTimeout");
|
||||
});
|
@ -1,66 +0,0 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
||||
* vim: sw=2 ts=2 sts=2 et filetype=javascript
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
function waitEitherEnabledOrDisabled() {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
function onEnabledDisabled(aEvent) {
|
||||
bluetoothManager.removeEventListener("adapteradded", onEnabledDisabled);
|
||||
bluetoothManager.removeEventListener("disabled", onEnabledDisabled);
|
||||
|
||||
ok(true, "Got event " + aEvent.type);
|
||||
deferred.resolve(aEvent.type === "adapteradded");
|
||||
}
|
||||
|
||||
// Listen 'adapteradded' rather than 'enabled' since the current API can't
|
||||
// disable BT before the BT adapter is initialized.
|
||||
// We should listen to 'enabled' when gecko can handle the case I mentioned
|
||||
// above, please refer to the follow-up bug 973482.
|
||||
bluetoothManager.addEventListener("adapteradded", onEnabledDisabled);
|
||||
bluetoothManager.addEventListener("disabled", onEnabledDisabled);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function test(aEnabled) {
|
||||
log("Testing 'bluetooth.enabled' => " + aEnabled);
|
||||
|
||||
let deferred = Promise.defer();
|
||||
|
||||
Promise.all([setBluetoothEnabled(aEnabled),
|
||||
waitEitherEnabledOrDisabled()])
|
||||
.then(function(aResults) {
|
||||
/* aResults is an array of two elements:
|
||||
* [ <result of setBluetoothEnabled>,
|
||||
* <result of waitEitherEnabledOrDisabled> ]
|
||||
*/
|
||||
log(" Examine results " + JSON.stringify(aResults));
|
||||
|
||||
is(bluetoothManager.enabled, aEnabled, "bluetoothManager.enabled");
|
||||
is(aResults[1], aEnabled, "'adapteradded' event received");
|
||||
|
||||
if (bluetoothManager.enabled === aEnabled && aResults[1] === aEnabled) {
|
||||
deferred.resolve();
|
||||
} else {
|
||||
deferred.reject();
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
startBluetoothTestBase(["settings-read", "settings-write"],
|
||||
function testCaseMain() {
|
||||
return getBluetoothEnabled()
|
||||
.then(function(aEnabled) {
|
||||
log("Original 'bluetooth.enabled' is " + aEnabled);
|
||||
// Set to !aEnabled and reset back to aEnabled.
|
||||
return test(!aEnabled).then(test.bind(null, aEnabled));
|
||||
});
|
||||
});
|
@ -17,7 +17,7 @@ using namespace mozilla::dom;
|
||||
* CellBroadcast::Listener Implementation.
|
||||
*/
|
||||
|
||||
class CellBroadcast::Listener : public nsICellBroadcastListener
|
||||
class CellBroadcast::Listener MOZ_FINAL : public nsICellBroadcastListener
|
||||
{
|
||||
private:
|
||||
CellBroadcast* mCellBroadcast;
|
||||
|
@ -68,6 +68,8 @@ public:
|
||||
|
||||
private:
|
||||
IDBDatabase* mDatabase;
|
||||
|
||||
~VersionChangeListener() {}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(VersionChangeListener, nsIDOMEventListener)
|
||||
|
@ -14,7 +14,7 @@ namespace dom {
|
||||
class IccManager;
|
||||
class Icc;
|
||||
|
||||
class IccListener : public nsIIccListener
|
||||
class IccListener MOZ_FINAL : public nsIIccListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
@ -764,11 +764,6 @@ TabChild::Observe(nsISupports *aSubject,
|
||||
|
||||
mContentDocumentIsDisplayed = true;
|
||||
|
||||
// Reset CSS viewport and zoom to default on new page, then
|
||||
// calculate them properly using the actual metadata from the
|
||||
// page.
|
||||
SetCSSViewport(kDefaultViewportSize);
|
||||
|
||||
// In some cases before-first-paint gets called before
|
||||
// RecvUpdateDimensions is called and therefore before we have an
|
||||
// mInnerSize value set. In such cases defer initializing the viewport
|
||||
|
@ -18,6 +18,7 @@ XPIDL_SOURCES += [
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
XPIDL_SOURCES += [
|
||||
'nsIDOMNetworkStatsManager.idl',
|
||||
'nsIEthernetManager.idl',
|
||||
'nsINetworkStatsServiceProxy.idl',
|
||||
]
|
||||
|
||||
|
137
dom/network/interfaces/nsIEthernetManager.idl
Normal file
137
dom/network/interfaces/nsIEthernetManager.idl
Normal file
@ -0,0 +1,137 @@
|
||||
/* 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 "nsISupports.idl"
|
||||
|
||||
[scriptable, function, uuid(2a3ad56c-edc0-439f-8aae-900b331ddf49)]
|
||||
interface nsIEthernetManagerCallback : nsISupports
|
||||
{
|
||||
/**
|
||||
* Callback function used to report the success of different operations.
|
||||
*
|
||||
* @param success
|
||||
* Boolean value indicates the success of an operation.
|
||||
* @prarm message
|
||||
* Message reported in the end of operation.
|
||||
*/
|
||||
void notify(in boolean success, in DOMString message);
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(1746e7dd-92d4-43fa-8ef4-bc13d0b60353)]
|
||||
interface nsIEthernetManagerScanCallback : nsISupports
|
||||
{
|
||||
/**
|
||||
* Callback function used to report the result of scan function.
|
||||
*
|
||||
* @param list
|
||||
* List of available ethernet interfaces.
|
||||
*/
|
||||
void notify(in jsval list);
|
||||
};
|
||||
|
||||
/**
|
||||
* An internal idl provides control to ethernet interfaces.
|
||||
*/
|
||||
[scriptable, uuid(a96441dd-36b3-4f7f-963b-2c032e28a039)]
|
||||
interface nsIEthernetManager : nsISupports
|
||||
{
|
||||
/**
|
||||
* List of exisiting interface name.
|
||||
*/
|
||||
readonly attribute jsval interfaceList;
|
||||
|
||||
/**
|
||||
* Scan available ethernet interfaces on device.
|
||||
*
|
||||
* @param callback
|
||||
* Callback function.
|
||||
*/
|
||||
void scan(in nsIEthernetManagerScanCallback callback);
|
||||
|
||||
/**
|
||||
* Add a new interface to the interface list.
|
||||
*
|
||||
* @param ifname
|
||||
* Interface name. Should be the form of "eth*".
|
||||
* @param callback
|
||||
* Callback function.
|
||||
*/
|
||||
void addInterface(in DOMString ifname,
|
||||
in nsIEthernetManagerCallback callback);
|
||||
|
||||
/**
|
||||
* Remove an existing interface from the interface list.
|
||||
*
|
||||
* @param ifname
|
||||
* Interface name.
|
||||
* @param Callback
|
||||
* Callback function.
|
||||
*/
|
||||
void removeInterface(in DOMString ifname,
|
||||
in nsIEthernetManagerCallback callback);
|
||||
|
||||
/**
|
||||
* Update a conifg of an existing interface in the interface list.
|
||||
*
|
||||
* @param ifname
|
||||
* Interface name.
|
||||
* @param config
|
||||
* .ip: ip address.
|
||||
* .prefixLength: mask length.
|
||||
* .gateway: gateway.
|
||||
* .dnses: dnses.
|
||||
* .httpProxyHost: http proxy host.
|
||||
* .httpProxyPort: http porxy port.
|
||||
* .ipMode: ip mode, can be 'dhcp' or 'static'.
|
||||
* @param callback
|
||||
* Callback function.
|
||||
*/
|
||||
void updateInterfaceConfig(in DOMString ifname,
|
||||
in jsval config,
|
||||
in nsIEthernetManagerCallback callback);
|
||||
|
||||
/**
|
||||
* Enable networking of an existing interface in the interface list.
|
||||
*
|
||||
* @param ifname
|
||||
* Interface name.
|
||||
* @param callback
|
||||
* Callback function.
|
||||
*/
|
||||
void enable(in DOMString ifname,
|
||||
in nsIEthernetManagerCallback callback);
|
||||
|
||||
/**
|
||||
* Disable networking of an existing interface in the interface list.
|
||||
*
|
||||
* @param ifname
|
||||
* Interface name.
|
||||
* @param callback
|
||||
* Callback function.
|
||||
*/
|
||||
void disable(in DOMString ifname,
|
||||
in nsIEthernetManagerCallback callback);
|
||||
|
||||
/**
|
||||
* Make an existing interface connect to network.
|
||||
*
|
||||
* @param ifname
|
||||
* Interface name.
|
||||
* @param callback
|
||||
* Callback function.
|
||||
*/
|
||||
void connect(in DOMString ifname,
|
||||
in nsIEthernetManagerCallback callback);
|
||||
|
||||
/**
|
||||
* Disconnect a connected interface in the interface list.
|
||||
*
|
||||
* @param ifname
|
||||
* Interface name.
|
||||
* @param callback
|
||||
* Callback function.
|
||||
*/
|
||||
void disconnect(in DOMString ifname,
|
||||
in nsIEthernetManagerCallback callback);
|
||||
};
|
619
dom/network/src/EthernetManager.js
Normal file
619
dom/network/src/EthernetManager.js
Normal file
@ -0,0 +1,619 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const DEBUG = false;
|
||||
function debug(s) {
|
||||
if (DEBUG) {
|
||||
dump("-*- EthernetManager: " + s + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
const TOPIC_INTERFACE_STATE_CHANGED = "network-interface-state-changed";
|
||||
|
||||
const ETHERNET_NETWORK_IFACE_PREFIX = "eth";
|
||||
const DEFAULT_ETHERNET_NETWORK_IFACE = "eth0";
|
||||
|
||||
const INTERFACE_IPADDR_NULL = "0.0.0.0";
|
||||
const INTERFACE_GATEWAY_NULL = "0.0.0.0";
|
||||
const INTERFACE_PREFIX_NULL = 0;
|
||||
const INTERFACE_MACADDR_NULL = "00:00:00:00:00:00";
|
||||
|
||||
const NETWORK_INTERFACE_UP = "up";
|
||||
const NETWORK_INTERFACE_DOWN = "down";
|
||||
|
||||
const IP_MODE_DHCP = "dhcp";
|
||||
const IP_MODE_STATIC = "static";
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager",
|
||||
"@mozilla.org/network/manager;1",
|
||||
"nsINetworkManager");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gNetworkService",
|
||||
"@mozilla.org/network/service;1",
|
||||
"nsINetworkService");
|
||||
|
||||
|
||||
// nsINetworkInterface
|
||||
|
||||
function EthernetInterface(attr) {
|
||||
this.state = attr.state;
|
||||
this.type = attr.type;
|
||||
this.name = attr.name;
|
||||
this.ipMode = attr.ipMode;
|
||||
this.ips = [attr.ip];
|
||||
this.prefixLengths = [attr.prefixLength];
|
||||
this.gateways = [attr.gateway];
|
||||
this.dnses = attr.dnses;
|
||||
this.httpProxyHost = "";
|
||||
this.httpProxyPort = 0;
|
||||
}
|
||||
EthernetInterface.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterface]),
|
||||
|
||||
updateConfig: function(config) {
|
||||
debug("Interface " + this.name + " updateConfig " + JSON.stringify(config));
|
||||
this.state = (config.state != undefined) ?
|
||||
config.state : this.state;
|
||||
this.ips = (config.ip != undefined) ? [config.ip] : this.ips;
|
||||
this.prefixLengths = (config.prefixLength != undefined) ?
|
||||
[config.prefixLength] : this.prefixLengths;
|
||||
this.gateways = (config.gateway != undefined) ?
|
||||
[config.gateway] : this.gateways;
|
||||
this.dnses = (config.dnses != undefined) ? config.dnses : this.dnses;
|
||||
this.httpProxyHost = (config.httpProxyHost != undefined) ?
|
||||
config.httpProxyHost : this.httpProxyHost;
|
||||
this.httpProxyPort = (config.httpProxyPort != undefined) ?
|
||||
config.httpProxyPort : this.httpProxyPort;
|
||||
this.ipMode = (config.ipMode != undefined) ?
|
||||
config.ipMode : this.ipMode;
|
||||
},
|
||||
|
||||
getAddresses: function(ips, prefixLengths) {
|
||||
ips.value = this.ips.slice();
|
||||
prefixLengths.value = this.prefixLengths.slice();
|
||||
|
||||
return this.ips.length;
|
||||
},
|
||||
|
||||
getGateways: function(count) {
|
||||
if (count) {
|
||||
count.value = this.gateways.length;
|
||||
}
|
||||
return this.gateways.slice();
|
||||
},
|
||||
|
||||
getDnses: function(count) {
|
||||
if (count) {
|
||||
count.value = this.dnses.length;
|
||||
}
|
||||
return this.dnses.slice();
|
||||
}
|
||||
};
|
||||
|
||||
// nsIEthernetManager
|
||||
|
||||
/*
|
||||
* Network state transition diagram
|
||||
*
|
||||
* ---------- enable --------- connect ----------- disconnect --------------
|
||||
* | Disabled | -----> | Enabled | -------> | Connected | <----------> | Disconnected |
|
||||
* ---------- --------- ----------- connect --------------
|
||||
* ^ | | |
|
||||
* | disable | | |
|
||||
* -----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
function EthernetManager() {
|
||||
debug("EthernetManager start");
|
||||
|
||||
// Interface list.
|
||||
this.ethernetInterfaces = {};
|
||||
|
||||
// Used to memorize last connection information.
|
||||
this.lastStaticConfig = {};
|
||||
|
||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
||||
}
|
||||
|
||||
EthernetManager.prototype = {
|
||||
classID: Components.ID("a96441dd-36b3-4f7f-963b-2c032e28a039"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIEthernetManager]),
|
||||
|
||||
ethernetInterfaces: null,
|
||||
lastStaticConfig: null,
|
||||
|
||||
observer: function(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case "xpcom-shutdown":
|
||||
debug("xpcom-shutdown");
|
||||
|
||||
this._shutdown();
|
||||
|
||||
Services.obs.removeObserver(this, "xpcom-shutdown");
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_shutdown: function() {
|
||||
debug("shuting down.");
|
||||
(function onRemove(ifnameList) {
|
||||
if (!ifnameList.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
let ifname = ifnameList.shift();
|
||||
this.removeInterface(ifname, { notify: onRemove.bind(this, ifnameList) });
|
||||
}).call(this, Object.keys(this.ethernetInterfaces));
|
||||
},
|
||||
|
||||
get interfaceList() {
|
||||
return Object.keys(this.ethernetInterfaces);
|
||||
},
|
||||
|
||||
scan: function(callback) {
|
||||
debug("scan");
|
||||
|
||||
gNetworkService.getInterfaces(function(success, list) {
|
||||
let ethList = [];
|
||||
|
||||
if (!success) {
|
||||
if (callback) {
|
||||
callback.notify(ethList);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
debug("Found interface " + list[i]);
|
||||
if (!list[i].startsWith(ETHERNET_NETWORK_IFACE_PREFIX)) {
|
||||
continue;
|
||||
}
|
||||
ethList.push(list[i]);
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
callback.notify(ethList);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
addInterface: function(ifname, callback) {
|
||||
debug("addInterfaces " + ifname);
|
||||
|
||||
if (!ifname || !ifname.startsWith(ETHERNET_NETWORK_IFACE_PREFIX)) {
|
||||
if (callback) {
|
||||
callback.notify(false, "Invalid interface.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.ethernetInterfaces[ifname]) {
|
||||
if (callback) {
|
||||
callback.notify(true, "Interface already exists.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
gNetworkService.getInterfaceConfig(ifname, function(success, result) {
|
||||
if (!success) {
|
||||
if (callback) {
|
||||
callback.notify(false, "Netd error.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Since the operation may still succeed with an invalid interface name,
|
||||
// check the mac address as well.
|
||||
if (result.macAddr == INTERFACE_MACADDR_NULL) {
|
||||
if (callback) {
|
||||
callback.notify(false, "Interface not found.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.ethernetInterfaces[ifname] = new EthernetInterface({
|
||||
state: result.link == NETWORK_INTERFACE_UP ?
|
||||
Ci.nsINetworkInterface.NETWORK_STATE_DISABLED :
|
||||
Ci.nsINetworkInterface.NETWORK_STATE_ENABLED,
|
||||
name: ifname,
|
||||
type: Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET,
|
||||
ip: result.ip,
|
||||
prefixLength: result.prefix,
|
||||
ipMode: IP_MODE_DHCP
|
||||
});
|
||||
|
||||
// Register the interface to NetworkManager.
|
||||
gNetworkManager.registerNetworkInterface(this.ethernetInterfaces[ifname]);
|
||||
|
||||
debug("Add interface " + ifname + " success with " +
|
||||
JSON.stringify(this.ethernetInterfaces[ifname]));
|
||||
|
||||
if (callback) {
|
||||
callback.notify(true, "ok");
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
removeInterface: function(ifname, callback) {
|
||||
debug("removeInterface");
|
||||
|
||||
if (!ifname || !ifname.startsWith(ETHERNET_NETWORK_IFACE_PREFIX)) {
|
||||
if (callback) {
|
||||
callback.notify(false, "Invalid interface.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.ethernetInterfaces[ifname]) {
|
||||
if (callback) {
|
||||
callback.notify(true, "Interface does not exist.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure interface is disable before removing.
|
||||
this.disable(ifname, { notify: function(success, message) {
|
||||
// Unregister the interface from NetworkManager and also remove it from
|
||||
// the interface list.
|
||||
gNetworkManager.unregisterNetworkInterface(this.ethernetInterfaces[ifname]);
|
||||
delete this.ethernetInterfaces[ifname];
|
||||
|
||||
debug("Remove interface " + ifname + " success.");
|
||||
|
||||
if (callback) {
|
||||
callback.notify(true, "ok");
|
||||
}
|
||||
}.bind(this)});
|
||||
},
|
||||
|
||||
updateInterfaceConfig: function(ifname, config, callback) {
|
||||
debug("interfaceConfigUpdate with " + ifname);
|
||||
|
||||
this._ensureIfname(ifname, callback, function(iface) {
|
||||
if (!config) {
|
||||
if (callback) {
|
||||
callback.notify(false, "No config to update.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Network state can not be modified externally.
|
||||
if (config.state) {
|
||||
delete config.state;
|
||||
}
|
||||
|
||||
let currentIpMode = iface.ipMode;
|
||||
|
||||
// Update config.
|
||||
this.ethernetInterfaces[iface.name].updateConfig(config);
|
||||
|
||||
// Do not automatically re-connect if the interface is not in connected
|
||||
// state.
|
||||
if (iface.state != Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED) {
|
||||
if (callback) {
|
||||
callback.notify(true, "ok");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let newIpMode = this.ethernetInterfaces[iface.name].ipMode;
|
||||
if (newIpMode == IP_MODE_STATIC) {
|
||||
this._setStaticIP(iface.name, callback);
|
||||
return;
|
||||
}
|
||||
if ((currentIpMode == IP_MODE_STATIC) && (newIpMode == IP_MODE_DHCP)) {
|
||||
gNetworkService.stopDhcp(iface.name);
|
||||
// Clear the current network settings before do dhcp request, otherwise
|
||||
// dhcp settings could fail.
|
||||
this.disconnect(iface.name, { notify: function(success, message) {
|
||||
if (!success) {
|
||||
if (callback) {
|
||||
callback.notify("Disconnect failed.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
this._runDhcp(iface.name, callback);
|
||||
}.bind(this) });
|
||||
return;
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
callback.notify(true, "ok");
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
enable: function(ifname, callback) {
|
||||
debug("enable with " + ifname);
|
||||
|
||||
this._ensureIfname(ifname, callback, function(iface) {
|
||||
// Interface can be only enabled in the state of disabled.
|
||||
if (iface.state != Ci.nsINetworkInterface.NETWORK_STATE_DISABLED) {
|
||||
if (callback) {
|
||||
callback.notify(true, "already enabled.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let ips = {};
|
||||
let prefixLengths = {};
|
||||
iface.getAddresses(ips, prefixLengths);
|
||||
let config = { ifname: iface.name,
|
||||
ip: ips.value[0],
|
||||
prefix: prefixLengths.value[0],
|
||||
link: NETWORK_INTERFACE_UP };
|
||||
gNetworkService.setInterfaceConfig(config, function(success) {
|
||||
if (!success) {
|
||||
if (callback) {
|
||||
callback.notify(false, "Netd Error.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.ethernetInterfaces[iface.name].updateConfig({
|
||||
state: Ci.nsINetworkInterface.NETWORK_STATE_ENABLED
|
||||
});
|
||||
|
||||
debug("Interface " + iface.name + " enable success.");
|
||||
|
||||
if (callback) {
|
||||
callback.notify(true, "ok");
|
||||
}
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
disable: function(ifname, callback) {
|
||||
debug("disable with " + ifname);
|
||||
|
||||
this._ensureIfname(ifname, callback, function(iface) {
|
||||
if (iface.state == Ci.nsINetworkInterface.NETWORK_STATE_DISABLED) {
|
||||
if (callback) {
|
||||
callback.notify(true, "Interface is already disabled.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (iface.state == Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED) {
|
||||
gNetworkService.stopDhcp(iface.name);
|
||||
}
|
||||
|
||||
let ips = {};
|
||||
let prefixLengths = {};
|
||||
iface.getAddresses(ips, prefixLengths);
|
||||
let config = { ifname: iface.name,
|
||||
ip: ips.value[0],
|
||||
prefix: prefixLengths.value[0],
|
||||
link: NETWORK_INTERFACE_DOWN };
|
||||
gNetworkService.setInterfaceConfig(config, function(success) {
|
||||
if (!success) {
|
||||
if (callback) {
|
||||
callback.notify(false, "Netd Error.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.ethernetInterfaces[iface.name].updateConfig({
|
||||
state: Ci.nsINetworkInterface.NETWORK_STATE_DISABLED
|
||||
});
|
||||
|
||||
debug("Disable interface " + iface.name + " success.");
|
||||
|
||||
if (callback) {
|
||||
callback.notify(true, "ok");
|
||||
}
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
connect: function(ifname, callback) {
|
||||
debug("connect wtih " + ifname);
|
||||
|
||||
this._ensureIfname(ifname, callback, function(iface) {
|
||||
// Interface can only be connected in the state of enabled or
|
||||
// disconnected.
|
||||
if (iface.state == Ci.nsINetworkInterface.NETWORK_STATE_DISABLED ||
|
||||
iface.state == Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED) {
|
||||
if (callback) {
|
||||
callback.notify(true, "Interface " + ifname + " is not available or "
|
||||
+ " already connected.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (iface.ipMode == IP_MODE_DHCP) {
|
||||
this._runDhcp(iface.name, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
if (iface.ipMode == IP_MODE_STATIC) {
|
||||
if (this._checkConfigNull(iface) && this.lastStaticConfig[iface.name]) {
|
||||
debug("connect with lastStaticConfig " +
|
||||
JSON.stringify(this.lastStaticConfig[iface.name]));
|
||||
this.ethernetInterfaces[iface.name].updateConfig(
|
||||
this.lastStaticConfig[iface.name]);
|
||||
}
|
||||
this._setStaticIP(iface.name, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
callback.notify(false, "Ip mode is wrong or not set.");
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
disconnect: function(ifname, callback) {
|
||||
debug("disconnect");
|
||||
|
||||
this._ensureIfname(ifname, callback, function(iface) {
|
||||
// Interface can be only disconnected in the state of connected.
|
||||
if (iface.state != Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED) {
|
||||
if (callback) {
|
||||
callback.notify(true, "interface is already disconnected");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let config = { ifname: iface.name,
|
||||
ip: INTERFACE_IPADDR_NULL,
|
||||
prefix: INTERFACE_PREFIX_NULL,
|
||||
link: NETWORK_INTERFACE_UP };
|
||||
gNetworkService.setInterfaceConfig(config, function(success) {
|
||||
if (!success) {
|
||||
if (callback) {
|
||||
callback.notify(false, "Netd error.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop dhcp daemon.
|
||||
gNetworkService.stopDhcp(iface.name);
|
||||
|
||||
this.ethernetInterfaces[iface.name].updateConfig({
|
||||
state: Ci.nsINetworkInterface.NETWORK_STATE_DISCONNECTED,
|
||||
ip: INTERFACE_IPADDR_NULL,
|
||||
prefixLength: INTERFACE_PREFIX_NULL,
|
||||
gateway: INTERFACE_GATEWAY_NULL
|
||||
});
|
||||
|
||||
Services.obs.notifyObservers(this.ethernetInterfaces[iface.name],
|
||||
TOPIC_INTERFACE_STATE_CHANGED,
|
||||
null);
|
||||
|
||||
debug("Disconnect interface " + iface.name + " success.");
|
||||
|
||||
if (callback) {
|
||||
callback.notify(true, "ok");
|
||||
}
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_checkConfigNull: function(iface) {
|
||||
let ips = {};
|
||||
let prefixLengths = {};
|
||||
let gateways = iface.getGateways();
|
||||
iface.getAddresses(ips, prefixLengths);
|
||||
|
||||
if (ips.value[0] == INTERFACE_IPADDR_NULL &&
|
||||
prefixLengths.value[0] == INTERFACE_PREFIX_NULL &&
|
||||
gateways[0] == INTERFACE_GATEWAY_NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_ensureIfname: function(ifname, callback, func) {
|
||||
// If no given ifname, use the default one.
|
||||
if (!ifname) {
|
||||
ifname = DEFAULT_ETHERNET_NETWORK_IFACE;
|
||||
}
|
||||
|
||||
let iface = this.ethernetInterfaces[ifname];
|
||||
if (!iface) {
|
||||
if (callback) {
|
||||
callback.notify(true, "Interface " + ifname + " is not available.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
func.call(this, iface);
|
||||
},
|
||||
|
||||
_runDhcp: function(ifname, callback) {
|
||||
debug("runDhcp with " + ifname);
|
||||
|
||||
if (!this.ethernetInterfaces[ifname]) {
|
||||
callback.notify(false, "Invalid interface.");
|
||||
return
|
||||
}
|
||||
|
||||
gNetworkService.runDhcp(ifname, function(success, result) {
|
||||
if (!success) {
|
||||
callback.notify(false, "Dhcp failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
debug("Dhcp success with " + JSON.stringify(result));
|
||||
|
||||
// Clear last static network information when connecting with dhcp mode.
|
||||
if (this.lastStaticConfig[ifname]) {
|
||||
this.lastStaticConfig[ifname] = null;
|
||||
}
|
||||
|
||||
this.ethernetInterfaces[ifname].updateConfig({
|
||||
state: Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED,
|
||||
ip: result.ip,
|
||||
gateway: result.gateway,
|
||||
prefixLength: result.prefix,
|
||||
dnses: [result.dns1, result.dns2]
|
||||
});
|
||||
|
||||
Services.obs.notifyObservers(this.ethernetInterfaces[ifname],
|
||||
TOPIC_INTERFACE_STATE_CHANGED,
|
||||
null);
|
||||
|
||||
debug("Connect interface " + ifname + "with dhcp success.");
|
||||
|
||||
callback.notify(true, "ok");
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_setStaticIP: function(ifname, callback) {
|
||||
let iface = this.ethernetInterfaces[ifname];
|
||||
if (!iface) {
|
||||
callback.notify(false, "Invalid interface.");
|
||||
return;
|
||||
}
|
||||
|
||||
let ips = {};
|
||||
let prefixLengths = {};
|
||||
iface.getAddresses(ips, prefixLengths);
|
||||
|
||||
let config = { ifname: iface.name,
|
||||
ip: ips.value[0],
|
||||
prefix: prefixLengths.value[0],
|
||||
link: NETWORK_INTERFACE_UP };
|
||||
gNetworkService.setInterfaceConfig(config, function(success) {
|
||||
if (!success) {
|
||||
callback.notify(false, "Netd Error.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Keep the lastest static network information.
|
||||
let ips = {};
|
||||
let prefixLengths = {};
|
||||
let gateways = iface.getGateways();
|
||||
iface.getAddresses(ips, prefixLengths);
|
||||
|
||||
this.lastStaticConfig[iface.name] = {
|
||||
ip: ips.value[0],
|
||||
prefixLength: prefixLengths.value[0],
|
||||
gateway: gateways[0]
|
||||
};
|
||||
|
||||
this.ethernetInterfaces[ifname].updateConfig({
|
||||
state: Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED,
|
||||
});
|
||||
|
||||
Services.obs.notifyObservers(this.ethernetInterfaces[ifname],
|
||||
TOPIC_INTERFACE_STATE_CHANGED,
|
||||
null);
|
||||
|
||||
debug("Connect interface " + ifname + "with static ip success.");
|
||||
|
||||
callback.notify(true, "ok");
|
||||
}.bind(this));
|
||||
},
|
||||
}
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([EthernetManager]);
|
2
dom/network/src/EthernetManager.manifest
Normal file
2
dom/network/src/EthernetManager.manifest
Normal file
@ -0,0 +1,2 @@
|
||||
component {a96441dd-36b3-4f7f-963b-2c032e28a039} EthernetManager.js
|
||||
contract @mozilla.org/ethernetManager;1 {a96441dd-36b3-4f7f-963b-2c032e28a039}
|
@ -44,6 +44,8 @@ EXTRA_PP_COMPONENTS += [
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
EXTRA_COMPONENTS += [
|
||||
'EthernetManager.js',
|
||||
'EthernetManager.manifest',
|
||||
'NetworkStatsManager.js',
|
||||
'NetworkStatsManager.manifest',
|
||||
'NetworkStatsServiceProxy.js',
|
||||
|
551
dom/network/tests/marionette/head.js
Normal file
551
dom/network/tests/marionette/head.js
Normal file
@ -0,0 +1,551 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let Promise = SpecialPowers.Cu.import("resource://gre/modules/Promise.jsm").Promise;
|
||||
|
||||
const ETHERNET_MANAGER_CONTRACT_ID = "@mozilla.org/ethernetManager;1";
|
||||
|
||||
const INTERFACE_UP = "UP";
|
||||
const INTERFACE_DOWN = "DOWN";
|
||||
|
||||
let gTestSuite = (function() {
|
||||
let suite = {};
|
||||
|
||||
// Private member variables of the returned object |suite|.
|
||||
let ethernetManager = SpecialPowers.Cc[ETHERNET_MANAGER_CONTRACT_ID]
|
||||
.getService(SpecialPowers.Ci.nsIEthernetManager);
|
||||
let pendingEmulatorShellCount = 0;
|
||||
|
||||
/**
|
||||
* Send emulator shell command with safe guard.
|
||||
*
|
||||
* We should only call |finish()| after all emulator command transactions
|
||||
* end, so here comes with the pending counter. Resolve when the emulator
|
||||
* gives positive response, and reject otherwise.
|
||||
*
|
||||
* Fulfill params: an array of emulator response lines.
|
||||
* Reject params: an array of emulator response lines.
|
||||
*
|
||||
* @param command
|
||||
* A string command to be passed to emulator through its telnet console.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function runEmulatorShellSafe(command) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
++pendingEmulatorShellCount;
|
||||
runEmulatorShell(command, function(aResult) {
|
||||
--pendingEmulatorShellCount;
|
||||
|
||||
ok(true, "Emulator shell response: " + JSON.stringify(aResult));
|
||||
if (Array.isArray(aResult)) {
|
||||
deferred.resolve(aResult);
|
||||
} else {
|
||||
deferred.reject(aResult);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the system network conifg by the given interface name.
|
||||
*
|
||||
* Use shell command 'netcfg' to get the list of network cofig.
|
||||
*
|
||||
* Fulfill params: An object of { name, flag, ip }
|
||||
*
|
||||
* @parm ifname
|
||||
* Interface name.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function getNetworkConfig(ifname) {
|
||||
return runEmulatorShellSafe(['netcfg'])
|
||||
.then(result => {
|
||||
// Sample 'netcfg' output:
|
||||
//
|
||||
// lo UP 127.0.0.1/8 0x00000049 00:00:00:00:00:00
|
||||
// eth0 UP 10.0.2.15/24 0x00001043 52:54:00:12:34:56
|
||||
// eth1 DOWN 0.0.0.0/0 0x00001002 52:54:00:12:34:57
|
||||
// rmnet1 DOWN 0.0.0.0/0 0x00001002 52:54:00:12:34:59
|
||||
|
||||
let config;
|
||||
|
||||
for (let i = 0; i < result.length; i++) {
|
||||
let tokens = result[i].split(/\s+/);
|
||||
let name = tokens[0];
|
||||
let flag = tokens[1];
|
||||
let ip = tokens[2].split(/\/+/)[0];
|
||||
if (name == ifname) {
|
||||
config = { name: name, flag: flag, ip: ip };
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ip assigned by dhcp server of a given interface name.
|
||||
*
|
||||
* Get the ip from android property 'dhcp.[ifname].ipaddress'.
|
||||
*
|
||||
* Fulfill params: A string of ip address.
|
||||
*
|
||||
* @parm ifname
|
||||
* Interface name.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function getDhcpIpAddr(ifname) {
|
||||
return runEmulatorShellSafe(['getprop', 'dhcp.' + ifname + '.ipaddress'])
|
||||
.then(function(ipAddr) {
|
||||
return ipAddr[0];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the gateway assigned by dhcp server of a given interface name.
|
||||
*
|
||||
* Get the ip from android property 'dhcp.[ifname].gateway'.
|
||||
*
|
||||
* Fulfill params: A string of gateway.
|
||||
*
|
||||
* @parm ifname
|
||||
* Interface name.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function getDhcpGateway(ifname) {
|
||||
return runEmulatorShellSafe(['getprop', 'dhcp.' + ifname + '.gateway'])
|
||||
.then(function(gateway) {
|
||||
return gateway[0];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default route.
|
||||
*
|
||||
* Use shell command 'ip route' to get the default of device.
|
||||
*
|
||||
* Fulfill params: An array of { name, gateway }
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function getDefaultRoute() {
|
||||
return runEmulatorShellSafe(['ip', 'route'])
|
||||
.then(result => {
|
||||
// Sample 'ip route' output:
|
||||
//
|
||||
// 10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15
|
||||
// default via 10.0.2.2 dev eth0 metric 2
|
||||
|
||||
let routeInfo = [];
|
||||
|
||||
for (let i = 0; i < result.length; i++) {
|
||||
if (!result[i].match('default')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let tokens = result[i].split(/\s+/);
|
||||
let name = tokens[4];
|
||||
let gateway = tokens[2];
|
||||
routeInfo.push({ name: name, gateway: gateway });
|
||||
}
|
||||
|
||||
return routeInfo;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a specific interface is enabled or not.
|
||||
*
|
||||
* @parm ifname
|
||||
* Interface name.
|
||||
* @parm enabled
|
||||
* A boolean value used to check interface is disable or not.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function checkInterfaceIsEnabled(ifname, enabled) {
|
||||
return getNetworkConfig(ifname)
|
||||
.then(function(config) {
|
||||
if (enabled) {
|
||||
is(config.flag, INTERFACE_UP, "Interface is enabled as expectation.");
|
||||
} else {
|
||||
is(config.flag, INTERFACE_DOWN, "Interface is disabled as expectation.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the ip of a specific interface is equal to given ip or not.
|
||||
*
|
||||
* @parm ifname
|
||||
* Interface name.
|
||||
* @parm ip
|
||||
* Given ip address.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function checkInterfaceIpAddr(ifname, ip) {
|
||||
return getNetworkConfig(ifname)
|
||||
.then(function(config) {
|
||||
is(config.ip, ip, "IP is right as expectation.");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the default gateway of a specific interface is equal to given gateway
|
||||
* or not.
|
||||
*
|
||||
* @parm ifname
|
||||
* Interface name.
|
||||
* @parm gateway
|
||||
* Given gateway.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function checkDefaultRoute(ifname, gateway) {
|
||||
return getDefaultRoute()
|
||||
.then(function(routeInfo) {
|
||||
for (let i = 0; i < routeInfo.length; i++) {
|
||||
if (routeInfo[i].name == ifname) {
|
||||
is(routeInfo[i].gateway, gateway,
|
||||
"Default gateway is right as expectation.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!gateway) {
|
||||
ok(true, "Default route is cleared.");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the length of interface list in EthernetManager is equal to given
|
||||
* length or not.
|
||||
*
|
||||
* @parm length
|
||||
* Given length.
|
||||
*/
|
||||
function checkInterfaceListLength(length) {
|
||||
let list = ethernetManager.interfaceList;
|
||||
is(length, list.length, "List length is equal as expectation.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the given interface exists on device or not.
|
||||
*
|
||||
* @parm ifname
|
||||
* Interface name.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function checkInterfaceExist(ifname) {
|
||||
return scanInterfaces()
|
||||
.then(list => {
|
||||
let index = list.indexOf(ifname);
|
||||
if (index < 0) {
|
||||
throw "Interface " + ifname + " not found.";
|
||||
}
|
||||
|
||||
ok(true, ifname + " exists.")
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan for available ethernet interfaces.
|
||||
*
|
||||
* Fulfill params: A list of available interfaces found in device.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function scanInterfaces() {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
ethernetManager.scan(function onScan(list) {
|
||||
deferred.resolve(list);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an interface into interface list.
|
||||
*
|
||||
* Fulfill params: A boolean value indicates success or not.
|
||||
*
|
||||
* @param ifname
|
||||
* Interface name.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function addInterface(ifname) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
ethernetManager.addInterface(ifname, function onAdd(success, message) {
|
||||
ok(success, "Add interface " + ifname + " success.");
|
||||
is(message, "ok", "Message is as expectation.");
|
||||
|
||||
deferred.resolve(success);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an interface form the interface list.
|
||||
*
|
||||
* Fulfill params: A boolean value indicates success or not.
|
||||
*
|
||||
* @param ifname
|
||||
* Interface name.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function removeInterface(ifname) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
ethernetManager.removeInterface(ifname, function onRemove(success, message) {
|
||||
ok(success, "Remove interface " + ifname + " success.");
|
||||
is(message, "ok", "Message is as expectation.");
|
||||
|
||||
deferred.resolve(success);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable networking of an interface in the interface list.
|
||||
*
|
||||
* Fulfill params: A boolean value indicates success or not.
|
||||
*
|
||||
* @param ifname
|
||||
* Interface name.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function enableInterface(ifname) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
ethernetManager.enable(ifname, function onEnable(success, message) {
|
||||
ok(success, "Enable interface " + ifname + " success.");
|
||||
is(message, "ok", "Message is as expectation.");
|
||||
|
||||
deferred.resolve(success);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable networking of an interface in the interface list.
|
||||
*
|
||||
* Fulfill params: A boolean value indicates success or not.
|
||||
*
|
||||
* @param ifname
|
||||
* Interface name.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function disableInterface(ifname) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
ethernetManager.disable(ifname, function onDisable(success, message) {
|
||||
ok(success, "Disable interface " + ifname + " success.");
|
||||
is(message, "ok", "Message is as expectation.");
|
||||
|
||||
deferred.resolve(success);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an interface connect to network.
|
||||
*
|
||||
* Fulfill params: A boolean value indicates success or not.
|
||||
*
|
||||
* @param ifname
|
||||
* Interface name.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function makeInterfaceConnect(ifname) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
ethernetManager.connect(ifname, function onConnect(success, message) {
|
||||
ok(success, "Interface " + ifname + " is connected successfully.");
|
||||
is(message, "ok", "Message is as expectation.");
|
||||
|
||||
deferred.resolve(success);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an interface disconnect to network.
|
||||
*
|
||||
* Fulfill params: A boolean value indicates success or not.
|
||||
*
|
||||
* @param ifname
|
||||
* Interface name.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function makeInterfaceDisconnect(ifname) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
ethernetManager.disconnect(ifname, function onDisconnect(success, message) {
|
||||
ok(success, "Interface " + ifname + " is disconnected successfully.");
|
||||
is(message, "ok", "Message is as expectation.");
|
||||
|
||||
deferred.resolve(success);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the config the an interface in the interface list.
|
||||
*
|
||||
* @param ifname
|
||||
* Interface name.
|
||||
* @param config
|
||||
* .ip: ip address.
|
||||
* .prefixLength: mask length.
|
||||
* .gateway: gateway.
|
||||
* .dnses: dnses.
|
||||
* .httpProxyHost: http proxy host.
|
||||
* .httpProxyPort: http porxy port.
|
||||
* .usingDhcp: an boolean value indicates using dhcp or not.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function updateInterfaceConfig(ifname, config) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
ethernetManager.updateInterfaceConfig(ifname, config,
|
||||
function onUpdated(success, message) {
|
||||
ok(success, "Interface " + ifname + " config is updated successfully " +
|
||||
" with " + JSON.stringify(config));
|
||||
is(message, "ok", "Message is as expectation.");
|
||||
|
||||
deferred.resolve(success);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for timeout.
|
||||
*
|
||||
* @param timeout
|
||||
* Time in ms.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function waitForTimeout(timeout) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
setTimeout(function() {
|
||||
ok(true, "waitForTimeout " + timeout);
|
||||
deferred.resolve();
|
||||
}, timeout);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for default route of a specific interface being set and
|
||||
* check.
|
||||
*
|
||||
* @param ifname
|
||||
* Interface name.
|
||||
* @param gateway
|
||||
* Target gateway.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function waitForDefaultRouteSet(ifname, gateway) {
|
||||
return gTestSuite.waitForTimeout(500)
|
||||
.then(() => gTestSuite.checkDefaultRoute(ifname, gateway))
|
||||
.then(success => {
|
||||
if (success) {
|
||||
ok(true, "Default route is set as expectation " + gateway);
|
||||
return;
|
||||
}
|
||||
|
||||
ok(true, "Default route is not set yet, check again. " + success);
|
||||
return waitForDefaultRouteSet(ifname, gateway);
|
||||
});
|
||||
}
|
||||
|
||||
//---------------------------------------------------
|
||||
// Public test suite functions
|
||||
//---------------------------------------------------
|
||||
suite.scanInterfaces = scanInterfaces;
|
||||
suite.addInterface = addInterface;
|
||||
suite.removeInterface = removeInterface;
|
||||
suite.enableInterface = enableInterface;
|
||||
suite.disableInterface = disableInterface;
|
||||
suite.makeInterfaceConnect = makeInterfaceConnect;
|
||||
suite.makeInterfaceDisconnect = makeInterfaceDisconnect;
|
||||
suite.updateInterfaceConfig = updateInterfaceConfig;
|
||||
suite.getDhcpIpAddr = getDhcpIpAddr;
|
||||
suite.getDhcpGateway = getDhcpGateway;
|
||||
suite.checkInterfaceExist = checkInterfaceExist;
|
||||
suite.checkInterfaceIsEnabled = checkInterfaceIsEnabled;
|
||||
suite.checkInterfaceIpAddr = checkInterfaceIpAddr;
|
||||
suite.checkDefaultRoute = checkDefaultRoute;
|
||||
suite.checkInterfaceListLength = checkInterfaceListLength;
|
||||
suite.waitForTimeout = waitForTimeout;
|
||||
suite.waitForDefaultRouteSet = waitForDefaultRouteSet;
|
||||
|
||||
/**
|
||||
* End up the test run.
|
||||
*
|
||||
* Wait until all pending emulator shell commands are done and then |finish|
|
||||
* will be called in the end.
|
||||
*/
|
||||
function cleanUp() {
|
||||
waitFor(finish, function() {
|
||||
return pendingEmulatorShellCount === 0;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Common test routine.
|
||||
*
|
||||
* Start a test with the given test case chain. The test environment will be
|
||||
* settled down before the test. After the test, all the affected things will
|
||||
* be restored.
|
||||
*
|
||||
* @param aTestCaseChain
|
||||
* The test case entry point, which can be a function or a promise.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
suite.doTest = function(aTestCaseChain) {
|
||||
return Promise.resolve()
|
||||
.then(aTestCaseChain)
|
||||
.then(function onresolve() {
|
||||
cleanUp();
|
||||
}, function onreject(aReason) {
|
||||
ok(false, 'Promise rejects during test' + (aReason ? '(' + aReason + ')' : ''));
|
||||
cleanUp();
|
||||
});
|
||||
};
|
||||
|
||||
return suite;
|
||||
})();
|
15
dom/network/tests/marionette/manifest.ini
Normal file
15
dom/network/tests/marionette/manifest.ini
Normal file
@ -0,0 +1,15 @@
|
||||
[DEFAULT]
|
||||
b2g = true
|
||||
browser = false
|
||||
qemu = true
|
||||
|
||||
[test_ethernet_add_interface.js]
|
||||
[test_ethernet_remove_interface.js]
|
||||
[test_ethernet_enable.js]
|
||||
[test_ethernet_disable.js]
|
||||
[test_ethernet_connect_with_dhcp.js]
|
||||
[test_ethernet_connect_with_static_ip.js]
|
||||
[test_ethernet_reconnect_with_dhcp.js]
|
||||
[test_ethernet_reconnect_with_static_ip.js]
|
||||
[test_ethernet_ip_mode_change.js]
|
||||
[test_ethernet_disconnect.js]
|
16
dom/network/tests/marionette/test_ethernet_add_interface.js
Normal file
16
dom/network/tests/marionette/test_ethernet_add_interface.js
Normal file
@ -0,0 +1,16 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
const ETHERNET_INTERFACE_NAME = "eth1";
|
||||
|
||||
gTestSuite.doTest(function() {
|
||||
return Promise.resolve()
|
||||
.then(() => gTestSuite.checkInterfaceExist(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.checkInterfaceListLength(0))
|
||||
.then(() => gTestSuite.addInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.checkInterfaceListLength(1))
|
||||
.then(() => gTestSuite.removeInterface(ETHERNET_INTERFACE_NAME));
|
||||
});
|
@ -0,0 +1,26 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
const ETHERNET_INTERFACE_NAME = "eth1";
|
||||
|
||||
function checkDhcpResult(ifname) {
|
||||
return gTestSuite.getDhcpIpAddr(ifname)
|
||||
.then(ip => gTestSuite.checkInterfaceIpAddr(ifname, ip))
|
||||
.then(() => gTestSuite.getDhcpGateway(ifname))
|
||||
.then(gateway => gTestSuite.waitForDefaultRouteSet(ifname, gateway));
|
||||
}
|
||||
|
||||
gTestSuite.doTest(function() {
|
||||
return Promise.resolve()
|
||||
.then(() => gTestSuite.checkInterfaceExist(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.addInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.enableInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.makeInterfaceConnect(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => checkDhcpResult(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.makeInterfaceDisconnect(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.disableInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.removeInterface(ETHERNET_INTERFACE_NAME));
|
||||
});
|
@ -0,0 +1,33 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
const ETHERNET_INTERFACE_NAME = "eth1";
|
||||
|
||||
let staticConfig = {
|
||||
ip: "1.2.3.4",
|
||||
gateway: "1.2.3.5",
|
||||
prefixLength: 24,
|
||||
dnses: ["1.2.3.6"],
|
||||
ipMode: "static"
|
||||
};
|
||||
|
||||
function checkStaticResult(ifname) {
|
||||
return gTestSuite.checkInterfaceIpAddr(ifname, staticConfig.ip)
|
||||
.then(() => gTestSuite.checkDefaultRoute(ifname, staticConfig.gateway));
|
||||
}
|
||||
|
||||
gTestSuite.doTest(function() {
|
||||
return Promise.resolve()
|
||||
.then(() => gTestSuite.checkInterfaceExist(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.addInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.enableInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.updateInterfaceConfig(ETHERNET_INTERFACE_NAME, staticConfig))
|
||||
.then(() => gTestSuite.makeInterfaceConnect(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => checkStaticResult(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.makeInterfaceDisconnect(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.disableInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.removeInterface(ETHERNET_INTERFACE_NAME));
|
||||
});
|
17
dom/network/tests/marionette/test_ethernet_disable.js
Normal file
17
dom/network/tests/marionette/test_ethernet_disable.js
Normal file
@ -0,0 +1,17 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
const ETHERNET_INTERFACE_NAME = "eth1";
|
||||
|
||||
gTestSuite.doTest(function() {
|
||||
return Promise.resolve()
|
||||
.then(() => gTestSuite.checkInterfaceExist(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.addInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.enableInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.disableInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.checkInterfaceIsEnabled(ETHERNET_INTERFACE_NAME, false))
|
||||
.then(() => gTestSuite.removeInterface(ETHERNET_INTERFACE_NAME));
|
||||
});
|
25
dom/network/tests/marionette/test_ethernet_disconnect.js
Normal file
25
dom/network/tests/marionette/test_ethernet_disconnect.js
Normal file
@ -0,0 +1,25 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
const ETHERNET_INTERFACE_NAME = "eth1";
|
||||
const INTERFACE_IP_NONE = "0.0.0.0";
|
||||
|
||||
function checkIpAddrIsReset(ifname) {
|
||||
return gTestSuite.checkInterfaceIpAddr(ifname, INTERFACE_IP_NONE)
|
||||
.then(() => gTestSuite.checkDefaultRoute(ifname));
|
||||
}
|
||||
|
||||
gTestSuite.doTest(function() {
|
||||
return Promise.resolve()
|
||||
.then(() => gTestSuite.checkInterfaceExist(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.addInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.enableInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.makeInterfaceConnect(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.makeInterfaceDisconnect(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => checkIpAddrIsReset(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.disableInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.removeInterface(ETHERNET_INTERFACE_NAME));
|
||||
});
|
17
dom/network/tests/marionette/test_ethernet_enable.js
Normal file
17
dom/network/tests/marionette/test_ethernet_enable.js
Normal file
@ -0,0 +1,17 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
const ETHERNET_INTERFACE_NAME = "eth1";
|
||||
|
||||
gTestSuite.doTest(function() {
|
||||
return Promise.resolve()
|
||||
.then(() => gTestSuite.checkInterfaceExist(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.addInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.enableInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.checkInterfaceIsEnabled(ETHERNET_INTERFACE_NAME, true))
|
||||
.then(() => gTestSuite.disableInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.removeInterface(ETHERNET_INTERFACE_NAME));
|
||||
});
|
43
dom/network/tests/marionette/test_ethernet_ip_mode_change.js
Normal file
43
dom/network/tests/marionette/test_ethernet_ip_mode_change.js
Normal file
@ -0,0 +1,43 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
const ETHERNET_INTERFACE_NAME = "eth1";
|
||||
|
||||
let staticConfig = {
|
||||
ip: "1.2.3.4",
|
||||
gateway: "1.2.3.5",
|
||||
prefixLength: 24,
|
||||
dnses: ["1.2.3.6"],
|
||||
ipMode: "static"
|
||||
};
|
||||
|
||||
function checkStaticResult(ifname) {
|
||||
return gTestSuite.checkInterfaceIpAddr(ifname, staticConfig.ip)
|
||||
.then(() => gTestSuite.waitForDefaultRouteSet(ifname, staticConfig.gateway));
|
||||
}
|
||||
|
||||
function checkDhcpResult(ifname) {
|
||||
return gTestSuite.getDhcpIpAddr(ifname)
|
||||
.then(ip => gTestSuite.checkInterfaceIpAddr(ifname, ip))
|
||||
.then(() => gTestSuite.getDhcpGateway(ifname))
|
||||
.then(gateway => gTestSuite.waitForDefaultRouteSet(ifname, gateway));
|
||||
}
|
||||
|
||||
gTestSuite.doTest(function() {
|
||||
return Promise.resolve()
|
||||
.then(() => gTestSuite.checkInterfaceExist(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.addInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.enableInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.makeInterfaceConnect(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => checkDhcpResult(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.updateInterfaceConfig(ETHERNET_INTERFACE_NAME, staticConfig))
|
||||
.then(() => checkStaticResult(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.updateInterfaceConfig(ETHERNET_INTERFACE_NAME, { ipMode: "dhcp"}))
|
||||
.then(() => checkDhcpResult(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.makeInterfaceDisconnect(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.disableInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.removeInterface(ETHERNET_INTERFACE_NAME));
|
||||
});
|
@ -0,0 +1,28 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
const ETHERNET_INTERFACE_NAME = "eth1";
|
||||
|
||||
function checkDhcpResult(ifname) {
|
||||
return gTestSuite.getDhcpIpAddr(ifname)
|
||||
.then(ip => gTestSuite.checkInterfaceIpAddr(ifname, ip))
|
||||
.then(() => gTestSuite.getDhcpGateway(ifname))
|
||||
.then(gateway => gTestSuite.waitForDefaultRouteSet(ifname, gateway));
|
||||
}
|
||||
|
||||
gTestSuite.doTest(function() {
|
||||
return Promise.resolve()
|
||||
.then(() => gTestSuite.checkInterfaceExist(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.addInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.enableInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.makeInterfaceConnect(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => checkDhcpResult(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.makeInterfaceDisconnect(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.makeInterfaceConnect(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => checkDhcpResult(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.disableInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.removeInterface(ETHERNET_INTERFACE_NAME));
|
||||
});
|
@ -0,0 +1,36 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
const ETHERNET_INTERFACE_NAME = "eth1";
|
||||
|
||||
let staticConfig = {
|
||||
ip: "1.2.3.4",
|
||||
gateway: "1.2.3.5",
|
||||
prefixLength: 24,
|
||||
dnses: ["1.2.3.6"],
|
||||
ipMode: "static"
|
||||
};
|
||||
|
||||
function checkStaticResult(ifname) {
|
||||
return gTestSuite.checkInterfaceIpAddr(ifname, staticConfig.ip)
|
||||
.then(() => gTestSuite.checkDefaultRoute(ifname, staticConfig.gateway));
|
||||
}
|
||||
|
||||
gTestSuite.doTest(function() {
|
||||
return Promise.resolve()
|
||||
.then(() => gTestSuite.checkInterfaceExist(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.addInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.enableInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.updateInterfaceConfig(ETHERNET_INTERFACE_NAME, staticConfig))
|
||||
.then(() => gTestSuite.makeInterfaceConnect(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => checkStaticResult(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.makeInterfaceDisconnect(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.makeInterfaceConnect(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => checkStaticResult(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.makeInterfaceDisconnect(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.disableInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.removeInterface(ETHERNET_INTERFACE_NAME));
|
||||
});
|
@ -0,0 +1,16 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
const ETHERNET_INTERFACE_NAME = "eth1";
|
||||
|
||||
gTestSuite.doTest(function() {
|
||||
return Promise.resolve()
|
||||
.then(() => gTestSuite.checkInterfaceExist(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.addInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.checkInterfaceListLength(1))
|
||||
.then(() => gTestSuite.removeInterface(ETHERNET_INTERFACE_NAME))
|
||||
.then(() => gTestSuite.checkInterfaceListLength(0));
|
||||
});
|
@ -45,6 +45,18 @@ let emulator = (function() {
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
function deactivate() {
|
||||
let deferred = Promise.defer();
|
||||
let cmd = 'nfc nci rf_intf_deactivate_ntf';
|
||||
|
||||
this.run(cmd, function(result) {
|
||||
is(result.pop(), 'OK', 'check deactivate');
|
||||
deferred.resolve();
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
function notifyDiscoverRE(re, type) {
|
||||
let deferred = Promise.defer();
|
||||
let cmd = 'nfc nci rf_discover_ntf ' + re + ' ' + type;
|
||||
@ -88,6 +100,7 @@ let emulator = (function() {
|
||||
return {
|
||||
run: run,
|
||||
activateRE: activateRE,
|
||||
deactivate: deactivate,
|
||||
notifyDiscoverRE: notifyDiscoverRE,
|
||||
setTagData: setTagData,
|
||||
snepPutNdef: snepPutNdef
|
||||
|
@ -7,6 +7,7 @@ qemu=true
|
||||
[test_nfc_enabled.js]
|
||||
[test_nfc_manager_tech_discovered.js]
|
||||
[test_nfc_manager_tech_discovered_ndef.js]
|
||||
[test_nfc_manager_tech_lost.js]
|
||||
[test_nfc_peer.js]
|
||||
[test_nfc_peer_sendndef.js]
|
||||
[test_nfc_tag.js]
|
||||
|
37
dom/nfc/tests/marionette/test_nfc_manager_tech_lost.js
Normal file
37
dom/nfc/tests/marionette/test_nfc_manager_tech_lost.js
Normal file
@ -0,0 +1,37 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 30000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
function handleTechnologyLost(msg) {
|
||||
log('Received \'nfc-manager-tech-lost\'');
|
||||
is(msg.type, 'techLost', 'check for correct message type');
|
||||
|
||||
toggleNFC(false).then(runNextTest)
|
||||
}
|
||||
|
||||
function handleTechnologyDiscoveredRE0(msg) {
|
||||
log('Received \'nfc-manager-tech-discovered\'');
|
||||
is(msg.type, 'techDiscovered', 'check for correct message type');
|
||||
is(msg.techList[0], 'P2P', 'check for correct tech type');
|
||||
|
||||
emulator.deactivate();
|
||||
}
|
||||
|
||||
function testTechLost() {
|
||||
log('Running \'testTechLost\'');
|
||||
window.navigator.mozSetMessageHandler(
|
||||
'nfc-manager-tech-discovered', handleTechnologyDiscoveredRE0);
|
||||
window.navigator.mozSetMessageHandler(
|
||||
'nfc-manager-tech-lost', handleTechnologyLost);
|
||||
|
||||
toggleNFC(true).then(() => emulator.activateRE(0));
|
||||
}
|
||||
|
||||
let tests = [
|
||||
testTechLost
|
||||
];
|
||||
|
||||
SpecialPowers.pushPermissions(
|
||||
[{'type': 'nfc-manager', 'allow': true, context: document}], runTests);
|
@ -13,9 +13,9 @@ Cu.import("resource://gre/modules/systemlibs.js");
|
||||
|
||||
const NETWORKMANAGER_CONTRACTID = "@mozilla.org/network/manager;1";
|
||||
const NETWORKMANAGER_CID =
|
||||
Components.ID("{33901e46-33b8-11e1-9869-f46d04d25bcc}");
|
||||
Components.ID("{1ba9346b-53b5-4660-9dc6-58f0b258d0a6}");
|
||||
|
||||
const DEFAULT_PREFERRED_NETWORK_TYPE = Ci.nsINetworkInterface.NETWORK_TYPE_WIFI;
|
||||
const DEFAULT_PREFERRED_NETWORK_TYPE = Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET;
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
|
||||
"@mozilla.org/settingsService;1",
|
||||
@ -276,7 +276,8 @@ NetworkManager.prototype = {
|
||||
if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
|
||||
gNetworkService.resetRoutingTable(network);
|
||||
#ifdef MOZ_B2G_RIL
|
||||
} else if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE) {
|
||||
} else if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE ||
|
||||
network.type == Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET) {
|
||||
gNetworkService.removeDefaultRoute(network);
|
||||
#endif
|
||||
}
|
||||
@ -367,7 +368,9 @@ NetworkManager.prototype = {
|
||||
getNetworkId: function(network) {
|
||||
let id = "device";
|
||||
#ifdef MOZ_B2G_RIL
|
||||
if (this.isNetworkTypeMobile(network.type)) {
|
||||
if (this.isNetworkTypeEthernet(network.type)) {
|
||||
id = network.name.substring(3);
|
||||
} else if (this.isNetworkTypeMobile(network.type)) {
|
||||
if (!(network instanceof Ci.nsIRilNetworkInterface)) {
|
||||
throw Components.Exception("Mobile network not an nsIRilNetworkInterface",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
@ -419,17 +422,51 @@ NetworkManager.prototype = {
|
||||
|
||||
_dataDefaultServiceId: null,
|
||||
|
||||
_networkTypePriorityList: [Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET,
|
||||
Ci.nsINetworkInterface.NETWORK_TYPE_WIFI,
|
||||
Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE],
|
||||
get networkTypePriorityList() {
|
||||
return this._networkTypePriorityList;
|
||||
},
|
||||
set networkTypePriorityList(val) {
|
||||
if (val.length != this._networkTypePriorityList.length) {
|
||||
throw "Priority list length should equal to " +
|
||||
this._networkTypePriorityList.length;
|
||||
}
|
||||
|
||||
// Check if types in new priority list are valid and also make sure there
|
||||
// are no duplicate types.
|
||||
let list = [Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET,
|
||||
Ci.nsINetworkInterface.NETWORK_TYPE_WIFI,
|
||||
Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE];
|
||||
while (list.length) {
|
||||
let type = list.shift();
|
||||
if (val.indexOf(type) == -1) {
|
||||
throw "There is missing network type";
|
||||
}
|
||||
}
|
||||
|
||||
this._networkTypePriorityList = val;
|
||||
},
|
||||
|
||||
getPriority: function(type) {
|
||||
if (this._networkTypePriorityList.indexOf(type) == -1) {
|
||||
// 0 indicates the lowest priority.
|
||||
return 0;
|
||||
}
|
||||
|
||||
return this._networkTypePriorityList.length -
|
||||
this._networkTypePriorityList.indexOf(type);
|
||||
},
|
||||
|
||||
_preferredNetworkType: DEFAULT_PREFERRED_NETWORK_TYPE,
|
||||
get preferredNetworkType() {
|
||||
return this._preferredNetworkType;
|
||||
},
|
||||
set preferredNetworkType(val) {
|
||||
#ifdef MOZ_B2G_RIL
|
||||
if ([Ci.nsINetworkInterface.NETWORK_TYPE_WIFI,
|
||||
Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE].indexOf(val) == -1) {
|
||||
#else
|
||||
if (val != Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
|
||||
#endif
|
||||
Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE,
|
||||
Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET].indexOf(val) == -1) {
|
||||
throw "Invalid network type";
|
||||
}
|
||||
this._preferredNetworkType = val;
|
||||
@ -461,6 +498,10 @@ NetworkManager.prototype = {
|
||||
this.isNetworkTypeSecondaryMobile(type));
|
||||
},
|
||||
|
||||
isNetworkTypeEthernet: function(type) {
|
||||
return (type == Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET);
|
||||
},
|
||||
|
||||
setExtraHostRoute: function(network) {
|
||||
if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS) {
|
||||
if (!(network instanceof Ci.nsIRilNetworkInterface)) {
|
||||
@ -601,11 +642,23 @@ NetworkManager.prototype = {
|
||||
defaultDataNetwork = network;
|
||||
}
|
||||
#endif
|
||||
this.active = network;
|
||||
if (network.type == this.preferredNetworkType) {
|
||||
this.active = network;
|
||||
debug("Found our preferred type of network: " + network.name);
|
||||
break;
|
||||
}
|
||||
|
||||
// Initialize the active network with the first connected network.
|
||||
if (!this.active) {
|
||||
this.active = network;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Compare the prioriy between two network types. If found incoming
|
||||
// network with higher priority, replace the active network.
|
||||
if (this.getPriority(this.active.type) < this.getPriority(network.type)) {
|
||||
this.active = network;
|
||||
}
|
||||
}
|
||||
if (this.active) {
|
||||
#ifdef MOZ_B2G_RIL
|
||||
@ -680,7 +733,8 @@ NetworkManager.prototype = {
|
||||
// the function will return null so that it won't trigger type change event
|
||||
// in NetworkInformation API.
|
||||
if (network.type != Ci.nsINetworkInterface.NETWORK_TYPE_WIFI &&
|
||||
network.type != Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE) {
|
||||
network.type != Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE &&
|
||||
network.type != Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -693,6 +747,8 @@ NetworkManager.prototype = {
|
||||
return CONNECTION_TYPE_WIFI;
|
||||
case Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE:
|
||||
return CONNECTION_TYPE_CULLULAR;
|
||||
case Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET:
|
||||
return CONNECTION_TYPE_ETHERNET;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
# NetworkManager.js
|
||||
component {33901e46-33b8-11e1-9869-f46d04d25bcc} NetworkManager.js
|
||||
contract @mozilla.org/network/manager;1 {33901e46-33b8-11e1-9869-f46d04d25bcc}
|
||||
component {1ba9346b-53b5-4660-9dc6-58f0b258d0a6} NetworkManager.js
|
||||
contract @mozilla.org/network/manager;1 {1ba9346b-53b5-4660-9dc6-58f0b258d0a6}
|
||||
|
@ -12,7 +12,7 @@ Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
|
||||
const NETWORKSERVICE_CONTRACTID = "@mozilla.org/network/service;1";
|
||||
const NETWORKSERVICE_CID = Components.ID("{baec696c-c78d-42db-8b44-603f8fbfafb4}");
|
||||
const NETWORKSERVICE_CID = Components.ID("{48c13741-aec9-4a86-8962-432011708261}");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gNetworkWorker",
|
||||
"@mozilla.org/network/worker;1",
|
||||
@ -542,6 +542,81 @@ NetworkService.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
getInterfaces: function(callback) {
|
||||
let params = {
|
||||
cmd: "getInterfaces",
|
||||
isAsync: true
|
||||
};
|
||||
|
||||
this.controlMessage(params, function(data) {
|
||||
if(DEBUG) debug("getInterfaces result: " + JSON.stringify(data));
|
||||
let success = !isError(data.resultCode);
|
||||
callback.getInterfacesResult(success, data.interfaceList);
|
||||
});
|
||||
},
|
||||
|
||||
setInterfaceConfig: function(config, callback) {
|
||||
config.cmd = "setInterfaceConfig";
|
||||
config.isAsync = true;
|
||||
|
||||
this.controlMessage(config, function(data) {
|
||||
if(DEBUG) debug("setInterfaceConfig result: " + JSON.stringify(data));
|
||||
let success = !isError(data.resultCode);
|
||||
callback.setInterfaceConfigResult(success);
|
||||
});
|
||||
},
|
||||
|
||||
getInterfaceConfig: function(ifname, callback) {
|
||||
let params = {
|
||||
cmd: "getInterfaceConfig",
|
||||
ifname: ifname,
|
||||
isAsync: true
|
||||
};
|
||||
|
||||
this.controlMessage(params, function(data) {
|
||||
if(DEBUG) debug("getInterfaceConfig result: " + JSON.stringify(data));
|
||||
let success = !isError(data.resultCode);
|
||||
let result = { ip: data.ipAddr,
|
||||
prefix: data.maskLength,
|
||||
link: data.flag,
|
||||
mac: data.macAddr };
|
||||
callback.getInterfaceConfigResult(success, result);
|
||||
});
|
||||
},
|
||||
|
||||
runDhcp: function(ifname, callback) {
|
||||
let params = {
|
||||
cmd: "runDhcp",
|
||||
ifname: ifname,
|
||||
isBlocking: true
|
||||
};
|
||||
|
||||
this.controlMessage(params, function(data) {
|
||||
if(DEBUG) debug("runDhcp result: " + JSON.stringify(data));
|
||||
let success = data.success;
|
||||
let result = {
|
||||
ip: data.ipAddr,
|
||||
gateway: data.gateway,
|
||||
dns1: data.dns1,
|
||||
dns2: data.dns2,
|
||||
prefix: data.maskLength,
|
||||
server: data.server
|
||||
};
|
||||
|
||||
callback.runDhcpResult(success, result);
|
||||
});
|
||||
},
|
||||
|
||||
stopDhcp: function(ifname) {
|
||||
let params = {
|
||||
cmd: "stopDhcp",
|
||||
ifname: ifname,
|
||||
isAsync: true
|
||||
};
|
||||
|
||||
this.controlMessage(params);
|
||||
},
|
||||
|
||||
shutdown: false,
|
||||
|
||||
observe: function observe(aSubject, aTopic, aData) {
|
||||
|
@ -1,3 +1,3 @@
|
||||
# NetworkService.js
|
||||
component {baec696c-c78d-42db-8b44-603f8fbfafb4} NetworkService.js
|
||||
contract @mozilla.org/network/service;1 {baec696c-c78d-42db-8b44-603f8fbfafb4}
|
||||
component {48c13741-aec9-4a86-8962-432011708261} NetworkService.js
|
||||
contract @mozilla.org/network/service;1 {48c13741-aec9-4a86-8962-432011708261}
|
||||
|
@ -111,7 +111,7 @@ CommandFunc NetworkUtils::sWifiEnableChain[] = {
|
||||
NetworkUtils::startAccessPointDriver,
|
||||
NetworkUtils::setAccessPoint,
|
||||
NetworkUtils::startSoftAP,
|
||||
NetworkUtils::setInterfaceUp,
|
||||
NetworkUtils::setConfig,
|
||||
NetworkUtils::tetherInterface,
|
||||
NetworkUtils::setIpForwardingEnabled,
|
||||
NetworkUtils::tetheringStatus,
|
||||
@ -152,7 +152,7 @@ CommandFunc NetworkUtils::sWifiRetryChain[] = {
|
||||
NetworkUtils::startAccessPointDriver,
|
||||
NetworkUtils::setAccessPoint,
|
||||
NetworkUtils::startSoftAP,
|
||||
NetworkUtils::setInterfaceUp,
|
||||
NetworkUtils::setConfig,
|
||||
NetworkUtils::tetherInterface,
|
||||
NetworkUtils::setIpForwardingEnabled,
|
||||
NetworkUtils::tetheringStatus,
|
||||
@ -168,7 +168,7 @@ CommandFunc NetworkUtils::sWifiOperationModeChain[] = {
|
||||
};
|
||||
|
||||
CommandFunc NetworkUtils::sUSBEnableChain[] = {
|
||||
NetworkUtils::setInterfaceUp,
|
||||
NetworkUtils::setConfig,
|
||||
NetworkUtils::enableNat,
|
||||
NetworkUtils::setIpForwardingEnabled,
|
||||
NetworkUtils::tetherInterface,
|
||||
@ -201,7 +201,7 @@ CommandFunc NetworkUtils::sUpdateUpStreamChain[] = {
|
||||
};
|
||||
|
||||
CommandFunc NetworkUtils::sStartDhcpServerChain[] = {
|
||||
NetworkUtils::setInterfaceUp,
|
||||
NetworkUtils::setConfig,
|
||||
NetworkUtils::startTethering,
|
||||
NetworkUtils::setDhcpServerSuccess
|
||||
};
|
||||
@ -240,6 +240,21 @@ CommandFunc NetworkUtils::sSetDnsChain[] = {
|
||||
NetworkUtils::setInterfaceDns
|
||||
};
|
||||
|
||||
CommandFunc NetworkUtils::sGetInterfacesChain[] = {
|
||||
NetworkUtils::getInterfaceList,
|
||||
NetworkUtils::getInterfacesSuccess
|
||||
};
|
||||
|
||||
CommandFunc NetworkUtils::sSetInterfaceConfigChain[] = {
|
||||
NetworkUtils::setConfig,
|
||||
NetworkUtils::setInterfaceConfigSuccess
|
||||
};
|
||||
|
||||
CommandFunc NetworkUtils::sGetInterfaceConfigChain[] = {
|
||||
NetworkUtils::getConfig,
|
||||
NetworkUtils::getInterfaceConfigSuccess
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to get the mask from given prefix length.
|
||||
*/
|
||||
@ -322,6 +337,15 @@ static void join(nsTArray<nsCString>& array,
|
||||
#undef CHECK_LEN
|
||||
}
|
||||
|
||||
static void convertUTF8toUTF16(nsTArray<nsCString>& narrow,
|
||||
nsTArray<nsString>& wide,
|
||||
uint32_t length)
|
||||
{
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
wide.AppendElement(NS_ConvertUTF8toUTF16(narrow[i].get()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get network interface properties from the system property table.
|
||||
*/
|
||||
@ -686,9 +710,9 @@ void NetworkUtils::setAlarm(CommandChain* aChain,
|
||||
doCommand(command, aChain, aCallback);
|
||||
}
|
||||
|
||||
void NetworkUtils::setInterfaceUp(CommandChain* aChain,
|
||||
CommandCallback aCallback,
|
||||
NetworkResultOptions& aResult)
|
||||
void NetworkUtils::setConfig(CommandChain* aChain,
|
||||
CommandCallback aCallback,
|
||||
NetworkResultOptions& aResult)
|
||||
{
|
||||
char command[MAX_COMMAND_SIZE];
|
||||
if (SDK_VERSION >= 16) {
|
||||
@ -923,6 +947,26 @@ void NetworkUtils::setInterfaceDns(CommandChain* aChain,
|
||||
doCommand(command, aChain, aCallback);
|
||||
}
|
||||
|
||||
void NetworkUtils::getInterfaceList(CommandChain* aChain,
|
||||
CommandCallback aCallback,
|
||||
NetworkResultOptions& aResult)
|
||||
{
|
||||
char command[MAX_COMMAND_SIZE];
|
||||
snprintf(command, MAX_COMMAND_SIZE - 1, "interface list");
|
||||
|
||||
doCommand(command, aChain, aCallback);
|
||||
}
|
||||
|
||||
void NetworkUtils::getConfig(CommandChain* aChain,
|
||||
CommandCallback aCallback,
|
||||
NetworkResultOptions& aResult)
|
||||
{
|
||||
char command[MAX_COMMAND_SIZE];
|
||||
snprintf(command, MAX_COMMAND_SIZE - 1, "interface getcfg %s", GET_CHAR(mIfname));
|
||||
|
||||
doCommand(command, aChain, aCallback);
|
||||
}
|
||||
|
||||
#undef GET_CHAR
|
||||
#undef GET_FIELD
|
||||
|
||||
@ -1063,6 +1107,75 @@ void NetworkUtils::setDnsFail(NetworkParams& aOptions, NetworkResultOptions& aRe
|
||||
postMessage(aOptions, aResult);
|
||||
}
|
||||
|
||||
void NetworkUtils::getInterfacesFail(NetworkParams& aOptions, NetworkResultOptions& aResult)
|
||||
{
|
||||
postMessage(aOptions, aResult);
|
||||
}
|
||||
|
||||
void NetworkUtils::getInterfacesSuccess(CommandChain* aChain,
|
||||
CommandCallback aCallback,
|
||||
NetworkResultOptions& aResult)
|
||||
{
|
||||
char buf[BUF_SIZE];
|
||||
NS_ConvertUTF16toUTF8 reason(aResult.mResultReason);
|
||||
memcpy(buf, reason.get(), strlen(reason.get()));
|
||||
|
||||
nsTArray<nsCString> result;
|
||||
split(buf, INTERFACE_DELIMIT, result);
|
||||
|
||||
nsTArray<nsString> interfaceList;
|
||||
uint32_t length = result.Length();
|
||||
convertUTF8toUTF16(result, interfaceList, length);
|
||||
|
||||
aResult.mInterfaceList.Construct();
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
aResult.mInterfaceList.Value().AppendElement(interfaceList[i]);
|
||||
}
|
||||
|
||||
postMessage(aChain->getParams(), aResult);
|
||||
}
|
||||
|
||||
void NetworkUtils::setInterfaceConfigFail(NetworkParams& aOptions, NetworkResultOptions& aResult)
|
||||
{
|
||||
postMessage(aOptions, aResult);
|
||||
}
|
||||
|
||||
void NetworkUtils::setInterfaceConfigSuccess(CommandChain* aChain,
|
||||
CommandCallback aCallback,
|
||||
NetworkResultOptions& aResult)
|
||||
{
|
||||
postMessage(aChain->getParams(), aResult);
|
||||
}
|
||||
|
||||
void NetworkUtils::getInterfaceConfigFail(NetworkParams& aOptions, NetworkResultOptions& aResult)
|
||||
{
|
||||
postMessage(aOptions, aResult);
|
||||
}
|
||||
|
||||
void NetworkUtils::getInterfaceConfigSuccess(CommandChain* aChain,
|
||||
CommandCallback aCallback,
|
||||
NetworkResultOptions& aResult)
|
||||
{
|
||||
char buf[BUF_SIZE];
|
||||
NS_ConvertUTF16toUTF8 reason(aResult.mResultReason);
|
||||
memcpy(buf, reason.get(), strlen(reason.get()));
|
||||
|
||||
nsTArray<nsCString> result;
|
||||
split(buf, NETD_MESSAGE_DELIMIT, result);
|
||||
|
||||
ASSIGN_FIELD_VALUE(mMacAddr, NS_ConvertUTF8toUTF16(result[0]))
|
||||
ASSIGN_FIELD_VALUE(mIpAddr, NS_ConvertUTF8toUTF16(result[1]))
|
||||
ASSIGN_FIELD_VALUE(mMaskLength, atof(result[2].get()))
|
||||
|
||||
if (result[3].Find("up")) {
|
||||
ASSIGN_FIELD_VALUE(mFlag, NS_ConvertUTF8toUTF16("up"))
|
||||
} else {
|
||||
ASSIGN_FIELD_VALUE(mFlag, NS_ConvertUTF8toUTF16("down"))
|
||||
}
|
||||
|
||||
postMessage(aChain->getParams(), aResult);
|
||||
}
|
||||
|
||||
#undef ASSIGN_FIELD
|
||||
#undef ASSIGN_FIELD_VALUE
|
||||
|
||||
@ -1127,6 +1240,14 @@ void NetworkUtils::ExecuteCommand(NetworkParams aOptions)
|
||||
enableUsbRndis(aOptions);
|
||||
} else if (aOptions.mCmd.EqualsLiteral("updateUpStream")) {
|
||||
updateUpStream(aOptions);
|
||||
} else if (aOptions.mCmd.EqualsLiteral("getInterfaces")) {
|
||||
getInterfaces(aOptions);
|
||||
} else if (aOptions.mCmd.EqualsLiteral("stopDhcp")) {
|
||||
stopDhcp(aOptions);
|
||||
} else if (aOptions.mCmd.EqualsLiteral("setInterfaceConfig")) {
|
||||
setInterfaceConfig(aOptions);
|
||||
} else if (aOptions.mCmd.EqualsLiteral("getInterfaceConfig")) {
|
||||
getInterfaceConfig(aOptions);
|
||||
} else {
|
||||
WARN("unknon message");
|
||||
return;
|
||||
@ -1716,7 +1837,7 @@ bool NetworkUtils::enableUsbRndis(NetworkParams& aOptions)
|
||||
}
|
||||
|
||||
/**
|
||||
* handling upstream interface change event.
|
||||
* Handling upstream interface change event.
|
||||
*/
|
||||
bool NetworkUtils::updateUpStream(NetworkParams& aOptions)
|
||||
{
|
||||
@ -1724,6 +1845,42 @@ bool NetworkUtils::updateUpStream(NetworkParams& aOptions)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop dhcp client deamon.
|
||||
*/
|
||||
bool NetworkUtils::stopDhcp(NetworkParams& aOptions)
|
||||
{
|
||||
mNetUtils->do_dhcp_stop(GET_CHAR(mIfname));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get existing network interfaces.
|
||||
*/
|
||||
bool NetworkUtils::getInterfaces(NetworkParams& aOptions)
|
||||
{
|
||||
RUN_CHAIN(aOptions, sGetInterfacesChain, getInterfacesFail)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set network config for a specified interface.
|
||||
*/
|
||||
bool NetworkUtils::setInterfaceConfig(NetworkParams& aOptions)
|
||||
{
|
||||
RUN_CHAIN(aOptions, sSetInterfaceConfigChain, setInterfaceConfigFail)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get network config of a specified interface.
|
||||
*/
|
||||
bool NetworkUtils::getInterfaceConfig(NetworkParams& aOptions)
|
||||
{
|
||||
RUN_CHAIN(aOptions, sGetInterfaceConfigChain, getInterfaceConfigFail)
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetworkUtils::sendBroadcastMessage(uint32_t code, char* reason)
|
||||
{
|
||||
NetworkResultOptions result;
|
||||
|
@ -72,6 +72,7 @@ public:
|
||||
mCurInternalIfname = aOther.mCurInternalIfname;
|
||||
mCurExternalIfname = aOther.mCurExternalIfname;
|
||||
mThreshold = aOther.mThreshold;
|
||||
mIsBlocking = aOther.mIsBlocking;
|
||||
}
|
||||
|
||||
NetworkParams(const mozilla::dom::NetworkCommandOptions& aOther) {
|
||||
@ -148,6 +149,7 @@ public:
|
||||
COPY_OPT_STRING_FIELD(mCurInternalIfname, EmptyString())
|
||||
COPY_OPT_STRING_FIELD(mCurExternalIfname, EmptyString())
|
||||
COPY_OPT_FIELD(mThreshold, -1)
|
||||
COPY_OPT_FIELD(mIsBlocking, false)
|
||||
|
||||
#undef COPY_SEQUENCE_FIELD
|
||||
#undef COPY_OPT_STRING_FIELD
|
||||
@ -198,6 +200,7 @@ public:
|
||||
nsString mCurInternalIfname;
|
||||
nsString mCurExternalIfname;
|
||||
long mThreshold;
|
||||
bool mIsBlocking;
|
||||
};
|
||||
|
||||
// CommandChain store the necessary information to execute command one by one.
|
||||
@ -281,6 +284,10 @@ private:
|
||||
bool setUSBTethering(NetworkParams& aOptions);
|
||||
bool enableUsbRndis(NetworkParams& aOptions);
|
||||
bool updateUpStream(NetworkParams& aOptions);
|
||||
bool getInterfaces(NetworkParams& aOptions);
|
||||
bool stopDhcp(NetworkParams& aOptions);
|
||||
bool setInterfaceConfig(NetworkParams& aOptions);
|
||||
bool getInterfaceConfig(NetworkParams& aOptions);
|
||||
|
||||
/**
|
||||
* function pointer array holds all netd commands should be executed
|
||||
@ -302,6 +309,9 @@ private:
|
||||
static CommandFunc sNetworkInterfaceDisableAlarmChain[];
|
||||
static CommandFunc sNetworkInterfaceSetAlarmChain[];
|
||||
static CommandFunc sSetDnsChain[];
|
||||
static CommandFunc sGetInterfacesChain[];
|
||||
static CommandFunc sSetInterfaceConfigChain[];
|
||||
static CommandFunc sGetInterfaceConfigChain[];
|
||||
|
||||
/**
|
||||
* Individual netd command stored in command chain.
|
||||
@ -338,6 +348,9 @@ private:
|
||||
static void disableNat(PARAMS);
|
||||
static void setDefaultInterface(PARAMS);
|
||||
static void setInterfaceDns(PARAMS);
|
||||
static void getInterfaceList(PARAMS);
|
||||
static void setConfig(PARAMS);
|
||||
static void getConfig(PARAMS);
|
||||
static void wifiTetheringSuccess(PARAMS);
|
||||
static void usbTetheringSuccess(PARAMS);
|
||||
static void networkInterfaceStatsSuccess(PARAMS);
|
||||
@ -345,6 +358,9 @@ private:
|
||||
static void updateUpStreamSuccess(PARAMS);
|
||||
static void setDhcpServerSuccess(PARAMS);
|
||||
static void wifiOperationModeSuccess(PARAMS);
|
||||
static void getInterfacesSuccess(PARAMS);
|
||||
static void setInterfaceConfigSuccess(PARAMS);
|
||||
static void getInterfaceConfigSuccess(PARAMS);
|
||||
#undef PARAMS
|
||||
|
||||
/**
|
||||
@ -360,6 +376,9 @@ private:
|
||||
static void networkInterfaceStatsFail(PARAMS);
|
||||
static void networkInterfaceAlarmFail(PARAMS);
|
||||
static void setDnsFail(PARAMS);
|
||||
static void getInterfacesFail(PARAMS);
|
||||
static void setInterfaceConfigFail(PARAMS);
|
||||
static void getInterfaceConfigFail(PARAMS);
|
||||
#undef PARAMS
|
||||
|
||||
/**
|
||||
|
@ -18,6 +18,8 @@ using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
#define PROPERTY_VALUE_MAX 80
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
nsCOMPtr<nsIThread> gWorkerThread;
|
||||
@ -37,6 +39,15 @@ public:
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
#define COPY_FIELD(prop) mResult.prop = aResult.prop;
|
||||
#define COPY_SEQUENCE_FIELD(prop, type) \
|
||||
if (aResult.prop.WasPassed()) { \
|
||||
mozilla::dom::Sequence<type > const & currentValue = aResult.prop.InternalValue(); \
|
||||
uint32_t length = currentValue.Length(); \
|
||||
mResult.prop.Construct(); \
|
||||
for (uint32_t idx = 0; idx < length; idx++) { \
|
||||
mResult.prop.Value().AppendElement(currentValue[idx]); \
|
||||
} \
|
||||
}
|
||||
COPY_FIELD(mId)
|
||||
COPY_FIELD(mRet)
|
||||
COPY_FIELD(mBroadcast)
|
||||
@ -53,6 +64,16 @@ public:
|
||||
COPY_FIELD(mSuccess)
|
||||
COPY_FIELD(mCurExternalIfname)
|
||||
COPY_FIELD(mCurInternalIfname)
|
||||
COPY_FIELD(mIpAddr)
|
||||
COPY_FIELD(mGateway)
|
||||
COPY_FIELD(mDns1)
|
||||
COPY_FIELD(mDns2)
|
||||
COPY_FIELD(mServer)
|
||||
COPY_FIELD(mLease)
|
||||
COPY_FIELD(mVendorInfo)
|
||||
COPY_FIELD(mMaskLength)
|
||||
COPY_FIELD(mFlag)
|
||||
COPY_SEQUENCE_FIELD(mInterfaceList, nsString)
|
||||
#undef COPY_FIELD
|
||||
}
|
||||
|
||||
@ -92,6 +113,66 @@ private:
|
||||
NetworkParams mParams;
|
||||
};
|
||||
|
||||
// Runnable used for blocking command.
|
||||
class RunDhcpEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
RunDhcpEvent(const NetworkParams& aParams)
|
||||
: mParams(aParams)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
nsAutoPtr<NetUtils> netUtils;
|
||||
netUtils = new NetUtils();
|
||||
|
||||
NetworkResultOptions result;
|
||||
result.mId = mParams.mId;
|
||||
|
||||
int32_t status;
|
||||
char ipaddr[PROPERTY_VALUE_MAX];
|
||||
char gateway[PROPERTY_VALUE_MAX];
|
||||
uint32_t prefixLength;
|
||||
char dns1[PROPERTY_VALUE_MAX];
|
||||
char dns2[PROPERTY_VALUE_MAX];
|
||||
char server[PROPERTY_VALUE_MAX];
|
||||
uint32_t lease;
|
||||
char vendorinfo[PROPERTY_VALUE_MAX];
|
||||
status = netUtils->do_dhcp_do_request(NS_ConvertUTF16toUTF8(mParams.mIfname).get(),
|
||||
ipaddr,
|
||||
gateway,
|
||||
&prefixLength,
|
||||
dns1,
|
||||
dns2,
|
||||
server,
|
||||
&lease,
|
||||
vendorinfo);
|
||||
|
||||
|
||||
if (status == 0) {
|
||||
// run dhcp success.
|
||||
result.mSuccess = true;
|
||||
result.mIpAddr = NS_ConvertUTF8toUTF16(ipaddr);
|
||||
result.mGateway = NS_ConvertUTF8toUTF16(gateway);
|
||||
result.mDns1 = NS_ConvertUTF8toUTF16(dns1);
|
||||
result.mDns2 = NS_ConvertUTF8toUTF16(dns2);
|
||||
result.mServer = NS_ConvertUTF8toUTF16(server);
|
||||
result.mLease = lease;
|
||||
result.mVendorInfo = NS_ConvertUTF8toUTF16(vendorinfo);
|
||||
result.mMaskLength = prefixLength;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = new NetworkResultDispatcher(result);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
NetworkParams mParams;
|
||||
};
|
||||
|
||||
// Runnable used dispatch netd result on the worker thread.
|
||||
class NetdEventRunnable : public nsRunnable
|
||||
{
|
||||
@ -224,8 +305,14 @@ NetworkWorker::PostMessage(JS::Handle<JS::Value> aOptions, JSContext* aCx)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Dispatch the command to the control thread.
|
||||
NetworkParams NetworkParams(options);
|
||||
|
||||
if (NetworkParams.mIsBlocking) {
|
||||
NetworkWorker::HandleBlockingCommand(NetworkParams);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Dispatch the command to the control thread.
|
||||
nsCOMPtr<nsIRunnable> runnable = new NetworkCommandDispatcher(NetworkParams);
|
||||
if (gWorkerThread) {
|
||||
gWorkerThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
|
||||
@ -233,6 +320,24 @@ NetworkWorker::PostMessage(JS::Handle<JS::Value> aOptions, JSContext* aCx)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
NetworkWorker::HandleBlockingCommand(NetworkParams& aOptions)
|
||||
{
|
||||
if (aOptions.mCmd.EqualsLiteral("runDhcp")) {
|
||||
NetworkWorker::RunDhcp(aOptions);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
NetworkWorker::RunDhcp(NetworkParams& aOptions)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = new RunDhcpEvent(aOptions);
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
NS_NewThread(getter_AddRefs(thread), runnable);
|
||||
}
|
||||
|
||||
void
|
||||
NetworkWorker::DispatchNetworkResult(const NetworkResultOptions& aOptions)
|
||||
{
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsThread.h"
|
||||
|
||||
class NetworkParams;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class NetworkWorker MOZ_FINAL : public nsINetworkWorker
|
||||
@ -29,6 +31,9 @@ private:
|
||||
|
||||
static void NotifyResult(mozilla::dom::NetworkResultOptions& aResult);
|
||||
|
||||
void HandleBlockingCommand(NetworkParams& aParams);
|
||||
void RunDhcp(NetworkParams& aParams);
|
||||
|
||||
nsCOMPtr<nsINetworkEventListener> mListener;
|
||||
};
|
||||
|
||||
|
@ -9,7 +9,7 @@ interface nsIWifiTetheringCallback;
|
||||
/**
|
||||
* Information about networks that is exposed to network manager API consumers.
|
||||
*/
|
||||
[scriptable, uuid(cb62ae03-6bda-43ff-9560-916d60203d33)]
|
||||
[scriptable, uuid(8f9ab9e0-72c1-4874-80c7-8143353b979f)]
|
||||
interface nsINetworkInterface : nsISupports
|
||||
{
|
||||
const long NETWORK_STATE_UNKNOWN = -1;
|
||||
@ -17,6 +17,8 @@ interface nsINetworkInterface : nsISupports
|
||||
const long NETWORK_STATE_CONNECTED = 1;
|
||||
const long NETWORK_STATE_DISCONNECTING = 2;
|
||||
const long NETWORK_STATE_DISCONNECTED = 3;
|
||||
const long NETWORK_STATE_ENABLED = 4;
|
||||
const long NETWORK_STATE_DISABLED = 5;
|
||||
|
||||
/**
|
||||
* Current network state, one of the NETWORK_STATE_* constants.
|
||||
@ -34,6 +36,7 @@ interface nsINetworkInterface : nsISupports
|
||||
const long NETWORK_TYPE_WIFI_P2P = 4;
|
||||
const long NETWORK_TYPE_MOBILE_IMS = 5;
|
||||
const long NETWORK_TYPE_MOBILE_DUN = 6;
|
||||
const long NETWORK_TYPE_ETHERNET = 7;
|
||||
|
||||
/**
|
||||
* Network type. One of the NETWORK_TYPE_* constants.
|
||||
@ -97,7 +100,7 @@ interface nsINetworkInterface : nsISupports
|
||||
/**
|
||||
* Manage network interfaces.
|
||||
*/
|
||||
[scriptable, uuid(3ea50550-4b3c-11e3-8f96-0800200c9a66)]
|
||||
[scriptable, uuid(1ba9346b-53b5-4660-9dc6-58f0b258d0a6)]
|
||||
interface nsINetworkManager : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -135,6 +138,15 @@ interface nsINetworkManager : nsISupports
|
||||
*/
|
||||
readonly attribute jsval networkInterfaces;
|
||||
|
||||
/**
|
||||
* Priority list of network types. An array of
|
||||
* nsINetworkInterface::NETWORK_TYPE_* constants.
|
||||
*
|
||||
* The piror position of the type indicates the higher priority. The priority
|
||||
* is used to determine route when there are multiple connected networks.
|
||||
*/
|
||||
attribute jsval networkTypePriorityList;
|
||||
|
||||
/**
|
||||
* The preferred network type. One of the
|
||||
* nsINetworkInterface::NETWORK_TYPE_* constants.
|
||||
|
@ -101,10 +101,65 @@ interface nsIUpdateUpStreamCallback : nsISupports
|
||||
void updateUpStreamResult(in boolean success, in DOMString externalIfname);
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(4a9166f3-7e4f-4d10-bb5c-b49ee21d6184)]
|
||||
interface nsIRunDhcpCallback : nsISupports
|
||||
{
|
||||
/**
|
||||
* Callback function used to report the result of dhcp request.
|
||||
*
|
||||
* @param success
|
||||
* Boolean to indicate the operation is successful or not.
|
||||
*/
|
||||
void runDhcpResult(in boolean success, in jsval result);
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(88e3ee22-f1b3-4fa0-8a5d-793fb827c42c)]
|
||||
interface nsIGetInterfacesCallback : nsISupports
|
||||
{
|
||||
/**
|
||||
* Callback function used to return the list of existing network interfaces.
|
||||
*
|
||||
* @param success
|
||||
* Boolean to indicate the operation is successful or not.
|
||||
* @param interfaceList
|
||||
* An array of interface name.
|
||||
*/
|
||||
void getInterfacesResult(in boolean success, in jsval interfaceList);
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(064e02a3-d2c0-42c5-a293-1efa84056100)]
|
||||
interface nsIGetInterfaceConfigCallback : nsISupports
|
||||
{
|
||||
/**
|
||||
* Callback function used to return the network config of a given interface.
|
||||
*
|
||||
* @param success
|
||||
* Boolean to indicate the operation is successful or not.
|
||||
* @param result
|
||||
* .ip: Ip address.
|
||||
* .prefix: mask length.
|
||||
* .link: network link properties.
|
||||
* .mac: mac address.
|
||||
*/
|
||||
void getInterfaceConfigResult(in boolean success, in jsval result);
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(b370f360-6ba8-4517-a4f9-31e8f004ee91)]
|
||||
interface nsISetInterfaceConfigCallback : nsISupports
|
||||
{
|
||||
/**
|
||||
* Callback function used to set network cofig for a specified interface.
|
||||
*
|
||||
* @param success
|
||||
* Boolean to indicate the operation is successful or not.
|
||||
*/
|
||||
void setInterfaceConfigResult(in boolean success);
|
||||
};
|
||||
|
||||
/**
|
||||
* Provide network services.
|
||||
*/
|
||||
[scriptable, uuid(f96461fa-e844-45d2-a6c3-8cd23ab0916b)]
|
||||
[scriptable, uuid(48c13741-aec9-4a86-8962-432011708261)]
|
||||
interface nsINetworkService : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -345,4 +400,53 @@ interface nsINetworkService : nsISupports
|
||||
void updateUpStream(in jsval previous,
|
||||
in jsval current,
|
||||
in nsIUpdateUpStreamCallback callback);
|
||||
|
||||
/**
|
||||
* Run Dhcp request.
|
||||
*
|
||||
* @param ifname
|
||||
* Target interface.
|
||||
* @param callback
|
||||
* Callback function to report the result.
|
||||
*/
|
||||
void runDhcp(in DOMString ifname, in nsIRunDhcpCallback callback);
|
||||
|
||||
/**
|
||||
* Stop Dhcp daemon.
|
||||
*
|
||||
* @param ifname
|
||||
* Target interface.
|
||||
*/
|
||||
void stopDhcp(in DOMString ifname);
|
||||
|
||||
/*
|
||||
* Obtain interfaces list.
|
||||
*
|
||||
* @param callback
|
||||
* Callback function to return the result.
|
||||
*/
|
||||
void getInterfaces(in nsIGetInterfacesCallback callback);
|
||||
|
||||
/**
|
||||
* Set config for a network interface.
|
||||
*
|
||||
* @param config
|
||||
* .ifname: Target interface.
|
||||
* .ip: Ip address.
|
||||
* .prefix: mask length.
|
||||
* .link: network link properties.
|
||||
* @param callback
|
||||
* Callback function to report the result.
|
||||
*/
|
||||
void setInterfaceConfig(in jsval config, in nsISetInterfaceConfigCallback callback);
|
||||
|
||||
/**
|
||||
* Get config of a network interface.
|
||||
*
|
||||
* @param ifname
|
||||
* Target interface.
|
||||
* @param callback
|
||||
* Callback function to report the result.
|
||||
*/
|
||||
void getInterfaceConfig(in DOMString ifname, in nsIGetInterfaceConfigCallback callback);
|
||||
};
|
||||
|
@ -32,9 +32,12 @@
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
||||
<!-- wrap svg in a div so that it can take its intrinsic width -->
|
||||
<div>
|
||||
<svg:svg id="svgbase" width="45" height="20" xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<svg:rect id="svgrect" x="3" y="5" width="45" height="20" fill="red"/>
|
||||
</svg:svg>
|
||||
</div>
|
||||
|
||||
</vbox>
|
||||
|
||||
|
@ -91,7 +91,7 @@ function invalidContent(next) {
|
||||
var request = navigator.mozApps.install(url, null);
|
||||
|
||||
request.onerror = function onInstallError() {
|
||||
is(this.error.name, "INVALID_MANIFEST", "manifest with bad content type");
|
||||
is(this.error.name, "INVALID_MANIFEST_CONTENT_TYPE", "manifest with bad content type");
|
||||
next();
|
||||
};
|
||||
|
||||
|
@ -20,7 +20,7 @@ const char* kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
class Voicemail::Listener : public nsIVoicemailListener
|
||||
class Voicemail::Listener MOZ_FINAL : public nsIVoicemailListener
|
||||
{
|
||||
Voicemail* mVoicemail;
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* This dictionnary holds the parameters sent to the network worker.
|
||||
* This dictionary holds the parameters sent to the network worker.
|
||||
*/
|
||||
dictionary NetworkCommandOptions
|
||||
{
|
||||
@ -55,6 +55,7 @@ dictionary NetworkCommandOptions
|
||||
DOMString preExternalIfname; // for "updateUpStream".
|
||||
DOMString curInternalIfname; // for "updateUpStream".
|
||||
DOMString curExternalIfname; // for "updateUpStream".
|
||||
boolean isBlocking; // for "runDhcp".
|
||||
};
|
||||
|
||||
/**
|
||||
@ -81,4 +82,18 @@ dictionary NetworkResultOptions
|
||||
boolean success = false; // for "setDhcpServer".
|
||||
DOMString curExternalIfname = ""; // for "updateUpStream".
|
||||
DOMString curInternalIfname = ""; // for "updateUpStream".
|
||||
|
||||
DOMString ipAddr = ""; // for "runDhcp", "getInterfaceConfig".
|
||||
DOMString gateway = ""; // for "runDhcp".
|
||||
DOMString dns1 = ""; // for "runDhcp".
|
||||
DOMString dns2 = ""; // for "runDhcp".
|
||||
DOMString server = ""; // for "runDhcp".
|
||||
short lease = 0; // for "runDhcp".
|
||||
DOMString vendorInfo = ""; // for "runDhcp".
|
||||
short maskLength = 0; // for "runDhcp".
|
||||
|
||||
DOMString flag = "down"; // for "getInterfaceConfig".
|
||||
DOMString macAddr = ""; // for "getInterfaceConfig".
|
||||
|
||||
sequence<DOMString> interfaceList; // for "getInterfaceList".
|
||||
};
|
||||
|
@ -213,6 +213,9 @@ class ServiceWorkerUpdateInstance MOZ_FINAL : public nsISupports
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
|
||||
bool mAborted;
|
||||
|
||||
~ServiceWorkerUpdateInstance() {}
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
|
@ -1,15 +0,0 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<script>
|
||||
<![CDATA[
|
||||
|
||||
function boom()
|
||||
{
|
||||
document.createElement("head").innerHTML = "<";
|
||||
}
|
||||
|
||||
]]>
|
||||
</script></head>
|
||||
|
||||
<body onload="boom();"></body>
|
||||
</html>
|
@ -17,14 +17,16 @@
|
||||
|
||||
class nsPrintProgress : public nsIPrintProgress, public nsIPrintStatusFeedback
|
||||
{
|
||||
public:
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIPRINTPROGRESS
|
||||
NS_DECL_NSIWEBPROGRESSLISTENER
|
||||
NS_DECL_NSIPRINTSTATUSFEEDBACK
|
||||
|
||||
nsPrintProgress();
|
||||
virtual ~nsPrintProgress();
|
||||
nsPrintProgress();
|
||||
|
||||
protected:
|
||||
virtual ~nsPrintProgress();
|
||||
|
||||
private:
|
||||
nsresult ReleaseListeners();
|
||||
|
@ -11,12 +11,14 @@
|
||||
|
||||
class nsPrintProgressParams : public nsIPrintProgressParams
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIPRINTPROGRESSPARAMS
|
||||
|
||||
nsPrintProgressParams();
|
||||
virtual ~nsPrintProgressParams();
|
||||
nsPrintProgressParams();
|
||||
|
||||
protected:
|
||||
virtual ~nsPrintProgressParams();
|
||||
|
||||
private:
|
||||
nsString mDocTitle;
|
||||
|
@ -30,7 +30,6 @@ class nsPrintingPromptService: public nsIPrintingPromptService,
|
||||
{
|
||||
public:
|
||||
nsPrintingPromptService();
|
||||
virtual ~nsPrintingPromptService();
|
||||
|
||||
nsresult Init();
|
||||
|
||||
@ -38,6 +37,9 @@ public:
|
||||
NS_DECL_NSIWEBPROGRESSLISTENER
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
protected:
|
||||
virtual ~nsPrintingPromptService();
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIPrintProgress> mPrintProgress;
|
||||
};
|
||||
|
@ -8,6 +8,10 @@
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/NullPtr.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#include "base/message_loop.h"
|
||||
#include "base/task.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -18,10 +22,21 @@ class AtomicRefCountedWithFinalize
|
||||
AtomicRefCountedWithFinalize()
|
||||
: mRecycleCallback(nullptr)
|
||||
, mRefCount(0)
|
||||
, mMessageLoopToPostDestructionTo(nullptr)
|
||||
{}
|
||||
|
||||
~AtomicRefCountedWithFinalize() {}
|
||||
|
||||
void SetMessageLoopToPostDestructionTo(MessageLoop* l) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mMessageLoopToPostDestructionTo = l;
|
||||
}
|
||||
|
||||
static void DestroyToBeCalledOnMainThread(T* ptr) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
public:
|
||||
void AddRef() {
|
||||
MOZ_ASSERT(mRefCount >= 0);
|
||||
@ -43,7 +58,17 @@ class AtomicRefCountedWithFinalize
|
||||
#endif
|
||||
T* derived = static_cast<T*>(this);
|
||||
derived->Finalize();
|
||||
delete derived;
|
||||
if (MOZ_LIKELY(!mMessageLoopToPostDestructionTo)) {
|
||||
delete derived;
|
||||
} else {
|
||||
if (MOZ_LIKELY(NS_IsMainThread())) {
|
||||
delete derived;
|
||||
} else {
|
||||
mMessageLoopToPostDestructionTo->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableFunction(&DestroyToBeCalledOnMainThread, derived));
|
||||
}
|
||||
}
|
||||
} else if (1 == currCount && recycleCallback) {
|
||||
T* derived = static_cast<T*>(this);
|
||||
recycleCallback(derived, mClosure);
|
||||
@ -71,6 +96,7 @@ private:
|
||||
RecycleCallback mRecycleCallback;
|
||||
void *mClosure;
|
||||
Atomic<int> mRefCount;
|
||||
MessageLoop *mMessageLoopToPostDestructionTo;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "basic/BasicLayers.h" // for BasicLayerManager, etc
|
||||
#include "gfx3DMatrix.h" // for gfx3DMatrix
|
||||
#include "gfxASurface.h" // for gfxASurface, etc
|
||||
#include "gfxCachedTempSurface.h" // for gfxCachedTempSurface
|
||||
#include "gfxColor.h" // for gfxRGBA
|
||||
#include "gfxContext.h" // for gfxContext, etc
|
||||
#include "gfxImageSurface.h" // for gfxImageSurface
|
||||
@ -98,7 +97,8 @@ BasicLayerManager::PushGroupForLayer(gfxContext* aContext, Layer* aLayer,
|
||||
// clipped precisely to the visible region.
|
||||
*aNeedsClipToVisibleRegion = !didCompleteClip || aRegion.GetNumRects() > 1;
|
||||
MOZ_ASSERT(!aContext->IsCairo());
|
||||
result = PushGroupWithCachedSurface(aContext, gfxContentType::COLOR);
|
||||
aContext->PushGroup(gfxContentType::COLOR);
|
||||
result = aContext;
|
||||
} else {
|
||||
*aNeedsClipToVisibleRegion = false;
|
||||
result = aContext;
|
||||
@ -235,7 +235,6 @@ BasicLayerManager::BasicLayerManager(nsIWidget* aWidget) :
|
||||
mPhase(PHASE_NONE),
|
||||
mWidget(aWidget)
|
||||
, mDoubleBuffering(BufferMode::BUFFER_NONE), mUsingDefaultTarget(false)
|
||||
, mCachedSurfaceInUse(false)
|
||||
, mTransactionIncomplete(false)
|
||||
, mCompositorMightResample(false)
|
||||
{
|
||||
@ -247,7 +246,6 @@ BasicLayerManager::BasicLayerManager() :
|
||||
mPhase(PHASE_NONE),
|
||||
mWidget(nullptr)
|
||||
, mDoubleBuffering(BufferMode::BUFFER_NONE), mUsingDefaultTarget(false)
|
||||
, mCachedSurfaceInUse(false)
|
||||
, mTransactionIncomplete(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(BasicLayerManager);
|
||||
@ -286,53 +284,6 @@ BasicLayerManager::BeginTransaction()
|
||||
BeginTransactionWithTarget(mDefaultTarget);
|
||||
}
|
||||
|
||||
already_AddRefed<gfxContext>
|
||||
BasicLayerManager::PushGroupWithCachedSurface(gfxContext *aTarget,
|
||||
gfxContentType aContent)
|
||||
{
|
||||
nsRefPtr<gfxContext> ctx;
|
||||
// We can't cache Azure DrawTargets at this point.
|
||||
if (!mCachedSurfaceInUse && aTarget->IsCairo()) {
|
||||
gfxContextMatrixAutoSaveRestore saveMatrix(aTarget);
|
||||
aTarget->IdentityMatrix();
|
||||
|
||||
nsRefPtr<gfxASurface> currentSurf = aTarget->CurrentSurface();
|
||||
gfxRect clip = aTarget->GetClipExtents();
|
||||
clip.RoundOut();
|
||||
|
||||
ctx = mCachedSurface.Get(aContent, clip, currentSurf);
|
||||
|
||||
if (ctx) {
|
||||
mCachedSurfaceInUse = true;
|
||||
/* Align our buffer for the original surface */
|
||||
ctx->SetMatrix(saveMatrix.Matrix());
|
||||
return ctx.forget();
|
||||
}
|
||||
}
|
||||
|
||||
ctx = aTarget;
|
||||
ctx->PushGroup(aContent);
|
||||
return ctx.forget();
|
||||
}
|
||||
|
||||
void
|
||||
BasicLayerManager::PopGroupToSourceWithCachedSurface(gfxContext *aTarget, gfxContext *aPushed)
|
||||
{
|
||||
if (!aTarget)
|
||||
return;
|
||||
if (aTarget->IsCairo()) {
|
||||
nsRefPtr<gfxASurface> current = aPushed->CurrentSurface();
|
||||
if (mCachedSurface.IsSurface(current)) {
|
||||
gfxContextMatrixAutoSaveRestore saveMatrix(aTarget);
|
||||
aTarget->IdentityMatrix();
|
||||
aTarget->SetSource(current);
|
||||
mCachedSurfaceInUse = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
aTarget->PopGroupToSource();
|
||||
}
|
||||
|
||||
void
|
||||
BasicLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
|
||||
{
|
||||
@ -924,7 +875,7 @@ BasicLayerManager::PaintLayer(gfxContext* aTarget,
|
||||
nsRefPtr<gfxContext> groupTarget = PushGroupForLayer(aTarget, aLayer, aLayer->GetEffectiveVisibleRegion(),
|
||||
&needsClipToVisibleRegion);
|
||||
PaintSelfOrChildren(paintLayerContext, groupTarget);
|
||||
PopGroupToSourceWithCachedSurface(aTarget, groupTarget);
|
||||
aTarget->PopGroupToSource();
|
||||
FlushGroup(paintLayerContext, needsClipToVisibleRegion);
|
||||
} else {
|
||||
PaintSelfOrChildren(paintLayerContext, aTarget);
|
||||
@ -988,7 +939,6 @@ BasicLayerManager::ClearCachedResources(Layer* aSubtree)
|
||||
} else if (mRoot) {
|
||||
ClearLayer(mRoot);
|
||||
}
|
||||
mCachedSurface.Expire();
|
||||
}
|
||||
void
|
||||
BasicLayerManager::ClearLayer(Layer* aLayer)
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include <stdint.h> // for INT32_MAX, int32_t
|
||||
#include "Layers.h" // for Layer (ptr only), etc
|
||||
#include "gfxTypes.h"
|
||||
#include "gfxCachedTempSurface.h" // for gfxCachedTempSurface
|
||||
#include "gfxContext.h" // for gfxContext
|
||||
#include "mozilla/Attributes.h" // for MOZ_OVERRIDE
|
||||
#include "mozilla/WidgetUtils.h" // for ScreenRotation
|
||||
@ -136,9 +135,6 @@ public:
|
||||
already_AddRefed<gfxContext> PushGroupForLayer(gfxContext* aContext, Layer* aLayer,
|
||||
const nsIntRegion& aRegion,
|
||||
bool* aNeedsClipToVisibleRegion);
|
||||
already_AddRefed<gfxContext> PushGroupWithCachedSurface(gfxContext *aTarget,
|
||||
gfxContentType aContent);
|
||||
void PopGroupToSourceWithCachedSurface(gfxContext *aTarget, gfxContext *aPushed);
|
||||
|
||||
virtual bool IsCompositingCheap() { return false; }
|
||||
virtual int32_t GetMaxTextureSize() const { return INT32_MAX; }
|
||||
@ -186,12 +182,8 @@ protected:
|
||||
// Image factory we use.
|
||||
nsRefPtr<ImageFactory> mFactory;
|
||||
|
||||
// Cached surface for double buffering
|
||||
gfxCachedTempSurface mCachedSurface;
|
||||
|
||||
BufferMode mDoubleBuffering;
|
||||
bool mUsingDefaultTarget;
|
||||
bool mCachedSurfaceInUse;
|
||||
bool mTransactionIncomplete;
|
||||
bool mCompositorMightResample;
|
||||
};
|
||||
|
@ -93,7 +93,7 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext,
|
||||
SetAntialiasingFlags(this, groupContext);
|
||||
aCallback(this, groupContext, toDraw, DrawRegionClip::CLIP_NONE, nsIntRegion(), aCallbackData);
|
||||
if (needsGroup) {
|
||||
BasicManager()->PopGroupToSourceWithCachedSurface(aContext, groupContext);
|
||||
aContext->PopGroupToSource();
|
||||
if (needsClipToVisibleRegion) {
|
||||
gfxUtils::ClipToRegion(aContext, toDraw);
|
||||
}
|
||||
|
@ -471,11 +471,12 @@ static void
|
||||
FillSurface(gfxASurface* aSurface, const nsIntRegion& aRegion,
|
||||
const nsIntPoint& aOffset, const gfxRGBA& aColor)
|
||||
{
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(aSurface);
|
||||
ctx->Translate(-gfxPoint(aOffset.x, aOffset.y));
|
||||
gfxUtils::ClipToRegion(ctx, aRegion);
|
||||
ctx->SetColor(aColor);
|
||||
ctx->Paint();
|
||||
nsIntRegionRectIterator iter(aRegion);
|
||||
const nsIntRect* r;
|
||||
while ((r = iter.Next()) != nullptr) {
|
||||
nsIntRect rect = *r + aOffset;
|
||||
gfxUtils::ClearThebesSurface(aSurface, &rect, aColor);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -526,17 +527,13 @@ ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode,
|
||||
if (!destinationSurface)
|
||||
return;
|
||||
|
||||
nsRefPtr<gfxContext> context;
|
||||
if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(BackendType::CAIRO)) {
|
||||
RefPtr<DrawTarget> dt =
|
||||
gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(destinationSurface,
|
||||
IntSize(destinationSurface->GetSize().width,
|
||||
destinationSurface->GetSize().height));
|
||||
MOZ_ASSERT(gfxPlatform::GetPlatform()->SupportsAzureContentForType(BackendType::CAIRO));
|
||||
RefPtr<DrawTarget> dt =
|
||||
gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(destinationSurface,
|
||||
IntSize(destinationSurface->GetSize().width,
|
||||
destinationSurface->GetSize().height));
|
||||
|
||||
context = new gfxContext(dt);
|
||||
} else {
|
||||
context = new gfxContext(destinationSurface);
|
||||
}
|
||||
nsRefPtr<gfxContext> context = new gfxContext(dt);
|
||||
|
||||
context->Translate(gfxPoint(-bounds.x, -bounds.y));
|
||||
LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user