diff --git a/configure.in b/configure.in index d91d92e94d3a..7cdf8e5624cc 100644 --- a/configure.in +++ b/configure.in @@ -7798,6 +7798,25 @@ AC_SUBST(PROFILE_GEN_LDFLAGS) AC_SUBST(PROFILE_USE_CFLAGS) AC_SUBST(PROFILE_USE_LDFLAGS) +dnl ============================================= +dnl Support for -fno-integrated-as (recent clang) +dnl ============================================= +dnl Under clang 3.4+, use -fno-integrated-as to +dnl build libvpx's vp8_asm_enc_offsets.c + +_SAVE_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -fno-integrated-as" + +AC_MSG_CHECKING([whether C compiler supports -fno-integrated-as]) +AC_TRY_COMPILE([], [return 0;], + [ NO_INTEGRATED_AS_CFLAGS="-fno-integrated-as" + result="yes" ], result="no") +AC_MSG_RESULT([$result]) + +CFLAGS="$_SAVE_CFLAGS" + +AC_SUBST(NO_INTEGRATED_AS_CFLAGS) + fi # ! SKIP_COMPILER_CHECKS AC_DEFINE(CPP_THROW_NEW, [throw()]) diff --git a/content/base/public/nsIDocument.h b/content/base/public/nsIDocument.h index 9259c24482e3..64f5484ce983 100644 --- a/content/base/public/nsIDocument.h +++ b/content/base/public/nsIDocument.h @@ -66,6 +66,7 @@ class nsIStyleRule; class nsIStyleSheet; class nsIURI; class nsIVariant; +class nsLocation; class nsViewManager; class nsPresContext; class nsRange; @@ -2184,7 +2185,7 @@ public: const nsAString& aQualifiedName, mozilla::ErrorResult& rv); void GetInputEncoding(nsAString& aInputEncoding); - already_AddRefed GetLocation() const; + already_AddRefed GetLocation() const; void GetReferrer(nsAString& aReferrer) const; void GetLastModified(nsAString& aLastModified) const; void GetReadyState(nsAString& aReadyState) const; diff --git a/content/base/src/Link.cpp b/content/base/src/Link.cpp index d5994b6cbed5..21f10cf3c1df 100644 --- a/content/base/src/Link.cpp +++ b/content/base/src/Link.cpp @@ -128,7 +128,7 @@ Link::GetURI() const } void -Link::SetProtocol(const nsAString &aProtocol) +Link::SetProtocol(const nsAString &aProtocol, ErrorResult& aError) { nsCOMPtr uri(GetURIToMutate()); if (!uri) { @@ -147,7 +147,7 @@ Link::SetProtocol(const nsAString &aProtocol) } void -Link::SetPassword(const nsAString &aPassword) +Link::SetPassword(const nsAString &aPassword, ErrorResult& aError) { nsCOMPtr uri(GetURIToMutate()); if (!uri) { @@ -160,7 +160,7 @@ Link::SetPassword(const nsAString &aPassword) } void -Link::SetUsername(const nsAString &aUsername) +Link::SetUsername(const nsAString &aUsername, ErrorResult& aError) { nsCOMPtr uri(GetURIToMutate()); if (!uri) { @@ -173,7 +173,7 @@ Link::SetUsername(const nsAString &aUsername) } void -Link::SetHost(const nsAString &aHost) +Link::SetHost(const nsAString &aHost, ErrorResult& aError) { nsCOMPtr uri(GetURIToMutate()); if (!uri) { @@ -186,7 +186,7 @@ Link::SetHost(const nsAString &aHost) } void -Link::SetHostname(const nsAString &aHostname) +Link::SetHostname(const nsAString &aHostname, ErrorResult& aError) { nsCOMPtr uri(GetURIToMutate()); if (!uri) { @@ -199,7 +199,7 @@ Link::SetHostname(const nsAString &aHostname) } void -Link::SetPathname(const nsAString &aPathname) +Link::SetPathname(const nsAString &aPathname, ErrorResult& aError) { nsCOMPtr uri(GetURIToMutate()); nsCOMPtr url(do_QueryInterface(uri)); @@ -213,7 +213,7 @@ Link::SetPathname(const nsAString &aPathname) } void -Link::SetSearch(const nsAString& aSearch) +Link::SetSearch(const nsAString& aSearch, ErrorResult& aError) { SetSearchInternal(aSearch); UpdateURLSearchParams(); @@ -234,7 +234,7 @@ Link::SetSearchInternal(const nsAString& aSearch) } void -Link::SetPort(const nsAString &aPort) +Link::SetPort(const nsAString &aPort, ErrorResult& aError) { nsCOMPtr uri(GetURIToMutate()); if (!uri) { @@ -259,7 +259,7 @@ Link::SetPort(const nsAString &aPort) } void -Link::SetHash(const nsAString &aHash) +Link::SetHash(const nsAString &aHash, ErrorResult& aError) { nsCOMPtr uri(GetURIToMutate()); if (!uri) { @@ -272,7 +272,7 @@ Link::SetHash(const nsAString &aHash) } void -Link::GetOrigin(nsAString &aOrigin) +Link::GetOrigin(nsAString &aOrigin, ErrorResult& aError) { aOrigin.Truncate(); @@ -287,7 +287,7 @@ Link::GetOrigin(nsAString &aOrigin) } void -Link::GetProtocol(nsAString &_protocol) +Link::GetProtocol(nsAString &_protocol, ErrorResult& aError) { nsCOMPtr uri(GetURI()); if (!uri) { @@ -303,7 +303,7 @@ Link::GetProtocol(nsAString &_protocol) } void -Link::GetUsername(nsAString& aUsername) +Link::GetUsername(nsAString& aUsername, ErrorResult& aError) { aUsername.Truncate(); @@ -318,7 +318,7 @@ Link::GetUsername(nsAString& aUsername) } void -Link::GetPassword(nsAString &aPassword) +Link::GetPassword(nsAString &aPassword, ErrorResult& aError) { aPassword.Truncate(); @@ -333,7 +333,7 @@ Link::GetPassword(nsAString &aPassword) } void -Link::GetHost(nsAString &_host) +Link::GetHost(nsAString &_host, ErrorResult& aError) { _host.Truncate(); @@ -351,7 +351,7 @@ Link::GetHost(nsAString &_host) } void -Link::GetHostname(nsAString &_hostname) +Link::GetHostname(nsAString &_hostname, ErrorResult& aError) { _hostname.Truncate(); @@ -371,7 +371,7 @@ Link::GetHostname(nsAString &_hostname) } void -Link::GetPathname(nsAString &_pathname) +Link::GetPathname(nsAString &_pathname, ErrorResult& aError) { _pathname.Truncate(); @@ -391,7 +391,7 @@ Link::GetPathname(nsAString &_pathname) } void -Link::GetSearch(nsAString &_search) +Link::GetSearch(nsAString &_search, ErrorResult& aError) { _search.Truncate(); @@ -411,7 +411,7 @@ Link::GetSearch(nsAString &_search) } void -Link::GetPort(nsAString &_port) +Link::GetPort(nsAString &_port, ErrorResult& aError) { _port.Truncate(); @@ -433,7 +433,7 @@ Link::GetPort(nsAString &_port) } void -Link::GetHash(nsAString &_hash) +Link::GetHash(nsAString &_hash, ErrorResult& aError) { _hash.Truncate(); diff --git a/content/base/src/Link.h b/content/base/src/Link.h index c378ddde085e..9ade6e495275 100644 --- a/content/base/src/Link.h +++ b/content/base/src/Link.h @@ -57,27 +57,27 @@ public: /** * Helper methods for modifying and obtaining parts of the URI of the Link. */ - void SetProtocol(const nsAString &aProtocol); - void SetUsername(const nsAString &aUsername); - void SetPassword(const nsAString &aPassword); - void SetHost(const nsAString &aHost); - void SetHostname(const nsAString &aHostname); - void SetPathname(const nsAString &aPathname); - void SetSearch(const nsAString &aSearch); + void SetProtocol(const nsAString &aProtocol, ErrorResult& aError); + void SetUsername(const nsAString &aUsername, ErrorResult& aError); + void SetPassword(const nsAString &aPassword, ErrorResult& aError); + void SetHost(const nsAString &aHost, ErrorResult& aError); + void SetHostname(const nsAString &aHostname, ErrorResult& aError); + void SetPathname(const nsAString &aPathname, ErrorResult& aError); + void SetSearch(const nsAString &aSearch, ErrorResult& aError); void SetSearchParams(mozilla::dom::URLSearchParams& aSearchParams); - void SetPort(const nsAString &aPort); - void SetHash(const nsAString &aHash); - void GetOrigin(nsAString &aOrigin); - void GetProtocol(nsAString &_protocol); - void GetUsername(nsAString &aUsername); - void GetPassword(nsAString &aPassword); - void GetHost(nsAString &_host); - void GetHostname(nsAString &_hostname); - void GetPathname(nsAString &_pathname); - void GetSearch(nsAString &_search); + void SetPort(const nsAString &aPort, ErrorResult& aError); + void SetHash(const nsAString &aHash, ErrorResult& aError); + void GetOrigin(nsAString &aOrigin, ErrorResult& aError); + void GetProtocol(nsAString &_protocol, ErrorResult& aError); + void GetUsername(nsAString &aUsername, ErrorResult& aError); + void GetPassword(nsAString &aPassword, ErrorResult& aError); + void GetHost(nsAString &_host, ErrorResult& aError); + void GetHostname(nsAString &_hostname, ErrorResult& aError); + void GetPathname(nsAString &_pathname, ErrorResult& aError); + void GetSearch(nsAString &_search, ErrorResult& aError); URLSearchParams* SearchParams(); - void GetPort(nsAString &_port); - void GetHash(nsAString &_hash); + void GetPort(nsAString &_port, ErrorResult& aError); + void GetHash(nsAString &_hash, ErrorResult& aError); /** * Invalidates any link caching, and resets the state to the default. diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 839e4de5d02b..ecd2b82af969 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -223,6 +223,7 @@ #include "nsContentPermissionHelper.h" #include "mozilla/dom/DOMStringList.h" #include "nsWindowMemoryReporter.h" +#include "nsLocation.h" using namespace mozilla; using namespace mozilla::dom; @@ -6546,7 +6547,7 @@ nsDocument::GetLocation(nsIDOMLocation **_retval) return NS_OK; } -already_AddRefed +already_AddRefed nsIDocument::GetLocation() const { nsCOMPtr w = do_QueryInterface(mScriptGlobalObject); @@ -6557,7 +6558,7 @@ nsIDocument::GetLocation() const nsCOMPtr loc; w->GetLocation(getter_AddRefs(loc)); - return loc.forget(); + return loc.forget().downcast(); } Element* diff --git a/content/canvas/src/CanvasRenderingContext2D.cpp b/content/canvas/src/CanvasRenderingContext2D.cpp index 623d114ca6aa..c0bde17a4983 100644 --- a/content/canvas/src/CanvasRenderingContext2D.cpp +++ b/content/canvas/src/CanvasRenderingContext2D.cpp @@ -367,7 +367,7 @@ public: mCtx->CurrentState().op); } - operator DrawTarget*() + operator DrawTarget*() { return mTarget; } @@ -944,7 +944,8 @@ CanvasRenderingContext2D::EnsureTarget() if (glue && glue->GetGrContext() && glue->GetGLContext()) { mTarget = Factory::CreateDrawTargetSkiaWithGrContext(glue->GetGrContext(), size, format); if (mTarget) { - mStream = gfx::SurfaceStream::CreateForType(SurfaceStreamType::TripleBuffer, glue->GetGLContext()); + mStream = gl::SurfaceStream::CreateForType(gl::SurfaceStreamType::TripleBuffer, + glue->GetGLContext()); AddDemotableContext(this); } else { printf_stderr("Failed to create a SkiaGL DrawTarget, falling back to software\n"); @@ -2526,7 +2527,7 @@ CanvasRenderingContext2D::AddHitRegion(const HitRegionOptions& options, ErrorRes nsINode::DeleteProperty); #endif } - + // finally, add the region to the list RegionInfo info; info.mId = options.mId; @@ -3468,7 +3469,7 @@ CanvasRenderingContext2D::DrawDirectlyToCanvas( nsRefPtr context = new gfxContext(tempTarget); context->SetMatrix(contextMatrix); - + // FLAG_CLAMP is added for increased performance uint32_t modifiedFlags = image.mDrawingFlags | imgIContainer::FLAG_CLAMP; diff --git a/content/canvas/src/CanvasRenderingContext2D.h b/content/canvas/src/CanvasRenderingContext2D.h index 5c7b8dacf49f..9f9d784bfedc 100644 --- a/content/canvas/src/CanvasRenderingContext2D.h +++ b/content/canvas/src/CanvasRenderingContext2D.h @@ -30,7 +30,7 @@ class nsGlobalWindow; class nsXULElement; namespace mozilla { -namespace gfx { +namespace gl { class SourceSurface; class SurfaceStream; } @@ -393,21 +393,21 @@ public: double endAngle, bool anticlockwise, mozilla::ErrorResult& error); void GetMozCurrentTransform(JSContext* cx, - JS::MutableHandle result, - mozilla::ErrorResult& error) const; + JS::MutableHandle result, + mozilla::ErrorResult& error) const; void SetMozCurrentTransform(JSContext* cx, JS::Handle currentTransform, mozilla::ErrorResult& error); void GetMozCurrentTransformInverse(JSContext* cx, - JS::MutableHandle result, - mozilla::ErrorResult& error) const; + JS::MutableHandle result, + mozilla::ErrorResult& error) const; void SetMozCurrentTransformInverse(JSContext* cx, JS::Handle currentTransform, mozilla::ErrorResult& error); void GetFillRule(nsAString& fillRule); void SetFillRule(const nsAString& fillRule); void GetMozDash(JSContext* cx, JS::MutableHandle retval, - mozilla::ErrorResult& error); + mozilla::ErrorResult& error); void SetMozDash(JSContext* cx, const JS::Value& mozDash, mozilla::ErrorResult& error); @@ -661,7 +661,7 @@ protected: void DrawImage(const HTMLImageOrCanvasOrVideoElement &imgElt, double sx, double sy, double sw, double sh, - double dx, double dy, double dw, double dh, + double dx, double dy, double dw, double dh, uint8_t optional_argc, mozilla::ErrorResult& error); void DrawDirectlyToCanvas(const nsLayoutUtils::DirectDrawInfo& image, @@ -711,7 +711,7 @@ protected: // sErrorTarget. mozilla::RefPtr mTarget; - RefPtr mStream; + RefPtr mStream; /** * Flag to avoid duplicate calls to InvalidateFrame. Set to true whenever @@ -789,7 +789,7 @@ protected: // The spec says we should not draw shadows if the operator is OVER. // If it's over and the alpha value is zero, nothing needs to be drawn. - return NS_GET_A(state.shadowColor) != 0 && + return NS_GET_A(state.shadowColor) != 0 && (state.shadowBlur != 0 || state.shadowOffset.x != 0 || state.shadowOffset.y != 0); } diff --git a/content/canvas/src/WebGLContextDraw.cpp b/content/canvas/src/WebGLContextDraw.cpp index 0d70767f6463..d4854aaf5402 100644 --- a/content/canvas/src/WebGLContextDraw.cpp +++ b/content/canvas/src/WebGLContextDraw.cpp @@ -450,7 +450,17 @@ WebGLContext::ValidateBufferFetching(const char *info) maxVertices = std::min(maxVertices, checked_maxAllowedCount.value()); hasPerVertex = true; } else { - maxInstances = std::min(maxInstances, checked_maxAllowedCount.value() / vd.divisor); + CheckedUint32 checked_curMaxInstances = checked_maxAllowedCount * vd.divisor; + + uint32_t curMaxInstances = UINT32_MAX; + // If this isn't valid, it's because we overflowed our + // uint32 above. Just leave this as UINT32_MAX, since + // sizeof(uint32) becomes our limiting factor. + if (checked_curMaxInstances.isValid()) { + curMaxInstances = checked_curMaxInstances.value(); + } + + maxInstances = std::min(maxInstances, curMaxInstances); } } diff --git a/content/html/content/public/HTMLAudioElement.h b/content/html/content/public/HTMLAudioElement.h index 4beac8c8fa00..ba06f2f899de 100644 --- a/content/html/content/public/HTMLAudioElement.h +++ b/content/html/content/public/HTMLAudioElement.h @@ -7,7 +7,6 @@ #define mozilla_dom_HTMLAudioElement_h #include "mozilla/Attributes.h" -#include "nsIDOMHTMLAudioElement.h" #include "mozilla/dom/HTMLMediaElement.h" #include "mozilla/dom/TypedArray.h" @@ -17,21 +16,18 @@ typedef uint16_t nsMediaReadyState; namespace mozilla { namespace dom { -class HTMLAudioElement MOZ_FINAL : public HTMLMediaElement, - public nsIDOMHTMLAudioElement +class HTMLAudioElement MOZ_FINAL : public HTMLMediaElement { public: - HTMLAudioElement(already_AddRefed& aNodeInfo); + typedef mozilla::dom::NodeInfo NodeInfo; - // nsISupports - NS_DECL_ISUPPORTS_INHERITED + HTMLAudioElement(already_AddRefed& aNodeInfo); // nsIDOMHTMLMediaElement using HTMLMediaElement::GetPaused; - NS_FORWARD_NSIDOMHTMLMEDIAELEMENT(HTMLMediaElement::) - virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const; - virtual nsresult SetAcceptHeader(nsIHttpChannel* aChannel); + virtual nsresult Clone(NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE; + virtual nsresult SetAcceptHeader(nsIHttpChannel* aChannel) MOZ_OVERRIDE; virtual nsIDOMNode* AsDOMNode() MOZ_OVERRIDE { return this; } diff --git a/content/html/content/public/HTMLMediaElement.h b/content/html/content/public/HTMLMediaElement.h index cde2717092c5..9bb7726a4232 100644 --- a/content/html/content/public/HTMLMediaElement.h +++ b/content/html/content/public/HTMLMediaElement.h @@ -72,6 +72,7 @@ class AudioTrackList; class VideoTrackList; class HTMLMediaElement : public nsGenericHTMLElement, + public nsIDOMHTMLMediaElement, public nsIObserver, public MediaDecoderOwner, public nsIAudioChannelAgentCallback diff --git a/content/html/content/public/HTMLVideoElement.h b/content/html/content/public/HTMLVideoElement.h index 80843332ce0d..c62aad859414 100644 --- a/content/html/content/public/HTMLVideoElement.h +++ b/content/html/content/public/HTMLVideoElement.h @@ -8,7 +8,6 @@ #define mozilla_dom_HTMLVideoElement_h #include "mozilla/Attributes.h" -#include "nsIDOMHTMLVideoElement.h" #include "mozilla/dom/HTMLMediaElement.h" namespace mozilla { @@ -17,41 +16,38 @@ namespace dom { class WakeLock; class VideoPlaybackQuality; -class HTMLVideoElement MOZ_FINAL : public HTMLMediaElement, - public nsIDOMHTMLVideoElement +class HTMLVideoElement MOZ_FINAL : public HTMLMediaElement { public: - HTMLVideoElement(already_AddRefed& aNodeInfo); + typedef mozilla::dom::NodeInfo NodeInfo; + + HTMLVideoElement(already_AddRefed& aNodeInfo); NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLVideoElement, video) - // nsISupports - NS_DECL_ISUPPORTS_INHERITED - - // nsIDOMHTMLMediaElement using HTMLMediaElement::GetPaused; - NS_FORWARD_NSIDOMHTMLMEDIAELEMENT(HTMLMediaElement::) - // nsIDOMHTMLVideoElement - NS_DECL_NSIDOMHTMLVIDEOELEMENT + NS_IMETHOD_(bool) IsVideo() MOZ_OVERRIDE { + return true; + } virtual bool ParseAttribute(int32_t aNamespaceID, - nsIAtom* aAttribute, - const nsAString& aValue, - nsAttrValue& aResult); + nsIAtom* aAttribute, + const nsAString& aValue, + nsAttrValue& aResult) MOZ_OVERRIDE; NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const MOZ_OVERRIDE; static void Init(); virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const MOZ_OVERRIDE; - virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE; + virtual nsresult Clone(NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE; // Set size with the current video frame's height and width. // If there is no video frame, returns NS_ERROR_FAILURE. nsresult GetVideoSize(nsIntSize* size); - virtual nsresult SetAcceptHeader(nsIHttpChannel* aChannel); + virtual nsresult SetAcceptHeader(nsIHttpChannel* aChannel) MOZ_OVERRIDE; // WebIDL @@ -85,7 +81,10 @@ public: return mMediaSize.height == -1 ? 0 : mMediaSize.height; } - // XPCOM GetPoster is OK + void GetPoster(nsAString& aValue) + { + GetURIAttr(nsGkAtoms::poster, nullptr, aValue); + } void SetPoster(const nsAString& aValue, ErrorResult& aRv) { SetHTMLAttr(nsGkAtoms::poster, aValue, aRv); diff --git a/content/html/content/src/HTMLAnchorElement.cpp b/content/html/content/src/HTMLAnchorElement.cpp index 860fd5d8113e..ceb36a23ed70 100644 --- a/content/html/content/src/HTMLAnchorElement.cpp +++ b/content/html/content/src/HTMLAnchorElement.cpp @@ -300,13 +300,17 @@ HTMLAnchorElement::RelList() NS_IMETHODIMP \ HTMLAnchorElement::Get##_part(nsAString& a##_part) \ { \ - Link::Get##_part(a##_part); \ + ErrorResult rv; \ + Link::Get##_part(a##_part, rv); \ + MOZ_ASSERT(!rv.Failed()); \ return NS_OK; \ } \ NS_IMETHODIMP \ HTMLAnchorElement::Set##_part(const nsAString& a##_part) \ { \ - Link::Set##_part(a##_part); \ + ErrorResult rv; \ + Link::Set##_part(a##_part, rv); \ + MOZ_ASSERT(!rv.Failed()); \ return NS_OK; \ } diff --git a/content/html/content/src/HTMLAnchorElement.h b/content/html/content/src/HTMLAnchorElement.h index 5d86f52ff704..9a0d4e24d947 100644 --- a/content/html/content/src/HTMLAnchorElement.h +++ b/content/html/content/src/HTMLAnchorElement.h @@ -86,7 +86,7 @@ public: virtual bool HasDeferredDNSPrefetchRequest(); // WebIDL API - void GetHref(nsString& aValue) + void GetHref(nsAString& aValue, ErrorResult& rv) { GetHTMLURIAttr(nsGkAtoms::href, aValue); } @@ -145,11 +145,32 @@ public: // Link::GetOrigin is OK for us + using Link::GetProtocol; + using Link::SetProtocol; + // Link::GetUsername is OK for us // Link::SetUsername is OK for us - // Link::Getpassword is OK for us - // Link::Setpassword is OK for us + // Link::GetPassword is OK for us + // Link::SetPassword is OK for us + + using Link::GetHost; + using Link::SetHost; + + using Link::GetHostname; + using Link::SetHostname; + + using Link::GetPort; + using Link::SetPort; + + using Link::GetPathname; + using Link::SetPathname; + + using Link::GetSearch; + using Link::SetSearch; + + using Link::GetHash; + using Link::SetHash; // The XPCOM URI decomposition attributes are fine for us void GetCoords(nsString& aValue) @@ -192,9 +213,9 @@ public: { SetHTMLAttr(nsGkAtoms::shape, aValue, rv); } - void Stringify(nsAString& aResult) + void Stringify(nsAString& aResult, ErrorResult& aError) { - GetHref(aResult); + GetHref(aResult, aError); } protected: diff --git a/content/html/content/src/HTMLAreaElement.cpp b/content/html/content/src/HTMLAreaElement.cpp index f1bd40cc8a6e..94927087c9b8 100644 --- a/content/html/content/src/HTMLAreaElement.cpp +++ b/content/html/content/src/HTMLAreaElement.cpp @@ -202,13 +202,17 @@ HTMLAreaElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute, NS_IMETHODIMP \ HTMLAreaElement::Get##_part(nsAString& a##_part) \ { \ - Link::Get##_part(a##_part); \ + ErrorResult rv; \ + Link::Get##_part(a##_part, rv); \ + MOZ_ASSERT(!rv.Failed()); \ return NS_OK; \ } \ NS_IMETHODIMP \ HTMLAreaElement::Set##_part(const nsAString& a##_part) \ { \ - Link::Set##_part(a##_part); \ + ErrorResult rv; \ + Link::Set##_part(a##_part, rv); \ + MOZ_ASSERT(!rv.Failed()); \ return NS_OK; \ } diff --git a/content/html/content/src/HTMLAreaElement.h b/content/html/content/src/HTMLAreaElement.h index 0c1f53ecca33..fb6502a93972 100644 --- a/content/html/content/src/HTMLAreaElement.h +++ b/content/html/content/src/HTMLAreaElement.h @@ -90,7 +90,10 @@ public: SetHTMLAttr(nsGkAtoms::shape, aShape, aError); } - // The XPCOM GetHref is OK for us + void GetHref(nsAString& aHref, ErrorResult& aError) + { + aError = GetHref(aHref); + } void SetHref(const nsAString& aHref, ErrorResult& aError) { aError = SetHref(aHref); @@ -124,10 +127,11 @@ public: SetHTMLAttr(nsGkAtoms::rel, aRel, aError); } nsDOMTokenList* RelList(); + // The Link::GetOrigin is OK for us - // The XPCOM GetProtocol is OK for us - // The XPCOM SetProtocol is OK for us + using Link::GetProtocol; + using Link::SetProtocol; // The Link::GetUsername is OK for us // The Link::SetUsername is OK for us @@ -135,23 +139,23 @@ public: // The Link::GetPassword is OK for us // The Link::SetPassword is OK for us - // The XPCOM GetHost is OK for us - // The XPCOM SetHost is OK for us + using Link::GetHost; + using Link::SetHost; - // The XPCOM GetHostname is OK for us - // The XPCOM SetHostname is OK for us + using Link::GetHostname; + using Link::SetHostname; - // The XPCOM GetPort is OK for us - // The XPCOM SetPort is OK for us + using Link::GetPort; + using Link::SetPort; - // The XPCOM GetPathname is OK for us - // The XPCOM SetPathname is OK for us + using Link::GetPathname; + using Link::SetPathname; - // The XPCOM GetSearch is OK for us - // The XPCOM SetSearch is OK for us + using Link::GetSearch; + using Link::SetSearch; - // The XPCOM GetHash is OK for us - // The XPCOM SetHash is OK for us + using Link::GetHash; + using Link::SetHash; // The Link::GetSearchParams is OK for us // The Link::SetSearchParams is OK for us @@ -166,9 +170,9 @@ public: SetHTMLBoolAttr(nsGkAtoms::nohref, aValue, aError); } - void Stringify(nsAString& aResult) + void Stringify(nsAString& aResult, ErrorResult& aError) { - GetHref(aResult); + GetHref(aResult, aError); } protected: diff --git a/content/html/content/src/HTMLAudioElement.cpp b/content/html/content/src/HTMLAudioElement.cpp index b4babceaad01..ee8a2168a7b2 100644 --- a/content/html/content/src/HTMLAudioElement.cpp +++ b/content/html/content/src/HTMLAudioElement.cpp @@ -7,7 +7,6 @@ #include "mozilla/dom/HTMLAudioElement.h" #include "mozilla/dom/HTMLAudioElementBinding.h" #include "nsError.h" -#include "nsIDOMHTMLAudioElement.h" #include "nsGenericHTMLElement.h" #include "nsGkAtoms.h" #include "nsIDocument.h" @@ -29,13 +28,10 @@ namespace dom { extern bool IsAudioAPIEnabled(); -NS_IMPL_ISUPPORTS_INHERITED(HTMLAudioElement, HTMLMediaElement, - nsIDOMHTMLMediaElement, nsIDOMHTMLAudioElement) - NS_IMPL_ELEMENT_CLONE(HTMLAudioElement) -HTMLAudioElement::HTMLAudioElement(already_AddRefed& aNodeInfo) +HTMLAudioElement::HTMLAudioElement(already_AddRefed& aNodeInfo) : HTMLMediaElement(aNodeInfo) { } @@ -44,7 +40,6 @@ HTMLAudioElement::~HTMLAudioElement() { } - already_AddRefed HTMLAudioElement::Audio(const GlobalObject& aGlobal, const Optional& aSrc, diff --git a/content/html/content/src/HTMLMediaElement.cpp b/content/html/content/src/HTMLMediaElement.cpp index d76e1cdfe44b..497ed0fb505c 100644 --- a/content/html/content/src/HTMLMediaElement.cpp +++ b/content/html/content/src/HTMLMediaElement.cpp @@ -48,7 +48,6 @@ #include "nsICategoryManager.h" #include "MediaResource.h" -#include "nsIDOMHTMLVideoElement.h" #include "nsIContentPolicy.h" #include "nsContentPolicyUtils.h" #include "nsCrossSiteListenerProxy.h" @@ -458,6 +457,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLE NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLMediaElement) + NS_INTERFACE_MAP_ENTRY(nsIDOMHTMLMediaElement) NS_INTERFACE_MAP_ENTRY(nsIObserver) NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgentCallback) NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement) @@ -488,6 +488,12 @@ HTMLMediaElement::SetMozAudioChannelType(const nsAString& aValue) return SetAttrHelper(nsGkAtoms::mozaudiochannel, aValue); } +NS_IMETHODIMP_(bool) +HTMLMediaElement::IsVideo() +{ + return false; +} + already_AddRefed HTMLMediaElement::GetMozSrcObject() const { @@ -1820,8 +1826,7 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded) // holistically. uint8_t hints = 0; if (Preferences::GetBool("media.capturestream_hints.enabled")) { - nsCOMPtr video = do_QueryObject(this); - if (video && GetVideoFrameContainer()) { + if (IsVideo() && GetVideoFrameContainer()) { hints = DOMMediaStream::HINT_CONTENTS_VIDEO | DOMMediaStream::HINT_CONTENTS_AUDIO; } else { hints = DOMMediaStream::HINT_CONTENTS_AUDIO; @@ -2763,11 +2768,14 @@ public: } aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget()); } - virtual void NotifyFinished(MediaStreamGraph* aGraph) MOZ_OVERRIDE + virtual void NotifyEvent(MediaStreamGraph* aGraph, + MediaStreamListener::MediaStreamGraphEvent event) MOZ_OVERRIDE { - nsCOMPtr event = - NS_NewRunnableMethod(this, &StreamListener::DoNotifyFinished); - aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget()); + if (event == EVENT_FINISHED) { + nsCOMPtr event = + NS_NewRunnableMethod(this, &StreamListener::DoNotifyFinished); + aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget()); + } } virtual void NotifyHasCurrentData(MediaStreamGraph* aGraph) MOZ_OVERRIDE { @@ -3275,9 +3283,9 @@ VideoFrameContainer* HTMLMediaElement::GetVideoFrameContainer() return mVideoFrameContainer; // Only video frames need an image container. - nsCOMPtr video = do_QueryObject(this); - if (!video) + if (!IsVideo()) { return nullptr; + } mVideoFrameContainer = new VideoFrameContainer(this, LayerManager::CreateAsynchronousImageContainer()); @@ -3884,9 +3892,8 @@ void HTMLMediaElement::UpdateAudioChannelPlayingState() if (!mAudioChannelAgent) { return; } - nsCOMPtr video = do_QueryObject(this); // Use a weak ref so the audio channel agent can't leak |this|. - if (AudioChannel::Normal == mAudioChannel && video) { + if (AudioChannel::Normal == mAudioChannel && IsVideo()) { mAudioChannelAgent->InitWithVideo(OwnerDoc()->GetWindow(), static_cast(mAudioChannel), this, true); diff --git a/content/html/content/src/HTMLMetaElement.cpp b/content/html/content/src/HTMLMetaElement.cpp index 0364d2612ef0..0d8f0f4ab7c4 100644 --- a/content/html/content/src/HTMLMetaElement.cpp +++ b/content/html/content/src/HTMLMetaElement.cpp @@ -48,6 +48,21 @@ HTMLMetaElement::SetItemValueText(const nsAString& aValue) } +nsresult +HTMLMetaElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, + const nsAttrValue* aValue, bool aNotify) +{ + if (aNameSpaceID == kNameSpaceID_None) { + if (aName == nsGkAtoms::content) { + nsIDocument *document = GetCurrentDoc(); + CreateAndDispatchEvent(document, NS_LITERAL_STRING("DOMMetaChanged")); + } + } + + return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue, + aNotify); +} + nsresult HTMLMetaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, nsIContent* aBindingParent, diff --git a/content/html/content/src/HTMLMetaElement.h b/content/html/content/src/HTMLMetaElement.h index 71598df5530a..d5ea4b8d4829 100644 --- a/content/html/content/src/HTMLMetaElement.h +++ b/content/html/content/src/HTMLMetaElement.h @@ -30,6 +30,10 @@ public: bool aCompileEventHandlers) MOZ_OVERRIDE; virtual void UnbindFromTree(bool aDeep = true, bool aNullParent = true) MOZ_OVERRIDE; + + virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, + const nsAttrValue* aValue, bool aNotify) MOZ_OVERRIDE; + void CreateAndDispatchEvent(nsIDocument* aDoc, const nsAString& aEventName); virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE; diff --git a/content/html/content/src/HTMLVideoElement.cpp b/content/html/content/src/HTMLVideoElement.cpp index 1b52e68a97c3..4705e6de6074 100644 --- a/content/html/content/src/HTMLVideoElement.cpp +++ b/content/html/content/src/HTMLVideoElement.cpp @@ -4,7 +4,6 @@ * 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 "nsIDOMHTMLVideoElement.h" #include "nsIDOMHTMLSourceElement.h" #include "mozilla/dom/HTMLVideoElement.h" #include "mozilla/dom/HTMLVideoElementBinding.h" @@ -40,31 +39,9 @@ namespace dom { static bool sVideoStatsEnabled; -NS_IMPL_ISUPPORTS_INHERITED(HTMLVideoElement, HTMLMediaElement, - nsIDOMHTMLMediaElement, nsIDOMHTMLVideoElement) - NS_IMPL_ELEMENT_CLONE(HTMLVideoElement) -// nsIDOMHTMLVideoElement -NS_IMPL_INT_ATTR(HTMLVideoElement, Width, width) -NS_IMPL_INT_ATTR(HTMLVideoElement, Height, height) - -// nsIDOMHTMLVideoElement -/* readonly attribute unsigned long videoWidth; */ -NS_IMETHODIMP HTMLVideoElement::GetVideoWidth(uint32_t *aVideoWidth) -{ - *aVideoWidth = VideoWidth(); - return NS_OK; -} - -/* readonly attribute unsigned long videoHeight; */ -NS_IMETHODIMP HTMLVideoElement::GetVideoHeight(uint32_t *aVideoHeight) -{ - *aVideoHeight = VideoHeight(); - return NS_OK; -} - -HTMLVideoElement::HTMLVideoElement(already_AddRefed& aNodeInfo) +HTMLVideoElement::HTMLVideoElement(already_AddRefed& aNodeInfo) : HTMLMediaElement(aNodeInfo) { } @@ -149,8 +126,6 @@ nsresult HTMLVideoElement::SetAcceptHeader(nsIHttpChannel* aChannel) false); } -NS_IMPL_URI_ATTR(HTMLVideoElement, Poster, poster) - uint32_t HTMLVideoElement::MozParsedFrames() const { MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread."); @@ -160,12 +135,6 @@ uint32_t HTMLVideoElement::MozParsedFrames() const return mDecoder ? mDecoder->GetFrameStatistics().GetParsedFrames() : 0; } -NS_IMETHODIMP HTMLVideoElement::GetMozParsedFrames(uint32_t *aMozParsedFrames) -{ - *aMozParsedFrames = MozParsedFrames(); - return NS_OK; -} - uint32_t HTMLVideoElement::MozDecodedFrames() const { MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread."); @@ -175,12 +144,6 @@ uint32_t HTMLVideoElement::MozDecodedFrames() const return mDecoder ? mDecoder->GetFrameStatistics().GetDecodedFrames() : 0; } -NS_IMETHODIMP HTMLVideoElement::GetMozDecodedFrames(uint32_t *aMozDecodedFrames) -{ - *aMozDecodedFrames = MozDecodedFrames(); - return NS_OK; -} - uint32_t HTMLVideoElement::MozPresentedFrames() const { MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread."); @@ -190,12 +153,6 @@ uint32_t HTMLVideoElement::MozPresentedFrames() const return mDecoder ? mDecoder->GetFrameStatistics().GetPresentedFrames() : 0; } -NS_IMETHODIMP HTMLVideoElement::GetMozPresentedFrames(uint32_t *aMozPresentedFrames) -{ - *aMozPresentedFrames = MozPresentedFrames(); - return NS_OK; -} - uint32_t HTMLVideoElement::MozPaintedFrames() { MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread."); @@ -206,12 +163,6 @@ uint32_t HTMLVideoElement::MozPaintedFrames() return container ? container->GetPaintCount() : 0; } -NS_IMETHODIMP HTMLVideoElement::GetMozPaintedFrames(uint32_t *aMozPaintedFrames) -{ - *aMozPaintedFrames = MozPaintedFrames(); - return NS_OK; -} - double HTMLVideoElement::MozFrameDelay() { MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread."); @@ -219,23 +170,12 @@ double HTMLVideoElement::MozFrameDelay() return container ? container->GetFrameDelay() : 0; } -NS_IMETHODIMP HTMLVideoElement::GetMozFrameDelay(double *aMozFrameDelay) { - *aMozFrameDelay = MozFrameDelay(); - return NS_OK; -} - -/* readonly attribute bool mozHasAudio */ bool HTMLVideoElement::MozHasAudio() const { MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread."); return mHasAudio; } -NS_IMETHODIMP HTMLVideoElement::GetMozHasAudio(bool *aHasAudio) { - *aHasAudio = MozHasAudio(); - return NS_OK; -} - JSObject* HTMLVideoElement::WrapNode(JSContext* aCx) { @@ -324,5 +264,6 @@ HTMLVideoElement::Init() { Preferences::AddBoolVarCache(&sVideoStatsEnabled, "media.video_stats.enabled"); } + } // namespace dom } // namespace mozilla diff --git a/content/html/content/src/nsHTMLDNSPrefetch.cpp b/content/html/content/src/nsHTMLDNSPrefetch.cpp index 6090d9f8c775..a9dc8c15bc4f 100644 --- a/content/html/content/src/nsHTMLDNSPrefetch.cpp +++ b/content/html/content/src/nsHTMLDNSPrefetch.cpp @@ -175,7 +175,8 @@ nsHTMLDNSPrefetch::CancelPrefetch(Link *aElement, return NS_ERROR_NOT_AVAILABLE; nsAutoString hostname; - aElement->GetHostname(hostname); + ErrorResult rv; + aElement->GetHostname(hostname, rv); return CancelPrefetch(hostname, flags, aReason); } diff --git a/content/html/document/src/nsHTMLDocument.h b/content/html/document/src/nsHTMLDocument.h index 15a5fffb33dd..5a64797f06ab 100644 --- a/content/html/document/src/nsHTMLDocument.h +++ b/content/html/document/src/nsHTMLDocument.h @@ -240,7 +240,7 @@ public: // The XPCOM CaptureEvents works fine for us. // The XPCOM ReleaseEvents works fine for us. // We're picking up GetLocation from Document - already_AddRefed GetLocation() const { + already_AddRefed GetLocation() const { return nsIDocument::GetLocation(); } diff --git a/content/media/MediaDecoder.cpp b/content/media/MediaDecoder.cpp index 6da23d43a930..6d57184cb64f 100644 --- a/content/media/MediaDecoder.cpp +++ b/content/media/MediaDecoder.cpp @@ -261,13 +261,15 @@ MediaDecoder::DecodedStreamGraphListener::DoNotifyFinished() } void -MediaDecoder::DecodedStreamGraphListener::NotifyFinished(MediaStreamGraph* aGraph) +MediaDecoder::DecodedStreamGraphListener::NotifyEvent(MediaStreamGraph* aGraph, + MediaStreamListener::MediaStreamGraphEvent event) { - nsCOMPtr event = - NS_NewRunnableMethod(this, &DecodedStreamGraphListener::DoNotifyFinished); - aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget()); + if (event == EVENT_FINISHED) { + nsCOMPtr event = + NS_NewRunnableMethod(this, &DecodedStreamGraphListener::DoNotifyFinished); + aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget()); + } } - void MediaDecoder::DestroyDecodedStream() { MOZ_ASSERT(NS_IsMainThread()); diff --git a/content/media/MediaDecoder.h b/content/media/MediaDecoder.h index 3a5247e5b044..795cadc6a092 100755 --- a/content/media/MediaDecoder.h +++ b/content/media/MediaDecoder.h @@ -440,7 +440,8 @@ public: public: DecodedStreamGraphListener(MediaStream* aStream, DecodedStreamData* aData); virtual void NotifyOutput(MediaStreamGraph* aGraph, GraphTime aCurrentTime) MOZ_OVERRIDE; - virtual void NotifyFinished(MediaStreamGraph* aGraph) MOZ_OVERRIDE; + virtual void NotifyEvent(MediaStreamGraph* aGraph, + MediaStreamListener::MediaStreamGraphEvent event) MOZ_OVERRIDE; void DoNotifyFinished(); diff --git a/content/media/MediaStreamGraph.cpp b/content/media/MediaStreamGraph.cpp index 34a7cb4aa546..d918a7116180 100644 --- a/content/media/MediaStreamGraph.cpp +++ b/content/media/MediaStreamGraph.cpp @@ -397,7 +397,7 @@ MediaStreamGraphImpl::UpdateCurrentTime() GraphTime blockedTime = 0; GraphTime t = prevCurrentTime; // include |nextCurrentTime| to ensure NotifyBlockingChanged() is called - // before NotifyFinished() when |nextCurrentTime == stream end time| + // before NotifyEvent(this, EVENT_FINISHED) when |nextCurrentTime == stream end time| while (t <= nextCurrentTime) { GraphTime end; bool blocked = stream->mBlocked.GetAt(t, &end); @@ -460,7 +460,7 @@ MediaStreamGraphImpl::UpdateCurrentTime() SetStreamOrderDirty(); for (uint32_t j = 0; j < stream->mListeners.Length(); ++j) { MediaStreamListener* l = stream->mListeners[j]; - l->NotifyFinished(this); + l->NotifyEvent(this, MediaStreamListener::EVENT_FINISHED); } } } @@ -1933,7 +1933,7 @@ MediaStream::RemoveAllListenersImpl() { for (int32_t i = mListeners.Length() - 1; i >= 0; --i) { nsRefPtr listener = mListeners[i].forget(); - listener->NotifyRemoved(GraphImpl()); + listener->NotifyEvent(GraphImpl(), MediaStreamListener::EVENT_REMOVED); } mListeners.Clear(); } @@ -2111,7 +2111,7 @@ MediaStream::AddListenerImpl(already_AddRefed aListener) listener->NotifyBlockingChanged(GraphImpl(), mNotifiedBlocked ? MediaStreamListener::BLOCKED : MediaStreamListener::UNBLOCKED); if (mNotifiedFinished) { - listener->NotifyFinished(GraphImpl()); + listener->NotifyEvent(GraphImpl(), MediaStreamListener::EVENT_FINISHED); } if (mNotifiedHasCurrentData) { listener->NotifyHasCurrentData(GraphImpl()); @@ -2140,7 +2140,7 @@ MediaStream::RemoveListenerImpl(MediaStreamListener* aListener) // wouldn't need this if we could do it in the opposite order nsRefPtr listener(aListener); mListeners.RemoveElement(aListener); - listener->NotifyRemoved(GraphImpl()); + listener->NotifyEvent(GraphImpl(), MediaStreamListener::EVENT_REMOVED); } void @@ -2367,15 +2367,37 @@ SourceMediaStream::NotifyDirectConsumers(TrackData *aTrack, void SourceMediaStream::AddDirectListener(MediaStreamDirectListener* aListener) { - MutexAutoLock lock(mMutex); - mDirectListeners.AppendElement(aListener); + bool wasEmpty; + { + MutexAutoLock lock(mMutex); + wasEmpty = mDirectListeners.IsEmpty(); + mDirectListeners.AppendElement(aListener); + } + + if (wasEmpty) { + for (uint32_t j = 0; j < mListeners.Length(); ++j) { + MediaStreamListener* l = mListeners[j]; + l->NotifyEvent(GraphImpl(), MediaStreamListener::EVENT_HAS_DIRECT_LISTENERS); + } + } } void SourceMediaStream::RemoveDirectListener(MediaStreamDirectListener* aListener) { - MutexAutoLock lock(mMutex); - mDirectListeners.RemoveElement(aListener); + bool isEmpty; + { + MutexAutoLock lock(mMutex); + mDirectListeners.RemoveElement(aListener); + isEmpty = mDirectListeners.IsEmpty(); + } + + if (isEmpty) { + for (uint32_t j = 0; j < mListeners.Length(); ++j) { + MediaStreamListener* l = mListeners[j]; + l->NotifyEvent(GraphImpl(), MediaStreamListener::EVENT_HAS_NO_DIRECT_LISTENERS); + } + } } bool @@ -2455,7 +2477,7 @@ SourceMediaStream::EndAllTrackAndFinish() data->mCommands |= TRACK_END; } FinishWithLockHeld(); - // we will call NotifyFinished() to let GetUserMedia know + // we will call NotifyEvent() to let GetUserMedia know } TrackTicks diff --git a/content/media/MediaStreamGraph.h b/content/media/MediaStreamGraph.h index 90e09b2f3b5a..57156f8bc3f7 100644 --- a/content/media/MediaStreamGraph.h +++ b/content/media/MediaStreamGraph.h @@ -111,6 +111,7 @@ public: CONSUMED, NOT_CONSUMED }; + /** * Notify that the stream is hooked up and we'd like to start or stop receiving * data on it. Only fires on SourceMediaStreams. @@ -157,16 +158,17 @@ public: */ virtual void NotifyOutput(MediaStreamGraph* aGraph, GraphTime aCurrentTime) {} - /** - * Notify that the stream finished. - */ - virtual void NotifyFinished(MediaStreamGraph* aGraph) {} + enum MediaStreamGraphEvent { + EVENT_FINISHED, + EVENT_REMOVED, + EVENT_HAS_DIRECT_LISTENERS, // transition from no direct listeners + EVENT_HAS_NO_DIRECT_LISTENERS, // transition to no direct listeners + }; /** - * Notify that your listener has been removed, either due to RemoveListener(), - * or due to the stream being destroyed. You will get no further notifications. + * Notify that an event has occurred on the Stream */ - virtual void NotifyRemoved(MediaStreamGraph* aGraph) {} + virtual void NotifyEvent(MediaStreamGraph* aGraph, MediaStreamGraphEvent aEvent) {} enum { TRACK_EVENT_CREATED = 0x01, diff --git a/content/media/encoder/MediaEncoder.cpp b/content/media/encoder/MediaEncoder.cpp index 919465653c2d..aabc15982162 100644 --- a/content/media/encoder/MediaEncoder.cpp +++ b/content/media/encoder/MediaEncoder.cpp @@ -64,17 +64,17 @@ MediaEncoder::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, } void -MediaEncoder::NotifyRemoved(MediaStreamGraph* aGraph) +MediaEncoder::NotifyEvent(MediaStreamGraph* aGraph, + MediaStreamListener::MediaStreamGraphEvent event) { // In case that MediaEncoder does not receive a TRACK_EVENT_ENDED event. LOG(PR_LOG_DEBUG, ("NotifyRemoved in [MediaEncoder].")); if (mAudioEncoder) { - mAudioEncoder->NotifyRemoved(aGraph); + mAudioEncoder->NotifyEvent(aGraph, event); } if (mVideoEncoder) { - mVideoEncoder->NotifyRemoved(aGraph); + mVideoEncoder->NotifyEvent(aGraph, event); } - } /* static */ diff --git a/content/media/encoder/MediaEncoder.h b/content/media/encoder/MediaEncoder.h index 78acdcfff6a1..d67242f8f969 100644 --- a/content/media/encoder/MediaEncoder.h +++ b/content/media/encoder/MediaEncoder.h @@ -80,12 +80,13 @@ public : TrackRate aTrackRate, TrackTicks aTrackOffset, uint32_t aTrackEvents, - const MediaSegment& aQueuedMedia); + const MediaSegment& aQueuedMedia) MOZ_OVERRIDE; /** * Notified the stream is being removed. */ - virtual void NotifyRemoved(MediaStreamGraph* aGraph); + virtual void NotifyEvent(MediaStreamGraph* aGraph, + MediaStreamListener::MediaStreamGraphEvent event) MOZ_OVERRIDE; /** * Creates an encoder with a given MIME type. Returns null if we are unable diff --git a/content/media/encoder/TrackEncoder.h b/content/media/encoder/TrackEncoder.h index 7ed2e4f3d568..41921282dbf4 100644 --- a/content/media/encoder/TrackEncoder.h +++ b/content/media/encoder/TrackEncoder.h @@ -13,11 +13,10 @@ #include "StreamBuffer.h" #include "TrackMetadataBase.h" #include "VideoSegment.h" +#include "MediaStreamGraph.h" namespace mozilla { -class MediaStreamGraph; - /** * Base class of AudioTrackEncoder and VideoTrackEncoder. Lifetimes managed by * MediaEncoder. Most methods can only be called on the MediaEncoder's thread, @@ -49,7 +48,13 @@ public: * Notified by the same callback of MediaEncoder when it has been removed from * MediaStreamGraph. Called on the MediaStreamGraph thread. */ - void NotifyRemoved(MediaStreamGraph* aGraph) { NotifyEndOfStream(); } + void NotifyEvent(MediaStreamGraph* aGraph, + MediaStreamListener::MediaStreamGraphEvent event) + { + if (event == MediaStreamListener::MediaStreamGraphEvent::EVENT_REMOVED) { + NotifyEndOfStream(); + } + } /** * Creates and sets up meta data for a specific codec, called on the worker diff --git a/content/media/gmp/GMPParent.cpp b/content/media/gmp/GMPParent.cpp index 2e3a5d228f46..12969ff4c4a8 100644 --- a/content/media/gmp/GMPParent.cpp +++ b/content/media/gmp/GMPParent.cpp @@ -13,6 +13,7 @@ #include "nsThreadUtils.h" #include "nsIRunnable.h" #include "mozIGeckoMediaPluginService.h" +#include "mozilla/unused.h" namespace mozilla { namespace gmp { @@ -126,7 +127,8 @@ GMPParent::VideoDecoderDestroyed(GMPVideoDecoderParent* aDecoder) { MOZ_ASSERT(GMPThread() == NS_GetCurrentThread()); - MOZ_ALWAYS_TRUE(mVideoDecoders.RemoveElement(aDecoder)); + // If the constructor fails, we'll get called before it's added + unused << NS_WARN_IF(!mVideoDecoders.RemoveElement(aDecoder)); // Recv__delete__ is on the stack, don't potentially destroy the top-level actor // until after this has completed. @@ -139,7 +141,8 @@ GMPParent::VideoEncoderDestroyed(GMPVideoEncoderParent* aEncoder) { MOZ_ASSERT(GMPThread() == NS_GetCurrentThread()); - MOZ_ALWAYS_TRUE(mVideoEncoders.RemoveElement(aEncoder)); + // If the constructor fails, we'll get called before it's added + unused << NS_WARN_IF(!mVideoEncoders.RemoveElement(aEncoder)); // Recv__delete__ is on the stack, don't potentially destroy the top-level actor // until after this has completed. diff --git a/content/media/omx/MediaCodecProxy.cpp b/content/media/omx/MediaCodecProxy.cpp new file mode 100644 index 000000000000..82e73bc671d9 --- /dev/null +++ b/content/media/omx/MediaCodecProxy.cpp @@ -0,0 +1,392 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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 "MediaCodecProxy.h" + +#include + +#include + +namespace android { + +sp +MediaCodecProxy::CreateByType(sp aLooper, + const char *aMime, + bool aEncoder, + bool aAsync, + wp aListener) +{ + sp codec = new MediaCodecProxy(aLooper, aMime, aEncoder, aAsync, aListener); + if ((!aAsync && codec->allocated()) || codec->requestResource()) { + return codec; + } + return nullptr; +} + +MediaCodecProxy::MediaCodecProxy(sp aLooper, + const char *aMime, + bool aEncoder, + bool aAsync, + wp aListener) + : mCodecLooper(aLooper) + , mCodecMime(aMime) + , mCodecEncoder(aEncoder) + , mListener(aListener) +{ + MOZ_ASSERT(mCodecLooper != nullptr, "ALooper should not be nullptr."); + if (aAsync) { + mResourceHandler = new MediaResourceHandler(this); + } else { + allocateCodec(); + } +} + +MediaCodecProxy::~MediaCodecProxy() +{ + releaseCodec(); + + // Complete all pending Binder ipc transactions + IPCThreadState::self()->flushCommands(); + + cancelResource(); +} + +bool +MediaCodecProxy::requestResource() +{ + if (mResourceHandler == nullptr) { + return false; + } + + if (strncasecmp(mCodecMime.get(), "video/", 6) == 0) { + mResourceHandler->requestResource(mCodecEncoder + ? IMediaResourceManagerService::HW_VIDEO_ENCODER + : IMediaResourceManagerService::HW_VIDEO_DECODER); + } else if (strncasecmp(mCodecMime.get(), "audio/", 6) == 0) { + mResourceHandler->requestResource(mCodecEncoder + ? IMediaResourceManagerService::HW_AUDIO_ENCODER + : IMediaResourceManagerService::HW_AUDIO_DECODER); + } else { + return false; + } + + return true; +} + +void +MediaCodecProxy::cancelResource() +{ + if (mResourceHandler == nullptr) { + return; + } + + mResourceHandler->cancelResource(); +} + +bool +MediaCodecProxy::allocateCodec() +{ + if (mCodecLooper == nullptr) { + return false; + } + + // Write Lock for mCodec + RWLock::AutoWLock awl(mCodecLock); + + // Create MediaCodec + mCodec = MediaCodec::CreateByType(mCodecLooper, mCodecMime.get(), mCodecEncoder); + if (mCodec == nullptr) { + return false; + } + + return true; +} + +void +MediaCodecProxy::releaseCodec() +{ + wp codec; + + { + // Write Lock for mCodec + RWLock::AutoWLock awl(mCodecLock); + + codec = mCodec; + + // Release MediaCodec + if (mCodec != nullptr) { + mCodec->release(); + mCodec = nullptr; + } + } + + while (codec.promote() != nullptr) { + // this value come from stagefright's AwesomePlayer. + usleep(1000); + } +} + +bool +MediaCodecProxy::allocated() const +{ + // Read Lock for mCodec + RWLock::AutoRLock arl(mCodecLock); + + return mCodec != nullptr; +} + +status_t +MediaCodecProxy::configure(const sp &aFormat, + const sp &aNativeWindow, + const sp &aCrypto, + uint32_t aFlags) +{ + // Read Lock for mCodec + RWLock::AutoRLock arl(mCodecLock); + + if (mCodec == nullptr) { + return NO_INIT; + } + return mCodec->configure(aFormat, aNativeWindow, aCrypto, aFlags); +} + +status_t +MediaCodecProxy::start() +{ + // Read Lock for mCodec + RWLock::AutoRLock arl(mCodecLock); + + if (mCodec == nullptr) { + return NO_INIT; + } + return mCodec->start(); +} + +status_t +MediaCodecProxy::stop() +{ + // Read Lock for mCodec + RWLock::AutoRLock arl(mCodecLock); + + if (mCodec == nullptr) { + return NO_INIT; + } + return mCodec->stop(); +} + +status_t +MediaCodecProxy::release() +{ + // Read Lock for mCodec + RWLock::AutoRLock arl(mCodecLock); + + if (mCodec == nullptr) { + return NO_INIT; + } + return mCodec->release(); +} + +status_t +MediaCodecProxy::flush() +{ + // Read Lock for mCodec + RWLock::AutoRLock arl(mCodecLock); + + if (mCodec == nullptr) { + return NO_INIT; + } + return mCodec->flush(); +} + +status_t +MediaCodecProxy::queueInputBuffer(size_t aIndex, + size_t aOffset, + size_t aSize, + int64_t aPresentationTimeUs, + uint32_t aFlags, + AString *aErrorDetailMessage) +{ + // Read Lock for mCodec + RWLock::AutoRLock arl(mCodecLock); + + if (mCodec == nullptr) { + return NO_INIT; + } + return mCodec->queueInputBuffer(aIndex, aOffset, aSize, + aPresentationTimeUs, aFlags, aErrorDetailMessage); +} + +status_t +MediaCodecProxy::queueSecureInputBuffer(size_t aIndex, + size_t aOffset, + const CryptoPlugin::SubSample *aSubSamples, + size_t aNumSubSamples, + const uint8_t aKey[16], + const uint8_t aIV[16], + CryptoPlugin::Mode aMode, + int64_t aPresentationTimeUs, + uint32_t aFlags, + AString *aErrorDetailMessage) +{ + // Read Lock for mCodec + RWLock::AutoRLock arl(mCodecLock); + + if (mCodec == nullptr) { + return NO_INIT; + } + return mCodec->queueSecureInputBuffer(aIndex, aOffset, + aSubSamples, aNumSubSamples, aKey, aIV, aMode, + aPresentationTimeUs, aFlags, aErrorDetailMessage); +} + +status_t +MediaCodecProxy::dequeueInputBuffer(size_t *aIndex, + int64_t aTimeoutUs) +{ + // Read Lock for mCodec + RWLock::AutoRLock arl(mCodecLock); + + if (mCodec == nullptr) { + return NO_INIT; + } + return mCodec->dequeueInputBuffer(aIndex, aTimeoutUs); +} + +status_t +MediaCodecProxy::dequeueOutputBuffer(size_t *aIndex, + size_t *aOffset, + size_t *aSize, + int64_t *aPresentationTimeUs, + uint32_t *aFlags, + int64_t aTimeoutUs) +{ + // Read Lock for mCodec + RWLock::AutoRLock arl(mCodecLock); + + if (mCodec == nullptr) { + return NO_INIT; + } + return mCodec->dequeueOutputBuffer(aIndex, aOffset, aSize, + aPresentationTimeUs, aFlags, aTimeoutUs); +} + +status_t +MediaCodecProxy::renderOutputBufferAndRelease(size_t aIndex) +{ + // Read Lock for mCodec + RWLock::AutoRLock arl(mCodecLock); + + if (mCodec == nullptr) { + return NO_INIT; + } + return mCodec->renderOutputBufferAndRelease(aIndex); +} + +status_t +MediaCodecProxy::releaseOutputBuffer(size_t aIndex) +{ + // Read Lock for mCodec + RWLock::AutoRLock arl(mCodecLock); + + if (mCodec == nullptr) { + return NO_INIT; + } + return mCodec->releaseOutputBuffer(aIndex); +} + +status_t +MediaCodecProxy::signalEndOfInputStream() +{ + // Read Lock for mCodec + RWLock::AutoRLock arl(mCodecLock); + + if (mCodec == nullptr) { + return NO_INIT; + } + return mCodec->signalEndOfInputStream(); +} + +status_t +MediaCodecProxy::getOutputFormat(sp *aFormat) const +{ + // Read Lock for mCodec + RWLock::AutoRLock arl(mCodecLock); + + if (mCodec == nullptr) { + return NO_INIT; + } + return mCodec->getOutputFormat(aFormat); +} + +status_t +MediaCodecProxy::getInputBuffers(Vector> *aBuffers) const +{ + // Read Lock for mCodec + RWLock::AutoRLock arl(mCodecLock); + + if (mCodec == nullptr) { + return NO_INIT; + } + return mCodec->getInputBuffers(aBuffers); +} + +status_t +MediaCodecProxy::getOutputBuffers(Vector> *aBuffers) const +{ + // Read Lock for mCodec + RWLock::AutoRLock arl(mCodecLock); + + if (mCodec == nullptr) { + return NO_INIT; + } + return mCodec->getOutputBuffers(aBuffers); +} + +void +MediaCodecProxy::requestActivityNotification(const sp &aNotify) +{ + // Read Lock for mCodec + RWLock::AutoRLock arl(mCodecLock); + + if (mCodec == nullptr) { + return; + } + mCodec->requestActivityNotification(aNotify); +} + +// Called on a Binder thread +void +MediaCodecProxy::resourceReserved() +{ + // Create MediaCodec + releaseCodec(); + if (!allocateCodec()) { + cancelResource(); + return; + } + + // Notification + sp listener = mListener.promote(); + if (listener != nullptr) { + listener->codecReserved(); + } +} + +// Called on a Binder thread +void +MediaCodecProxy::resourceCanceled() +{ + // Release MediaCodec + releaseCodec(); + + // Notification + sp listener = mListener.promote(); + if (listener != nullptr) { + listener->codecCanceled(); + } +} + +} // namespace android diff --git a/content/media/omx/MediaCodecProxy.h b/content/media/omx/MediaCodecProxy.h new file mode 100644 index 000000000000..3b4435b24664 --- /dev/null +++ b/content/media/omx/MediaCodecProxy.h @@ -0,0 +1,156 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MEDIA_CODEC_PROXY_H +#define MEDIA_CODEC_PROXY_H + +#include + +#include +#include + +#include "MediaResourceHandler.h" + +namespace android { + +class MediaCodecProxy : public MediaResourceHandler::ResourceListener +{ +public: + /* Codec resource notification listener. + * All functions are called on the Binder thread. + */ + struct CodecResourceListener : public virtual RefBase { + /* The codec resource is reserved and can be granted. + * The client can allocate the requested resource. + */ + virtual void codecReserved() = 0; + /* The codec resource is not reserved any more. + * The client should release the resource as soon as possible if the + * resource is still being held. + */ + virtual void codecCanceled() = 0; + }; + + // Check whether MediaCodec has been allocated. + bool allocated() const; + + // Static MediaCodec methods + // Only support MediaCodec::CreateByType() + static sp CreateByType(sp aLooper, + const char *aMime, + bool aEncoder, + bool aAsync=false, + wp aListener=nullptr); + + // MediaCodec methods + status_t configure(const sp &aFormat, + const sp &aNativeWindow, + const sp &aCrypto, + uint32_t aFlags); + + status_t start(); + + status_t stop(); + + status_t release(); + + status_t flush(); + + status_t queueInputBuffer(size_t aIndex, + size_t aOffset, + size_t aSize, + int64_t aPresentationTimeUs, + uint32_t aFlags, + AString *aErrorDetailMessage=nullptr); + + status_t queueSecureInputBuffer(size_t aIndex, + size_t aOffset, + const CryptoPlugin::SubSample *aSubSamples, + size_t aNumSubSamples, + const uint8_t aKey[16], + const uint8_t aIV[16], + CryptoPlugin::Mode aMode, + int64_t aPresentationTimeUs, + uint32_t aFlags, + AString *aErrorDetailMessage=nullptr); + + status_t dequeueInputBuffer(size_t *aIndex, + int64_t aTimeoutUs=INT64_C(0)); + + status_t dequeueOutputBuffer(size_t *aIndex, + size_t *aOffset, + size_t *aSize, + int64_t *aPresentationTimeUs, + uint32_t *aFlags, + int64_t aTimeoutUs=INT64_C(0)); + + status_t renderOutputBufferAndRelease(size_t aIndex); + + status_t releaseOutputBuffer(size_t aIndex); + + status_t signalEndOfInputStream(); + + status_t getOutputFormat(sp *aFormat) const; + + status_t getInputBuffers(Vector> *aBuffers) const; + + status_t getOutputBuffers(Vector> *aBuffers) const; + + // Notification will be posted once there "is something to do", i.e. + // an input/output buffer has become available, a format change is + // pending, an error is pending. + void requestActivityNotification(const sp &aNotify); + +protected: + virtual ~MediaCodecProxy(); + + // MediaResourceHandler::EventListener::resourceReserved() + virtual void resourceReserved(); + // MediaResourceHandler::EventListener::resourceCanceled() + virtual void resourceCanceled(); + +private: + // Forbidden + MediaCodecProxy() MOZ_DELETE; + MediaCodecProxy(const MediaCodecProxy &) MOZ_DELETE; + const MediaCodecProxy &operator=(const MediaCodecProxy &) MOZ_DELETE; + + // Constructor for MediaCodecProxy::CreateByType + MediaCodecProxy(sp aLooper, + const char *aMime, + bool aEncoder, + bool aAsync, + wp aListener); + + // Request Resource + bool requestResource(); + // Cancel Resource + void cancelResource(); + + // Allocate Codec Resource + bool allocateCodec(); + // Release Codec Resource + void releaseCodec(); + + // MediaCodec Parameter + sp mCodecLooper; + nsCString mCodecMime; + bool mCodecEncoder; + + // Codec Resource Notification Listener + wp mListener; + + // Media Resource Management + sp mResourceHandler; + + // MediaCodec instance + mutable RWLock mCodecLock; + sp mCodec; +}; + +} // namespace android + +#endif // MEDIA_CODEC_PROXY_H diff --git a/content/media/omx/mediaresourcemanager/IMediaResourceManagerService.h b/content/media/omx/mediaresourcemanager/IMediaResourceManagerService.h index 24dc190975b5..3bd8d1bbf5b0 100644 --- a/content/media/omx/mediaresourcemanager/IMediaResourceManagerService.h +++ b/content/media/omx/mediaresourcemanager/IMediaResourceManagerService.h @@ -27,6 +27,7 @@ public: HW_VIDEO_DECODER = 0, HW_AUDIO_DECODER, // Not supported currently. HW_VIDEO_ENCODER, + HW_AUDIO_ENCODER, // Not supported currently. HW_CAMERA, // Not supported currently. NUM_OF_RESOURCE_TYPES, INVALID_RESOURCE_TYPE = -1 diff --git a/content/media/omx/mediaresourcemanager/MediaResourceHandler.cpp b/content/media/omx/mediaresourcemanager/MediaResourceHandler.cpp new file mode 100644 index 000000000000..26c5c2ee44b8 --- /dev/null +++ b/content/media/omx/mediaresourcemanager/MediaResourceHandler.cpp @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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 "MediaResourceHandler.h" + +#include "mozilla/NullPtr.h" + +namespace android { + +MediaResourceHandler::MediaResourceHandler(const wp &aListener) + : mListener(aListener) + , mState(MediaResourceManagerClient::CLIENT_STATE_WAIT_FOR_RESOURCE) + , mType(IMediaResourceManagerService::INVALID_RESOURCE_TYPE) +{ +} + +MediaResourceHandler::~MediaResourceHandler() +{ + cancelResource(); +} + +bool +MediaResourceHandler::requestResource(IMediaResourceManagerService::ResourceType aType) +{ + Mutex::Autolock al(mLock); + + if (mClient != nullptr && mService != nullptr) { + return false; + } + + sp client = new MediaResourceManagerClient(this); + sp service = client->getMediaResourceManagerService(); + + if (service == nullptr) { + return false; + } + + if (service->requestMediaResource(client, (int)aType, true) != OK) { + return false; + } + + mClient = client; + mService = service; + mType = aType; + + return true; +} + +void +MediaResourceHandler::cancelResource() +{ + Mutex::Autolock al(mLock); + + if (mClient != nullptr && mService != nullptr) { + mService->cancelClient(mClient, (int)mType); + } + + mClient = nullptr; + mService = nullptr; +} + +// Called on a Binder thread +void +MediaResourceHandler::statusChanged(int aEvent) +{ + sp listener; + + Mutex::Autolock autoLock(mLock); + + MediaResourceManagerClient::State state = (MediaResourceManagerClient::State)aEvent; + if (state == mState) { + return; + } + + mState = state; + + listener = mListener.promote(); + if (listener == nullptr) { + return; + } + + if (mState == MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) { + listener->resourceReserved(); + } else { + listener->resourceCanceled(); + } +} + +} // namespace android diff --git a/content/media/omx/mediaresourcemanager/MediaResourceHandler.h b/content/media/omx/mediaresourcemanager/MediaResourceHandler.h new file mode 100644 index 000000000000..04268f7e7504 --- /dev/null +++ b/content/media/omx/mediaresourcemanager/MediaResourceHandler.h @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MEDIA_RESOURCE_HANDLER_H +#define MEDIA_RESOURCE_HANDLER_H + +#include + +#include + +#include "MediaResourceManagerClient.h" + +namespace android { + +class MediaResourceHandler : public MediaResourceManagerClient::EventListener +{ +public: + /* Resource notification listener. + * All functions are called on the Binder thread. + */ + struct ResourceListener : public virtual RefBase { + /* The resource is reserved and can be granted. + * The client can allocate the requested resource. + */ + virtual void resourceReserved() = 0; + /* The resource is not reserved any more. + * The client should release the resource as soon as possible if the + * resource is still being held. + */ + virtual void resourceCanceled() = 0; + }; + + MediaResourceHandler(const wp &aListener); + + virtual ~MediaResourceHandler(); + + // Request Resource + bool requestResource(IMediaResourceManagerService::ResourceType aType); + // Cancel Resource + void cancelResource(); + +protected: + // MediaResourceManagerClient::EventListener::statusChanged() + virtual void statusChanged(int event); + +private: + // Forbidden + MediaResourceHandler() MOZ_DELETE; + MediaResourceHandler(const MediaResourceHandler &) MOZ_DELETE; + const MediaResourceHandler &operator=(const MediaResourceHandler &) MOZ_DELETE; + + // Resource Notification Listener + wp mListener; + + // Resource Management + Mutex mLock; + MediaResourceManagerClient::State mState; + sp mClient; + sp mService; + IMediaResourceManagerService::ResourceType mType; +}; + +} // namespace android + +#endif // MEDIA_RESOURCE_HANDLER_H diff --git a/content/media/omx/mediaresourcemanager/moz.build b/content/media/omx/mediaresourcemanager/moz.build index 024ccf809cb0..e9d6841e9918 100644 --- a/content/media/omx/mediaresourcemanager/moz.build +++ b/content/media/omx/mediaresourcemanager/moz.build @@ -16,6 +16,7 @@ SOURCES += [ 'IMediaResourceManagerClient.cpp', 'IMediaResourceManagerDeathNotifier.cpp', 'IMediaResourceManagerService.cpp', + 'MediaResourceHandler.cpp', 'MediaResourceManagerClient.cpp', 'MediaResourceManagerService.cpp', ] diff --git a/content/media/omx/moz.build b/content/media/omx/moz.build index c577820d49f7..2dd24ba7ea82 100755 --- a/content/media/omx/moz.build +++ b/content/media/omx/moz.build @@ -47,6 +47,14 @@ if 'rtsp' in CONFIG['NECKO_PROTOCOLS']: 'RtspOmxReader.cpp', ] +if int(CONFIG['ANDROID_VERSION']) >= 16: + EXPORTS += [ + 'MediaCodecProxy.h', + ] + SOURCES += [ + 'MediaCodecProxy.cpp', + ] + include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'gklayout' diff --git a/content/media/webrtc/MediaEngine.h b/content/media/webrtc/MediaEngine.h index b03ca2f4ce31..241c6b4dfabe 100644 --- a/content/media/webrtc/MediaEngine.h +++ b/content/media/webrtc/MediaEngine.h @@ -86,6 +86,9 @@ public: * immediately after. */ virtual nsresult Start(SourceMediaStream*, TrackID) = 0; + /* tell the source if there are any direct listeners attached */ + virtual void SetDirectListeners(bool) = 0; + /* Take a snapshot from this source. In the case of video this is a single * image, and for audio, it is a snippet lasting aDuration milliseconds. The * duration argument is ignored for a MediaEngineVideoSource. diff --git a/content/media/webrtc/MediaEngineDefault.h b/content/media/webrtc/MediaEngineDefault.h index e64895ae2259..0cfd70e8a15f 100644 --- a/content/media/webrtc/MediaEngineDefault.h +++ b/content/media/webrtc/MediaEngineDefault.h @@ -45,6 +45,7 @@ public: virtual nsresult Deallocate(); virtual nsresult Start(SourceMediaStream*, TrackID); virtual nsresult Stop(SourceMediaStream*, TrackID); + virtual void SetDirectListeners(bool aHasDirectListeners) {}; virtual nsresult Snapshot(uint32_t aDuration, nsIDOMFile** aFile); virtual nsresult Config(bool aEchoOn, uint32_t aEcho, bool aAgcOn, uint32_t aAGC, @@ -100,6 +101,7 @@ public: virtual nsresult Deallocate(); virtual nsresult Start(SourceMediaStream*, TrackID); virtual nsresult Stop(SourceMediaStream*, TrackID); + virtual void SetDirectListeners(bool aHasDirectListeners) {}; virtual nsresult Snapshot(uint32_t aDuration, nsIDOMFile** aFile); virtual nsresult Config(bool aEchoOn, uint32_t aEcho, bool aAgcOn, uint32_t aAGC, diff --git a/content/media/webrtc/MediaEngineTabVideoSource.h b/content/media/webrtc/MediaEngineTabVideoSource.h index 94de33193c1d..4cab38cf3a53 100644 --- a/content/media/webrtc/MediaEngineTabVideoSource.h +++ b/content/media/webrtc/MediaEngineTabVideoSource.h @@ -24,6 +24,7 @@ class MediaEngineTabVideoSource : public MediaEngineVideoSource, nsIDOMEventList const mozilla::MediaEnginePrefs&); virtual nsresult Deallocate(); virtual nsresult Start(mozilla::SourceMediaStream*, mozilla::TrackID); + virtual void SetDirectListeners(bool aHasDirectListeners) {}; virtual nsresult Snapshot(uint32_t, nsIDOMFile**); virtual void NotifyPull(mozilla::MediaStreamGraph*, mozilla::SourceMediaStream*, mozilla::TrackID, mozilla::StreamTime, mozilla::TrackTicks&); virtual nsresult Stop(mozilla::SourceMediaStream*, mozilla::TrackID); diff --git a/content/media/webrtc/MediaEngineWebRTC.h b/content/media/webrtc/MediaEngineWebRTC.h index a323de9cd24d..79e1fae12c36 100644 --- a/content/media/webrtc/MediaEngineWebRTC.h +++ b/content/media/webrtc/MediaEngineWebRTC.h @@ -104,6 +104,7 @@ public: , mMonitor("WebRTCCamera.Monitor") , mWidth(0) , mHeight(0) + , mHasDirectListeners(false) , mInitDone(false) , mInSnapshotMode(false) , mSnapshotPath(nullptr) @@ -131,6 +132,7 @@ public: , mMonitor("WebRTCCamera.Monitor") , mWidth(0) , mHeight(0) + , mHasDirectListeners(false) , mInitDone(false) , mInSnapshotMode(false) , mSnapshotPath(nullptr) { @@ -147,6 +149,7 @@ public: virtual nsresult Deallocate(); virtual nsresult Start(SourceMediaStream*, TrackID); virtual nsresult Stop(SourceMediaStream*, TrackID); + virtual void SetDirectListeners(bool aHasListeners); virtual nsresult Snapshot(uint32_t aDuration, nsIDOMFile** aFile); virtual nsresult Config(bool aEchoOn, uint32_t aEcho, bool aAgcOn, uint32_t aAGC, @@ -245,6 +248,7 @@ private: int mWidth, mHeight; nsRefPtr mImage; nsRefPtr mImageContainer; + bool mHasDirectListeners; nsTArray mSources; // When this goes empty, we shut down HW @@ -297,6 +301,7 @@ public: virtual nsresult Deallocate(); virtual nsresult Start(SourceMediaStream*, TrackID); virtual nsresult Stop(SourceMediaStream*, TrackID); + virtual void SetDirectListeners(bool aHasDirectListeners) {}; virtual nsresult Snapshot(uint32_t aDuration, nsIDOMFile** aFile); virtual nsresult Config(bool aEchoOn, uint32_t aEcho, bool aAgcOn, uint32_t aAGC, diff --git a/content/media/webrtc/MediaEngineWebRTCVideo.cpp b/content/media/webrtc/MediaEngineWebRTCVideo.cpp index bc343459f6c3..353572301e23 100644 --- a/content/media/webrtc/MediaEngineWebRTCVideo.cpp +++ b/content/media/webrtc/MediaEngineWebRTCVideo.cpp @@ -584,6 +584,13 @@ MediaEngineWebRTCVideoSource::Stop(SourceMediaStream *aSource, TrackID aID) return NS_OK; } +void +MediaEngineWebRTCVideoSource::SetDirectListeners(bool aHasDirectListeners) +{ + LOG((__FUNCTION__)); + mHasDirectListeners = aHasDirectListeners; +} + nsresult MediaEngineWebRTCVideoSource::Snapshot(uint32_t aDuration, nsIDOMFile** aFile) { @@ -734,16 +741,19 @@ GetRotateAmount(ScreenOrientation aScreen, int aCameraMountAngle, bool aBackCame } // undefine to remove on-the-fly rotation support -// #define DYNAMIC_GUM_ROTATION +#define DYNAMIC_GUM_ROTATION void MediaEngineWebRTCVideoSource::Notify(const hal::ScreenConfiguration& aConfiguration) { #ifdef DYNAMIC_GUM_ROTATION - MonitorAutoLock enter(mMonitor); - mRotation = GetRotateAmount(aConfiguration.orientation(), mCameraAngle, mBackCamera); + if (mHasDirectListeners) { + // aka hooked to PeerConnection + MonitorAutoLock enter(mMonitor); + mRotation = GetRotateAmount(aConfiguration.orientation(), mCameraAngle, mBackCamera); - LOG(("*** New orientation: %d (Camera %d Back %d MountAngle: %d)", - mRotation, mCaptureIndex, mBackCamera, mCameraAngle)); + LOG(("*** New orientation: %d (Camera %d Back %d MountAngle: %d)", + mRotation, mCaptureIndex, mBackCamera, mCameraAngle)); + } #endif } diff --git a/content/media/webspeech/recognition/SpeechStreamListener.cpp b/content/media/webspeech/recognition/SpeechStreamListener.cpp index 1f2aba605e77..d8f77c3bb9e4 100644 --- a/content/media/webspeech/recognition/SpeechStreamListener.cpp +++ b/content/media/webspeech/recognition/SpeechStreamListener.cpp @@ -84,7 +84,8 @@ SpeechStreamListener::ConvertAndDispatchAudioChunk(int aDuration, float aVolume, } void -SpeechStreamListener::NotifyFinished(MediaStreamGraph* aGraph) +SpeechStreamListener::NotifyEvent(MediaStreamGraph* aGraph, + MediaStreamListener::MediaStreamGraphEvent event) { // TODO dispatch SpeechEnd event so services can be informed } diff --git a/content/media/webspeech/recognition/SpeechStreamListener.h b/content/media/webspeech/recognition/SpeechStreamListener.h index e6550a1ef1fa..ca6a11fcda67 100644 --- a/content/media/webspeech/recognition/SpeechStreamListener.h +++ b/content/media/webspeech/recognition/SpeechStreamListener.h @@ -30,7 +30,8 @@ public: uint32_t aTrackEvents, const MediaSegment& aQueuedMedia) MOZ_OVERRIDE; - void NotifyFinished(MediaStreamGraph* aGraph) MOZ_OVERRIDE; + void NotifyEvent(MediaStreamGraph* aGraph, + MediaStreamListener::MediaStreamGraphEvent event) MOZ_OVERRIDE; private: template diff --git a/content/media/webspeech/synth/nsSpeechTask.cpp b/content/media/webspeech/synth/nsSpeechTask.cpp index e75a7df38825..2a2b5e6477e4 100644 --- a/content/media/webspeech/synth/nsSpeechTask.cpp +++ b/content/media/webspeech/synth/nsSpeechTask.cpp @@ -49,11 +49,23 @@ public: } } - virtual void NotifyFinished(MediaStreamGraph* aGraph) + virtual void NotifyEvent(MediaStreamGraph* aGraph, + MediaStreamListener::MediaStreamGraphEvent event) MOZ_OVERRIDE { - nsCOMPtr event = - NS_NewRunnableMethod(this, &SynthStreamListener::DoNotifyFinished); - aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget()); + switch (event) { + case EVENT_FINISHED: + { + nsCOMPtr runnable = + NS_NewRunnableMethod(this, &SynthStreamListener::DoNotifyFinished); + aGraph->DispatchToMainThreadAfterStreamStateUpdate(runnable.forget()); + } + break; + case EVENT_REMOVED: + mSpeechTask = nullptr; + break; + default: + break; + } } virtual void NotifyBlockingChanged(MediaStreamGraph* aGraph, Blocking aBlocked) @@ -66,11 +78,6 @@ public: } } - virtual void NotifyRemoved(MediaStreamGraph* aGraph) - { - mSpeechTask = nullptr; - } - private: // Raw pointer; if we exist, the stream exists, // and 'mSpeechTask' exclusively owns it and therefor exists as well. diff --git a/content/svg/content/src/SVGEllipseElement.cpp b/content/svg/content/src/SVGEllipseElement.cpp index 512193af87c3..488f62345771 100644 --- a/content/svg/content/src/SVGEllipseElement.cpp +++ b/content/svg/content/src/SVGEllipseElement.cpp @@ -103,8 +103,7 @@ SVGEllipseElement::ConstructPath(gfxContext *aCtx) RefPtr builder = dt->CreatePathBuilder(fillRule); RefPtr path = BuildPath(builder); if (path) { - nsRefPtr gfxpath = new gfxPath(path); - aCtx->SetPath(gfxpath); + aCtx->SetPath(path); } } diff --git a/docshell/base/nsIContentViewer.idl b/docshell/base/nsIContentViewer.idl index 2f7999c258fa..7f3d7c549144 100644 --- a/docshell/base/nsIContentViewer.idl +++ b/docshell/base/nsIContentViewer.idl @@ -27,7 +27,7 @@ class nsDOMNavigationTiming; [ptr] native nsViewPtr(nsView); [ptr] native nsDOMNavigationTimingPtr(nsDOMNavigationTiming); -[scriptable, builtinclass, uuid(0cb321bd-5b38-4586-8fcd-d43b366886fb)] +[scriptable, builtinclass, uuid(f92298b8-4fe3-40d1-aad7-44e704fffd0d)] interface nsIContentViewer : nsISupports { @@ -176,8 +176,10 @@ interface nsIContentViewer : nsISupports /** * Returns whether this content viewer is in a hidden state. + * + * @note Only Gecko internal code should set the attribute! */ - readonly attribute boolean isHidden; + attribute boolean isHidden; [noscript] readonly attribute nsIPresShellPtr presShell; [noscript] readonly attribute nsPresContextPtr presContext; diff --git a/dom/apps/tests/file_packaged_app.sjs b/dom/apps/tests/file_packaged_app.sjs index 9e0e44842ea6..90ff6cb133cc 100644 --- a/dom/apps/tests/file_packaged_app.sjs +++ b/dom/apps/tests/file_packaged_app.sjs @@ -20,12 +20,23 @@ var gDevUrl = "http://dev.url"; function handleRequest(request, response) { var query = getQuery(request); - response.setHeader("Access-Control-Allow-Origin", "*", false); - var packageSize = ("packageSize" in query) ? query.packageSize : 0; var appName = ("appName" in query) ? query.appName : gAppName; var devName = ("devName" in query) ? query.devName : gDevName; var devUrl = ("devUrl" in query) ? query.devUrl : gDevUrl; + // allowCancel just means deliver the file slowly so we have time to cancel it + var allowCancel = "allowCancel" in query; + var getPackage = "getPackage" in query; + var alreadyDeferred = Number(getState("alreadyDeferred")); + + if (allowCancel && getPackage && !alreadyDeferred) { + // Only do this for the actual package delivery. + response.processAsync(); + // And to avoid timer problems, only do this once. + setState("alreadyDeferred", "1"); + } + + response.setHeader("Access-Control-Allow-Origin", "*", false); // If this is a version update, update state, prepare the manifest, // the application package and return. @@ -36,7 +47,8 @@ function handleRequest(request, response) { var packageName = "test_packaged_app_" + packageVersion + ".zip"; setState("packageName", packageName); - var packagePath = "/" + gBasePath + "file_packaged_app.sjs?getPackage=" + + var packagePath = "/" + gBasePath + "file_packaged_app.sjs?" + + (allowCancel?"allowCancel&": "") + "getPackage=" + packageName; setState("packagePath", packagePath); @@ -84,11 +96,19 @@ function handleRequest(request, response) { response.setHeader("Etag", etag, false); // Serve the application package corresponding to the requested app version. - if ("getPackage" in query) { + if (getPackage) { var resource = readFile(packageName, true); response.setHeader("Content-Type", "Content-Type: application/java-archive", false); - response.write(resource); + if (allowCancel && !alreadyDeferred) { + var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + timer.initWithCallback(function (aTimer) { + response.write(resource); + response.finish(); + }, 3000, Ci.nsITimer.TYPE_ONE_SHOT); + } else { + response.write(resource); + } return; } diff --git a/dom/apps/tests/test_packaged_app_common.js b/dom/apps/tests/test_packaged_app_common.js index 9a0bddbff4c3..abcdeacf6008 100644 --- a/dom/apps/tests/test_packaged_app_common.js +++ b/dom/apps/tests/test_packaged_app_common.js @@ -57,13 +57,17 @@ var PackagedTestHelper = (function PackagedTestHelper() { finish(); } - function setAppVersion(aVersion, aCb, aDontUpdatePackage) { + function setAppVersion(aVersion, aCb, aDontUpdatePackage, aAllowCancel) { var xhr = new XMLHttpRequest(); var dontUpdate = ""; + var allowCancel = ""; if (aDontUpdatePackage) { dontUpdate = "&dontUpdatePackage=1"; } - var url = gSJS + "?setVersion=" + aVersion + dontUpdate; + if (aAllowCancel) { + allowCancel= "&allowCancel=1"; + } + var url = gSJS + "?setVersion=" + aVersion + dontUpdate + allowCancel; xhr.addEventListener("load", function() { is(xhr.responseText, "OK", "setAppVersion OK"); aCb(); diff --git a/dom/apps/tests/test_packaged_app_install.html b/dom/apps/tests/test_packaged_app_install.html index e3f40b7967f1..2b6bc91a7cb8 100644 --- a/dom/apps/tests/test_packaged_app_install.html +++ b/dom/apps/tests/test_packaged_app_install.html @@ -34,7 +34,7 @@ function checkAppInstallError(aMiniManifestURL, aExpectedError) { req.onerror = function(evt) { var error = evt.target.error.name; if (error == aExpectedError) { - ok(true, "Got expected " + aExpectedError); + info("Got expected " + aExpectedError); PackagedTestHelper.next(); } else { ok(false, "Got unexpected " + error); @@ -46,7 +46,7 @@ function checkAppInstallError(aMiniManifestURL, aExpectedError) { function checkUninstallApp(aApp) { var req = navigator.mozApps.mgmt.uninstall(aApp); req.onsuccess = function() { - ok(true, "App uninstalled"); + info("App uninstalled"); aApp.ondownloadsuccess = null; aApp.ondownloaderror = null; aApp.onprogress = null; @@ -83,11 +83,11 @@ var steps = [ // Set up SpecialPowers.setAllAppsLaunchable(true); SpecialPowers.addPermission("webapps-manage", true, document); - ok(true, "Set up"); + info("Set up"); PackagedTestHelper.next(); }, function() { - ok(true, "autoConfirmAppInstall"); + info("autoConfirmAppInstall"); SpecialPowers.autoConfirmAppInstall(PackagedTestHelper.next); }, function() { @@ -96,17 +96,17 @@ var steps = [ function() { // Bug 927699 - navigator.mozApps.install(url) lets NS_ERROR_FAILURE onto // the web. - ok(true, "== TEST == INVALID_URL"); + info("== TEST == INVALID_URL"); checkAppInstallError("", "INVALID_URL"); }, function() { // Test network error. - ok(true, "== TEST == Network error"); + info("== TEST == Network error"); checkAppInstallError("http://notvalidurl", "NETWORK_ERROR"); }, function() { // Test wrong mini-manifest content type. - ok(true, "== TEST == Not valid mini-manifest content type"); + info("== TEST == Not valid mini-manifest content type"); var miniManifestURL = PackagedTestHelper.gSJS + "?getManifest=true" + "&noManifestContentType=true"; @@ -114,7 +114,7 @@ var steps = [ }, function() { // Test mini-manifest 'size' value is not number. Bug 839435. - ok(true, "== TEST == Size value is not a number"); + info("== TEST == Size value is not a number"); var miniManifestURL = PackagedTestHelper.gSJS + "?getManifest=true" + "&packageSize=\"NotANumber\""; @@ -122,7 +122,7 @@ var steps = [ }, function() { // Test mini-manifest negative 'size' value. Bug 839435. - ok(true, "== TEST == Negative size value"); + info("== TEST == Negative size value"); var miniManifestURL = PackagedTestHelper.gSJS + "?getManifest=true" + "&packageSize=-1"; @@ -130,7 +130,7 @@ var steps = [ }, function() { // Test wrong package path - ok(true, "== TEST == Installing app with wrong package path"); + info("== TEST == Installing app with wrong package path"); var miniManifestURL = PackagedTestHelper.gSJS + "?getManifest=true" + "&wrongPackagePath=true"; @@ -138,7 +138,7 @@ var steps = [ }, function() { // Test no manifest in zip file. - ok(true, "== TEST == No manifest in the zip file"); + info("== TEST == No manifest in the zip file"); var miniManifestURL = PackagedTestHelper.gSJS + "?getManifest=true"; PackagedTestHelper.checkAppDownloadError(miniManifestURL, "MISSING_MANIFEST", 0, true, true, @@ -150,7 +150,7 @@ var steps = [ function() { // Test mini-manifest app name is different from the webapp manifest name. // Bug 844243. - ok(true, "== TEST == Mini-manifest app name is different from webapp " + + info("== TEST == Mini-manifest app name is different from webapp " + "manifest name"); var miniManifestURL = PackagedTestHelper.gSJS + "?getManifest=true" + @@ -187,11 +187,11 @@ var steps = [ PackagedTestHelper.setAppVersion(2, PackagedTestHelper.next); }, function() { - ok(true, "== TEST == Install packaged app"); + info("== TEST == Install packaged app"); var miniManifestURL = PackagedTestHelper.gSJS + "?getManifest=true"; navigator.mozApps.mgmt.oninstall = function(evt) { - ok(true, "Got oninstall event"); + info("Got oninstall event"); PackagedTestHelper.gApp = evt.application; PackagedTestHelper.gApp.ondownloaderror = function() { ok(false, "Download error " + @@ -199,7 +199,7 @@ var steps = [ PackagedTestHelper.finish(); }; PackagedTestHelper.gApp.ondownloadsuccess = function() { - ok(true, "App downloaded"); + info("App downloaded"); var expected = { name: PackagedTestHelper.gAppName, manifestURL: miniManifestURL, @@ -220,11 +220,85 @@ var steps = [ var request = navigator.mozApps.installPackage(miniManifestURL); request.onerror = PackagedTestHelper.mozAppsError; request.onsuccess = function() { - ok(true, "Application installed"); + info("Application installed"); }; }, function() { - ok(true, "all done!\n"); + PackagedTestHelper.setAppVersion(3, PackagedTestHelper.next, false, true); + }, + function() { + info("== TEST == Install packaged app with a cancel/resume"); + var miniManifestURL = PackagedTestHelper.gSJS + + "?getManifest=true&allowCancel"; + navigator.mozApps.mgmt.oninstall = function(evt) { + info("Got oninstall event"); + PackagedTestHelper.gApp = evt.application; + + PackagedTestHelper.gApp.onprogress = function() { + // Let's try cancelling and resuming the download later on. + PackagedTestHelper.gApp.cancelDownload(); + // And only do this once. + PackagedTestHelper.gApp.onprogress = null; + }; + + var alreadyCancelled = false; + PackagedTestHelper.gApp.ondownloaderror = function() { + ok(!alreadyCancelled, "The download should be cancelled only once!"); + is(PackagedTestHelper.gApp.downloadError.name, "DOWNLOAD_CANCELED", + "Download error " + PackagedTestHelper.gApp.downloadError.name); + if (!alreadyCancelled) { + PackagedTestHelper.gApp.download(); + alreadyCancelled = true; + } + }; + + PackagedTestHelper.gApp.ondownloadsuccess = function() { + info("App downloaded"); + // We could try also applying the download we just made. + var expected = { + name: PackagedTestHelper.gAppName, + manifestURL: miniManifestURL, + installOrigin: PackagedTestHelper.gInstallOrigin, + progress: 0, + installState: "pending", + downloadAvailable: false, + downloading: false, + downloadSize: 0, + size: 0, + readyToApplyDownload: true + }; + PackagedTestHelper.checkAppState(PackagedTestHelper.gApp, 3, expected, + true, false, function() {}); + }; + + PackagedTestHelper.gApp.ondownloadapplied = function() { + info("App download applied."); + var expected = { + name: PackagedTestHelper.gAppName, + manifestURL: miniManifestURL, + installOrigin: PackagedTestHelper.gInstallOrigin, + progress: 0, + installState: "installed", + downloadAvailable: false, + downloading: false, + downloadSize: 0, + size: 0, + readyToApplyDownload: false + }; + PackagedTestHelper.checkAppState(PackagedTestHelper.gApp, 3, expected, + true, false, PackagedTestHelper.next); + } + + }; + + var request = navigator.mozApps.installPackage(miniManifestURL); + request.onerror = PackagedTestHelper.mozAppsError; + request.onsuccess = function() { + info("Application installed"); + }; + }, + function() { + info("all done!\n"); PackagedTestHelper.finish(); } ]; diff --git a/dom/base/URL.cpp b/dom/base/URL.cpp index d002dd64e030..80fe487d8471 100644 --- a/dom/base/URL.cpp +++ b/dom/base/URL.cpp @@ -204,7 +204,7 @@ URL::RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aURL) } void -URL::GetHref(nsString& aHref) const +URL::GetHref(nsString& aHref, ErrorResult& aRv) const { aHref.Truncate(); @@ -240,13 +240,13 @@ URL::SetHref(const nsAString& aHref, ErrorResult& aRv) } void -URL::GetOrigin(nsString& aOrigin) const +URL::GetOrigin(nsString& aOrigin, ErrorResult& aRv) const { nsContentUtils::GetUTFNonNullOrigin(mURI, aOrigin); } void -URL::GetProtocol(nsString& aProtocol) const +URL::GetProtocol(nsString& aProtocol, ErrorResult& aRv) const { nsCString protocol; if (NS_SUCCEEDED(mURI->GetScheme(protocol))) { @@ -258,7 +258,7 @@ URL::GetProtocol(nsString& aProtocol) const } void -URL::SetProtocol(const nsAString& aProtocol) +URL::SetProtocol(const nsAString& aProtocol, ErrorResult& aRv) { nsAString::const_iterator start, end; aProtocol.BeginReading(start); @@ -305,37 +305,37 @@ URL::SetProtocol(const nsAString& aProtocol) } void -URL::GetUsername(nsString& aUsername) const +URL::GetUsername(nsString& aUsername, ErrorResult& aRv) const { URL_GETTER(aUsername, GetUsername); } void -URL::SetUsername(const nsAString& aUsername) +URL::SetUsername(const nsAString& aUsername, ErrorResult& aRv) { mURI->SetUsername(NS_ConvertUTF16toUTF8(aUsername)); } void -URL::GetPassword(nsString& aPassword) const +URL::GetPassword(nsString& aPassword, ErrorResult& aRv) const { URL_GETTER(aPassword, GetPassword); } void -URL::SetPassword(const nsAString& aPassword) +URL::SetPassword(const nsAString& aPassword, ErrorResult& aRv) { mURI->SetPassword(NS_ConvertUTF16toUTF8(aPassword)); } void -URL::GetHost(nsString& aHost) const +URL::GetHost(nsString& aHost, ErrorResult& aRv) const { URL_GETTER(aHost, GetHostPort); } void -URL::SetHost(const nsAString& aHost) +URL::SetHost(const nsAString& aHost, ErrorResult& aRv) { mURI->SetHostPort(NS_ConvertUTF16toUTF8(aHost)); } @@ -370,7 +370,7 @@ URL::UpdateURLSearchParams() } void -URL::GetHostname(nsString& aHostname) const +URL::GetHostname(nsString& aHostname, ErrorResult& aRv) const { aHostname.Truncate(); nsAutoCString tmp; @@ -387,7 +387,7 @@ URL::GetHostname(nsString& aHostname) const } void -URL::SetHostname(const nsAString& aHostname) +URL::SetHostname(const nsAString& aHostname, ErrorResult& aRv) { // nsStandardURL returns NS_ERROR_UNEXPECTED for an empty hostname // The return code is silently ignored @@ -395,7 +395,7 @@ URL::SetHostname(const nsAString& aHostname) } void -URL::GetPort(nsString& aPort) const +URL::GetPort(nsString& aPort, ErrorResult& aRv) const { aPort.Truncate(); @@ -409,7 +409,7 @@ URL::GetPort(nsString& aPort) const } void -URL::SetPort(const nsAString& aPort) +URL::SetPort(const nsAString& aPort, ErrorResult& aRv) { nsresult rv; nsAutoString portStr(aPort); @@ -427,7 +427,7 @@ URL::SetPort(const nsAString& aPort) } void -URL::GetPathname(nsString& aPathname) const +URL::GetPathname(nsString& aPathname, ErrorResult& aRv) const { aPathname.Truncate(); @@ -446,7 +446,7 @@ URL::GetPathname(nsString& aPathname) const } void -URL::SetPathname(const nsAString& aPathname) +URL::SetPathname(const nsAString& aPathname, ErrorResult& aRv) { nsCOMPtr url(do_QueryInterface(mURI)); if (!url) { @@ -458,7 +458,7 @@ URL::SetPathname(const nsAString& aPathname) } void -URL::GetSearch(nsString& aSearch) const +URL::GetSearch(nsString& aSearch, ErrorResult& aRv) const { aSearch.Truncate(); @@ -477,7 +477,7 @@ URL::GetSearch(nsString& aSearch) const } void -URL::SetSearch(const nsAString& aSearch) +URL::SetSearch(const nsAString& aSearch, ErrorResult& aRv) { SetSearchInternal(aSearch); UpdateURLSearchParams(); @@ -519,7 +519,7 @@ URL::SetSearchParams(URLSearchParams& aSearchParams) } void -URL::GetHash(nsString& aHash) const +URL::GetHash(nsString& aHash, ErrorResult& aRv) const { aHash.Truncate(); @@ -533,7 +533,7 @@ URL::GetHash(nsString& aHash) const } void -URL::SetHash(const nsAString& aHash) +URL::SetHash(const nsAString& aHash, ErrorResult& aRv) { mURI->SetRef(NS_ConvertUTF16toUTF8(aHash)); } diff --git a/dom/base/URL.h b/dom/base/URL.h index 75bb13c93d67..1ed7b85dcbcb 100644 --- a/dom/base/URL.h +++ b/dom/base/URL.h @@ -69,55 +69,55 @@ public: static void RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aURL); - void GetHref(nsString& aHref) const; + void GetHref(nsString& aHref, ErrorResult& aRv) const; void SetHref(const nsAString& aHref, ErrorResult& aRv); - void GetOrigin(nsString& aOrigin) const; + void GetOrigin(nsString& aOrigin, ErrorResult& aRv) const; - void GetProtocol(nsString& aProtocol) const; + void GetProtocol(nsString& aProtocol, ErrorResult& aRv) const; - void SetProtocol(const nsAString& aProtocol); + void SetProtocol(const nsAString& aProtocol, ErrorResult& aRv); - void GetUsername(nsString& aUsername) const; + void GetUsername(nsString& aUsername, ErrorResult& aRv) const; - void SetUsername(const nsAString& aUsername); + void SetUsername(const nsAString& aUsername, ErrorResult& aRv); - void GetPassword(nsString& aPassword) const; + void GetPassword(nsString& aPassword, ErrorResult& aRv) const; - void SetPassword(const nsAString& aPassword); + void SetPassword(const nsAString& aPassword, ErrorResult& aRv); - void GetHost(nsString& aHost) const; + void GetHost(nsString& aHost, ErrorResult& aRv) const; - void SetHost(const nsAString& aHost); + void SetHost(const nsAString& aHost, ErrorResult& aRv); - void GetHostname(nsString& aHostname) const; + void GetHostname(nsString& aHostname, ErrorResult& aRv) const; - void SetHostname(const nsAString& aHostname); + void SetHostname(const nsAString& aHostname, ErrorResult& aRv); - void GetPort(nsString& aPort) const; + void GetPort(nsString& aPort, ErrorResult& aRv) const; - void SetPort(const nsAString& aPort); + void SetPort(const nsAString& aPort, ErrorResult& aRv); - void GetPathname(nsString& aPathname) const; + void GetPathname(nsString& aPathname, ErrorResult& aRv) const; - void SetPathname(const nsAString& aPathname); + void SetPathname(const nsAString& aPathname, ErrorResult& aRv); - void GetSearch(nsString& aRetval) const; + void GetSearch(nsString& aRetval, ErrorResult& aRv) const; - void SetSearch(const nsAString& aArg); + void SetSearch(const nsAString& aArg, ErrorResult& aRv); URLSearchParams* SearchParams(); void SetSearchParams(URLSearchParams& aSearchParams); - void GetHash(nsString& aRetval) const; + void GetHash(nsString& aRetval, ErrorResult& aRv) const; - void SetHash(const nsAString& aArg); + void SetHash(const nsAString& aArg, ErrorResult& aRv); - void Stringify(nsString& aRetval) const + void Stringify(nsString& aRetval, ErrorResult& aRv) const { - GetHref(aRetval); + GetHref(aRetval, aRv); } // URLSearchParamsObserver diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index a93d8e7b2e8a..f12f6c2fa4eb 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -9649,14 +9649,14 @@ nsGlobalWindow::GetPrivateRoot() } -nsIDOMLocation* +nsLocation* nsGlobalWindow::GetLocation(ErrorResult& aError) { FORWARD_TO_INNER_OR_THROW(GetLocation, (aError), aError, nullptr); nsIDocShell *docShell = GetDocShell(); if (!mLocation && docShell) { - mLocation = new nsLocation(docShell); + mLocation = new nsLocation(this, docShell); } return mLocation; } diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 4e70b9d7926f..3fac9cd869b3 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -827,7 +827,7 @@ public: } void GetName(nsAString& aName, mozilla::ErrorResult& aError); void SetName(const nsAString& aName, mozilla::ErrorResult& aError); - nsIDOMLocation* GetLocation(mozilla::ErrorResult& aError); + nsLocation* GetLocation(mozilla::ErrorResult& aError); nsHistory* GetHistory(mozilla::ErrorResult& aError); mozilla::dom::BarProp* GetLocationbar(mozilla::ErrorResult& aError); mozilla::dom::BarProp* GetMenubar(mozilla::ErrorResult& aError); diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 2144e0d80082..109eb5e2c97e 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -3079,16 +3079,6 @@ mozilla::dom::ShutdownJSEnvironment() sDidShutdown = true; } -class nsJSArgArray; - -namespace mozilla { -template<> -struct HasDangerousPublicDestructor -{ - static const bool value = true; -}; -} - // A fast-array class for JS. This class supports both nsIJSScriptArray and // nsIArray. If it is JS itself providing and consuming this class, all work // can be done via nsIJSScriptArray, and avoid the conversion of elements @@ -3099,7 +3089,7 @@ class nsJSArgArray MOZ_FINAL : public nsIJSArgArray { public: nsJSArgArray(JSContext *aContext, uint32_t argc, JS::Value *argv, nsresult *prv); - ~nsJSArgArray(); + // nsISupports NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSArgArray, @@ -3114,6 +3104,7 @@ public: void ReleaseJSObjects(); protected: + ~nsJSArgArray(); JSContext *mContext; JS::Heap *mArgv; uint32_t mArgc; @@ -3243,13 +3234,11 @@ nsresult NS_CreateJSArgv(JSContext *aContext, uint32_t argc, void *argv, nsIJSArgArray **aArray) { nsresult rv; - nsJSArgArray *ret = new nsJSArgArray(aContext, argc, - static_cast(argv), &rv); - if (ret == nullptr) - return NS_ERROR_OUT_OF_MEMORY; + nsCOMPtr ret = new nsJSArgArray(aContext, argc, + static_cast(argv), &rv); if (NS_FAILED(rv)) { - delete ret; return rv; } - return ret->QueryInterface(NS_GET_IID(nsIArray), (void **)aArray); + ret.forget(aArray); + return NS_OK; } diff --git a/dom/base/nsJSTimeoutHandler.cpp b/dom/base/nsJSTimeoutHandler.cpp index ed387b011cbb..ed38513f36d9 100644 --- a/dom/base/nsJSTimeoutHandler.cpp +++ b/dom/base/nsJSTimeoutHandler.cpp @@ -349,8 +349,8 @@ nsJSScriptTimeoutHandler::Init(nsGlobalWindow *aWindow, bool *aIsInterval, return error.ErrorCode(); } - mExpr.Append(JS_GetFlatStringChars(expr), - JS_GetStringLength(JS_FORGET_STRING_FLATNESS(expr))); + MOZ_ASSERT(mExpr.IsEmpty()); + AssignJSFlatString(mExpr, expr); // Get the calling location. const char *filename; diff --git a/dom/base/nsJSUtils.h b/dom/base/nsJSUtils.h index d78151a21d0c..d9c78a566cfa 100644 --- a/dom/base/nsJSUtils.h +++ b/dom/base/nsJSUtils.h @@ -157,6 +157,18 @@ AssignJSString(JSContext *cx, T &dest, JSString *s) return true; } +inline void +AssignJSFlatString(nsAString &dest, JSFlatString *s) +{ + size_t len = js::GetFlatStringLength(s); + static_assert(js::MaxStringLength < (1 << 28), + "Shouldn't overflow here or in SetCapacity"); + dest.SetCapacity(len + 1); + js::CopyFlatStringChars(dest.BeginWriting(), s, len); + dest.BeginWriting()[len] = '\0'; + dest.SetLength(len); +} + class nsAutoJSString : public nsAutoString { public: diff --git a/dom/base/nsLocation.cpp b/dom/base/nsLocation.cpp index c939e98c169e..4727e4bdb040 100644 --- a/dom/base/nsLocation.cpp +++ b/dom/base/nsLocation.cpp @@ -32,6 +32,10 @@ #include "nsCycleCollectionParticipant.h" #include "nsNullPrincipal.h" #include "ScriptSettings.h" +#include "mozilla/dom/LocationBinding.h" + +using namespace mozilla; +using namespace mozilla::dom; static nsresult GetDocumentCharacterSetForURI(const nsAString& aHref, nsACString& aCharset) @@ -52,13 +56,14 @@ GetDocumentCharacterSetForURI(const nsAString& aHref, nsACString& aCharset) return NS_OK; } -nsLocation::nsLocation(nsIDocShell *aDocShell) +nsLocation::nsLocation(nsPIDOMWindow* aWindow, nsIDocShell *aDocShell) + : mInnerWindow(aWindow) { MOZ_ASSERT(aDocShell); + MOZ_ASSERT(mInnerWindow->IsInnerWindow()); + SetIsDOMBinding(); mDocShell = do_GetWeakReference(aDocShell); - nsCOMPtr outer = aDocShell->GetWindow(); - mOuter = do_GetWeakReference(outer); } nsLocation::~nsLocation() @@ -75,7 +80,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsLocation) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Location) NS_INTERFACE_MAP_END -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsLocation) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsLocation, mInnerWindow) NS_IMPL_CYCLE_COLLECTING_ADDREF(nsLocation) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsLocation) @@ -729,6 +734,102 @@ nsLocation::SetProtocol(const nsAString& aProtocol) return SetURI(uri); } +void +nsLocation::GetUsername(nsAString& aUsername, ErrorResult& aError) +{ + if (!CallerSubsumes()) { + aError.Throw(NS_ERROR_DOM_SECURITY_ERR); + return; + } + + aUsername.Truncate(); + nsCOMPtr uri; + nsresult result = GetURI(getter_AddRefs(uri)); + if (uri) { + nsAutoCString username; + result = uri->GetUsername(username); + if (NS_SUCCEEDED(result)) { + CopyUTF8toUTF16(username, aUsername); + } + } +} + +void +nsLocation::SetUsername(const nsAString& aUsername, ErrorResult& aError) +{ + if (!CallerSubsumes()) { + aError.Throw(NS_ERROR_DOM_SECURITY_ERR); + return; + } + + nsCOMPtr uri; + nsresult rv = GetWritableURI(getter_AddRefs(uri)); + if (NS_WARN_IF(NS_FAILED(rv))) { + aError.Throw(rv); + return; + } + + if (!uri) { + return; + } + + rv = uri->SetUsername(NS_ConvertUTF16toUTF8(aUsername)); + if (NS_WARN_IF(NS_FAILED(rv))) { + aError.Throw(rv); + return; + } + + rv = SetURI(uri); +} + +void +nsLocation::GetPassword(nsAString& aPassword, ErrorResult& aError) +{ + if (!CallerSubsumes()) { + aError.Throw(NS_ERROR_DOM_SECURITY_ERR); + return; + } + + aPassword.Truncate(); + nsCOMPtr uri; + nsresult result = GetURI(getter_AddRefs(uri)); + if (uri) { + nsAutoCString password; + result = uri->GetPassword(password); + if (NS_SUCCEEDED(result)) { + CopyUTF8toUTF16(password, aPassword); + } + } +} + +void +nsLocation::SetPassword(const nsAString& aPassword, ErrorResult& aError) +{ + if (!CallerSubsumes()) { + aError.Throw(NS_ERROR_DOM_SECURITY_ERR); + return; + } + + nsCOMPtr uri; + nsresult rv = GetWritableURI(getter_AddRefs(uri)); + if (NS_WARN_IF(NS_FAILED(rv))) { + aError.Throw(rv); + return; + } + + if (!uri) { + return; + } + + rv = uri->SetPassword(NS_ConvertUTF16toUTF8(aPassword)); + if (NS_WARN_IF(NS_FAILED(rv))) { + aError.Throw(rv); + return; + } + + rv = SetURI(uri); +} + NS_IMETHODIMP nsLocation::GetSearch(nsAString& aSearch) { @@ -918,8 +1019,12 @@ nsLocation::GetSourceBaseURL(JSContext* cx, nsIURI** sourceURL) bool nsLocation::CallerSubsumes() { - // Get the principal associated with the location object. - nsCOMPtr outer = do_QueryReferent(mOuter); + // Get the principal associated with the location object. Note that this is + // the principal of the page which will actually be navigated, not the + // principal of the Location object itself. This is why we need this check + // even though we only allow limited cross-origin access to Location objects + // in general. + nsCOMPtr outer = mInnerWindow->GetOuterWindow(); if (MOZ_UNLIKELY(!outer)) return false; nsCOMPtr sop = do_QueryInterface(outer); @@ -928,3 +1033,9 @@ nsLocation::CallerSubsumes() NS_ENSURE_SUCCESS(rv, false); return subsumes; } + +JSObject* +nsLocation::WrapObject(JSContext* aCx) +{ + return LocationBinding::Wrap(aCx, this); +} diff --git a/dom/base/nsLocation.h b/dom/base/nsLocation.h index f688f5737931..f3fc3b4d73e6 100644 --- a/dom/base/nsLocation.h +++ b/dom/base/nsLocation.h @@ -13,6 +13,8 @@ #include "nsWrapperCache.h" #include "nsCycleCollectionParticipant.h" #include "js/TypeDecls.h" +#include "mozilla/ErrorResult.h" +#include "nsPIDOMWindow.h" class nsIURI; class nsIDocShell; @@ -22,11 +24,13 @@ class nsIDocShellLoadInfo; // nsLocation: Script "location" object //***************************************************************************** -class nsLocation : public nsIDOMLocation - , public nsWrapperCache +class nsLocation MOZ_FINAL : public nsIDOMLocation + , public nsWrapperCache { + typedef mozilla::ErrorResult ErrorResult; + public: - nsLocation(nsIDocShell *aDocShell); + nsLocation(nsPIDOMWindow* aWindow, nsIDocShell *aDocShell); NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsLocation) @@ -37,6 +41,101 @@ public: // nsIDOMLocation NS_DECL_NSIDOMLOCATION + // WebIDL API: + void Assign(const nsAString& aUrl, ErrorResult& aError) + { + aError = Assign(aUrl); + } + void Replace(const nsAString& aUrl, ErrorResult& aError) + { + aError = Replace(aUrl); + } + void Reload(bool aForceget, ErrorResult& aError) + { + aError = Reload(aForceget); + } + void GetHref(nsAString& aHref, ErrorResult& aError) + { + aError = GetHref(aHref); + } + void SetHref(const nsAString& aHref, ErrorResult& aError) + { + aError = SetHref(aHref); + } + void GetOrigin(nsAString& aOrigin, ErrorResult& aError) + { + aError = GetOrigin(aOrigin); + } + void GetProtocol(nsAString& aProtocol, ErrorResult& aError) + { + aError = GetProtocol(aProtocol); + } + void SetProtocol(const nsAString& aProtocol, ErrorResult& aError) + { + aError = SetProtocol(aProtocol); + } + void GetUsername(nsAString& aUsername, ErrorResult& aError); + void SetUsername(const nsAString& aUsername, ErrorResult& aError); + void GetPassword(nsAString& aPassword, ErrorResult& aError); + void SetPassword(const nsAString& aPassword, ErrorResult& aError); + void GetHost(nsAString& aHost, ErrorResult& aError) + { + aError = GetHost(aHost); + } + void SetHost(const nsAString& aHost, ErrorResult& aError) + { + aError = SetHost(aHost); + } + void GetHostname(nsAString& aHostname, ErrorResult& aError) + { + aError = GetHostname(aHostname); + } + void SetHostname(const nsAString& aHostname, ErrorResult& aError) + { + aError = SetHostname(aHostname); + } + void GetPort(nsAString& aPort, ErrorResult& aError) + { + aError = GetPort(aPort); + } + void SetPort(const nsAString& aPort, ErrorResult& aError) + { + aError = SetPort(aPort); + } + void GetPathname(nsAString& aPathname, ErrorResult& aError) + { + aError = GetPathname(aPathname); + } + void SetPathname(const nsAString& aPathname, ErrorResult& aError) + { + aError = SetPathname(aPathname); + } + void GetSearch(nsAString& aSeach, ErrorResult& aError) + { + aError = GetSearch(aSeach); + } + void SetSearch(const nsAString& aSeach, ErrorResult& aError) + { + aError = SetSearch(aSeach); + } + void GetHash(nsAString& aHash, ErrorResult& aError) + { + aError = GetHash(aHash); + } + void SetHash(const nsAString& aHash, ErrorResult& aError) + { + aError = SetHash(aHash); + } + void Stringify(nsAString& aRetval, ErrorResult& aError) + { + GetHref(aRetval, aError); + } + nsPIDOMWindow* GetParentObject() const + { + return mInnerWindow; + } + virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; + protected: virtual ~nsLocation(); @@ -56,8 +155,8 @@ protected: bool CallerSubsumes(); nsString mCachedHash; + nsCOMPtr mInnerWindow; nsWeakPtr mDocShell; - nsWeakPtr mOuter; }; #endif // nsLocation_h__ diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index 7153836c3244..275e43d1a133 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -86,10 +86,13 @@ ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs, MOZ_ASSERT(func); JS::Rooted funcName(aCx, JS_GetFunctionDisplayId(func)); MOZ_ASSERT(funcName); + nsAutoJSString funcNameStr; + if (!funcNameStr.init(aCx, funcName)) { + return false; + } JS_ReportErrorNumberUC(aCx, GetErrorMessage, nullptr, static_cast(aErrorNumber), - JS_GetStringCharsZ(aCx, funcName), - ifaceName.get()); + funcNameStr.get(), ifaceName.get()); return false; } @@ -909,6 +912,14 @@ GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor, } } +bool +UnforgeableValueOf(JSContext* cx, unsigned argc, JS::Value* vp) +{ + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + args.rval().set(args.thisv()); + return true; +} + bool ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp) { @@ -1053,18 +1064,91 @@ XrayResolveAttribute(JSContext* cx, JS::Handle wrapper, return true; } +static bool +XrayResolveMethod(JSContext* cx, JS::Handle wrapper, + JS::Handle obj, JS::Handle id, + const Prefable* methods, + jsid* methodIds, + const JSFunctionSpec* methodsSpecs, + JS::MutableHandle desc) +{ + const Prefable* method; + for (method = methods; method->specs; ++method) { + if (method->isEnabled(cx, obj)) { + // Set i to be the index into our full list of ids/specs that we're + // looking at now. + size_t i = method->specs - methodsSpecs; + for ( ; methodIds[i] != JSID_VOID; ++i) { + if (id == methodIds[i]) { + const JSFunctionSpec& methodSpec = methodsSpecs[i]; + JSFunction *fun; + if (methodSpec.selfHostedName) { + fun = JS::GetSelfHostedFunction(cx, methodSpec.selfHostedName, id, methodSpec.nargs); + if (!fun) { + return false; + } + MOZ_ASSERT(!methodSpec.call.op, "Bad FunctionSpec declaration: non-null native"); + MOZ_ASSERT(!methodSpec.call.info, "Bad FunctionSpec declaration: non-null jitinfo"); + } else { + fun = JS_NewFunctionById(cx, methodSpec.call.op, methodSpec.nargs, 0, wrapper, id); + if (!fun) { + return false; + } + SET_JITINFO(fun, methodSpec.call.info); + } + JSObject *funobj = JS_GetFunctionObject(fun); + desc.value().setObject(*funobj); + desc.setAttributes(methodSpec.flags); + desc.object().set(wrapper); + desc.setSetter(nullptr); + desc.setGetter(nullptr); + return true; + } + } + } + } + return true; +} + /* static */ bool XrayResolveUnforgeableProperty(JSContext* cx, JS::Handle wrapper, JS::Handle obj, JS::Handle id, JS::MutableHandle desc, const NativeProperties* nativeProperties) { - return !nativeProperties || !nativeProperties->unforgeableAttributes || - XrayResolveAttribute(cx, wrapper, obj, id, + if (!nativeProperties) { + return true; + } + + if (nativeProperties->unforgeableAttributes) { + if (!XrayResolveAttribute(cx, wrapper, obj, id, nativeProperties->unforgeableAttributes, nativeProperties->unforgeableAttributeIds, nativeProperties->unforgeableAttributeSpecs, - desc); + desc)) { + return false; + } + + if (desc.object()) { + return true; + } + } + + if (nativeProperties->unforgeableMethods) { + if (!XrayResolveMethod(cx, wrapper, obj, id, + nativeProperties->unforgeableMethods, + nativeProperties->unforgeableMethodIds, + nativeProperties->unforgeableMethodSpecs, + desc)) { + return false; + } + + if (desc.object()) { + return true; + } + } + + return true; } static bool @@ -1086,40 +1170,12 @@ XrayResolveProperty(JSContext* cx, JS::Handle wrapper, methodsSpecs = nativeProperties->methodsSpecs; } if (methods) { - const Prefable* method; - for (method = methods; method->specs; ++method) { - if (method->isEnabled(cx, obj)) { - // Set i to be the index into our full list of ids/specs that we're - // looking at now. - size_t i = method->specs - methodsSpecs; - for ( ; methodIds[i] != JSID_VOID; ++i) { - if (id == methodIds[i]) { - const JSFunctionSpec& methodSpec = methodsSpecs[i]; - JSFunction *fun; - if (methodSpec.selfHostedName) { - fun = JS::GetSelfHostedFunction(cx, methodSpec.selfHostedName, id, methodSpec.nargs); - if (!fun) { - return false; - } - MOZ_ASSERT(!methodSpec.call.op, "Bad FunctionSpec declaration: non-null native"); - MOZ_ASSERT(!methodSpec.call.info, "Bad FunctionSpec declaration: non-null jitinfo"); - } else { - fun = JS_NewFunctionById(cx, methodSpec.call.op, methodSpec.nargs, 0, wrapper, id); - if (!fun) { - return false; - } - SET_JITINFO(fun, methodSpec.call.info); - } - JSObject *funobj = JS_GetFunctionObject(fun); - desc.value().setObject(*funobj); - desc.setAttributes(methodSpec.flags); - desc.object().set(wrapper); - desc.setSetter(nullptr); - desc.setGetter(nullptr); - return true; - } - } - } + if (!XrayResolveMethod(cx, wrapper, obj, id, methods, methodIds, + methodsSpecs, desc)) { + return false; + } + if (desc.object()) { + return true; } } diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index 30ec98c95bb7..492358459ab9 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -1700,6 +1700,9 @@ GetInterface(JSContext* aCx, T* aThis, nsIJSID* aIID, GetInterfaceImpl(aCx, aThis, aThis, aIID, aRetval, aError); } +bool +UnforgeableValueOf(JSContext* cx, unsigned argc, JS::Value* vp); + bool ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp); diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index dcabf2bacae3..d337e31a32e4 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -742,11 +742,7 @@ DOMInterfaces = { }, 'Location': { - # NOTE: Before you turn on codegen for Location, make sure all the - # Unforgeable stuff is dealt with. - 'nativeType': 'nsIDOMLocation', - 'skipGen': True, - 'register': False + 'nativeType': 'nsLocation', }, 'MediaList': { diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 3755edd20153..a43af48895ad 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -489,10 +489,22 @@ def PrototypeIDAndDepth(descriptor): return (prototypeID, depth) +def MemberIsUnforgeable(member, descriptor): + # Note: "or" and "and" return either their LHS or RHS, not + # necessarily booleans. Make sure to return a boolean from this + # method, because callers will compare its return value to + # booleans. + return bool((member.isAttr() or member.isMethod()) and + not member.isStatic() and + (member.isUnforgeable() or + descriptor.interface.getExtendedAttribute("Unforgeable"))) + + def UseHolderForUnforgeable(descriptor): return (descriptor.concrete and descriptor.proxy and - any(m for m in descriptor.interface.members if (m.isAttr() or m.isMethod()) and m.isUnforgeable())) + any(m for m in descriptor.interface.members + if MemberIsUnforgeable(m, descriptor))) def CallOnUnforgeableHolder(descriptor, code, isXrayCheck=None, @@ -1999,7 +2011,7 @@ class MethodDefiner(PropertyDefiner): if descriptor.interface.hasInterfacePrototypeObject() or static: methods = [m for m in descriptor.interface.members if m.isMethod() and m.isStatic() == static and - m.isUnforgeable() == unforgeable and + MemberIsUnforgeable(m, descriptor) == unforgeable and not m.isIdentifierLess()] else: methods = [] @@ -2072,7 +2084,8 @@ class MethodDefiner(PropertyDefiner): if not static: stringifier = descriptor.operations['Stringifier'] - if stringifier: + if (stringifier and + unforgeable == MemberIsUnforgeable(stringifier, descriptor)): toStringDesc = { "name": "toString", "nativeName": stringifier.identifier.name, @@ -2097,6 +2110,18 @@ class MethodDefiner(PropertyDefiner): self.chrome.append(toJSONDesc) else: self.regular.append(toJSONDesc) + if (unforgeable and + descriptor.interface.getExtendedAttribute("Unforgeable")): + # Synthesize our valueOf method + self.regular.append({ + "name": 'valueOf', + "nativeName": "UnforgeableValueOf", + "methodInfo": False, + "length": 0, + "flags": "JSPROP_ENUMERATE", # readonly/permanent added + # automatically. + "condition": MemberCondition(None, None) + }) elif (descriptor.interface.isJSImplemented() and descriptor.interface.hasInterfaceObject()): self.chrome.append({ @@ -2127,7 +2152,7 @@ class MethodDefiner(PropertyDefiner): return m["condition"] def flags(m): - unforgeable = " | JSPROP_PERMANENT" if self.unforgeable else "" + unforgeable = " | JSPROP_PERMANENT | JSPROP_READONLY" if self.unforgeable else "" return m["flags"] + unforgeable def specData(m): @@ -2175,6 +2200,23 @@ class MethodDefiner(PropertyDefiner): condition, specData, doIdArrays) +def IsCrossOriginWritable(attr, descriptor): + """ + Return whether the IDLAttribute in question is cross-origin writable on the + interface represented by descriptor. This is needed to handle the fact that + some, but not all, interfaces implementing URLUtils want a cross-origin + writable .href. + """ + crossOriginWritable = attr.getExtendedAttribute("CrossOriginWritable") + if not crossOriginWritable: + return False + if crossOriginWritable == True: + return True + assert (isinstance(crossOriginWritable, list) and + len(crossOriginWritable) == 1) + return crossOriginWritable[0] == descriptor.interface.identifier.name + + class AttrDefiner(PropertyDefiner): def __init__(self, descriptor, name, static, unforgeable=False): assert not (static and unforgeable) @@ -2184,7 +2226,7 @@ class AttrDefiner(PropertyDefiner): if descriptor.interface.hasInterfacePrototypeObject() or static: attributes = [m for m in descriptor.interface.members if m.isAttr() and m.isStatic() == static and - m.isUnforgeable() == unforgeable] + MemberIsUnforgeable(m, descriptor) == unforgeable] else: attributes = [] self.chrome = [m for m in attributes if isChromeOnly(m)] @@ -2238,7 +2280,7 @@ class AttrDefiner(PropertyDefiner): else: if attr.hasLenientThis(): accessor = "genericLenientSetter" - elif attr.getExtendedAttribute("CrossOriginWritable"): + elif IsCrossOriginWritable(attr, self.descriptor): accessor = "genericCrossOriginSetter" elif self.descriptor.needsSpecialGenericOps(): accessor = "genericSetter" @@ -2786,6 +2828,11 @@ def InitUnforgeablePropertiesOnObject(descriptor, obj, properties, failureReturn """ unforgeables = [] + if failureReturnValue: + failureReturnValue = " " + failureReturnValue + else: + failureReturnValue = "" + defineUnforgeableAttrs = fill( """ if (!DefineUnforgeableAttributes(aCx, ${obj}, %s)) { @@ -2793,7 +2840,7 @@ def InitUnforgeablePropertiesOnObject(descriptor, obj, properties, failureReturn } """, obj=obj, - rv=" " + failureReturnValue if failureReturnValue else "") + rv=failureReturnValue) defineUnforgeableMethods = fill( """ if (!DefineUnforgeableMethods(aCx, ${obj}, %s)) { @@ -2801,7 +2848,7 @@ def InitUnforgeablePropertiesOnObject(descriptor, obj, properties, failureReturn } """, obj=obj, - rv=" " + failureReturnValue if failureReturnValue else "") + rv=failureReturnValue) unforgeableMembers = [ (defineUnforgeableAttrs, properties.unforgeableAttrs), @@ -2815,6 +2862,19 @@ def InitUnforgeablePropertiesOnObject(descriptor, obj, properties, failureReturn CGIfWrapper(CGGeneric(template % array.variableName(True)), "nsContentUtils::ThreadsafeIsCallerChrome()")) + if descriptor.interface.getExtendedAttribute("Unforgeable"): + # We do our undefined toJSON here, not as a regular property + # because we don't have a concept of value props anywhere. + unforgeables.append(CGGeneric(fill( + """ + if (!JS_DefineProperty(aCx, ${obj}, "toJSON", JS::UndefinedHandleValue, + JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT)) { + return${rv}; + } + """, + obj=obj, + rv=failureReturnValue))) + return CGList(unforgeables) @@ -10353,13 +10413,13 @@ class CGDescriptor(CGThing): cgThings.append(CGSpecializedSetter(descriptor, m)) if m.hasLenientThis(): hasLenientSetter = True - elif m.getExtendedAttribute("CrossOriginWritable"): + elif IsCrossOriginWritable(m, descriptor): crossOriginSetters.add(m.identifier.name) elif descriptor.needsSpecialGenericOps(): hasSetter = True elif m.getExtendedAttribute("PutForwards"): cgThings.append(CGSpecializedForwardingSetter(descriptor, m)) - if m.getExtendedAttribute("CrossOriginWritable"): + if IsCrossOriginWritable(m, descriptor): crossOriginSetters.add(m.identifier.name) elif descriptor.needsSpecialGenericOps(): hasSetter = True diff --git a/dom/bindings/Exceptions.cpp b/dom/bindings/Exceptions.cpp index 59efe286aa95..e9166199763f 100644 --- a/dom/bindings/Exceptions.cpp +++ b/dom/bindings/Exceptions.cpp @@ -394,9 +394,7 @@ NS_IMETHODIMP JSStackFrame::GetName(nsAString& aFunction) if (!mFunnameInitialized) { JS::FrameDescription& desc = mStackDescription->FrameAt(mIndex); if (JSFlatString *name = desc.funDisplayName()) { - mFunname.Assign(JS_GetFlatStringChars(name), - // XXXbz Can't JS_GetStringLength on JSFlatString! - JS_GetStringLength(JS_FORGET_STRING_FLATNESS(name))); + AssignJSFlatString(mFunname, name); } mFunnameInitialized = true; } diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py index edeebf05fd3a..4c239e36eb72 100644 --- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -669,8 +669,36 @@ class IDLInterface(IDLObjectWithScope): for ancestorConsequential in ancestor.getConsequentialInterfaces(): ancestorConsequential.interfacesBasedOnSelf.add(self) + # Deal with interfaces marked [Unforgeable], now that we have our full + # member list, except unforgeables pulled in from parents. We want to + # do this before we set "originatingInterface" on our unforgeable + # members. + if self.getExtendedAttribute("Unforgeable"): + # Check that the interface already has all the things the + # spec would otherwise require us to synthesize and is + # missing the ones we plan to synthesize. + if not any(m.isMethod() and m.isStringifier() for m in self.members): + raise WebIDLError("Unforgeable interface %s does not have a " + "stringifier" % self.identifier.name, + [self.location]) + + for m in self.members: + if ((m.isMethod() and m.isJsonifier()) or + m.identifier.name == "toJSON"): + raise WebIDLError("Unforgeable interface %s has a " + "jsonifier so we won't be able to add " + "one ourselves" % self.identifier.name, + [self.location, m.location]) + + if m.identifier.name == "valueOf" and not m.isStatic(): + raise WebIDLError("Unforgeable interface %s has a valueOf " + "member so we won't be able to add one " + "ourselves" % self.identifier.name, + [self.location, m.location]) + for member in self.members: - if (member.isAttr() and member.isUnforgeable() and + if ((member.isAttr() or member.isMethod()) and + member.isUnforgeable() and not hasattr(member, "originatingInterface")): member.originatingInterface = self @@ -693,16 +721,16 @@ class IDLInterface(IDLObjectWithScope): # worry about anything other than our parent, because it has already # imported its ancestors unforgeable attributes into its member # list. - for unforgeableAttr in (attr for attr in self.parent.members if - attr.isAttr() and not attr.isStatic() and - attr.isUnforgeable()): + for unforgeableMember in (member for member in self.parent.members if + (member.isAttr() or member.isMethod()) and + member.isUnforgeable()): shadows = [ m for m in self.members if (m.isAttr() or m.isMethod()) and not m.isStatic() and - m.identifier.name == unforgeableAttr.identifier.name ] + m.identifier.name == unforgeableMember.identifier.name ] if len(shadows) != 0: - locs = [unforgeableAttr.location] + [ s.location for s - in shadows ] + locs = [unforgeableMember.location] + [ s.location for s + in shadows ] raise WebIDLError("Interface %s shadows [Unforgeable] " "members of %s" % (self.identifier.name, @@ -711,10 +739,10 @@ class IDLInterface(IDLObjectWithScope): # And now just stick it in our members, since we won't be # inheriting this down the proto chain. If we really cared we # could try to do something where we set up the unforgeable - # attributes of ancestor interfaces, with their corresponding - # getters, on our interface, but that gets pretty complicated - # and seems unnecessary. - self.members.append(unforgeableAttr) + # attributes/methods of ancestor interfaces, with their + # corresponding getters, on our interface, but that gets pretty + # complicated and seems unnecessary. + self.members.append(unforgeableMember) # Ensure that there's at most one of each {named,indexed} # {getter,setter,creator,deleter}, at most one stringifier, @@ -785,6 +813,26 @@ class IDLInterface(IDLObjectWithScope): parent = parent.parent def validate(self): + # We don't support consequential unforgeable interfaces. Need to check + # this here, becaue in finish() an interface might not know yet that + # it's consequential. + if self.getExtendedAttribute("Unforgeable") and self.isConsequential(): + raise WebIDLError( + "%s is an unforgeable consequential interface" % + self.identifier.name, + [self.location] + + list(i.location for i in + (self.interfacesBasedOnSelf - { self }) )) + + # We also don't support inheriting from unforgeable interfaces. + if self.getExtendedAttribute("Unforgeable") and self.hasChildInterfaces(): + raise WebIDLError("%s is an unforgeable ancestor interface" % + self.identifier.name, + [self.location] + + list(i.location for i in + self.interfacesBasedOnSelf if i.parent == self)) + + for member in self.members: member.validate() @@ -992,6 +1040,7 @@ class IDLInterface(IDLObjectWithScope): elif (identifier == "NeedNewResolve" or identifier == "OverrideBuiltins" or identifier == "ChromeOnly" or + identifier == "Unforgeable" or identifier == "LegacyEventInit"): # Known extended attributes that do not take values if not attr.noArguments(): @@ -2889,9 +2938,6 @@ class IDLAttribute(IDLInterfaceMember): [attr.location, self.location]) self.lenientThis = True elif identifier == "Unforgeable": - if not self.readonly: - raise WebIDLError("[Unforgeable] is only allowed on readonly " - "attributes", [attr.location, self.location]) if self.isStatic(): raise WebIDLError("[Unforgeable] is only allowed on non-static " "attributes", [attr.location, self.location]) @@ -2951,7 +2997,7 @@ class IDLAttribute(IDLInterfaceMember): [attr.location, self.location]) elif (identifier == "CrossOriginReadable" or identifier == "CrossOriginWritable"): - if not attr.noArguments(): + if not attr.noArguments() and identifier == "CrossOriginReadable": raise WebIDLError("[%s] must take no arguments" % identifier, [attr.location]) if self.isStatic(): @@ -3545,15 +3591,19 @@ class IDLMethod(IDLInterfaceMember, IDLScope): raise WebIDLError("[LenientFloat] used on an operation with no " "restricted float type arguments", [attr.location, self.location]) + elif (identifier == "Pure" or + identifier == "CrossOriginCallable" or + identifier == "WebGLHandlesContextLoss"): + # Known no-argument attributes. + if not attr.noArguments(): + raise WebIDLError("[%s] must take no arguments" % identifier, + [attr.location]) elif (identifier == "Throws" or identifier == "NewObject" or identifier == "ChromeOnly" or identifier == "Pref" or identifier == "Func" or identifier == "AvailableIn" or - identifier == "Pure" or - identifier == "CrossOriginCallable" or - identifier == "WebGLHandlesContextLoss" or identifier == "CheckPermissions"): # Known attributes that we don't need to do anything with here pass diff --git a/dom/bindings/parser/tests/test_unforgeable.py b/dom/bindings/parser/tests/test_unforgeable.py index e512bde215bc..3787e8c6af1e 100644 --- a/dom/bindings/parser/tests/test_unforgeable.py +++ b/dom/bindings/parser/tests/test_unforgeable.py @@ -79,6 +79,25 @@ def WebIDLTest(parser, harness): "Should have thrown when shadowing unforgeable attribute on " "parent with operation.") + parser = parser.reset(); + threw = False + try: + parser.parse(""" + interface Child : Parent { + void foo(); + }; + interface Parent { + [Unforgeable] void foo(); + }; + """) + + results = parser.finish() + except: + threw = True + harness.ok(threw, + "Should have thrown when shadowing unforgeable operation on " + "parent with operation.") + parser = parser.reset(); threw = False try: @@ -98,6 +117,25 @@ def WebIDLTest(parser, harness): "Should have thrown when shadowing unforgeable attribute on " "parent with attribute.") + parser = parser.reset(); + threw = False + try: + parser.parse(""" + interface Child : Parent { + attribute short foo; + }; + interface Parent { + [Unforgeable] void foo(); + }; + """) + + results = parser.finish() + except Exception,x: + threw = True + harness.ok(threw, + "Should have thrown when shadowing unforgeable operation on " + "parent with attribute.") + parser = parser.reset(); parser.parse(""" interface Child : Parent { @@ -166,16 +204,38 @@ def WebIDLTest(parser, harness): threw = False try: parser.parse(""" - interface iface { - [Unforgeable] attribute long foo; + interface Child : Parent { }; + interface Parent : GrandParent {}; + interface GrandParent {}; + interface Consequential { + [Unforgeable] void foo(); + }; + GrandParent implements Consequential; + interface ChildConsequential { + void foo(); + }; + Child implements ChildConsequential; """) results = parser.finish() except: threw = True - harness.ok(threw, "Should have thrown for writable [Unforgeable] attribute.") + harness.ok(threw, + "Should have thrown when our consequential interface shadows unforgeable operation " + "of ancestor's consequential interface.") + + parser = parser.reset(); + parser.parse(""" + interface iface { + [Unforgeable] attribute long foo; + }; + """) + + results = parser.finish() + harness.check(len(results), 1, + "Should allow writable [Unforgeable] attribute.") parser = parser.reset(); threw = False diff --git a/dom/browser-element/BrowserElementChildPreload.js b/dom/browser-element/BrowserElementChildPreload.js index 393d8d63ba2e..82da8310faf1 100644 --- a/dom/browser-element/BrowserElementChildPreload.js +++ b/dom/browser-element/BrowserElementChildPreload.js @@ -186,10 +186,21 @@ BrowserElementChild.prototype = { /* wantsUntrusted = */ false); addEventListener('DOMMetaAdded', - this._metaAddedHandler.bind(this), + this._metaChangedHandler.bind(this), /* useCapture = */ true, /* wantsUntrusted = */ false); + addEventListener('DOMMetaChanged', + this._metaChangedHandler.bind(this), + /* useCapture = */ true, + /* wantsUntrusted = */ false); + + addEventListener('DOMMetaRemoved', + this._metaChangedHandler.bind(this), + /* useCapture = */ true, + /* wantsUntrusted = */ false); + + // This listens to unload events from our message manager, but /not/ from // the |content| window. That's because the window's unload event doesn't // bubble, and we're not using a capturing listener. If we'd used @@ -513,7 +524,7 @@ BrowserElementChild.prototype = { }, this); }, - _metaAddedHandler: function(e) { + _metaChangedHandler: function(e) { let win = e.target.ownerDocument.defaultView; // Ignore metas which don't come from the top-level //