diff --git a/dom/base/Console.cpp b/dom/base/Console.cpp index a63df8f9e9..ff255349bc 100644 --- a/dom/base/Console.cpp +++ b/dom/base/Console.cpp @@ -1038,6 +1038,7 @@ METHOD(Error, "error") METHOD(Exception, "exception") METHOD(Debug, "debug") METHOD(Table, "table") +METHOD(Clear, "clear") void Console::Trace(JSContext* aCx) @@ -1533,6 +1534,11 @@ Console::ProcessCallData(JSContext* aCx, ConsoleCallData* aData, innerID.AppendInt(aData->mInnerIDNumber); } + if (aData->mMethodName == MethodClear) { + nsresult rv = mStorage->ClearEvents(innerID); + NS_WARN_IF(NS_FAILED(rv)); + } + if (NS_FAILED(mStorage->RecordEvent(innerID, outerID, eventValue))) { NS_WARNING("Failed to record a console event."); } diff --git a/dom/base/Console.h b/dom/base/Console.h index 507905dd6e..cdc1758e45 100644 --- a/dom/base/Console.h +++ b/dom/base/Console.h @@ -115,6 +115,9 @@ public: void Count(JSContext* aCx, const Sequence& aData); + void + Clear(JSContext* aCx, const Sequence& aData); + void NoopMethod(); @@ -156,7 +159,8 @@ private: MethodTimeEnd, MethodTimeStamp, MethodAssert, - MethodCount + MethodCount, + MethodClear }; void diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index 2d06322d42..8a31d9e2fe 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -1657,7 +1657,7 @@ nsMessageManagerScriptExecutor::DidCreateGlobal() // static void -nsMessageManagerScriptExecutor::Shutdown() +nsMessageManagerScriptExecutor::PurgeCache() { if (sCachedScripts) { NS_ASSERTION(sCachedScripts != nullptr, "Need cached scripts"); @@ -1665,6 +1665,15 @@ nsMessageManagerScriptExecutor::Shutdown() delete iter.Data(); iter.Remove(); } + } +} + +// static +void +nsMessageManagerScriptExecutor::Shutdown() +{ + if (sCachedScripts) { + PurgeCache(); delete sCachedScripts; sCachedScripts = nullptr; diff --git a/dom/base/nsFrameMessageManager.h b/dom/base/nsFrameMessageManager.h index 46afed4877..73748c7ff0 100644 --- a/dom/base/nsFrameMessageManager.h +++ b/dom/base/nsFrameMessageManager.h @@ -377,6 +377,7 @@ struct nsMessageManagerScriptHolder class nsMessageManagerScriptExecutor { public: + static void PurgeCache(); static void Shutdown(); already_AddRefed GetGlobal() { @@ -417,15 +418,21 @@ class nsScriptCacheCleaner final : public nsIObserver nsScriptCacheCleaner() { nsCOMPtr obsSvc = mozilla::services::GetObserverService(); - if (obsSvc) + if (obsSvc) { + obsSvc->AddObserver(this, "message-manager-flush-caches", false); obsSvc->AddObserver(this, "xpcom-shutdown", false); + } } NS_IMETHODIMP Observe(nsISupports *aSubject, const char *aTopic, const char16_t *aData) override { - nsMessageManagerScriptExecutor::Shutdown(); + if (strcmp("message-manager-flush-caches", aTopic) == 0) { + nsMessageManagerScriptExecutor::PurgeCache(); + } else if (strcmp("xpcom-shutdown", aTopic) == 0) { + nsMessageManagerScriptExecutor::Shutdown(); + } return NS_OK; } }; diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h index 6cc273c91d..64ef0c8fad 100644 --- a/dom/base/nsGkAtomList.h +++ b/dom/base/nsGkAtomList.h @@ -275,6 +275,7 @@ GK_ATOM(decimalFormat, "decimal-format") GK_ATOM(decimalSeparator, "decimal-separator") GK_ATOM(deck, "deck") GK_ATOM(declare, "declare") +GK_ATOM(decoderDoctor, "decoder-doctor") GK_ATOM(decrement, "decrement") GK_ATOM(_default, "default") GK_ATOM(headerDefaultStyle, "default-style") diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index db96b43932..9114b49af0 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -621,6 +621,7 @@ skip-if = toolkit == 'android' #bug 687032 [test_bug647518.html] [test_bug650001.html] [test_bug656283.html] +[test_bug659625.html] [test_bug664916.html] [test_bug666604.html] skip-if = buildapp == 'b2g' # b2g(dom.disable_open_during_load not implemented in b2g) b2g-debug(dom.disable_open_during_load not implemented in b2g) b2g-desktop(dom.disable_open_during_load not implemented in b2g) diff --git a/dom/base/test/test_bug659625.html b/dom/base/test/test_bug659625.html new file mode 100644 index 0000000000..7adf872642 --- /dev/null +++ b/dom/base/test/test_bug659625.html @@ -0,0 +1,92 @@ + + + + + + Test for Bug 659625 + + + + +Mozilla Bug 659625 + + + diff --git a/dom/bindings/SimpleGlobalObject.cpp b/dom/bindings/SimpleGlobalObject.cpp index 9019ade2f1..5cfb653bad 100644 --- a/dom/bindings/SimpleGlobalObject.cpp +++ b/dom/bindings/SimpleGlobalObject.cpp @@ -41,19 +41,6 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SimpleGlobalObject) NS_INTERFACE_MAP_ENTRY(nsIGlobalObject) NS_INTERFACE_MAP_END -static bool -SimpleGlobal_enumerate(JSContext *cx, JS::Handle obj) -{ - return JS_EnumerateStandardClasses(cx, obj); -} - -static bool -SimpleGlobal_resolve(JSContext *cx, JS::Handle obj, - JS::Handle id, bool *resolvedp) -{ - return JS_ResolveStandardClass(cx, obj, id, resolvedp); -} - static void SimpleGlobal_finalize(js::FreeOp *fop, JSObject *obj) { @@ -75,9 +62,9 @@ static const js::ClassOps SimpleGlobalClassOps = { nullptr, nullptr, nullptr, - SimpleGlobal_enumerate, - SimpleGlobal_resolve, - nullptr, + JS_EnumerateStandardClasses, + JS_ResolveStandardClass, + JS_MayResolveStandardClass, SimpleGlobal_finalize, nullptr, nullptr, diff --git a/dom/locales/en-US/chrome/dom/dom.properties b/dom/locales/en-US/chrome/dom/dom.properties index 335e11cc2c..4daf2d07c7 100644 --- a/dom/locales/en-US/chrome/dom/dom.properties +++ b/dom/locales/en-US/chrome/dom/dom.properties @@ -112,6 +112,8 @@ MediaLoadDecodeError=Media resource %S could not be decoded. # LOCALIZATION NOTE: %S is a comma-separated list of codecs (e.g. 'video/mp4, video/webm') MediaCannotPlayNoDecoders=Cannot play media. No decoders for requested formats: %S # LOCALIZATION NOTE: %S is a comma-separated list of codecs (e.g. 'video/mp4, video/webm') +MediaPlatformDecoderNotFound=The video on this page can't be played. Your system may not have the required video codecs for: %S +# LOCALIZATION NOTE: %S is a comma-separated list of codecs (e.g. 'video/mp4, video/webm') MediaNoDecoders=No decoders for some of the requested formats: %S # LOCALIZATION NOTE: Do not translate "MediaRecorder". MediaRecorderMultiTracksNotSupported=MediaRecorder does not support recording multiple tracks of the same type at this time. diff --git a/dom/media/ADTSDecoder.cpp b/dom/media/ADTSDecoder.cpp index 08cdfe9765..02c5d51ec0 100644 --- a/dom/media/ADTSDecoder.cpp +++ b/dom/media/ADTSDecoder.cpp @@ -35,7 +35,7 @@ ADTSDecoder::IsEnabled() PDMFactory::Init(); RefPtr platform = new PDMFactory(); return (platform && platform->SupportsMimeType(NS_LITERAL_CSTRING("audio/mp4a-latm"), - /* DecoderDoctorDiagnostics* */ nullptr)); + /* DecoderDoctorDiagnostics* */ nullptr)); } /* static */ bool diff --git a/dom/media/DecoderDoctorDiagnostics.cpp b/dom/media/DecoderDoctorDiagnostics.cpp index c2851191cb..3d247ee8ae 100644 --- a/dom/media/DecoderDoctorDiagnostics.cpp +++ b/dom/media/DecoderDoctorDiagnostics.cpp @@ -6,30 +6,430 @@ #include "DecoderDoctorDiagnostics.h" +#include "mozilla/dom/DecoderDoctorNotificationBinding.h" #include "mozilla/Logging.h" +#include "nsGkAtoms.h" +#include "nsIDocument.h" +#include "nsIObserverService.h" +#include "nsITimer.h" +#include "nsIWeakReference.h" static mozilla::LazyLogModule sDecoderDoctorLog("DecoderDoctor"); #define DD_LOG(level, arg, ...) MOZ_LOG(sDecoderDoctorLog, level, (arg, ##__VA_ARGS__)) #define DD_DEBUG(arg, ...) DD_LOG(mozilla::LogLevel::Debug, arg, ##__VA_ARGS__) +#define DD_INFO(arg, ...) DD_LOG(mozilla::LogLevel::Info, arg, ##__VA_ARGS__) #define DD_WARN(arg, ...) DD_LOG(mozilla::LogLevel::Warning, arg, ##__VA_ARGS__) namespace mozilla { +// Class that collects a sequence of diagnostics from the same document over a +// small period of time, in order to provide a synthesized analysis. +// +// Referenced by the document through a nsINode property, mTimer, and +// inter-task captures. +// When notified that the document is dead, or when the timer expires but +// nothing new happened, StopWatching() will remove the document property and +// timer (if present), so no more work will happen and the watcher will be +// destroyed once all references are gone. +class DecoderDoctorDocumentWatcher : public nsITimerCallback +{ +public: + static RefPtr + RetrieveOrCreate(nsIDocument* aDocument); + + NS_DECL_ISUPPORTS + NS_DECL_NSITIMERCALLBACK + + void AddDiagnostics(const nsAString& aFormat, + const char* aCallSite, + DecoderDoctorDiagnostics&& aDiagnostics); + +private: + explicit DecoderDoctorDocumentWatcher(nsIDocument* aDocument); + virtual ~DecoderDoctorDocumentWatcher(); + + // This will prevent further work from happening, watcher will deregister + // itself from document (if requested) and cancel any timer, and soon die. + void StopWatching(bool aRemoveProperty); + + // Remove property from document; will call DestroyPropertyCallback. + void RemovePropertyFromDocument(); + // Callback for property destructor, will be automatically called when the + // document (in aObject) is being destroyed. + static void DestroyPropertyCallback(void* aObject, + nsIAtom* aPropertyName, + void* aPropertyValue, + void* aData); + + static const uint32_t sAnalysisPeriod_ms = 1000; + void EnsureTimerIsStarted(); + + void ReportAnalysis(dom::DecoderDoctorNotificationType aNotificationType, + const char* aReportStringId, + const nsAString& aFormats); + + void SynthesizeAnalysis(); + + // Raw pointer to an nsIDocument. + // Must be non-null during construction. + // Nulled when we want to stop watching, because either: + // 1. The document has been destroyed (notified through + // DestroyPropertyCallback). + // 2. We have not received new diagnostic information within a short time + // period, so we just stop watching. + // Once nulled, no more actual work will happen, and the watcher will be + // destroyed soon. + nsIDocument* mDocument; + + struct Diagnostics + { + Diagnostics(DecoderDoctorDiagnostics&& aDiagnostics, + const nsAString& aFormat, + const char* aCallSite) + : mDecoderDoctorDiagnostics(Move(aDiagnostics)) + , mFormat(aFormat) + , mCallSite(aCallSite) + {} + Diagnostics(const Diagnostics&) = delete; + Diagnostics(Diagnostics&& aOther) + : mDecoderDoctorDiagnostics(Move(aOther.mDecoderDoctorDiagnostics)) + , mFormat(Move(aOther.mFormat)) + , mCallSite(Move(aOther.mCallSite)) + {} + + const DecoderDoctorDiagnostics mDecoderDoctorDiagnostics; + const nsString mFormat; + const nsCString mCallSite; + }; + typedef nsTArray DiagnosticsSequence; + DiagnosticsSequence mDiagnosticsSequence; + + nsCOMPtr mTimer; // Keep timer alive until we run. + DiagnosticsSequence::size_type mDiagnosticsHandled = 0; +}; + + +NS_IMPL_ISUPPORTS(DecoderDoctorDocumentWatcher, nsITimerCallback) + +// static +RefPtr +DecoderDoctorDocumentWatcher::RetrieveOrCreate(nsIDocument* aDocument) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aDocument); + RefPtr watcher = + static_cast( + aDocument->GetProperty(nsGkAtoms::decoderDoctor)); + if (!watcher) { + watcher = new DecoderDoctorDocumentWatcher(aDocument); + if (NS_WARN_IF(NS_FAILED( + aDocument->SetProperty(nsGkAtoms::decoderDoctor, + watcher.get(), + DestroyPropertyCallback, + /*transfer*/ false)))) { + DD_WARN("DecoderDoctorDocumentWatcher::RetrieveOrCreate(doc=%p) - Could not set property in document, will destroy new watcher[%p]", + aDocument, watcher.get()); + return nullptr; + } + // Document owns watcher through this property. + // Released in DestroyPropertyCallback(). + NS_ADDREF(watcher.get()); + } + return watcher; +} + +DecoderDoctorDocumentWatcher::DecoderDoctorDocumentWatcher(nsIDocument* aDocument) + : mDocument(aDocument) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mDocument); + DD_DEBUG("DecoderDoctorDocumentWatcher[%p]::DecoderDoctorDocumentWatcher(doc=%p)", + this, mDocument); +} + +DecoderDoctorDocumentWatcher::~DecoderDoctorDocumentWatcher() +{ + MOZ_ASSERT(NS_IsMainThread()); + DD_DEBUG("DecoderDoctorDocumentWatcher[%p, doc=%p <- expect 0]::~DecoderDoctorDocumentWatcher()", + this, mDocument); + // mDocument should have been reset through StopWatching()! + MOZ_ASSERT(!mDocument); +} + +void +DecoderDoctorDocumentWatcher::RemovePropertyFromDocument() +{ + MOZ_ASSERT(NS_IsMainThread()); + DecoderDoctorDocumentWatcher* watcher = + static_cast( + mDocument->GetProperty(nsGkAtoms::decoderDoctor)); + if (!watcher) { + return; + } + DD_DEBUG("DecoderDoctorDocumentWatcher[%p, doc=%p]::RemovePropertyFromDocument()\n", + watcher, watcher->mDocument); + // This will remove the property and call our DestroyPropertyCallback. + mDocument->DeleteProperty(nsGkAtoms::decoderDoctor); +} + +// Callback for property destructors. |aObject| is the object +// the property is being removed for, |aPropertyName| is the property +// being removed, |aPropertyValue| is the value of the property, and |aData| +// is the opaque destructor data that was passed to SetProperty(). +// static +void +DecoderDoctorDocumentWatcher::DestroyPropertyCallback(void* aObject, + nsIAtom* aPropertyName, + void* aPropertyValue, + void*) +{ + MOZ_ASSERT(NS_IsMainThread()); +#ifdef DEBUG + nsIDocument* document = static_cast(aObject); +#endif + MOZ_ASSERT(aPropertyName == nsGkAtoms::decoderDoctor); + DecoderDoctorDocumentWatcher* watcher = + static_cast(aPropertyValue); + MOZ_ASSERT(watcher); + MOZ_ASSERT(watcher->mDocument == document); + DD_DEBUG("DecoderDoctorDocumentWatcher[%p, doc=%p]::DestroyPropertyCallback()\n", + watcher, watcher->mDocument); + // 'false': StopWatching should not try and remove the property. + watcher->StopWatching(false); + NS_RELEASE(watcher); +} + +void +DecoderDoctorDocumentWatcher::StopWatching(bool aRemoveProperty) +{ + MOZ_ASSERT(NS_IsMainThread()); + // StopWatching() shouldn't be called twice. + MOZ_ASSERT(mDocument); + + if (aRemoveProperty) { + RemovePropertyFromDocument(); + } + + // Forget document now, this will prevent more work from being started. + mDocument = nullptr; + + if (mTimer) { + mTimer->Cancel(); + mTimer = nullptr; + } +} + +void +DecoderDoctorDocumentWatcher::EnsureTimerIsStarted() +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (!mTimer) { + mTimer = do_CreateInstance(NS_TIMER_CONTRACTID); + if (NS_WARN_IF(!mTimer)) { + return; + } + if (NS_WARN_IF(NS_FAILED( + mTimer->InitWithCallback( + this, sAnalysisPeriod_ms, nsITimer::TYPE_ONE_SHOT)))) { + mTimer = nullptr; + } + } +} + +static void +DispatchNotification(nsISupports* aSubject, + dom::DecoderDoctorNotificationType aNotificationType, + const nsAString& aFormats) +{ + if (!aSubject) { + return; + } + dom::DecoderDoctorNotification data; + data.mType = aNotificationType; + if (!aFormats.IsEmpty()) { + data.mFormats.Construct(aFormats); + } + nsAutoString json; + data.ToJSON(json); + if (json.IsEmpty()) { + DD_WARN("DecoderDoctorDiagnostics/DispatchEvent() - Could not create json for dispatch"); + // No point in dispatching this notification without data, the front-end + // wouldn't know what to display. + return; + } + DD_DEBUG("DecoderDoctorDiagnostics/DispatchEvent() %s", NS_ConvertUTF16toUTF8(json).get()); + nsCOMPtr obs = services::GetObserverService(); + if (obs) { + obs->NotifyObservers(aSubject, "decoder-doctor-notification", json.get()); + } +} + +void +DecoderDoctorDocumentWatcher::ReportAnalysis( + dom::DecoderDoctorNotificationType aNotificationType, + const char* aReportStringId, + const nsAString& aFormats) +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (!mDocument) { + return; + } + + const char16_t* params[] = { aFormats.Data() }; + DD_DEBUG("DecoderDoctorDocumentWatcher[%p, doc=%p]::ReportAnalysis() ReportToConsole - aMsg='%s' params[0]='%s'", + this, mDocument, aReportStringId, + NS_ConvertUTF16toUTF8(params[0]).get()); + nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, + NS_LITERAL_CSTRING("Media"), + mDocument, + nsContentUtils::eDOM_PROPERTIES, + aReportStringId, + params, + ArrayLength(params)); + + // For now, disable all front-end notifications by default. + // TODO: Future bugs will use finer-grained filtering instead. + if (Preferences::GetBool("media.decoderdoctor.enable-notification-bar", false)) { + DispatchNotification( + mDocument->GetInnerWindow(), aNotificationType, aFormats); + } +} + +void +DecoderDoctorDocumentWatcher::SynthesizeAnalysis() +{ + MOZ_ASSERT(NS_IsMainThread()); + + bool canPlay = false; +#if defined(MOZ_FFMPEG) + bool PlatformDecoderNeeded = false; +#endif + nsAutoString formats; + for (auto& diag : mDiagnosticsSequence) { + if (diag.mDecoderDoctorDiagnostics.CanPlay()) { + canPlay = true; + } else { +#if defined(MOZ_FFMPEG) + if (diag.mDecoderDoctorDiagnostics.DidFFmpegFailToLoad()) { + PlatformDecoderNeeded = true; + } +#endif + if (!formats.IsEmpty()) { + formats += NS_LITERAL_STRING(", "); + } + formats += diag.mFormat; + } + } + if (!canPlay) { +#if defined(MOZ_FFMPEG) + if (PlatformDecoderNeeded) { + DD_DEBUG("DecoderDoctorDocumentWatcher[%p, doc=%p]::Notify() - formats: %s -> Cannot play media because platform decoder was not found", + this, mDocument, NS_ConvertUTF16toUTF8(formats).get()); + ReportAnalysis(dom::DecoderDoctorNotificationType::Platform_decoder_not_found, + "MediaPlatformDecoderNotFound", formats); + } else +#endif + { + DD_WARN("DecoderDoctorDocumentWatcher[%p, doc=%p]::Notify() - Cannot play media, formats: %s", + this, mDocument, NS_ConvertUTF16toUTF8(formats).get()); + ReportAnalysis(dom::DecoderDoctorNotificationType::Cannot_play, + "MediaCannotPlayNoDecoders", formats); + } + } else if (!formats.IsEmpty()) { + DD_INFO("DecoderDoctorDocumentWatcher[%p, doc=%p]::Notify() - Can play media, but no decoders for some requested formats: %s", + this, mDocument, NS_ConvertUTF16toUTF8(formats).get()); + if (Preferences::GetBool("media.decoderdoctor.verbose", false)) { + ReportAnalysis( + dom::DecoderDoctorNotificationType::Can_play_but_some_missing_decoders, + "MediaNoDecoders", formats); + } + } else { + DD_DEBUG("DecoderDoctorDocumentWatcher[%p, doc=%p]::Notify() - Can play media, decoders available for all requested formats", + this, mDocument); + } +} + +void +DecoderDoctorDocumentWatcher::AddDiagnostics(const nsAString& aFormat, + const char* aCallSite, + DecoderDoctorDiagnostics&& aDiagnostics) +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (!mDocument) { + return; + } + + DD_DEBUG("DecoderDoctorDocumentWatcher[%p, doc=%p]::AddDiagnostics(format='%s', call site '%s', can play=%d, platform lib failed to load=%d)", + this, mDocument, NS_ConvertUTF16toUTF8(aFormat).get(), + aCallSite, aDiagnostics.CanPlay(), aDiagnostics.DidFFmpegFailToLoad()); + mDiagnosticsSequence.AppendElement( + Diagnostics(Move(aDiagnostics), aFormat, aCallSite)); + EnsureTimerIsStarted(); +} + +NS_IMETHODIMP +DecoderDoctorDocumentWatcher::Notify(nsITimer* timer) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(timer == mTimer); + + // Forget timer. (Assuming timer keeps itself and us alive during this call.) + mTimer = nullptr; + + if (!mDocument) { + return NS_OK; + } + + if (mDiagnosticsSequence.Length() > mDiagnosticsHandled) { + // We have new diagnostic data. + mDiagnosticsHandled = mDiagnosticsSequence.Length(); + + SynthesizeAnalysis(); + + // Restart timer, to redo analysis or stop watching this document, + // depending on whether anything new happens. + EnsureTimerIsStarted(); + } else { + DD_DEBUG("DecoderDoctorDocumentWatcher[%p, doc=%p]::Notify() - No new diagnostics to analyze -> Stop watching", + this, mDocument); + // Stop watching this document, we don't expect more diagnostics for now. + // If more diagnostics come in, we'll treat them as another burst, separately. + // 'true' to remove the property from the document. + StopWatching(true); + } + + return NS_OK; +} + + void DecoderDoctorDiagnostics::StoreDiagnostics(nsIDocument* aDocument, const nsAString& aFormat, const char* aCallSite) { + MOZ_ASSERT(NS_IsMainThread()); if (NS_WARN_IF(!aDocument)) { DD_WARN("DecoderDoctorDiagnostics[%p]::StoreDiagnostics(nsIDocument* aDocument=nullptr, format='%s', call site '%s')", this, NS_ConvertUTF16toUTF8(aFormat).get(), aCallSite); return; } - // TODO: Actually analyze data. - DD_DEBUG("DecoderDoctorDiagnostics[%p]::StoreDiagnostics(nsIDocument* aDocument=%p, format='%s', call site '%s')", - this, aDocument, NS_ConvertUTF16toUTF8(aFormat).get(), aCallSite); + RefPtr watcher = + DecoderDoctorDocumentWatcher::RetrieveOrCreate(aDocument); + + if (NS_WARN_IF(!watcher)) { + DD_WARN("DecoderDoctorDiagnostics[%p]::StoreDiagnostics(nsIDocument* aDocument=nullptr, format='%s', call site '%s') - Could not create document watcher", + this, NS_ConvertUTF16toUTF8(aFormat).get(), aCallSite); + return; + } + + // StoreDiagnostics should only be called once, after all data is available, + // so it is safe to Move() from this object. + watcher->AddDiagnostics(aFormat, aCallSite, Move(*this)); } } // namespace mozilla diff --git a/dom/media/DecoderDoctorDiagnostics.h b/dom/media/DecoderDoctorDiagnostics.h index cffb8d01dd..b2e9347af3 100644 --- a/dom/media/DecoderDoctorDiagnostics.h +++ b/dom/media/DecoderDoctorDiagnostics.h @@ -44,9 +44,14 @@ public: void SetCanPlay() { mCanPlay = true; } bool CanPlay() const { return mCanPlay; } + void SetFFmpegFailedToLoad() { mFFmpegFailedToLoad = true; } + bool DidFFmpegFailToLoad() const { return mFFmpegFailedToLoad; } + private: // True if there is at least one decoder that can play the media. bool mCanPlay = false; + + bool mFFmpegFailedToLoad = false; }; } // namespace mozilla diff --git a/dom/media/DecoderTraits.cpp b/dom/media/DecoderTraits.cpp index 38ee59e7ed..be72773b58 100644 --- a/dom/media/DecoderTraits.cpp +++ b/dom/media/DecoderTraits.cpp @@ -9,6 +9,7 @@ #include "nsCharSeparatedTokenizer.h" #include "nsMimeTypes.h" #include "mozilla/Preferences.h" +#include "mozilla/Telemetry.h" #include "OggDecoder.h" #include "OggReader.h" @@ -176,6 +177,21 @@ DecoderTraits::IsWebMAudioType(const nsACString& aType) return aType.EqualsASCII("audio/webm"); } +static char const *const gHttpLiveStreamingTypes[] = { + // For m3u8. + // https://tools.ietf.org/html/draft-pantos-http-live-streaming-19#section-10 + "application/vnd.apple.mpegurl", + // Some sites serve these as the informal m3u type. + "audio/x-mpegurl", + nullptr +}; + +static bool +IsHttpLiveStreamingType(const nsACString& aType) +{ + return CodecListContains(gHttpLiveStreamingTypes, aType); +} + #ifdef MOZ_OMX_DECODER static const char* const gOmxTypes[] = { "audio/mpeg", @@ -481,6 +497,10 @@ DecoderTraits::CanHandleMediaType(const char* aMIMEType, { MOZ_ASSERT(NS_IsMainThread()); + if (IsHttpLiveStreamingType(nsDependentCString(aMIMEType))) { + Telemetry::Accumulate(Telemetry::MEDIA_HLS_CANPLAY_REQUESTED, true); + } + if (aHaveRequestedCodecs) { CanPlayStatus result = CanHandleCodecsType(aMIMEType, aRequestedCodecs, @@ -625,6 +645,11 @@ InstantiateDecoder(const nsACString& aType, } #endif + if (IsHttpLiveStreamingType(aType)) { + // We don't have an HLS decoder. + Telemetry::Accumulate(Telemetry::MEDIA_HLS_DECODER_SUCCESS, false); + } + return nullptr; } diff --git a/dom/media/MediaInfo.h b/dom/media/MediaInfo.h index b01414652b..5b69c70a3b 100644 --- a/dom/media/MediaInfo.h +++ b/dom/media/MediaInfo.h @@ -190,10 +190,11 @@ public: EmptyString(), EmptyString(), true, 2) , mDisplay(nsIntSize(aWidth, aHeight)) , mStereoMode(StereoMode::MONO) - , mImage(nsIntRect(0, 0, aWidth, aHeight)) + , mImage(nsIntSize(aWidth, aHeight)) , mCodecSpecificConfig(new MediaByteBuffer) , mExtraData(new MediaByteBuffer) , mRotation(kDegree_0) + , mImageRect(nsIntRect(0, 0, aWidth, aHeight)) { } @@ -205,6 +206,7 @@ public: , mCodecSpecificConfig(aOther.mCodecSpecificConfig) , mExtraData(aOther.mExtraData) , mRotation(aOther.mRotation) + , mImageRect(aOther.mImageRect) { } @@ -228,6 +230,40 @@ public: return MakeUnique(*this); } + nsIntRect ImageRect() const + { + if (mImageRect.width < 0 || mImageRect.height < 0) { + return nsIntRect(0, 0, mImage.width, mImage.height); + } + return mImageRect; + } + + void SetImageRect(const nsIntRect& aRect) + { + mImageRect = aRect; + } + + // Returned the crop rectangle scaled to aWidth/aHeight size relative to + // mImage size. + // If aWidth and aHeight are identical to the original mImage.width/mImage.height + // then the scaling ratio will be 1. + // This is used for when the frame size is different from what the container + // reports. This is legal in WebM, and we will preserve the ratio of the crop + // rectangle as it was reported relative to the picture size reported by the + // container. + nsIntRect ScaledImageRect(int64_t aWidth, int64_t aHeight) const + { + if (aWidth == mImage.width && aHeight == mImage.height) { + return ImageRect(); + } + nsIntRect imageRect = ImageRect(); + imageRect.x = (imageRect.x * aWidth) / mImage.width; + imageRect.y = (imageRect.y * aHeight) / mImage.height; + imageRect.width = (aWidth * imageRect.width) / mImage.width; + imageRect.height = (aHeight * imageRect.height) / mImage.height; + return imageRect; + } + Rotation ToSupportedRotation(int32_t aDegree) { switch (aDegree) { @@ -250,14 +286,20 @@ public: // Indicates the frame layout for single track stereo videos. StereoMode mStereoMode; - // Visible area of the decoded video's image. - nsIntRect mImage; + // Size of the decoded video's image. + nsIntSize mImage; + RefPtr mCodecSpecificConfig; RefPtr mExtraData; // Describing how many degrees video frames should be rotated in clock-wise to // get correct view. Rotation mRotation; + +private: + // mImage may be cropped; currently only used with the WebM container. + // A negative width or height indicate that no cropping is to occur. + nsIntRect mImageRect; }; class AudioInfo : public TrackInfo { @@ -530,7 +572,12 @@ public: : ChannelLayout(aChannels, SMPTEDefault(aChannels)) {} ChannelLayout(uint32_t aChannels, const Channel* aConfig) + : ChannelLayout() { + if (!aConfig) { + mValid = false; + return; + } mChannels.AppendElements(aConfig, aChannels); UpdateChannelMap(); } diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp index a7feb79fe1..2e01991f9d 100644 --- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -227,8 +227,7 @@ CreateTestH264Decoder(layers::LayersBackend aBackend, aConfig.mId = 1; aConfig.mDuration = 40000; aConfig.mMediaTime = 0; - aConfig.mDisplay = nsIntSize(640, 360); - aConfig.mImage = nsIntRect(0, 0, 640, 360); + aConfig.mImage = aConfig.mDisplay = nsIntSize(640, 360); aConfig.mExtraData = new MediaByteBuffer(); aConfig.mExtraData->AppendElements(sTestH264ExtraData, MOZ_ARRAY_LENGTH(sTestH264ExtraData)); @@ -278,10 +277,10 @@ MP4Decoder::IsVideoAccelerated(layers::LayersBackend aBackend, nsIGlobalObject* result.AssignLiteral("Yes"); } else { result.AssignLiteral("No"); - if (failureReason.Length()) { - result.AppendLiteral("; "); - AppendUTF8toUTF16(failureReason, result); - } + } + if (failureReason.Length()) { + result.AppendLiteral("; "); + AppendUTF8toUTF16(failureReason, result); } decoder->Shutdown(); taskQueue->BeginShutdown(); diff --git a/dom/media/omx/OMXCodecWrapper.h b/dom/media/omx/OMXCodecWrapper.h index 06c00ec43e..8d4002f7e7 100644 --- a/dom/media/omx/OMXCodecWrapper.h +++ b/dom/media/omx/OMXCodecWrapper.h @@ -14,9 +14,8 @@ #include "AudioSegment.h" #include "GonkNativeWindow.h" -#include "GonkNativeWindowClient.h" #include "mozilla/media/MediaSystemResourceClient.h" -#include "RefPtr.h" +#include "mozilla/RefPtr.h" #include diff --git a/dom/media/omx/OmxDecoder.cpp b/dom/media/omx/OmxDecoder.cpp index 3867c1390c..2c6bd2d43e 100644 --- a/dom/media/omx/OmxDecoder.cpp +++ b/dom/media/omx/OmxDecoder.cpp @@ -29,7 +29,6 @@ #include "mozilla/Logging.h" #include "GonkNativeWindow.h" -#include "GonkNativeWindowClient.h" #include "OMXCodecProxy.h" #include "OmxDecoder.h" diff --git a/dom/media/platforms/PDMFactory.cpp b/dom/media/platforms/PDMFactory.cpp index 3caa8217f2..ec6b541881 100644 --- a/dom/media/platforms/PDMFactory.cpp +++ b/dom/media/platforms/PDMFactory.cpp @@ -39,6 +39,8 @@ #include "mozilla/CDMProxy.h" #endif +#include "DecoderDoctorDiagnostics.h" + namespace mozilla { extern already_AddRefed CreateAgnosticDecoderModule(); @@ -147,6 +149,14 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig, aImageContainer); } + if (aDiagnostics) { + // If libraries failed to load, the following loop over mCurrentPDMs + // will not even try to use them. So we record failures now. + if (mFFmpegFailedToLoad) { + aDiagnostics->SetFFmpegFailedToLoad(); + } + } + for (auto& current : mCurrentPDMs) { if (!current->SupportsMimeType(aConfig.mMimeType, aDiagnostics)) { continue; @@ -273,7 +283,9 @@ PDMFactory::CreatePDMs() #ifdef MOZ_FFMPEG if (sFFmpegDecoderEnabled) { m = FFmpegRuntimeLinker::CreateDecoderModule(); - StartupPDM(m); + if (!StartupPDM(m)) { + mFFmpegFailedToLoad = true; + } } #endif #ifdef MOZ_APPLEMEDIA @@ -316,6 +328,14 @@ already_AddRefed PDMFactory::GetDecoder(const nsACString& aMimeType, DecoderDoctorDiagnostics* aDiagnostics) const { + if (aDiagnostics) { + // If libraries failed to load, the following loop over mCurrentPDMs + // will not even try to use them. So we record failures now. + if (mFFmpegFailedToLoad) { + aDiagnostics->SetFFmpegFailedToLoad(); + } + } + RefPtr pdm; for (auto& current : mCurrentPDMs) { if (current->SupportsMimeType(aMimeType, aDiagnostics)) { diff --git a/dom/media/platforms/PDMFactory.h b/dom/media/platforms/PDMFactory.h index 3b128da11d..ec9c1291ea 100644 --- a/dom/media/platforms/PDMFactory.h +++ b/dom/media/platforms/PDMFactory.h @@ -91,6 +91,8 @@ private: nsTArray> mCurrentPDMs; RefPtr mEMEPDM; + + bool mFFmpegFailedToLoad = false; }; } // namespace mozilla diff --git a/dom/media/platforms/agnostic/VPXDecoder.cpp b/dom/media/platforms/agnostic/VPXDecoder.cpp index 2fb87f6508..644361ecaa 100644 --- a/dom/media/platforms/agnostic/VPXDecoder.cpp +++ b/dom/media/platforms/agnostic/VPXDecoder.cpp @@ -114,7 +114,9 @@ VPXDecoder::DoDecodeFrame(MediaRawData* aSample) vpx_image_t *img; while ((img = vpx_codec_get_frame(&mVPX, &iter))) { - NS_ASSERTION(img->fmt == VPX_IMG_FMT_I420, "WebM image format not I420"); + NS_ASSERTION(img->fmt == VPX_IMG_FMT_I420 || + img->fmt == VPX_IMG_FMT_I444, + "WebM image format not I420 or I444"); // Chroma shifts are rounded down as per the decoding examples in the SDK VideoData::YCbCrBuffer b; @@ -126,27 +128,39 @@ VPXDecoder::DoDecodeFrame(MediaRawData* aSample) b.mPlanes[1].mData = img->planes[1]; b.mPlanes[1].mStride = img->stride[1]; - b.mPlanes[1].mHeight = (img->d_h + 1) >> img->y_chroma_shift; - b.mPlanes[1].mWidth = (img->d_w + 1) >> img->x_chroma_shift; b.mPlanes[1].mOffset = b.mPlanes[1].mSkip = 0; b.mPlanes[2].mData = img->planes[2]; b.mPlanes[2].mStride = img->stride[2]; - b.mPlanes[2].mHeight = (img->d_h + 1) >> img->y_chroma_shift; - b.mPlanes[2].mWidth = (img->d_w + 1) >> img->x_chroma_shift; b.mPlanes[2].mOffset = b.mPlanes[2].mSkip = 0; - VideoInfo info; - info.mDisplay = mInfo.mDisplay; - RefPtr v = VideoData::Create(info, - mImageContainer, - aSample->mOffset, - aSample->mTime, - aSample->mDuration, - b, - aSample->mKeyframe, - aSample->mTimecode, - mInfo.mImage); + if (img->fmt == VPX_IMG_FMT_I420) { + b.mPlanes[1].mHeight = (img->d_h + 1) >> img->y_chroma_shift; + b.mPlanes[1].mWidth = (img->d_w + 1) >> img->x_chroma_shift; + + b.mPlanes[2].mHeight = (img->d_h + 1) >> img->y_chroma_shift; + b.mPlanes[2].mWidth = (img->d_w + 1) >> img->x_chroma_shift; + } else if (img->fmt == VPX_IMG_FMT_I444) { + b.mPlanes[1].mHeight = img->d_h; + b.mPlanes[1].mWidth = img->d_w; + + b.mPlanes[2].mHeight = img->d_h; + b.mPlanes[2].mWidth = img->d_w; + } else { + LOG("VPX Unknown image format"); + return -1; + } + + RefPtr v = VideoData::Create(mInfo, + mImageContainer, + aSample->mOffset, + aSample->mTime, + aSample->mDuration, + b, + aSample->mKeyframe, + aSample->mTimecode, + mInfo.ScaledImageRect(img->d_w, + img->d_h)); if (!v) { LOG("Image allocation error source %ldx%ld display %ldx%ld picture %ldx%ld", @@ -199,10 +213,12 @@ VPXDecoder::Drain() /* static */ bool -VPXDecoder::IsVPX(const nsACString& aMimeType) +VPXDecoder::IsVPX(const nsACString& aMimeType, uint8_t aCodecMask) { - return aMimeType.EqualsLiteral("video/webm; codecs=vp8") || - aMimeType.EqualsLiteral("video/webm; codecs=vp9"); + return ((aCodecMask & VPXDecoder::VP8) && + aMimeType.EqualsLiteral("video/webm; codecs=vp8")) || + ((aCodecMask & VPXDecoder::VP9) && + aMimeType.EqualsLiteral("video/webm; codecs=vp9")); } } // namespace mozilla diff --git a/dom/media/platforms/agnostic/VPXDecoder.h b/dom/media/platforms/agnostic/VPXDecoder.h index b6c3233668..2cb4ab2785 100644 --- a/dom/media/platforms/agnostic/VPXDecoder.h +++ b/dom/media/platforms/agnostic/VPXDecoder.h @@ -38,14 +38,14 @@ public: return "libvpx video decoder"; } - // Return true if mimetype is a VPX codec - static bool IsVPX(const nsACString& aMimeType); - - enum Codec { - VP8, - VP9 + enum Codec: uint8_t { + VP8 = 1 << 0, + VP9 = 1 << 1 }; + // Return true if mimetype is a VPX codec of given types. + static bool IsVPX(const nsACString& aMimeType, uint8_t aCodecMask=VP8|VP9); + private: void DecodeFrame (MediaRawData* aSample); int DoDecodeFrame (MediaRawData* aSample); diff --git a/dom/media/platforms/ffmpeg/FFmpegH264Decoder.cpp b/dom/media/platforms/ffmpeg/FFmpegH264Decoder.cpp index 2189236d50..bc3561ac78 100644 --- a/dom/media/platforms/ffmpeg/FFmpegH264Decoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegH264Decoder.cpp @@ -115,8 +115,7 @@ FFmpegH264Decoder::FFmpegH264Decoder( ImageContainer* aImageContainer) : FFmpegDataDecoder(aTaskQueue, aCallback, GetCodecId(aConfig.mMimeType)) , mImageContainer(aImageContainer) - , mDisplay(aConfig.mDisplay) - , mImage(aConfig.mImage) + , mInfo(aConfig) , mCodecParser(nullptr) { MOZ_COUNT_CTOR(FFmpegH264Decoder); @@ -141,18 +140,18 @@ FFmpegH264Decoder::Init() void FFmpegH264Decoder::InitCodecContext() { - mCodecContext->width = mImage.width; - mCodecContext->height = mImage.height; + mCodecContext->width = mInfo.mImage.width; + mCodecContext->height = mInfo.mImage.height; // We use the same logic as libvpx in determining the number of threads to use // so that we end up behaving in the same fashion when using ffmpeg as // we would otherwise cause various crashes (see bug 1236167) int decode_threads = 1; - if (mDisplay.width >= 2048) { + if (mInfo.mDisplay.width >= 2048) { decode_threads = 8; - } else if (mDisplay.width >= 1024) { + } else if (mInfo.mDisplay.width >= 1024) { decode_threads = 4; - } else if (mDisplay.width >= 320) { + } else if (mInfo.mDisplay.width >= 320) { decode_threads = 2; } @@ -308,9 +307,6 @@ FFmpegH264Decoder::DoDecodeFrame(MediaRawData* aSample, mDurationMap.Clear(); } - VideoInfo info; - info.mDisplay = mDisplay; - VideoData::YCbCrBuffer b; b.mPlanes[0].mData = mFrame->data[0]; b.mPlanes[1].mData = mFrame->data[1]; @@ -334,15 +330,17 @@ FFmpegH264Decoder::DoDecodeFrame(MediaRawData* aSample, b.mPlanes[1].mHeight = b.mPlanes[2].mHeight = (mFrame->height + 1) >> 1; } - RefPtr v = VideoData::Create(info, - mImageContainer, - aSample->mOffset, - pts, - duration, - b, - !!mFrame->key_frame, - -1, - mImage); + RefPtr v = VideoData::Create(mInfo, + mImageContainer, + aSample->mOffset, + pts, + duration, + b, + !!mFrame->key_frame, + -1, + mInfo.ScaledImageRect(mFrame->width, + mFrame->height)); + if (!v) { NS_WARNING("image allocation error."); mCallback->Error(); diff --git a/dom/media/platforms/ffmpeg/FFmpegH264Decoder.h b/dom/media/platforms/ffmpeg/FFmpegH264Decoder.h index 913c48fec1..8d71b63767 100644 --- a/dom/media/platforms/ffmpeg/FFmpegH264Decoder.h +++ b/dom/media/platforms/ffmpeg/FFmpegH264Decoder.h @@ -69,8 +69,7 @@ private: AVFrame* aFrame); RefPtr mImageContainer; - nsIntSize mDisplay; - nsIntRect mImage; + VideoInfo mInfo; // Parser used for VP8 and VP9 decoding. AVCodecParserContext* mCodecParser; diff --git a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp index 12c9c49c13..78bd3dd0f0 100644 --- a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp +++ b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp @@ -8,6 +8,7 @@ #include #include #include "GonkVideoDecoderManager.h" +#include "GrallocImages.h" #include "MediaDecoderReader.h" #include "ImageContainer.h" #include "VideoUtils.h" @@ -19,7 +20,6 @@ #include #include #include "GonkNativeWindow.h" -#include "GonkNativeWindowClient.h" #include "mozilla/layers/GrallocTextureClient.h" #include "mozilla/layers/ImageBridgeChild.h" #include "mozilla/layers/TextureClient.h" @@ -43,25 +43,13 @@ namespace mozilla { GonkVideoDecoderManager::GonkVideoDecoderManager( mozilla::layers::ImageContainer* aImageContainer, const VideoInfo& aConfig) - : mImageContainer(aImageContainer) + : mConfig(aConfig) + , mImageContainer(aImageContainer) , mColorConverterBufferSize(0) - , mNativeWindow(nullptr) , mPendingReleaseItemsLock("GonkVideoDecoderManager::mPendingReleaseItemsLock") , mNeedsCopyBuffer(false) { MOZ_COUNT_CTOR(GonkVideoDecoderManager); - mMimeType = aConfig.mMimeType; - mVideoWidth = aConfig.mDisplay.width; - mVideoHeight = aConfig.mDisplay.height; - mDisplayWidth = aConfig.mDisplay.width; - mDisplayHeight = aConfig.mDisplay.height; - mInfo.mVideo = aConfig; - - mCodecSpecificData = aConfig.mCodecSpecificConfig; - nsIntRect pictureRect(0, 0, mVideoWidth, mVideoHeight); - nsIntSize frameSize(mVideoWidth, mVideoHeight); - mPicture = pictureRect; - mInitialFrame = frameSize; } GonkVideoDecoderManager::~GonkVideoDecoderManager() @@ -81,12 +69,21 @@ GonkVideoDecoderManager::Init() { mNeedsCopyBuffer = false; - nsIntSize displaySize(mDisplayWidth, mDisplayHeight); - nsIntRect pictureRect(0, 0, mVideoWidth, mVideoHeight); + uint32_t maxWidth, maxHeight; + char propValue[PROPERTY_VALUE_MAX]; + property_get("ro.moz.omx.hw.max_width", propValue, "-1"); + maxWidth = -1 == atoi(propValue) ? MAX_VIDEO_WIDTH : atoi(propValue); + property_get("ro.moz.omx.hw.max_height", propValue, "-1"); + maxHeight = -1 == atoi(propValue) ? MAX_VIDEO_HEIGHT : atoi(propValue) ; + + if (uint32_t(mConfig.mImage.width * mConfig.mImage.height) > maxWidth * maxHeight) { + GVDM_LOG("Video resolution exceeds hw codec capability"); + return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); + } + // Validate the container-reported frame and pictureRect sizes. This ensures // that our video frame creation code doesn't overflow. - nsIntSize frameSize(mVideoWidth, mVideoHeight); - if (!IsValidVideoRegion(frameSize, pictureRect, displaySize)) { + if (!IsValidVideoRegion(mConfig.mImage, mConfig.ImageRect(), mConfig.mDisplay)) { GVDM_LOG("It is not a valid region"); return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); } @@ -104,12 +101,20 @@ GonkVideoDecoderManager::Init() RefPtr p = mInitPromise.Ensure(__func__); android::sp self = this; - mDecoder = MediaCodecProxy::CreateByType(mDecodeLooper, mMimeType.get(), false); + mDecoder = MediaCodecProxy::CreateByType(mDecodeLooper, + mConfig.mMimeType.get(), + false); uint32_t capability = MediaCodecProxy::kEmptyCapability; if (mDecoder->getCapability(&capability) == OK && (capability & MediaCodecProxy::kCanExposeGraphicBuffer)) { +#if ANDROID_VERSION >= 21 + sp consumer; + GonkBufferQueue::createBufferQueue(&mGraphicBufferProducer, &consumer); + mNativeWindow = new GonkNativeWindow(consumer); +#else mNativeWindow = new GonkNativeWindow(); +#endif } mVideoCodecRequest.Begin(mDecoder->AsyncAllocateVideoMediaCodec() @@ -163,19 +168,8 @@ GonkVideoDecoderManager::CreateVideoData(MediaBuffer* aBuffer, keyFrame = 0; } - gfx::IntRect picture = mPicture; - if (mFrameInfo.mWidth != mInitialFrame.width || - mFrameInfo.mHeight != mInitialFrame.height) { - - // Frame size is different from what the container reports. This is legal, - // and we will preserve the ratio of the crop rectangle as it - // was reported relative to the picture size reported by the container. - picture.x = (mPicture.x * mFrameInfo.mWidth) / mInitialFrame.width; - picture.y = (mPicture.y * mFrameInfo.mHeight) / mInitialFrame.height; - picture.width = (mFrameInfo.mWidth * mPicture.width) / mInitialFrame.width; - picture.height = (mFrameInfo.mHeight * mPicture.height) / mInitialFrame.height; - } - + gfx::IntRect picture = + mConfig.ScaledImageRect(mFrameInfo.mWidth, mFrameInfo.mHeight); if (aBuffer->graphicBuffer().get()) { data = CreateVideoDataFromGraphicBuffer(aBuffer, picture); if (data && !mNeedsCopyBuffer) { @@ -364,7 +358,7 @@ GonkVideoDecoderManager::CreateVideoDataFromGraphicBuffer(MediaBuffer* aSource, static_cast(textureClient->GetInternalData())->SetMediaBuffer(aSource); } - RefPtr data = VideoData::Create(mInfo.mVideo, + RefPtr data = VideoData::Create(mConfig, mImageContainer, 0, // Filled later by caller. 0, // Filled later by caller. @@ -433,7 +427,7 @@ GonkVideoDecoderManager::CreateVideoDataFromDataBuffer(MediaBuffer* aSource, gfx b.mPlanes[2].mOffset = 0; b.mPlanes[2].mSkip = 0; - RefPtr data = VideoData::Create(mInfo.mVideo, + RefPtr data = VideoData::Create(mConfig, mImageContainer, 0, // Filled later by caller. 0, // Filled later by caller. @@ -479,7 +473,9 @@ GonkVideoDecoderManager::SetVideoFormat() mFrameInfo.mColorFormat = color_format; nsIntSize displaySize(width, height); - if (!IsValidVideoRegion(mInitialFrame, mPicture, displaySize)) { + if (!IsValidVideoRegion(mConfig.mDisplay, + mConfig.ScaledImageRect(width, height), + displaySize)) { GVDM_LOG("It is not a valid region"); return false; } @@ -537,7 +533,7 @@ GonkVideoDecoderManager::Output(int64_t aStreamOffset, } case -EAGAIN: { - GVDM_LOG("Need to try again!"); +// GVDM_LOG("Need to try again!"); return NS_ERROR_NOT_AVAILABLE; } case android::ERROR_END_OF_STREAM: @@ -580,21 +576,28 @@ GonkVideoDecoderManager::codecReserved() GVDM_LOG("codecReserved"); sp format = new AMessage; sp surface; - + status_t rv = OK; // Fixed values - GVDM_LOG("Configure video mime type: %s, widht:%d, height:%d", mMimeType.get(), mVideoWidth, mVideoHeight); - format->setString("mime", mMimeType.get()); - format->setInt32("width", mVideoWidth); - format->setInt32("height", mVideoHeight); + GVDM_LOG("Configure video mime type: %s, width:%d, height:%d", mConfig.mMimeType.get(), mConfig.mImage.width, mConfig.mImage.height); + format->setString("mime", mConfig.mMimeType.get()); + format->setInt32("width", mConfig.mImage.width); + format->setInt32("height", mConfig.mImage.height); + // Set the "moz-use-undequeued-bufs" to use the undeque buffers to accelerate + // the video decoding. + format->setInt32("moz-use-undequeued-bufs", 1); if (mNativeWindow != nullptr) { +#if ANDROID_VERSION >= 21 + surface = new Surface(mGraphicBufferProducer); +#else surface = new Surface(mNativeWindow->getBufferQueue()); +#endif } mDecoder->configure(format, surface, nullptr, 0); mDecoder->Prepare(); - if (mMimeType.EqualsLiteral("video/mp4v-es")) { - rv = mDecoder->Input(mCodecSpecificData->Elements(), - mCodecSpecificData->Length(), 0, + if (mConfig.mMimeType.EqualsLiteral("video/mp4v-es")) { + rv = mDecoder->Input(mConfig.mCodecSpecificConfig->Elements(), + mConfig.mCodecSpecificConfig->Length(), 0, android::MediaCodec::BUFFER_FLAG_CODECCONFIG, CODECCONFIG_TIMEOUT_US); } @@ -689,7 +692,7 @@ void GonkVideoDecoderManager::ReleaseAllPendingVideoBuffers() // Free all pending video buffers without holding mPendingReleaseItemsLock. size_t size = releasingItems.Length(); for (size_t i = 0; i < size; i++) { - nsRefPtr fdObj = releasingItems[i].mReleaseFence.GetAndResetFdObj(); + RefPtr fdObj = releasingItems[i].mReleaseFence.GetAndResetFdObj(); sp fence = new Fence(fdObj->GetAndResetFd()); fence->waitForever("GonkVideoDecoderManager"); mDecoder->ReleaseMediaBuffer(releasingItems[i].mBuffer); diff --git a/dom/media/platforms/gonk/GonkVideoDecoderManager.h b/dom/media/platforms/gonk/GonkVideoDecoderManager.h index 730ce1ab54..8537d96397 100644 --- a/dom/media/platforms/gonk/GonkVideoDecoderManager.h +++ b/dom/media/platforms/gonk/GonkVideoDecoderManager.h @@ -13,7 +13,6 @@ #include "I420ColorConverterHelper.h" #include "MediaCodecProxy.h" #include "GonkNativeWindow.h" -#include "GonkNativeWindowClient.h" #include "mozilla/layers/FenceUtils.h" #include "mozilla/UniquePtr.h" #include @@ -101,17 +100,11 @@ private: void PostReleaseVideoBuffer(android::MediaBuffer *aBuffer, layers::FenceHandle mReleaseFence); - uint32_t mVideoWidth; - uint32_t mVideoHeight; - uint32_t mDisplayWidth; - uint32_t mDisplayHeight; - nsIntRect mPicture; - nsIntSize mInitialFrame; + VideoInfo mConfig; RefPtr mImageContainer; RefPtr mCopyAllocator; - MediaInfo mInfo; MozPromiseRequestHolder mVideoCodecRequest; FrameInfo mFrameInfo; @@ -121,6 +114,10 @@ private: size_t mColorConverterBufferSize; android::sp mNativeWindow; +#if ANDROID_VERSION >= 21 + android::sp mGraphicBufferProducer; +#endif + enum { kNotifyPostReleaseBuffer = 'nprb', }; diff --git a/dom/media/platforms/omx/OmxPlatformLayer.cpp b/dom/media/platforms/omx/OmxPlatformLayer.cpp deleted file mode 100644 index a3a3a226c0..0000000000 --- a/dom/media/platforms/omx/OmxPlatformLayer.cpp +++ /dev/null @@ -1,212 +0,0 @@ -/* -*- 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 "OmxPlatformLayer.h" - -#if defined(MOZ_WIDGET_GONK) && (ANDROID_VERSION == 20 || ANDROID_VERSION == 19) -#define OMX_PLATFORM_GONK -#include "GonkOmxPlatformLayer.h" -#endif - -extern mozilla::LogModule* GetPDMLog(); - -#ifdef LOG -#undef LOG -#endif - -#define LOG(arg, ...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, ("OmxPlatformLayer -- %s: " arg, __func__, ##__VA_ARGS__)) - -#define RETURN_IF_ERR(err) \ - if (err != OMX_ErrorNone) { \ - LOG("error: 0x%08x", err); \ - return err; \ - } \ - -// Common OMX decoder configuration code. -namespace mozilla { - -// This helper class encapsulates the details of component parameters setting -// for different OMX audio & video codecs. -template -class OmxConfig -{ -public: - virtual ~OmxConfig() {} - // Subclasses should implement this method to configure the codec. - virtual OMX_ERRORTYPE Apply(OmxPlatformLayer& aOmx, const ParamType& aParam) = 0; -}; - -typedef OmxConfig OmxAudioConfig; -typedef OmxConfig OmxVideoConfig; - -template -UniquePtr ConfigForMime(const nsACString&); - -class OmxAacConfig : public OmxAudioConfig -{ -public: - OMX_ERRORTYPE Apply(OmxPlatformLayer& aOmx, const AudioInfo& aInfo) override - { - OMX_ERRORTYPE err; - - OMX_AUDIO_PARAM_AACPROFILETYPE aacProfile; - InitOmxParameter(&aacProfile); - err = aOmx.GetParameter(OMX_IndexParamAudioAac, &aacProfile, sizeof(aacProfile)); - RETURN_IF_ERR(err); - - aacProfile.nChannels = aInfo.mChannels; - aacProfile.nSampleRate = aInfo.mRate; - aacProfile.eAACProfile = static_cast(aInfo.mProfile); - err = aOmx.SetParameter(OMX_IndexParamAudioAac, &aacProfile, sizeof(aacProfile)); - RETURN_IF_ERR(err); - - LOG("Config OMX_IndexParamAudioAac, channel %d, sample rate %d, profile %d", - aacProfile.nChannels, aacProfile.nSampleRate, aacProfile.eAACProfile); - - return OMX_ErrorNone; - } -}; - -template<> -UniquePtr -ConfigForMime(const nsACString& aMimeType) -{ - UniquePtr conf; - - if (OmxPlatformLayer::SupportsMimeType(aMimeType)) { - if (aMimeType.EqualsLiteral("audio/mp4a-latm")) { - conf.reset(new OmxAacConfig()); - } - } - return Move(conf); -} - -// There should be a better way to calculate it. -#define MIN_VIDEO_INPUT_BUFFER_SIZE 64 * 1024 - -class OmxCommonVideoConfig : public OmxVideoConfig -{ -public: - explicit OmxCommonVideoConfig(OMX_VIDEO_CODINGTYPE aCodec) - : OmxVideoConfig() - , mCodec(aCodec) - {} - - OMX_ERRORTYPE Apply(OmxPlatformLayer& aOmx, const VideoInfo& aInfo) override - { - OMX_ERRORTYPE err; - OMX_PARAM_PORTDEFINITIONTYPE def; - - // Set up in/out port definition. - nsTArray ports; - GetOmxPortIndex(ports); - for (auto idx : ports) { - InitOmxParameter(&def); - def.nPortIndex = idx; - err = aOmx.GetParameter(OMX_IndexParamPortDefinition, &def, sizeof(def)); - RETURN_IF_ERR(err); - - def.format.video.nFrameWidth = aInfo.mDisplay.width; - def.format.video.nFrameHeight = aInfo.mDisplay.height; - def.format.video.nStride = aInfo.mImage.width; - def.format.video.nSliceHeight = aInfo.mImage.height; - - if (def.eDir == OMX_DirInput) { - def.format.video.eCompressionFormat = mCodec; - def.format.video.eColorFormat = OMX_COLOR_FormatUnused; - if (def.nBufferSize < MIN_VIDEO_INPUT_BUFFER_SIZE) { - def.nBufferSize = aInfo.mImage.width * aInfo.mImage.height; - LOG("Change input buffer size to %d", def.nBufferSize); - } - } else { - def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; - } - - err = aOmx.SetParameter(OMX_IndexParamPortDefinition, &def, sizeof(def)); - } - return err; - } - -private: - const OMX_VIDEO_CODINGTYPE mCodec; -}; - -template<> -UniquePtr -ConfigForMime(const nsACString& aMimeType) -{ - UniquePtr conf; - - if (OmxPlatformLayer::SupportsMimeType(aMimeType)) { - if (aMimeType.EqualsLiteral("video/avc")) { - conf.reset(new OmxCommonVideoConfig(OMX_VIDEO_CodingAVC)); - } else if (aMimeType.EqualsLiteral("video/mp4v-es") || - aMimeType.EqualsLiteral("video/mp4")) { - conf.reset(new OmxCommonVideoConfig(OMX_VIDEO_CodingMPEG4)); - } else if (aMimeType.EqualsLiteral("video/3gpp")) { - conf.reset(new OmxCommonVideoConfig(OMX_VIDEO_CodingH263)); - } - } - return Move(conf); -} - -OMX_ERRORTYPE -OmxPlatformLayer::Config() -{ - MOZ_ASSERT(mInfo); - - if (mInfo->IsAudio()) { - UniquePtr conf(ConfigForMime(mInfo->mMimeType)); - MOZ_ASSERT(conf.get()); - return conf->Apply(*this, *(mInfo->GetAsAudioInfo())); - } else if (mInfo->IsVideo()) { - UniquePtr conf(ConfigForMime(mInfo->mMimeType)); - MOZ_ASSERT(conf.get()); - return conf->Apply(*this, *(mInfo->GetAsVideoInfo())); - } else { - MOZ_ASSERT_UNREACHABLE("non-AV data (text?) is not supported."); - return OMX_ErrorNotImplemented; - } -} - -// Implementations for different platforms will be defined in their own files. -#ifdef OMX_PLATFORM_GONK - -bool -OmxPlatformLayer::SupportsMimeType(const nsACString& aMimeType) -{ - return GonkOmxPlatformLayer::FindComponents(aMimeType); -} - -OmxPlatformLayer* -OmxPlatformLayer::Create(OmxDataDecoder* aDataDecoder, - OmxPromiseLayer* aPromiseLayer, - TaskQueue* aTaskQueue, - layers::ImageContainer* aImageContainer) -{ - return new GonkOmxPlatformLayer(aDataDecoder, aPromiseLayer, aTaskQueue, aImageContainer); -} - -#else // For platforms without OMX IL support. - -bool -OmxPlatformLayer::SupportsMimeType(const nsACString& aMimeType) -{ - return false; -} - -OmxPlatformLayer* -OmxPlatformLayer::Create(OmxDataDecoder* aDataDecoder, - OmxPromiseLayer* aPromiseLayer, - TaskQueue* aTaskQueue, - layers::ImageContainer* aImageContainer) -{ - return nullptr; -} - -#endif - -} diff --git a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp index be7cf4cc4f..34d363a429 100644 --- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp +++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp @@ -33,6 +33,8 @@ using mozilla::layers::IMFYCbCrImage; using mozilla::layers::LayerManager; using mozilla::layers::LayersBackend; +#if MOZ_WINSDK_MAXVER < 0x0A000000 +// Windows 10+ SDK has VP80 and VP90 defines const GUID MFVideoFormat_VP80 = { 0x30385056, @@ -48,6 +50,7 @@ const GUID MFVideoFormat_VP90 = 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} }; +#endif const CLSID CLSID_WebmMfVp8Dec = { @@ -74,6 +77,7 @@ WMFVideoMFTManager::WMFVideoMFTManager( bool aDXVAEnabled) : mVideoInfo(aConfig) , mVideoStride(0) + , mImageSize(aConfig.mImage) , mImageContainer(aImageContainer) , mDXVAEnabled(aDXVAEnabled) , mLayersBackend(aLayersBackend) @@ -154,13 +158,23 @@ public: NS_IMETHOD Run() { NS_ASSERTION(NS_IsMainThread(), "Must be on main thread."); + nsACString* failureReason = &mFailureReason; + nsCString secondFailureReason; if (mBackend == LayersBackend::LAYERS_D3D11 && - Preferences::GetBool("media.windows-media-foundation.allow-d3d11-dxva", false) && + Preferences::GetBool("media.windows-media-foundation.allow-d3d11-dxva", true) && IsWin8OrLater()) { - mDXVA2Manager = DXVA2Manager::CreateD3D11DXVA(mFailureReason); - } else { - mDXVA2Manager = DXVA2Manager::CreateD3D9DXVA(mFailureReason); + mDXVA2Manager = DXVA2Manager::CreateD3D11DXVA(*failureReason); + if (mDXVA2Manager) { + return NS_OK; + } + // Try again with d3d9, but record the failure reason + // into a new var to avoid overwriting the d3d11 failure. + failureReason = &secondFailureReason; + mFailureReason.Append(NS_LITERAL_CSTRING("; ")); } + mDXVA2Manager = DXVA2Manager::CreateD3D9DXVA(*failureReason); + // Make sure we include the messages from both attempts (if applicable). + mFailureReason.Append(secondFailureReason); return NS_OK; } nsAutoPtr mDXVA2Manager; @@ -204,14 +218,14 @@ WMFVideoMFTManager::Init() { bool success = InitInternal(/* aForceD3D9 = */ false); - // If initialization failed with d3d11 DXVA then try falling back - // to d3d9. - if (!success && mDXVA2Manager && mDXVA2Manager->IsD3D11()) { - mDXVA2Manager = nullptr; - nsCString d3d11Failure = mDXVAFailureReason; - success = InitInternal(true); - mDXVAFailureReason.Append(NS_LITERAL_CSTRING("; ")); - mDXVAFailureReason.Append(d3d11Failure); + if (success && mDXVA2Manager) { + // If we had some failures but eventually made it work, + // make sure we preserve the messages. + if (mDXVA2Manager->IsD3D11()) { + mDXVAFailureReason.Append(NS_LITERAL_CSTRING("Using D3D11 API")); + } else { + mDXVAFailureReason.Append(NS_LITERAL_CSTRING("Using D3D9 API")); + } } return success; @@ -383,18 +397,17 @@ WMFVideoMFTManager::ConfigureVideoFrameGeometry() NS_ENSURE_TRUE(videoFormat == MFVideoFormat_NV12 || !mUseHwAccel, E_FAIL); NS_ENSURE_TRUE(videoFormat == MFVideoFormat_YV12 || mUseHwAccel, E_FAIL); - UINT32 width = 0, height = 0; - hr = MFGetAttributeSize(mediaType, MF_MT_FRAME_SIZE, &width, &height); + nsIntRect pictureRegion; + hr = GetPictureRegion(mediaType, pictureRegion); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); - mVideoInfo.mImage.width = width; - mVideoInfo.mImage.height = height; - nsIntRect pictureRegion = mVideoInfo.mImage; + UINT32 width = pictureRegion.width; + UINT32 height = pictureRegion.height; + mImageSize = nsIntSize(width, height); // Calculate and validate the picture region and frame dimensions after // scaling by the pixel aspect ratio. - nsIntSize frameSize = nsIntSize(width, height); - nsIntSize displaySize = nsIntSize(mVideoInfo.mDisplay.width, mVideoInfo.mDisplay.height); - if (!IsValidVideoRegion(frameSize, pictureRegion, displaySize)) { + pictureRegion = mVideoInfo.ScaledImageRect(width, height); + if (!IsValidVideoRegion(mImageSize, pictureRegion, mVideoInfo.mDisplay)) { // Video track's frame sizes will overflow. Ignore the video track. return E_FAIL; } @@ -453,8 +466,8 @@ WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample, // i.e., Y, then V, then U. VideoData::YCbCrBuffer b; - uint32_t videoWidth = mVideoInfo.mImage.width; - uint32_t videoHeight = mVideoInfo.mImage.height; + uint32_t videoWidth = mImageSize.width; + uint32_t videoHeight = mImageSize.height; // Y (Y') plane b.mPlanes[0].mData = data; @@ -500,10 +513,11 @@ WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample, RefPtr image = new IMFYCbCrImage(buffer, twoDBuffer); + nsIntRect pictureRegion = mVideoInfo.ScaledImageRect(videoWidth, videoHeight); VideoData::SetVideoDataToImage(image, mVideoInfo, b, - mVideoInfo.mImage, + pictureRegion, false); RefPtr v = @@ -515,7 +529,7 @@ WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample, image.forget(), false, -1, - mVideoInfo.mImage); + pictureRegion); v.forget(aOutVideoData); return S_OK; @@ -534,9 +548,11 @@ WMFVideoMFTManager::CreateD3DVideoFrame(IMFSample* aSample, *aOutVideoData = nullptr; HRESULT hr; + nsIntRect pictureRegion = + mVideoInfo.ScaledImageRect(mImageSize.width, mImageSize.height); RefPtr image; hr = mDXVA2Manager->CopyToImage(aSample, - mVideoInfo.mImage, + pictureRegion, mImageContainer, getter_AddRefs(image)); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); @@ -547,14 +563,14 @@ WMFVideoMFTManager::CreateD3DVideoFrame(IMFSample* aSample, media::TimeUnit duration = GetSampleDuration(aSample); NS_ENSURE_TRUE(duration.IsValid(), E_FAIL); RefPtr v = VideoData::CreateFromImage(mVideoInfo, - mImageContainer, - aStreamOffset, - pts.ToMicroseconds(), - duration.ToMicroseconds(), - image.forget(), - false, - -1, - mVideoInfo.mImage); + mImageContainer, + aStreamOffset, + pts.ToMicroseconds(), + duration.ToMicroseconds(), + image.forget(), + false, + -1, + pictureRegion); NS_ENSURE_TRUE(v, E_FAIL); v.forget(aOutVideoData); @@ -669,6 +685,7 @@ WMFVideoMFTManager::ConfigurationChanged(const TrackInfo& aConfig) { MOZ_ASSERT(aConfig.GetAsVideoInfo()); mVideoInfo = *aConfig.GetAsVideoInfo(); + mImageSize = mVideoInfo.mImage; } } // namespace mozilla diff --git a/dom/media/platforms/wmf/WMFVideoMFTManager.h b/dom/media/platforms/wmf/WMFVideoMFTManager.h index 186d209fa7..8f75c37058 100644 --- a/dom/media/platforms/wmf/WMFVideoMFTManager.h +++ b/dom/media/platforms/wmf/WMFVideoMFTManager.h @@ -66,6 +66,7 @@ private: // Video frame geometry. VideoInfo mVideoInfo; uint32_t mVideoStride; + nsIntSize mImageSize; RefPtr mImageContainer; nsAutoPtr mDXVA2Manager; diff --git a/dom/media/webaudio/AudioBuffer.h b/dom/media/webaudio/AudioBuffer.h index badb7959be..3771c49491 100644 --- a/dom/media/webaudio/AudioBuffer.h +++ b/dom/media/webaudio/AudioBuffer.h @@ -68,7 +68,7 @@ public: return mSampleRate; } - int32_t Length() const + uint32_t Length() const { return mLength; } diff --git a/dom/media/webm/WebMDemuxer.cpp b/dom/media/webm/WebMDemuxer.cpp index 20a703879c..4b7d5b6991 100644 --- a/dom/media/webm/WebMDemuxer.cpp +++ b/dom/media/webm/WebMDemuxer.cpp @@ -11,6 +11,7 @@ #include "WebMDemuxer.h" #include "WebMBufferedParser.h" #include "gfx2DGlue.h" +#include "mozilla/Atomics.h" #include "mozilla/Endian.h" #include "mozilla/Preferences.h" #include "mozilla/SharedThreadPool.h" @@ -42,6 +43,8 @@ LazyLogModule gNesteggLog("Nestegg"); // files encountered appear to have keyframes located < 4s. #define MAX_LOOK_AHEAD 10000000 +static Atomic sStreamSourceID(0u); + // Functions for reading and seeking using WebMDemuxer required for // nestegg_io. The 'user data' passed to these functions is the // demuxer. @@ -337,7 +340,8 @@ WebMDemuxer::ReadMetadata() mHasVideo = true; mInfo.mVideo.mDisplay = displaySize; - mInfo.mVideo.mImage = pictureRect; + mInfo.mVideo.mImage = frameSize; + mInfo.mVideo.SetImageRect(pictureRect); switch (params.stereo_mode) { case NESTEGG_VIDEO_MONO: @@ -572,6 +576,18 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl break; } isKeyframe = si.is_kf; + if (isKeyframe) { + // We only look for resolution changes on keyframes for both VP8 and + // VP9. Other resolution changes are invalid. + if (mLastSeenFrameWidth.isSome() && mLastSeenFrameHeight.isSome() && + (si.w != mLastSeenFrameWidth.value() || + si.h != mLastSeenFrameHeight.value())) { + mInfo.mVideo.mDisplay = nsIntSize(si.w, si.h); + mSharedVideoTrackInfo = new SharedTrackInfo(mInfo.mVideo, ++sStreamSourceID); + } + mLastSeenFrameWidth = Some(si.w); + mLastSeenFrameHeight = Some(si.h); + } } WEBM_DEBUG("push sample tstamp: %ld next_tstamp: %ld length: %ld kf: %d", @@ -582,12 +598,15 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl sample->mDuration = next_tstamp - tstamp; sample->mOffset = holder->Offset(); sample->mKeyframe = isKeyframe; - if (discardPadding) { + if (discardPadding && i == count - 1) { uint8_t c[8]; BigEndian::writeInt64(&c[0], discardPadding); sample->mExtraData = new MediaByteBuffer; sample->mExtraData->AppendElements(&c[0], 8); } + if (aType == TrackInfo::kVideoTrack) { + sample->mTrackInfo = mSharedVideoTrackInfo; + } aSamples->Push(sample); } return true; @@ -792,6 +811,7 @@ WebMTrackDemuxer::WebMTrackDemuxer(WebMDemuxer* aParent, uint32_t aTrackNumber) : mParent(aParent) , mType(aType) + , mNeedKeyframe(true) { mInfo = mParent->GetTrackInfo(aType, aTrackNumber); MOZ_ASSERT(mInfo); @@ -818,6 +838,7 @@ WebMTrackDemuxer::Seek(media::TimeUnit aTime) mSamples.Reset(); mParent->SeekInternal(aTime); mParent->GetNextPacket(mType, &mSamples); + mNeedKeyframe = true; // Check what time we actually seeked to. if (mSamples.GetSize() > 0) { @@ -853,6 +874,10 @@ WebMTrackDemuxer::GetSamples(int32_t aNumSamples) if (!sample) { break; } + if (mNeedKeyframe && !sample->mKeyframe) { + continue; + } + mNeedKeyframe = false; samples->mSamples.AppendElement(sample); aNumSamples--; } @@ -929,6 +954,7 @@ WebMTrackDemuxer::Reset() { mSamples.Reset(); media::TimeIntervals buffered = GetBuffered(); + mNeedKeyframe = true; if (buffered.Length()) { WEBM_DEBUG("Seek to start point: %f", buffered.Start(0).ToSeconds()); mParent->SeekInternal(buffered.Start(0)); diff --git a/dom/media/webm/WebMDemuxer.h b/dom/media/webm/WebMDemuxer.h index a06415e933..d54043bc96 100644 --- a/dom/media/webm/WebMDemuxer.h +++ b/dom/media/webm/WebMDemuxer.h @@ -201,6 +201,12 @@ private: // as nestegg only performs 1-byte read at a time. int64_t mLastWebMBlockOffset; const bool mIsMediaSource; + + Maybe mLastSeenFrameWidth; + Maybe mLastSeenFrameHeight; + // This will be populated only if a resolution change occurs, otherwise it + // will be left as null so the original metadata is used + RefPtr mSharedVideoTrackInfo; }; class WebMTrackDemuxer : public MediaTrackDemuxer @@ -236,6 +242,7 @@ private: TrackInfo::TrackType mType; UniquePtr mInfo; Maybe mNextKeyframeTime; + bool mNeedKeyframe; // Queued samples extracted by the demuxer, but not yet returned. MediaRawDataQueue mSamples; diff --git a/dom/webidl/AudioBuffer.webidl b/dom/webidl/AudioBuffer.webidl index cb91e6292b..119daa7e2c 100644 --- a/dom/webidl/AudioBuffer.webidl +++ b/dom/webidl/AudioBuffer.webidl @@ -13,12 +13,12 @@ interface AudioBuffer { readonly attribute float sampleRate; - readonly attribute long length; + readonly attribute unsigned long length; // in seconds readonly attribute double duration; - readonly attribute long numberOfChannels; + readonly attribute unsigned long numberOfChannels; [Throws] Float32Array getChannelData(unsigned long channel); diff --git a/dom/webidl/Console.webidl b/dom/webidl/Console.webidl index da4554cf2b..fe96841eec 100644 --- a/dom/webidl/Console.webidl +++ b/dom/webidl/Console.webidl @@ -23,6 +23,7 @@ interface Console { void time(optional any time); void timeEnd(optional any time); void timeStamp(optional any data); + void clear(any... data); void profile(any... data); void profileEnd(any... data); @@ -32,8 +33,6 @@ interface Console { // No-op methods for compatibility with other browsers. [BinaryName="noopMethod"] - void clear(); - [BinaryName="noopMethod"] void markTimeline(); [BinaryName="noopMethod"] void timeline(); diff --git a/dom/webidl/DecoderDoctorNotification.webidl b/dom/webidl/DecoderDoctorNotification.webidl index 6f7ec2c6ff..a14bc33bd1 100644 --- a/dom/webidl/DecoderDoctorNotification.webidl +++ b/dom/webidl/DecoderDoctorNotification.webidl @@ -6,6 +6,7 @@ enum DecoderDoctorNotificationType { "cannot-play", + "platform-decoder-not-found", "can-play-but-some-missing-decoders" }; diff --git a/dom/webidl/Promise.webidl b/dom/webidl/Promise.webidl index af658c5609..4dcb7d43e7 100644 --- a/dom/webidl/Promise.webidl +++ b/dom/webidl/Promise.webidl @@ -63,7 +63,7 @@ interface _Promise { }; #else // SPIDERMONKEY_PROMISE [NoInterfaceObject, - Exposed=(Window,Worker,System)] + Exposed=(Window,Worker,WorkerDebugger,System)] // Need to escape "Promise" so it's treated as an identifier. interface _Promise { }; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 73d82ee693..a15bdfa0ef 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -111,6 +111,7 @@ WEBIDL_FILES = [ 'DataStore.webidl', 'DataStoreImpl.webidl', 'DataTransfer.webidl', + 'DecoderDoctorNotification.webidl', 'DedicatedWorkerGlobalScope.webidl', 'DelayNode.webidl', 'DesktopNotification.webidl', diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp index 666f2f1d42..16929dcac8 100644 --- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -400,18 +400,6 @@ SandboxCloneInto(JSContext* cx, unsigned argc, Value* vp) return xpc::CloneInto(cx, args[0], args[1], options, args.rval()); } -static bool -sandbox_enumerate(JSContext* cx, HandleObject obj) -{ - return JS_EnumerateStandardClasses(cx, obj); -} - -static bool -sandbox_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp) -{ - return JS_ResolveStandardClass(cx, obj, id, resolvedp); -} - static void sandbox_finalize(js::FreeOp* fop, JSObject* obj) { @@ -491,9 +479,9 @@ sandbox_addProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v) CompartmentPrivate* priv = CompartmentPrivate::Get(obj); MOZ_ASSERT(priv->writeToGlobalPrototype); - // Whenever JS_EnumerateStandardClasses is called (by sandbox_enumerate for - // example), it defines the "undefined" property, even if it's already - // defined. We don't want to do anything in that case. + // Whenever JS_EnumerateStandardClasses is called, it defines the + // "undefined" property, even if it's already defined. We don't want to do + // anything in that case. if (id == XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_UNDEFINED)) return true; @@ -553,8 +541,8 @@ sandbox_addProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v) static const js::ClassOps SandboxClassOps = { nullptr, nullptr, nullptr, nullptr, - sandbox_enumerate, sandbox_resolve, - nullptr, /* mayResolve */ + JS_EnumerateStandardClasses, JS_ResolveStandardClass, + JS_MayResolveStandardClass, sandbox_finalize, nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook, }; @@ -577,8 +565,8 @@ static const js::Class SandboxClass = { // to do the work for this class. static const js::ClassOps SandboxWriteToProtoClassOps = { sandbox_addProperty, nullptr, nullptr, nullptr, - sandbox_enumerate, sandbox_resolve, - nullptr, /* mayResolve */ + JS_EnumerateStandardClasses, JS_ResolveStandardClass, + JS_MayResolveStandardClass, sandbox_finalize, nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook, }; diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index a5ce9bccce..ce03ea730b 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -349,6 +349,7 @@ pref("media.wmf.enabled", true); pref("media.wmf.decoder.thread-count", -1); pref("media.wmf.low-latency.enabled", false); pref("media.wmf.skip-blacklist", false); +pref("media.windows-media-foundation.allow-d3d11-dxva", true); #endif #if defined(MOZ_FFMPEG) pref("media.ffmpeg.enabled", true); diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 31e500cfa9..bcb2776359 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -6101,6 +6101,21 @@ "description": "Whether Ogg audio/video encountered are chained or not.", "bug_numbers": [1230295] }, + "MEDIA_HLS_CANPLAY_REQUESTED": { + "alert_emails": ["ajones@mozilla.com", "giles@mozilla.com"], + "expires_in_version": "50", + "kind": "boolean", + "description": "Reports a true value when a page requests canPlayType for an HTTP Live Streaming media type (or generic m3u playlist).", + "bug_numbers": [1262659] + }, + "MEDIA_HLS_DECODER_SUCCESS": { + "alert_emails": ["ajones@mozilla.com", "giles@mozilla.com"], + "expires_in_version": "50", + "kind": "boolean", + "description": "Reports whether a decoder for an HTTP Live Streaming media type was created when requested.", + "bug_numbers": [1262659] + + }, "VIDEO_MFT_OUTPUT_NULL_SAMPLES": { "alert_emails": ["cpearce@mozilla.com"], "expires_in_version": "53", diff --git a/toolkit/devtools/Console.jsm b/toolkit/devtools/Console.jsm index 324e202acf..09b3edb5f3 100644 --- a/toolkit/devtools/Console.jsm +++ b/toolkit/devtools/Console.jsm @@ -300,6 +300,7 @@ const LOG_LEVELS = { "debug": 2, "log": 3, "info": 3, + "clear": 3, "trace": 3, "timeEnd": 3, "time": 3, diff --git a/toolkit/devtools/webconsole/console-output.js b/toolkit/devtools/webconsole/console-output.js index edc6971542..0a937c9219 100644 --- a/toolkit/devtools/webconsole/console-output.js +++ b/toolkit/devtools/webconsole/console-output.js @@ -89,6 +89,7 @@ const CONSOLE_API_LEVELS_TO_SEVERITIES = { warn: "warning", info: "info", log: "log", + clear: "log", trace: "log", table: "log", debug: "log", diff --git a/toolkit/devtools/webconsole/test/browser.ini b/toolkit/devtools/webconsole/test/browser.ini index 585dcc38f7..c397f48dbe 100644 --- a/toolkit/devtools/webconsole/test/browser.ini +++ b/toolkit/devtools/webconsole/test/browser.ini @@ -71,6 +71,7 @@ support-files = test-closure-optimized-out.html test-closures.html test-console-assert.html + test-console-clear.html test-console-count.html test-console-count-external-file.js test-console-extras.html @@ -149,6 +150,7 @@ skip-if = e10s # Bug 1042253 - webconsole e10s tests (intermittent Linux debug) skip-if = buildapp == 'mulet' || e10s # Bug 1042253 - webconsole e10s tests (expectUncaughtException) [browser_console.js] [browser_console_addonsdk_loader_exception.js] +[browser_console_clear_method.js] [browser_console_clear_on_reload.js] [browser_console_click_focus.js] [browser_console_consolejsm_output.js] diff --git a/toolkit/devtools/webconsole/test/browser_console_clear_method.js b/toolkit/devtools/webconsole/test/browser_console_clear_method.js new file mode 100644 index 0000000000..9bb8ac68b0 --- /dev/null +++ b/toolkit/devtools/webconsole/test/browser_console_clear_method.js @@ -0,0 +1,131 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Check that calls to console.clear from a script delete the messages +// previously logged. + +"use strict"; + +add_task(function* () { + const TEST_URI = "http://example.com/browser/toolkit/devtools/webconsole/" + + "test/test-console-clear.html"; + + yield loadTab(TEST_URI); + let hud = yield openConsole(); + ok(hud, "Web Console opened"); + + info("Check the console.clear() done on page load has been processed."); + yield waitForLog("Console was cleared", hud); + ok(hud.outputNode.textContent.includes("Console was cleared"), + "console.clear() message is displayed"); + ok(!hud.outputNode.textContent.includes("log1"), "log1 not displayed"); + ok(!hud.outputNode.textContent.includes("log2"), "log2 not displayed"); + + info("Logging two messages log3, log4"); + ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () { + content.wrappedJSObject.console.log("log3"); + content.wrappedJSObject.console.log("log4"); + }); + + yield waitForLog("log3", hud); + yield waitForLog("log4", hud); + + ok(hud.outputNode.textContent.includes("Console was cleared"), + "console.clear() message is still displayed"); + ok(hud.outputNode.textContent.includes("log3"), "log3 is displayed"); + ok(hud.outputNode.textContent.includes("log4"), "log4 is displayed"); + + info("Open the variables view sidebar for 'objFromPage'"); + yield openSidebar("objFromPage", { a: 1 }, hud); + let sidebarClosed = hud.jsterm.once("sidebar-closed"); + + info("Call console.clear from the page"); + ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () { + content.wrappedJSObject.console.clear(); + }); + + // Cannot wait for "Console was cleared" here because such a message is + // already present and would yield immediately. + info("Wait for variables view sidebar to be closed after console.clear()"); + yield sidebarClosed; + + ok(!hud.outputNode.textContent.includes("log3"), "log3 not displayed"); + ok(!hud.outputNode.textContent.includes("log4"), "log4 not displayed"); + ok(hud.outputNode.textContent.includes("Console was cleared"), + "console.clear() message is still displayed"); + is(hud.outputNode.textContent.split("Console was cleared").length, 2, + "console.clear() message is only displayed once"); + + info("Logging one messages log5"); + ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () { + content.wrappedJSObject.console.log("log5"); + }); + yield waitForLog("log5", hud); + + info("Close and reopen the webconsole."); + yield closeConsole(gBrowser.selectedTab); + hud = yield openConsole(); + yield waitForLog("Console was cleared", hud); + + ok(hud.outputNode.textContent.includes("Console was cleared"), + "console.clear() message is still displayed"); + ok(!hud.outputNode.textContent.includes("log1"), "log1 not displayed"); + ok(!hud.outputNode.textContent.includes("log2"), "log1 not displayed"); + ok(!hud.outputNode.textContent.includes("log3"), "log3 not displayed"); + ok(!hud.outputNode.textContent.includes("log4"), "log4 not displayed"); + ok(hud.outputNode.textContent.includes("log5"), "log5 still displayed"); +}); + +/** + * Wait for a single message to be logged in the provided webconsole instance + * with the category CATEGORY_WEBDEV and the SEVERITY_LOG severity. + * + * @param {String} message + * The expected messaged. + * @param {WebConsole} webconsole + * WebConsole instance in which the message should be logged. + */ +function* waitForLog(message, webconsole, options) { + yield waitForMessages({ + webconsole: webconsole, + messages: [{ + text: message, + category: CATEGORY_WEBDEV, + severity: SEVERITY_LOG, + }], + }); +} + +/** + * Open the variables view sidebar for the object with the provided name objName + * and wait for the expected object is displayed in the variables view. + * + * @param {String} objName + * The name of the object to open in the sidebar. + * @param {Object} expectedObj + * The properties that should be displayed in the variables view. + * @param {WebConsole} webconsole + * WebConsole instance in which the message should be logged. + * + */ +function* openSidebar(objName, expectedObj, webconsole) { + let msg = yield webconsole.jsterm.execute(objName); + ok(msg, "output message found"); + + let anchor = msg.querySelector("a"); + let body = msg.querySelector(".message-body"); + ok(anchor, "object anchor"); + ok(body, "message body"); + + yield EventUtils.synthesizeMouse(anchor, 2, 2, {}, webconsole.iframeWindow); + + let vviewVar = yield webconsole.jsterm.once("variablesview-fetched"); + let vview = vviewVar._variablesView; + ok(vview, "variables view object exists"); + + yield findVariableViewProperties(vviewVar, [ + expectedObj, + ], { webconsole: webconsole }); +} diff --git a/toolkit/devtools/webconsole/test/test-console-clear.html b/toolkit/devtools/webconsole/test/test-console-clear.html new file mode 100644 index 0000000000..8009db858d --- /dev/null +++ b/toolkit/devtools/webconsole/test/test-console-clear.html @@ -0,0 +1,16 @@ + + + + Console.clear() tests + + + +

Clear Demo

+ + diff --git a/toolkit/devtools/webconsole/webconsole.js b/toolkit/devtools/webconsole/webconsole.js index ebd65b617b..6055ea141b 100644 --- a/toolkit/devtools/webconsole/webconsole.js +++ b/toolkit/devtools/webconsole/webconsole.js @@ -126,6 +126,7 @@ const LEVELS = { warn: SEVERITY_WARNING, info: SEVERITY_INFO, log: SEVERITY_LOG, + clear: SEVERITY_LOG, trace: SEVERITY_LOG, table: SEVERITY_LOG, debug: SEVERITY_LOG, @@ -1271,6 +1272,11 @@ WebConsoleFrame.prototype = { node = msg.init(this.output).render().element; break; } + case "clear": { + body = l10n.getStr("consoleCleared"); + clipboardText = body; + break; + } case "dir": { body = { arguments: args }; let clipboardArray = []; @@ -2279,6 +2285,14 @@ WebConsoleFrame.prototype = { let isRepeated = this._filterRepeatedMessage(node); + // If a clear message is processed while the webconsole is opened, the UI + // should be cleared. + if (message && message.level == "clear") { + // Do not clear the consoleStorage here as it has been cleared already + // by the clear method, only clear the UI. + this.jsterm.clearOutput(false); + } + let visible = !isRepeated && !isFiltered; if (!isRepeated) { this.outputNode.insertBefore(node, diff --git a/toolkit/locales/en-US/chrome/global/devtools/webconsole.properties b/toolkit/locales/en-US/chrome/global/devtools/webconsole.properties index 7b4ada4254..3649415830 100644 --- a/toolkit/locales/en-US/chrome/global/devtools/webconsole.properties +++ b/toolkit/locales/en-US/chrome/global/devtools/webconsole.properties @@ -129,6 +129,11 @@ timerStarted=%S: timer started # is the number of milliseconds. timeEnd=%1$S: %2$Sms +# LOCALIZATION NOTE (consoleCleared): this string is displayed when receiving a +# call to console.clear() to let the user know the previous messages of the +# console have been removed programmatically. +consoleCleared=Console was cleared. + # LOCALIZATION NOTE (noCounterLabel): this string is used to display # count-messages with no label provided. noCounterLabel= diff --git a/widget/GfxDriverInfo.h b/widget/GfxDriverInfo.h index 40e7c91505..91f9f39a80 100644 --- a/widget/GfxDriverInfo.h +++ b/widget/GfxDriverInfo.h @@ -54,6 +54,7 @@ enum OperatingSystem { DRIVER_OS_OS_X_10_8, DRIVER_OS_OS_X_10_9, DRIVER_OS_OS_X_10_10, + DRIVER_OS_OS_X_10_11, DRIVER_OS_ANDROID, DRIVER_OS_IOS, DRIVER_OS_ALL diff --git a/widget/GfxInfoBase.cpp b/widget/GfxInfoBase.cpp index bc801d9102..59aac521f2 100644 --- a/widget/GfxInfoBase.cpp +++ b/widget/GfxInfoBase.cpp @@ -154,7 +154,13 @@ GetPrefNameForFeature(int32_t aFeature) break; case nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION: name = BLACKLIST_PREF_BRANCH "canvas2d.acceleration"; + break; + case nsIGfxInfo::FEATURE_VP8_HW_DECODE: + case nsIGfxInfo::FEATURE_VP9_HW_DECODE: + // We don't provide prefs for this features. + break; default: + MOZ_ASSERT_UNREACHABLE("Unexpected nsIGfxInfo feature?!"); break; } @@ -299,6 +305,8 @@ BlacklistOSToOperatingSystem(const nsAString& os) return DRIVER_OS_OS_X_10_9; else if (os.EqualsLiteral("Darwin 14")) return DRIVER_OS_OS_X_10_10; + else if (os.EqualsLiteral("Darwin 15")) + return DRIVER_OS_OS_X_10_11; else if (os.EqualsLiteral("Android")) return DRIVER_OS_ANDROID; else if (os.EqualsLiteral("All")) @@ -1190,10 +1198,11 @@ nsresult GfxInfoBase::GetInfo(JSContext* aCx, JS::MutableHandle aResu return NS_OK; } +nsAutoCString gBaseAppVersion; + const nsCString& GfxInfoBase::GetApplicationVersion() { - static nsCString version; static bool versionInitialized = false; if (!versionInitialized) { // If we fail to get the version, we will not try again. @@ -1202,10 +1211,10 @@ GfxInfoBase::GetApplicationVersion() // Get the version from xpcom/system/nsIXULAppInfo.idl nsCOMPtr app = do_GetService("@mozilla.org/xre/app-info;1"); if (app) { - app->GetVersion(version); + app->GetVersion(gBaseAppVersion); } } - return version; + return gBaseAppVersion; } void diff --git a/widget/cocoa/GfxInfo.mm b/widget/cocoa/GfxInfo.mm index 76defc7867..2b92ccbe49 100644 --- a/widget/cocoa/GfxInfo.mm +++ b/widget/cocoa/GfxInfo.mm @@ -50,6 +50,8 @@ OSXVersionToOperatingSystem(uint32_t aOSXVersion) return DRIVER_OS_OS_X_10_9; case 10: return DRIVER_OS_OS_X_10_10; + case 11: + return DRIVER_OS_OS_X_10_11; } } diff --git a/widget/gonk/nativewindow/GonkNativeWindowClient.h b/widget/gonk/nativewindow/GonkNativeWindowClient.h deleted file mode 100644 index 90ca0561df..0000000000 --- a/widget/gonk/nativewindow/GonkNativeWindowClient.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Copyright 2013 Mozilla Foundation and Mozilla contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21 -# include "GonkNativeWindowClientLL.h" -#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19 -# include "GonkNativeWindowClientKK.h" -#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 -# include "GonkNativeWindowClientJB.h" -#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION == 15 -# include "GonkNativeWindowClientICS.h" -#endif diff --git a/widget/gonk/nativewindow/GonkNativeWindowClientICS.cpp b/widget/gonk/nativewindow/GonkNativeWindowClientICS.cpp deleted file mode 100644 index 63fc075e66..0000000000 --- a/widget/gonk/nativewindow/GonkNativeWindowClientICS.cpp +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012 Mozilla Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "base/basictypes.h" - -#include "CameraCommon.h" -#include "GonkNativeWindow.h" -#include "GonkNativeWindowClient.h" -#include "nsDebug.h" - -/** - * DOM_CAMERA_LOGI() is enabled in debug builds, and turned on by setting - * NSPR_LOG_MODULES=Camera:N environment variable, where N >= 3. - * - * CNW_LOGE() is always enabled. - */ -#define CNW_LOGD(...) DOM_CAMERA_LOGI(__VA_ARGS__) -#define CNW_LOGE(...) {(void)printf_stderr(__VA_ARGS__);} - -using namespace android; -using namespace mozilla::layers; - -GonkNativeWindowClient::GonkNativeWindowClient(const sp& window) - : mNativeWindow(window) { - GonkNativeWindowClient::init(); -} - -GonkNativeWindowClient::~GonkNativeWindowClient() { - if (mConnectedToCpu) { - GonkNativeWindowClient::disconnect(NATIVE_WINDOW_API_CPU); - } -} - -void GonkNativeWindowClient::init() { - // Initialize the ANativeWindow function pointers. - ANativeWindow::setSwapInterval = hook_setSwapInterval; - ANativeWindow::dequeueBuffer = hook_dequeueBuffer; - ANativeWindow::cancelBuffer = hook_cancelBuffer; - ANativeWindow::lockBuffer = hook_lockBuffer; - ANativeWindow::queueBuffer = hook_queueBuffer; - ANativeWindow::query = hook_query; - ANativeWindow::perform = hook_perform; - - mReqWidth = 0; - mReqHeight = 0; - mReqFormat = 0; - mReqUsage = 0; - mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO; - mDefaultWidth = 0; - mDefaultHeight = 0; - mTransformHint = 0; - mConnectedToCpu = false; -} - - -int GonkNativeWindowClient::hook_setSwapInterval(ANativeWindow* window, int interval) { - GonkNativeWindowClient* c = getSelf(window); - return c->setSwapInterval(interval); -} - -int GonkNativeWindowClient::hook_dequeueBuffer(ANativeWindow* window, - ANativeWindowBuffer** buffer) { - GonkNativeWindowClient* c = getSelf(window); - return c->dequeueBuffer(buffer); -} - -int GonkNativeWindowClient::hook_cancelBuffer(ANativeWindow* window, - ANativeWindowBuffer* buffer) { - GonkNativeWindowClient* c = getSelf(window); - return c->cancelBuffer(buffer); -} - -int GonkNativeWindowClient::hook_lockBuffer(ANativeWindow* window, - ANativeWindowBuffer* buffer) { - GonkNativeWindowClient* c = getSelf(window); - return c->lockBuffer(buffer); -} - -int GonkNativeWindowClient::hook_queueBuffer(ANativeWindow* window, - ANativeWindowBuffer* buffer) { - GonkNativeWindowClient* c = getSelf(window); - return c->queueBuffer(buffer); -} - -int GonkNativeWindowClient::hook_query(const ANativeWindow* window, - int what, int* value) { - const GonkNativeWindowClient* c = getSelf(window); - return c->query(what, value); -} - -int GonkNativeWindowClient::hook_perform(ANativeWindow* window, int operation, ...) { - va_list args; - va_start(args, operation); - GonkNativeWindowClient* c = getSelf(window); - return c->perform(operation, args); -} - -int GonkNativeWindowClient::setSwapInterval(int interval) { - return NO_ERROR; -} - -int GonkNativeWindowClient::dequeueBuffer(android_native_buffer_t** buffer) { - CNW_LOGD("GonkNativeWindowClient::dequeueBuffer"); - Mutex::Autolock lock(mMutex); - int buf = -1; - status_t result = mNativeWindow->dequeueBuffer(&buf, mReqWidth, mReqHeight, - mReqFormat, mReqUsage); - if (result < 0) { - CNW_LOGD("dequeueBuffer: ISurfaceTexture::dequeueBuffer(%d, %d, %d, %d)" - "failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage, - result); - return result; - } - sp& gbuf(mSlots[buf]); - if (result & ISurfaceTexture::RELEASE_ALL_BUFFERS) { - freeAllBuffers(); - } - - if ((result & ISurfaceTexture::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) { - result = mNativeWindow->requestBuffer(buf, &gbuf); - if (result != NO_ERROR) { - CNW_LOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed: %d", - result); - return result; - } - } - *buffer = gbuf.get(); - return OK; -} - -int GonkNativeWindowClient::cancelBuffer(ANativeWindowBuffer* buffer) { - CNW_LOGD("GonkNativeWindowClient::cancelBuffer"); - Mutex::Autolock lock(mMutex); - int i = getSlotFromBufferLocked(buffer); - if (i < 0) { - return i; - } - mNativeWindow->cancelBuffer(i); - return OK; -} - -int GonkNativeWindowClient::getSlotFromBufferLocked( - android_native_buffer_t* buffer) const { - bool dumpedState = false; - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - // XXX: Dump the slots whenever we hit a NULL entry while searching for - // a buffer. - if (mSlots[i] == NULL) { - if (!dumpedState) { - CNW_LOGD("getSlotFromBufferLocked: encountered NULL buffer in slot %d " - "looking for buffer %p", i, buffer->handle); - for (int j = 0; j < NUM_BUFFER_SLOTS; j++) { - if (mSlots[j] == NULL) { - CNW_LOGD("getSlotFromBufferLocked: %02d: NULL", j); - } else { - CNW_LOGD("getSlotFromBufferLocked: %02d: %p", j, mSlots[j]->handle); - } - } - dumpedState = true; - } - } - - if (mSlots[i] != NULL && mSlots[i]->handle == buffer->handle) { - return i; - } - } - CNW_LOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle); - return BAD_VALUE; -} - - -int GonkNativeWindowClient::lockBuffer(android_native_buffer_t* buffer) { - CNW_LOGD("GonkNativeWindowClient::lockBuffer"); - Mutex::Autolock lock(mMutex); - return OK; -} - -int GonkNativeWindowClient::queueBuffer(android_native_buffer_t* buffer) { - CNW_LOGD("GonkNativeWindowClient::queueBuffer"); - Mutex::Autolock lock(mMutex); - int64_t timestamp; - if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) { - timestamp = systemTime(SYSTEM_TIME_MONOTONIC); - CNW_LOGD("GonkNativeWindowClient::queueBuffer making up timestamp: %.2f ms", - timestamp / 1000000.f); - } else { - timestamp = mTimestamp; - } - int i = getSlotFromBufferLocked(buffer); - if (i < 0) { - return i; - } - status_t err = mNativeWindow->queueBuffer(i, timestamp, - &mDefaultWidth, &mDefaultHeight, &mTransformHint); - if (err != OK) { - CNW_LOGE("queueBuffer: error queuing buffer to GonkNativeWindow, %d", err); - } - return err; -} - -int GonkNativeWindowClient::query(int what, int* value) const { - CNW_LOGD("query"); - { // scope for the lock - Mutex::Autolock lock(mMutex); - switch (what) { - case NATIVE_WINDOW_FORMAT: - if (mReqFormat) { - *value = mReqFormat; - return NO_ERROR; - } - break; - case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: - *value = 0; - return NO_ERROR; - case NATIVE_WINDOW_CONCRETE_TYPE: - *value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT; - return NO_ERROR; - case NATIVE_WINDOW_DEFAULT_WIDTH: - *value = mDefaultWidth; - return NO_ERROR; - case NATIVE_WINDOW_DEFAULT_HEIGHT: - *value = mDefaultHeight; - return NO_ERROR; - case NATIVE_WINDOW_TRANSFORM_HINT: - *value = mTransformHint; - return NO_ERROR; - } - } - return mNativeWindow->query(what, value); -} - -int GonkNativeWindowClient::perform(int operation, va_list args) -{ - int res = NO_ERROR; - switch (operation) { - case NATIVE_WINDOW_CONNECT: - // deprecated. must return NO_ERROR. - break; - case NATIVE_WINDOW_DISCONNECT: - // deprecated. must return NO_ERROR. - break; - case NATIVE_WINDOW_SET_SCALING_MODE: - return NO_ERROR; - case NATIVE_WINDOW_SET_USAGE: - res = dispatchSetUsage(args); - break; - case NATIVE_WINDOW_SET_CROP: - //not implemented - break; - case NATIVE_WINDOW_SET_BUFFER_COUNT: - res = dispatchSetBufferCount(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY: - res = dispatchSetBuffersGeometry(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: - //not implemented - break; - case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP: - res = dispatchSetBuffersTimestamp(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: - res = dispatchSetBuffersDimensions(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_FORMAT: - res = dispatchSetBuffersFormat(args); - break; - case NATIVE_WINDOW_LOCK: - res = INVALID_OPERATION;// not supported - break; - case NATIVE_WINDOW_UNLOCK_AND_POST: - res = INVALID_OPERATION;// not supported - break; - case NATIVE_WINDOW_API_CONNECT: - res = dispatchConnect(args); - break; - case NATIVE_WINDOW_API_DISCONNECT: - res = dispatchDisconnect(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_SIZE: - //not implemented - break; - default: - res = NAME_NOT_FOUND; - break; - } - return res; -} - -int GonkNativeWindowClient::dispatchConnect(va_list args) { - int api = va_arg(args, int); - return connect(api); -} - -int GonkNativeWindowClient::dispatchDisconnect(va_list args) { - int api = va_arg(args, int); - return disconnect(api); -} - -int GonkNativeWindowClient::dispatchSetUsage(va_list args) { - int usage = va_arg(args, int); - return setUsage(usage); -} - -int GonkNativeWindowClient::dispatchSetBufferCount(va_list args) { - size_t bufferCount = va_arg(args, size_t); - return setBufferCount(bufferCount); -} - -int GonkNativeWindowClient::dispatchSetBuffersGeometry(va_list args) { - int w = va_arg(args, int); - int h = va_arg(args, int); - int f = va_arg(args, int); - int err = setBuffersDimensions(w, h); - if (err != 0) { - return err; - } - return setBuffersFormat(f); -} - -int GonkNativeWindowClient::dispatchSetBuffersDimensions(va_list args) { - int w = va_arg(args, int); - int h = va_arg(args, int); - return setBuffersDimensions(w, h); -} - -int GonkNativeWindowClient::dispatchSetBuffersFormat(va_list args) { - int f = va_arg(args, int); - return setBuffersFormat(f); -} - -int GonkNativeWindowClient::dispatchSetBuffersTimestamp(va_list args) { - int64_t timestamp = va_arg(args, int64_t); - return setBuffersTimestamp(timestamp); -} - -int GonkNativeWindowClient::connect(int api) { - CNW_LOGD("GonkNativeWindowClient::connect"); - Mutex::Autolock lock(mMutex); - int err = mNativeWindow->connect(api, - &mDefaultWidth, &mDefaultHeight, &mTransformHint); - if (!err && api == NATIVE_WINDOW_API_CPU) { - mConnectedToCpu = true; - } - return err; -} - -int GonkNativeWindowClient::disconnect(int api) { - CNW_LOGD("GonkNativeWindowClient::disconnect"); - Mutex::Autolock lock(mMutex); - freeAllBuffers(); - int err = mNativeWindow->disconnect(api); - if (!err) { - mReqFormat = 0; - mReqWidth = 0; - mReqHeight = 0; - mReqUsage = 0; - if (api == NATIVE_WINDOW_API_CPU) { - mConnectedToCpu = false; - } - } - return err; -} - -int GonkNativeWindowClient::setUsage(uint32_t reqUsage) -{ - CNW_LOGD("GonkNativeWindowClient::setUsage"); - Mutex::Autolock lock(mMutex); - mReqUsage = reqUsage; - return OK; -} - -int GonkNativeWindowClient::setBufferCount(int bufferCount) -{ - CNW_LOGD("GonkNativeWindowClient::setBufferCount"); - Mutex::Autolock lock(mMutex); - - status_t err = mNativeWindow->setBufferCount(bufferCount); - if (err == NO_ERROR) { - freeAllBuffers(); - } - - return err; -} - -int GonkNativeWindowClient::setBuffersDimensions(int w, int h) -{ - CNW_LOGD("GonkNativeWindowClient::setBuffersDimensions"); - Mutex::Autolock lock(mMutex); - - if (w<0 || h<0) - return BAD_VALUE; - - if ((w && !h) || (!w && h)) - return BAD_VALUE; - - mReqWidth = w; - mReqHeight = h; - - status_t err = OK; - - return err; -} - -int GonkNativeWindowClient::setBuffersFormat(int format) -{ - CNW_LOGD("GonkNativeWindowClient::setBuffersFormat"); - Mutex::Autolock lock(mMutex); - - if (format<0) - return BAD_VALUE; - - mReqFormat = format; - - return NO_ERROR; -} - - -int GonkNativeWindowClient::setBuffersTimestamp(int64_t timestamp) -{ - CNW_LOGD("GonkNativeWindowClient::setBuffersTimestamp"); - Mutex::Autolock lock(mMutex); - mTimestamp = timestamp; - return NO_ERROR; -} - -void GonkNativeWindowClient::freeAllBuffers() { - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - mSlots[i] = 0; - } -} - diff --git a/widget/gonk/nativewindow/GonkNativeWindowClientICS.h b/widget/gonk/nativewindow/GonkNativeWindowClientICS.h deleted file mode 100644 index bd5720000d..0000000000 --- a/widget/gonk/nativewindow/GonkNativeWindowClientICS.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2012 Mozilla Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef NATIVEWINDOW_GONKNATIVEWINDOWCLIENT_ICS_H -#define NATIVEWINDOW_GONKNATIVEWINDOWCLIENT_ICS_H - -#include - -#include "GonkNativeWindow.h" - -namespace android { - -class GonkNativeWindowClient : public EGLNativeBase -{ -public: - GonkNativeWindowClient(const sp& window); - ~GonkNativeWindowClient(); // this class cannot be overloaded - -private: - void init(); - - // ANativeWindow hooks - static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer); - static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer); - static int hook_lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer); - static int hook_perform(ANativeWindow* window, int operation, ...); - static int hook_query(const ANativeWindow* window, int what, int* value); - static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer); - static int hook_setSwapInterval(ANativeWindow* window, int interval); - - int dispatchConnect(va_list args); - int dispatchDisconnect(va_list args); - int dispatchSetBufferCount(va_list args); - int dispatchSetBuffersGeometry(va_list args); - int dispatchSetBuffersDimensions(va_list args); - int dispatchSetBuffersFormat(va_list args); - int dispatchSetBuffersTimestamp(va_list args); - int dispatchSetUsage(va_list args); - -protected: - virtual int cancelBuffer(ANativeWindowBuffer* buffer); - virtual int dequeueBuffer(ANativeWindowBuffer** buffer); - virtual int lockBuffer(ANativeWindowBuffer* buffer); - virtual int perform(int operation, va_list args); - virtual int query(int what, int* value) const; - virtual int queueBuffer(ANativeWindowBuffer* buffer); - virtual int setSwapInterval(int interval); - - virtual int connect(int api); - virtual int disconnect(int api); - virtual int setBufferCount(int bufferCount); - virtual int setBuffersDimensions(int w, int h); - virtual int setBuffersFormat(int format); - virtual int setBuffersTimestamp(int64_t timestamp); - virtual int setUsage(uint32_t reqUsage); - - int getNumberOfArgsForOperation(int operation); - - enum { MIN_UNDEQUEUED_BUFFERS = GonkNativeWindow::MIN_UNDEQUEUED_BUFFERS }; - enum { NUM_BUFFER_SLOTS = GonkNativeWindow::NUM_BUFFER_SLOTS }; - enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 }; - enum { NATIVE_WINDOW_SET_BUFFERS_SIZE = 0x10000000 }; - -private: - void freeAllBuffers(); - int getSlotFromBufferLocked(android_native_buffer_t* buffer) const; - - sp mNativeWindow; - - // mSlots stores the buffers that have been allocated for each buffer slot. - // It is initialized to null pointers, and gets filled in with the result of - // ISurfaceTexture::requestBuffer when the client dequeues a buffer from a - // slot that has not yet been used. The buffer allocated to a slot will also - // be replaced if the requested buffer usage or geometry differs from that - // of the buffer allocated to a slot. - sp mSlots[NUM_BUFFER_SLOTS]; - - // mReqWidth is the buffer width that will be requested at the next dequeue - // operation. It is initialized to 1. - uint32_t mReqWidth; - - // mReqHeight is the buffer height that will be requested at the next deuque - // operation. It is initialized to 1. - uint32_t mReqHeight; - - // mReqFormat is the buffer pixel format that will be requested at the next - // deuque operation. It is initialized to PIXEL_FORMAT_RGBA_8888. - uint32_t mReqFormat; - - // mReqUsage is the set of buffer usage flags that will be requested - // at the next deuque operation. It is initialized to 0. - uint32_t mReqUsage; - - // mTimestamp is the timestamp that will be used for the next buffer queue - // operation. It defaults to NATIVE_WINDOW_TIMESTAMP_AUTO, which means that - // a timestamp is auto-generated when queueBuffer is called. - int64_t mTimestamp; - - // mDefaultWidth is default width of the window, regardless of the - // native_window_set_buffers_dimensions call - uint32_t mDefaultWidth; - - // mDefaultHeight is default width of the window, regardless of the - // native_window_set_buffers_dimensions call - uint32_t mDefaultHeight; - - // mTransformHint is the transform probably applied to buffers of this - // window. this is only a hint, actual transform may differ. - uint32_t mTransformHint; - - // mMutex is the mutex used to prevent concurrent access to the member - // variables of GonkNativeWindow objects. It must be locked whenever the - // member variables are accessed. - mutable Mutex mMutex; - - bool mConnectedToCpu; -}; - - -}; // namespace android - -#endif // NATIVEWINDOW_GONKNATIVEWINDOWCLIENT_ICS_H diff --git a/widget/gonk/nativewindow/GonkNativeWindowClientJB.cpp b/widget/gonk/nativewindow/GonkNativeWindowClientJB.cpp deleted file mode 100644 index 7345bb49ac..0000000000 --- a/widget/gonk/nativewindow/GonkNativeWindowClientJB.cpp +++ /dev/null @@ -1,679 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "GonkNativeWindowClient" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#include -#if ANDROID_VERSION == 17 -#include -#else -#include -#endif - -#include -#include -#include - -#include "GonkNativeWindowClientJB.h" - -namespace android { - -GonkNativeWindowClient::GonkNativeWindowClient( - const sp& bufferProducer) - : mBufferProducer(bufferProducer) -{ - // Initialize the ANativeWindow function pointers. - ANativeWindow::setSwapInterval = hook_setSwapInterval; - ANativeWindow::dequeueBuffer = hook_dequeueBuffer; - ANativeWindow::cancelBuffer = hook_cancelBuffer; - ANativeWindow::queueBuffer = hook_queueBuffer; - ANativeWindow::query = hook_query; - ANativeWindow::perform = hook_perform; - - ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED; - ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED; - ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED; - ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED; - - const_cast(ANativeWindow::minSwapInterval) = 0; - const_cast(ANativeWindow::maxSwapInterval) = 1; - - mReqWidth = 0; - mReqHeight = 0; - mReqFormat = 0; - mReqUsage = 0; - mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO; - mCrop.clear(); - mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; - mTransform = 0; - mDefaultWidth = 0; - mDefaultHeight = 0; - mUserWidth = 0; - mUserHeight = 0; - mTransformHint = 0; - mConsumerRunningBehind = false; - mConnectedToCpu = false; -} - -GonkNativeWindowClient::~GonkNativeWindowClient() { - if (mConnectedToCpu) { - GonkNativeWindowClient::disconnect(NATIVE_WINDOW_API_CPU); - } -} - -#if ANDROID_VERSION == 17 -sp GonkNativeWindowClient::getISurfaceTexture() const { -#else -sp GonkNativeWindowClient::getIGraphicBufferProducer() const { -#endif - return mBufferProducer; -} - -int GonkNativeWindowClient::hook_setSwapInterval(ANativeWindow* window, int interval) { - GonkNativeWindowClient* c = getSelf(window); - return c->setSwapInterval(interval); -} - -int GonkNativeWindowClient::hook_dequeueBuffer(ANativeWindow* window, - ANativeWindowBuffer** buffer, int* fenceFd) { - GonkNativeWindowClient* c = getSelf(window); - return c->dequeueBuffer(buffer, fenceFd); -} - -int GonkNativeWindowClient::hook_cancelBuffer(ANativeWindow* window, - ANativeWindowBuffer* buffer, int fenceFd) { - GonkNativeWindowClient* c = getSelf(window); - return c->cancelBuffer(buffer, fenceFd); -} - -int GonkNativeWindowClient::hook_queueBuffer(ANativeWindow* window, - ANativeWindowBuffer* buffer, int fenceFd) { - GonkNativeWindowClient* c = getSelf(window); - return c->queueBuffer(buffer, fenceFd); -} - -int GonkNativeWindowClient::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer** buffer) { - GonkNativeWindowClient* c = getSelf(window); - ANativeWindowBuffer* buf; - int fenceFd = -1; - int result = c->dequeueBuffer(&buf, &fenceFd); - sp fence(new Fence(fenceFd)); -#if ANDROID_VERSION == 17 - int waitResult = fence->waitForever(1000, "dequeueBuffer_DEPRECATED"); -#else - int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED"); -#endif - if (waitResult != OK) { - ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d", - waitResult); - c->cancelBuffer(buf, -1); - return waitResult; - } - *buffer = buf; - return result; -} - -int GonkNativeWindowClient::hook_cancelBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer) { - GonkNativeWindowClient* c = getSelf(window); - return c->cancelBuffer(buffer, -1); -} - -int GonkNativeWindowClient::hook_lockBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer) { - GonkNativeWindowClient* c = getSelf(window); - return c->lockBuffer_DEPRECATED(buffer); -} - -int GonkNativeWindowClient::hook_queueBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer) { - GonkNativeWindowClient* c = getSelf(window); - return c->queueBuffer(buffer, -1); -} - -int GonkNativeWindowClient::hook_query(const ANativeWindow* window, - int what, int* value) { - const GonkNativeWindowClient* c = getSelf(window); - return c->query(what, value); -} - -int GonkNativeWindowClient::hook_perform(ANativeWindow* window, int operation, ...) { - va_list args; - va_start(args, operation); - GonkNativeWindowClient* c = getSelf(window); - return c->perform(operation, args); -} - -int GonkNativeWindowClient::setSwapInterval(int interval) { - // EGL specification states: - // interval is silently clamped to minimum and maximum implementation - // dependent values before being stored. - // Although we don't have to, we apply the same logic here. - - if (interval < minSwapInterval) - interval = minSwapInterval; - - if (interval > maxSwapInterval) - interval = maxSwapInterval; - - status_t res = mBufferProducer->setSynchronousMode(interval ? true : false); - - return res; -} - -int GonkNativeWindowClient::dequeueBuffer(android_native_buffer_t** buffer, - int* fenceFd) { - ALOGV("GonkNativeWindowClient::dequeueBuffer"); - Mutex::Autolock lock(mMutex); - int buf = -1; - int reqW = mReqWidth ? mReqWidth : mUserWidth; - int reqH = mReqHeight ? mReqHeight : mUserHeight; - sp fence; -#if ANDROID_VERSION == 17 - status_t result = mBufferProducer->dequeueBuffer(&buf, fence, - reqW, reqH, mReqFormat, mReqUsage); -#else - status_t result = mBufferProducer->dequeueBuffer(&buf, &fence, - reqW, reqH, mReqFormat, mReqUsage); -#endif - - if (result < 0) { - ALOGV("dequeueBuffer: dequeueBuffer(%d, %d, %d, %d)" - "failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage, - result); - return result; - } - sp& gbuf(mSlots[buf].buffer); - if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) { - freeAllBuffers(); - } - - if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) { - result = mBufferProducer->requestBuffer(buf, &gbuf); - - if (result != NO_ERROR) { - ALOGE("dequeueBuffer: requestBuffer failed: %d", - result); - return result; - } - } - - if (fence.get() && fence->isValid()) { - *fenceFd = fence->dup(); - if (*fenceFd == -1) { - ALOGE("dequeueBuffer: error duping fence: %d", errno); - // dup() should never fail; something is badly wrong. Soldier on - // and hope for the best; the worst that should happen is some - // visible corruption that lasts until the next frame. - } - } else { - *fenceFd = -1; - } - - *buffer = gbuf.get(); - return OK; -} - -int GonkNativeWindowClient::cancelBuffer(android_native_buffer_t* buffer, - int fenceFd) { - ALOGV("GonkNativeWindowClient::cancelBuffer"); - Mutex::Autolock lock(mMutex); - int i = getSlotFromBufferLocked(buffer); - if (i < 0) { - return i; - } - sp fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); - mBufferProducer->cancelBuffer(i, fence); - return OK; -} - -int GonkNativeWindowClient::getSlotFromBufferLocked( - android_native_buffer_t* buffer) const { - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].buffer != NULL && - mSlots[i].buffer->handle == buffer->handle) { - return i; - } - } - ALOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle); - return BAD_VALUE; -} - -int GonkNativeWindowClient::lockBuffer_DEPRECATED(android_native_buffer_t* buffer) { - ALOGV("GonkNativeWindowClient::lockBuffer"); - Mutex::Autolock lock(mMutex); - return OK; -} - -int GonkNativeWindowClient::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { - ALOGV("GonkNativeWindowClient::queueBuffer"); - Mutex::Autolock lock(mMutex); - int64_t timestamp; - if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) { - timestamp = systemTime(SYSTEM_TIME_MONOTONIC); - ALOGV("GonkNativeWindowClient::queueBuffer making up timestamp: %.2f ms", - timestamp / 1000000.f); - } else { - timestamp = mTimestamp; - } - int i = getSlotFromBufferLocked(buffer); - if (i < 0) { - return i; - } - - - // Make sure the crop rectangle is entirely inside the buffer. - Rect crop; - mCrop.intersect(Rect(buffer->width, buffer->height), &crop); - - sp fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); - IGraphicBufferProducer::QueueBufferOutput output; - - IGraphicBufferProducer::QueueBufferInput input(timestamp, crop, mScalingMode, - mTransform, fence); - status_t err = mBufferProducer->queueBuffer(i, input, &output); - if (err != OK) { - ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err); - } - uint32_t numPendingBuffers = 0; - output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint, - &numPendingBuffers); - - mConsumerRunningBehind = (numPendingBuffers >= 2); - - return err; -} - -int GonkNativeWindowClient::query(int what, int* value) const { - ALOGV("GonkNativeWindowClient::query"); - { // scope for the lock - Mutex::Autolock lock(mMutex); - switch (what) { - case NATIVE_WINDOW_FORMAT: - if (mReqFormat) { - *value = mReqFormat; - return NO_ERROR; - } - break; - case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: { - //sp composer( - // ComposerService::getComposerService()); - //if (composer->authenticateSurfaceTexture(mBufferProducer)) { - // *value = 1; - //} else { - *value = 0; - //} - return NO_ERROR; - } - case NATIVE_WINDOW_CONCRETE_TYPE: -#if ANDROID_VERSION == 17 - *value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT; -#else - *value = NATIVE_WINDOW_SURFACE; -#endif - return NO_ERROR; - case NATIVE_WINDOW_DEFAULT_WIDTH: - *value = mUserWidth ? mUserWidth : mDefaultWidth; - return NO_ERROR; - case NATIVE_WINDOW_DEFAULT_HEIGHT: - *value = mUserHeight ? mUserHeight : mDefaultHeight; - return NO_ERROR; - case NATIVE_WINDOW_TRANSFORM_HINT: - *value = mTransformHint; - return NO_ERROR; - case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: { - status_t err = NO_ERROR; - if (!mConsumerRunningBehind) { - *value = 0; - } else { - err = mBufferProducer->query(what, value); - if (err == NO_ERROR) { - mConsumerRunningBehind = *value; - } - } - return err; - } - } - } - - return mBufferProducer->query(what, value); -} - -int GonkNativeWindowClient::perform(int operation, va_list args) -{ - int res = NO_ERROR; - switch (operation) { - case NATIVE_WINDOW_CONNECT: - // deprecated. must return NO_ERROR. - break; - case NATIVE_WINDOW_DISCONNECT: - // deprecated. must return NO_ERROR. - break; - case NATIVE_WINDOW_SET_USAGE: - res = dispatchSetUsage(args); - break; - case NATIVE_WINDOW_SET_CROP: - res = dispatchSetCrop(args); - break; - case NATIVE_WINDOW_SET_BUFFER_COUNT: - res = dispatchSetBufferCount(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY: - res = dispatchSetBuffersGeometry(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: - res = dispatchSetBuffersTransform(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP: - res = dispatchSetBuffersTimestamp(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: - res = dispatchSetBuffersDimensions(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS: - res = dispatchSetBuffersUserDimensions(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_FORMAT: - res = dispatchSetBuffersFormat(args); - break; - case NATIVE_WINDOW_LOCK: - res = dispatchLock(args); - break; - case NATIVE_WINDOW_UNLOCK_AND_POST: - res = dispatchUnlockAndPost(args); - break; - case NATIVE_WINDOW_SET_SCALING_MODE: - res = dispatchSetScalingMode(args); - break; - case NATIVE_WINDOW_API_CONNECT: - res = dispatchConnect(args); - break; - case NATIVE_WINDOW_API_DISCONNECT: - res = dispatchDisconnect(args); - break; - default: - res = NAME_NOT_FOUND; - break; - } - return res; -} - -int GonkNativeWindowClient::dispatchConnect(va_list args) { - int api = va_arg(args, int); - return connect(api); -} - -int GonkNativeWindowClient::dispatchDisconnect(va_list args) { - int api = va_arg(args, int); - return disconnect(api); -} - -int GonkNativeWindowClient::dispatchSetUsage(va_list args) { - int usage = va_arg(args, int); - return setUsage(usage); -} - -int GonkNativeWindowClient::dispatchSetCrop(va_list args) { - android_native_rect_t const* rect = va_arg(args, android_native_rect_t*); - return setCrop(reinterpret_cast(rect)); -} - -int GonkNativeWindowClient::dispatchSetBufferCount(va_list args) { - size_t bufferCount = va_arg(args, size_t); - return setBufferCount(bufferCount); -} - -int GonkNativeWindowClient::dispatchSetBuffersGeometry(va_list args) { - int w = va_arg(args, int); - int h = va_arg(args, int); - int f = va_arg(args, int); - int err = setBuffersDimensions(w, h); - if (err != 0) { - return err; - } - return setBuffersFormat(f); -} - -int GonkNativeWindowClient::dispatchSetBuffersDimensions(va_list args) { - int w = va_arg(args, int); - int h = va_arg(args, int); - return setBuffersDimensions(w, h); -} - -int GonkNativeWindowClient::dispatchSetBuffersUserDimensions(va_list args) { - int w = va_arg(args, int); - int h = va_arg(args, int); - return setBuffersUserDimensions(w, h); -} - -int GonkNativeWindowClient::dispatchSetBuffersFormat(va_list args) { - int f = va_arg(args, int); - return setBuffersFormat(f); -} - -int GonkNativeWindowClient::dispatchSetScalingMode(va_list args) { - int m = va_arg(args, int); - return setScalingMode(m); -} - -int GonkNativeWindowClient::dispatchSetBuffersTransform(va_list args) { - int transform = va_arg(args, int); - return setBuffersTransform(transform); -} - -int GonkNativeWindowClient::dispatchSetBuffersTimestamp(va_list args) { - int64_t timestamp = va_arg(args, int64_t); - return setBuffersTimestamp(timestamp); -} - -int GonkNativeWindowClient::dispatchLock(va_list args) { - ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*); - ARect* inOutDirtyBounds = va_arg(args, ARect*); - return lock(outBuffer, inOutDirtyBounds); -} - -int GonkNativeWindowClient::dispatchUnlockAndPost(va_list args) { - return unlockAndPost(); -} - - -int GonkNativeWindowClient::connect(int api) { - ALOGV("GonkNativeWindowClient::connect"); - - Mutex::Autolock lock(mMutex); - IGraphicBufferProducer::QueueBufferOutput output; - - int err = mBufferProducer->connect(api, &output); - if (err == NO_ERROR) { - uint32_t numPendingBuffers = 0; - output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint, - &numPendingBuffers); - mConsumerRunningBehind = (numPendingBuffers >= 2); - } - if (!err && api == NATIVE_WINDOW_API_CPU) { - mConnectedToCpu = true; - } - return err; -} - -int GonkNativeWindowClient::disconnect(int api) { - ALOGV("GonkNativeWindowClient::disconnect"); - Mutex::Autolock lock(mMutex); - freeAllBuffers(); - int err = mBufferProducer->disconnect(api); - - if (!err) { - mReqFormat = 0; - mReqWidth = 0; - mReqHeight = 0; - mReqUsage = 0; - mCrop.clear(); - mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; - mTransform = 0; - if (api == NATIVE_WINDOW_API_CPU) { - mConnectedToCpu = false; - } - } - return err; -} - -int GonkNativeWindowClient::setUsage(uint32_t reqUsage) -{ - ALOGV("GonkNativeWindowClient::setUsage"); - Mutex::Autolock lock(mMutex); - mReqUsage = reqUsage; - return OK; -} - -int GonkNativeWindowClient::setCrop(Rect const* rect) -{ - Rect realRect; - if (rect == NULL || rect->isEmpty()) { - realRect.clear(); - } else { - realRect = *rect; - } - - ALOGV("GonkNativeWindowClient::setCrop rect=[%d %d %d %d]", - realRect.left, realRect.top, realRect.right, realRect.bottom); - - Mutex::Autolock lock(mMutex); - mCrop = realRect; - return NO_ERROR; -} - -int GonkNativeWindowClient::setBufferCount(int bufferCount) -{ - ALOGV("GonkNativeWindowClient::setBufferCount"); - Mutex::Autolock lock(mMutex); - - status_t err = mBufferProducer->setBufferCount(bufferCount); - ALOGE_IF(err, "IGraphicBufferProducer::setBufferCount(%d) returned %s", - bufferCount, strerror(-err)); - - if (err == NO_ERROR) { - freeAllBuffers(); - } - - return err; -} - -int GonkNativeWindowClient::setBuffersDimensions(int w, int h) -{ - ALOGV("GonkNativeWindowClient::setBuffersDimensions"); - - if (w<0 || h<0) - return BAD_VALUE; - - if ((w && !h) || (!w && h)) - return BAD_VALUE; - - Mutex::Autolock lock(mMutex); - mReqWidth = w; - mReqHeight = h; - return NO_ERROR; -} - -int GonkNativeWindowClient::setBuffersUserDimensions(int w, int h) -{ - ALOGV("GonkNativeWindowClient::setBuffersUserDimensions"); - - if (w<0 || h<0) - return BAD_VALUE; - - if ((w && !h) || (!w && h)) - return BAD_VALUE; - - Mutex::Autolock lock(mMutex); - mUserWidth = w; - mUserHeight = h; - return NO_ERROR; -} - -int GonkNativeWindowClient::setBuffersFormat(int format) -{ - ALOGV("GonkNativeWindowClient::setBuffersFormat"); - - if (format<0) - return BAD_VALUE; - - Mutex::Autolock lock(mMutex); - mReqFormat = format; - return NO_ERROR; -} - -int GonkNativeWindowClient::setScalingMode(int mode) -{ - ALOGV("GonkNativeWindowClient::setScalingMode(%d)", mode); - - switch (mode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: - case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: - break; - default: - ALOGE("unknown scaling mode: %d", mode); - return BAD_VALUE; - } - - Mutex::Autolock lock(mMutex); - mScalingMode = mode; - return NO_ERROR; -} - -int GonkNativeWindowClient::setBuffersTransform(int transform) -{ - ALOGV("GonkNativeWindowClient::setBuffersTransform"); - Mutex::Autolock lock(mMutex); - mTransform = transform; - return NO_ERROR; -} - -int GonkNativeWindowClient::setBuffersTimestamp(int64_t timestamp) -{ - ALOGV("GonkNativeWindowClient::setBuffersTimestamp"); - Mutex::Autolock lock(mMutex); - mTimestamp = timestamp; - return NO_ERROR; -} - -void GonkNativeWindowClient::freeAllBuffers() { - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - mSlots[i].buffer = 0; - } -} - -// ---------------------------------------------------------------------- -// the lock/unlock APIs must be used from the same thread - -// ---------------------------------------------------------------------------- - -status_t GonkNativeWindowClient::lock( - ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds) -{ - return INVALID_OPERATION; -} - -status_t GonkNativeWindowClient::unlockAndPost() -{ - return INVALID_OPERATION; -} - -}; // namespace android diff --git a/widget/gonk/nativewindow/GonkNativeWindowClientJB.h b/widget/gonk/nativewindow/GonkNativeWindowClientJB.h deleted file mode 100644 index 1e2fb00667..0000000000 --- a/widget/gonk/nativewindow/GonkNativeWindowClientJB.h +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef NATIVEWINDOW_GONKNATIVEWINDOWCLIENT_JB_H -#define NATIVEWINDOW_GONKNATIVEWINDOWCLIENT_JB_H - -#if ANDROID_VERSION == 17 -#include -#else -#include -#endif - -#include -#include - -#include -#include -#include - -#include "mozilla/Types.h" -#include "GonkBufferQueue.h" - -struct ANativeWindow_Buffer; - -namespace android { - -/* - * An implementation of ANativeWindow that feeds graphics buffers into a - * BufferQueue. - * - * This is typically used by programs that want to render frames through - * some means (maybe OpenGL, a software renderer, or a hardware decoder) - * and have the frames they create forwarded to SurfaceFlinger for - * compositing. For example, a video decoder could render a frame and call - * eglSwapBuffers(), which invokes ANativeWindow callbacks defined by - * GonkNativeWindowClient. GonkNativeWindowClient then forwards the buffers through Binder IPC - * to the BufferQueue's producer interface, providing the new frame to a - * consumer such as GLConsumer. - */ -class GonkNativeWindowClient - : public ANativeObjectBase -{ -public: - - /* - * creates a GonkNativeWindowClient from the given IGraphicBufferProducer (which concrete - * implementation is a BufferQueue). - * - * GonkNativeWindowClient is mainly state-less while it's disconnected, it can be - * viewed as a glorified IGraphicBufferProducer holder. It's therefore - * safe to create other GonkNativeWindowClients from the same IGraphicBufferProducer. - * - * However, once a GonkNativeWindowClient is connected, it'll prevent other GonkNativeWindowClients - * referring to the same IGraphicBufferProducer to become connected and - * therefore prevent them to be used as actual producers of buffers. - */ - GonkNativeWindowClient(const sp& bufferProducer); - - /* getIGraphicBufferProducer() returns the IGraphicBufferProducer this - * GonkNativeWindowClient was created with. Usually it's an error to use the - * IGraphicBufferProducer while the GonkNativeWindowClient is connected. - */ -#if ANDROID_VERSION == 17 - sp getISurfaceTexture() const; -#else - sp getIGraphicBufferProducer() const; -#endif - - /* convenience function to check that the given surface is non NULL as - * well as its IGraphicBufferProducer */ -#if ANDROID_VERSION >= 18 - static bool isValid(const sp& surface) { - return surface != NULL && surface->getIGraphicBufferProducer() != NULL; - } -#endif - -protected: - virtual ~GonkNativeWindowClient(); - -private: - // can't be copied - GonkNativeWindowClient& operator = (const GonkNativeWindowClient& rhs); - GonkNativeWindowClient(const GonkNativeWindowClient& rhs); - - // ANativeWindow hooks - static int hook_cancelBuffer(ANativeWindow* window, - ANativeWindowBuffer* buffer, int fenceFd); - static int hook_dequeueBuffer(ANativeWindow* window, - ANativeWindowBuffer** buffer, int* fenceFd); - static int hook_perform(ANativeWindow* window, int operation, ...); - static int hook_query(const ANativeWindow* window, int what, int* value); - static int hook_queueBuffer(ANativeWindow* window, - ANativeWindowBuffer* buffer, int fenceFd); - static int hook_setSwapInterval(ANativeWindow* window, int interval); - - static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer); - static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer** buffer); - static int hook_lockBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer); - static int hook_queueBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer); - - int dispatchConnect(va_list args); - int dispatchDisconnect(va_list args); - int dispatchSetBufferCount(va_list args); - int dispatchSetBuffersGeometry(va_list args); - int dispatchSetBuffersDimensions(va_list args); - int dispatchSetBuffersUserDimensions(va_list args); - int dispatchSetBuffersFormat(va_list args); - int dispatchSetScalingMode(va_list args); - int dispatchSetBuffersTransform(va_list args); - int dispatchSetBuffersTimestamp(va_list args); - int dispatchSetCrop(va_list args); - int dispatchSetPostTransformCrop(va_list args); - int dispatchSetUsage(va_list args); - int dispatchLock(va_list args); - int dispatchUnlockAndPost(va_list args); - -protected: - virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); - virtual int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd); - virtual int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd); - virtual int perform(int operation, va_list args); - virtual int query(int what, int* value) const; - virtual int setSwapInterval(int interval); - - virtual int lockBuffer_DEPRECATED(ANativeWindowBuffer* buffer); - - virtual int connect(int api); - virtual int disconnect(int api); - virtual int setBufferCount(int bufferCount); - virtual int setBuffersDimensions(int w, int h); - virtual int setBuffersUserDimensions(int w, int h); - virtual int setBuffersFormat(int format); - virtual int setScalingMode(int mode); - virtual int setBuffersTransform(int transform); - virtual int setBuffersTimestamp(int64_t timestamp); - virtual int setCrop(Rect const* rect); - virtual int setUsage(uint32_t reqUsage); - -public: - virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds); - virtual int unlockAndPost(); - -protected: - enum { NUM_BUFFER_SLOTS = GonkBufferQueue::NUM_BUFFER_SLOTS }; - enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 }; - -private: - void freeAllBuffers(); - int getSlotFromBufferLocked(android_native_buffer_t* buffer) const; - - struct BufferSlot { - sp buffer; - Region dirtyRegion; - }; - - // mSurfaceTexture is the interface to the surface texture server. All - // operations on the surface texture client ultimately translate into - // interactions with the server using this interface. - sp mBufferProducer; - - // mSlots stores the buffers that have been allocated for each buffer slot. - // It is initialized to null pointers, and gets filled in with the result of - // IGraphicBufferProducer::requestBuffer when the client dequeues a buffer from a - // slot that has not yet been used. The buffer allocated to a slot will also - // be replaced if the requested buffer usage or geometry differs from that - // of the buffer allocated to a slot. - BufferSlot mSlots[NUM_BUFFER_SLOTS]; - - // mReqWidth is the buffer width that will be requested at the next dequeue - // operation. It is initialized to 1. - uint32_t mReqWidth; - - // mReqHeight is the buffer height that will be requested at the next - // dequeue operation. It is initialized to 1. - uint32_t mReqHeight; - - // mReqFormat is the buffer pixel format that will be requested at the next - // deuque operation. It is initialized to PIXEL_FORMAT_RGBA_8888. - uint32_t mReqFormat; - - // mReqUsage is the set of buffer usage flags that will be requested - // at the next deuque operation. It is initialized to 0. - uint32_t mReqUsage; - - // mTimestamp is the timestamp that will be used for the next buffer queue - // operation. It defaults to NATIVE_WINDOW_TIMESTAMP_AUTO, which means that - // a timestamp is auto-generated when queueBuffer is called. - int64_t mTimestamp; - - // mCrop is the crop rectangle that will be used for the next buffer - // that gets queued. It is set by calling setCrop. - Rect mCrop; - - // mScalingMode is the scaling mode that will be used for the next - // buffers that get queued. It is set by calling setScalingMode. - int mScalingMode; - - // mTransform is the transform identifier that will be used for the next - // buffer that gets queued. It is set by calling setTransform. - uint32_t mTransform; - - // mDefaultWidth is default width of the buffers, regardless of the - // native_window_set_buffers_dimensions call. - uint32_t mDefaultWidth; - - // mDefaultHeight is default height of the buffers, regardless of the - // native_window_set_buffers_dimensions call. - uint32_t mDefaultHeight; - - // mUserWidth, if non-zero, is an application-specified override - // of mDefaultWidth. This is lower priority than the width set by - // native_window_set_buffers_dimensions. - uint32_t mUserWidth; - - // mUserHeight, if non-zero, is an application-specified override - // of mDefaultHeight. This is lower priority than the height set - // by native_window_set_buffers_dimensions. - uint32_t mUserHeight; - - // mTransformHint is the transform probably applied to buffers of this - // window. this is only a hint, actual transform may differ. - uint32_t mTransformHint; - - // mConsumerRunningBehind whether the consumer is running more than - // one buffer behind the producer. - mutable bool mConsumerRunningBehind; - - // mMutex is the mutex used to prevent concurrent access to the member - // variables of GonkNativeWindowClient objects. It must be locked whenever the - // member variables are accessed. - mutable Mutex mMutex; - - // must be used from the lock/unlock thread - sp mLockedBuffer; - sp mPostedBuffer; - bool mConnectedToCpu; - - // must be accessed from lock/unlock thread only - Region mDirtyRegion; -}; - -}; // namespace android - -#endif // NATIVEWINDOW_GONKNATIVEWINDOWCLIENT_JB_H diff --git a/widget/gonk/nativewindow/GonkNativeWindowClientKK.cpp b/widget/gonk/nativewindow/GonkNativeWindowClientKK.cpp deleted file mode 100644 index 06d1c4efc0..0000000000 --- a/widget/gonk/nativewindow/GonkNativeWindowClientKK.cpp +++ /dev/null @@ -1,673 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "GonkNativeWindowClient" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#include - -#include - -#include -#include - -#include - -#include "GonkNativeWindowClientKK.h" - -namespace android { - -GonkNativeWindowClient::GonkNativeWindowClient( - const sp& bufferProducer, - bool controlledByApp) - : mGraphicBufferProducer(bufferProducer) -{ - // Initialize the ANativeWindow function pointers. - ANativeWindow::setSwapInterval = hook_setSwapInterval; - ANativeWindow::dequeueBuffer = hook_dequeueBuffer; - ANativeWindow::cancelBuffer = hook_cancelBuffer; - ANativeWindow::queueBuffer = hook_queueBuffer; - ANativeWindow::query = hook_query; - ANativeWindow::perform = hook_perform; - - ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED; - ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED; - ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED; - ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED; - - const_cast(ANativeWindow::minSwapInterval) = 0; - const_cast(ANativeWindow::maxSwapInterval) = 1; - - mReqWidth = 0; - mReqHeight = 0; - mReqFormat = 0; - mReqUsage = 0; - mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO; - mCrop.clear(); - mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; - mTransform = 0; - mDefaultWidth = 0; - mDefaultHeight = 0; - mUserWidth = 0; - mUserHeight = 0; - mTransformHint = 0; - mConsumerRunningBehind = false; - mConnectedToCpu = false; - mProducerControlledByApp = controlledByApp; - mSwapIntervalZero = false; -} - -GonkNativeWindowClient::~GonkNativeWindowClient() { - if (mConnectedToCpu) { - GonkNativeWindowClient::disconnect(NATIVE_WINDOW_API_CPU); - } -} - -sp GonkNativeWindowClient::getIGraphicBufferProducer() const { - return mGraphicBufferProducer; -} - -int GonkNativeWindowClient::hook_setSwapInterval(ANativeWindow* window, int interval) { - GonkNativeWindowClient* c = getSelf(window); - return c->setSwapInterval(interval); -} - -int GonkNativeWindowClient::hook_dequeueBuffer(ANativeWindow* window, - ANativeWindowBuffer** buffer, int* fenceFd) { - GonkNativeWindowClient* c = getSelf(window); - return c->dequeueBuffer(buffer, fenceFd); -} - -int GonkNativeWindowClient::hook_cancelBuffer(ANativeWindow* window, - ANativeWindowBuffer* buffer, int fenceFd) { - GonkNativeWindowClient* c = getSelf(window); - return c->cancelBuffer(buffer, fenceFd); -} - -int GonkNativeWindowClient::hook_queueBuffer(ANativeWindow* window, - ANativeWindowBuffer* buffer, int fenceFd) { - GonkNativeWindowClient* c = getSelf(window); - return c->queueBuffer(buffer, fenceFd); -} - -int GonkNativeWindowClient::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer** buffer) { - GonkNativeWindowClient* c = getSelf(window); - ANativeWindowBuffer* buf; - int fenceFd = -1; - int result = c->dequeueBuffer(&buf, &fenceFd); - sp fence(new Fence(fenceFd)); - int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED"); - if (waitResult != OK) { - ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d", - waitResult); - c->cancelBuffer(buf, -1); - return waitResult; - } - *buffer = buf; - return result; -} - -int GonkNativeWindowClient::hook_cancelBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer) { - GonkNativeWindowClient* c = getSelf(window); - return c->cancelBuffer(buffer, -1); -} - -int GonkNativeWindowClient::hook_lockBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer) { - GonkNativeWindowClient* c = getSelf(window); - return c->lockBuffer_DEPRECATED(buffer); -} - -int GonkNativeWindowClient::hook_queueBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer) { - GonkNativeWindowClient* c = getSelf(window); - return c->queueBuffer(buffer, -1); -} - -int GonkNativeWindowClient::hook_query(const ANativeWindow* window, - int what, int* value) { - const GonkNativeWindowClient* c = getSelf(window); - return c->query(what, value); -} - -int GonkNativeWindowClient::hook_perform(ANativeWindow* window, int operation, ...) { - va_list args; - va_start(args, operation); - GonkNativeWindowClient* c = getSelf(window); - return c->perform(operation, args); -} - -int GonkNativeWindowClient::setSwapInterval(int interval) { - ATRACE_CALL(); - // EGL specification states: - // interval is silently clamped to minimum and maximum implementation - // dependent values before being stored. - - if (interval < minSwapInterval) - interval = minSwapInterval; - - if (interval > maxSwapInterval) - interval = maxSwapInterval; - - return NO_ERROR; -} - -int GonkNativeWindowClient::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::dequeueBuffer"); - Mutex::Autolock lock(mMutex); - int buf = -1; - int reqW = mReqWidth ? mReqWidth : mUserWidth; - int reqH = mReqHeight ? mReqHeight : mUserHeight; - sp fence; - status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, mSwapIntervalZero, - reqW, reqH, mReqFormat, mReqUsage); - if (result < 0) { - ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d)" - "failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage, - result); - return result; - } - sp& gbuf(mSlots[buf].buffer); - - // this should never happen - ALOGE_IF(fence == NULL, "Surface::dequeueBuffer: received null Fence! buf=%d", buf); - - if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) { - freeAllBuffers(); - } - - if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) { - result = mGraphicBufferProducer->requestBuffer(buf, &gbuf); - if (result != NO_ERROR) { - ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result); - return result; - } - } - - if (fence->isValid()) { - *fenceFd = fence->dup(); - if (*fenceFd == -1) { - ALOGE("dequeueBuffer: error duping fence: %d", errno); - // dup() should never fail; something is badly wrong. Soldier on - // and hope for the best; the worst that should happen is some - // visible corruption that lasts until the next frame. - } - } else { - *fenceFd = -1; - } - - *buffer = gbuf.get(); - return OK; -} - -int GonkNativeWindowClient::cancelBuffer(android_native_buffer_t* buffer, - int fenceFd) { - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::cancelBuffer"); - Mutex::Autolock lock(mMutex); - int i = getSlotFromBufferLocked(buffer); - if (i < 0) { - return i; - } - sp fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); - mGraphicBufferProducer->cancelBuffer(i, fence); - return OK; -} - -int GonkNativeWindowClient::getSlotFromBufferLocked( - android_native_buffer_t* buffer) const { - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].buffer != NULL && - mSlots[i].buffer->handle == buffer->handle) { - return i; - } - } - ALOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle); - return BAD_VALUE; -} - -int GonkNativeWindowClient::lockBuffer_DEPRECATED(android_native_buffer_t* buffer) { - ALOGV("GonkNativeWindowClient::lockBuffer"); - Mutex::Autolock lock(mMutex); - return OK; -} - -int GonkNativeWindowClient::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::queueBuffer"); - Mutex::Autolock lock(mMutex); - int64_t timestamp; - bool isAutoTimestamp = false; - if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) { - timestamp = systemTime(SYSTEM_TIME_MONOTONIC); - isAutoTimestamp = true; - ALOGV("GonkNativeWindowClient::queueBuffer making up timestamp: %.2f ms", - timestamp / 1000000.f); - } else { - timestamp = mTimestamp; - } - int i = getSlotFromBufferLocked(buffer); - if (i < 0) { - return i; - } - - - // Make sure the crop rectangle is entirely inside the buffer. - Rect crop; - mCrop.intersect(Rect(buffer->width, buffer->height), &crop); - - sp fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); - IGraphicBufferProducer::QueueBufferOutput output; - IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp, - crop, mScalingMode, mTransform, mSwapIntervalZero, fence); - status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output); - if (err != OK) { - ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err); - } - uint32_t numPendingBuffers = 0; - output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint, - &numPendingBuffers); - - mConsumerRunningBehind = (numPendingBuffers >= 2); - - return err; -} - -int GonkNativeWindowClient::query(int what, int* value) const { - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::query"); - { // scope for the lock - Mutex::Autolock lock(mMutex); - switch (what) { - case NATIVE_WINDOW_FORMAT: - if (mReqFormat) { - *value = mReqFormat; - return NO_ERROR; - } - break; - case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: { - //sp composer( - // ComposerService::getComposerService()); - //if (composer->authenticateSurfaceTexture(mGraphicBufferProducer)) { - // *value = 1; - //} else { - *value = 0; - //} - return NO_ERROR; - } - case NATIVE_WINDOW_CONCRETE_TYPE: - *value = NATIVE_WINDOW_SURFACE; - return NO_ERROR; - case NATIVE_WINDOW_DEFAULT_WIDTH: - *value = mUserWidth ? mUserWidth : mDefaultWidth; - return NO_ERROR; - case NATIVE_WINDOW_DEFAULT_HEIGHT: - *value = mUserHeight ? mUserHeight : mDefaultHeight; - return NO_ERROR; - case NATIVE_WINDOW_TRANSFORM_HINT: - *value = mTransformHint; - return NO_ERROR; - case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: { - status_t err = NO_ERROR; - if (!mConsumerRunningBehind) { - *value = 0; - } else { - err = mGraphicBufferProducer->query(what, value); - if (err == NO_ERROR) { - mConsumerRunningBehind = *value; - } - } - return err; - } - } - } - return mGraphicBufferProducer->query(what, value); -} - -int GonkNativeWindowClient::perform(int operation, va_list args) -{ - int res = NO_ERROR; - switch (operation) { - case NATIVE_WINDOW_CONNECT: - // deprecated. must return NO_ERROR. - break; - case NATIVE_WINDOW_DISCONNECT: - // deprecated. must return NO_ERROR. - break; - case NATIVE_WINDOW_SET_USAGE: - res = dispatchSetUsage(args); - break; - case NATIVE_WINDOW_SET_CROP: - res = dispatchSetCrop(args); - break; - case NATIVE_WINDOW_SET_BUFFER_COUNT: - res = dispatchSetBufferCount(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY: - res = dispatchSetBuffersGeometry(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: - res = dispatchSetBuffersTransform(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP: - res = dispatchSetBuffersTimestamp(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: - res = dispatchSetBuffersDimensions(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS: - res = dispatchSetBuffersUserDimensions(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_FORMAT: - res = dispatchSetBuffersFormat(args); - break; - case NATIVE_WINDOW_LOCK: - res = dispatchLock(args); - break; - case NATIVE_WINDOW_UNLOCK_AND_POST: - res = dispatchUnlockAndPost(args); - break; - case NATIVE_WINDOW_SET_SCALING_MODE: - res = dispatchSetScalingMode(args); - break; - case NATIVE_WINDOW_API_CONNECT: - res = dispatchConnect(args); - break; - case NATIVE_WINDOW_API_DISCONNECT: - res = dispatchDisconnect(args); - break; - default: - res = NAME_NOT_FOUND; - break; - } - return res; -} - -int GonkNativeWindowClient::dispatchConnect(va_list args) { - int api = va_arg(args, int); - return connect(api); -} - -int GonkNativeWindowClient::dispatchDisconnect(va_list args) { - int api = va_arg(args, int); - return disconnect(api); -} - -int GonkNativeWindowClient::dispatchSetUsage(va_list args) { - int usage = va_arg(args, int); - return setUsage(usage); -} - -int GonkNativeWindowClient::dispatchSetCrop(va_list args) { - android_native_rect_t const* rect = va_arg(args, android_native_rect_t*); - return setCrop(reinterpret_cast(rect)); -} - -int GonkNativeWindowClient::dispatchSetBufferCount(va_list args) { - size_t bufferCount = va_arg(args, size_t); - return setBufferCount(bufferCount); -} - -int GonkNativeWindowClient::dispatchSetBuffersGeometry(va_list args) { - int w = va_arg(args, int); - int h = va_arg(args, int); - int f = va_arg(args, int); - int err = setBuffersDimensions(w, h); - if (err != 0) { - return err; - } - return setBuffersFormat(f); -} - -int GonkNativeWindowClient::dispatchSetBuffersDimensions(va_list args) { - int w = va_arg(args, int); - int h = va_arg(args, int); - return setBuffersDimensions(w, h); -} - -int GonkNativeWindowClient::dispatchSetBuffersUserDimensions(va_list args) { - int w = va_arg(args, int); - int h = va_arg(args, int); - return setBuffersUserDimensions(w, h); -} - -int GonkNativeWindowClient::dispatchSetBuffersFormat(va_list args) { - int f = va_arg(args, int); - return setBuffersFormat(f); -} - -int GonkNativeWindowClient::dispatchSetScalingMode(va_list args) { - int m = va_arg(args, int); - return setScalingMode(m); -} - -int GonkNativeWindowClient::dispatchSetBuffersTransform(va_list args) { - int transform = va_arg(args, int); - return setBuffersTransform(transform); -} - -int GonkNativeWindowClient::dispatchSetBuffersTimestamp(va_list args) { - int64_t timestamp = va_arg(args, int64_t); - return setBuffersTimestamp(timestamp); -} - -int GonkNativeWindowClient::dispatchLock(va_list args) { - ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*); - ARect* inOutDirtyBounds = va_arg(args, ARect*); - return lock(outBuffer, inOutDirtyBounds); -} - -int GonkNativeWindowClient::dispatchUnlockAndPost(va_list args) { - return unlockAndPost(); -} - - -int GonkNativeWindowClient::connect(int api) { - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::connect"); - static sp sLife = new BBinder(); - Mutex::Autolock lock(mMutex); - IGraphicBufferProducer::QueueBufferOutput output; - int err = mGraphicBufferProducer->connect(sLife, api, true, &output); - if (err == NO_ERROR) { - uint32_t numPendingBuffers = 0; - output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint, - &numPendingBuffers); - mConsumerRunningBehind = (numPendingBuffers >= 2); - } - if (!err && api == NATIVE_WINDOW_API_CPU) { - mConnectedToCpu = true; - } - return err; -} - - -int GonkNativeWindowClient::disconnect(int api) { - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::disconnect"); - Mutex::Autolock lock(mMutex); - freeAllBuffers(); - int err = mGraphicBufferProducer->disconnect(api); - if (!err) { - mReqFormat = 0; - mReqWidth = 0; - mReqHeight = 0; - mReqUsage = 0; - mCrop.clear(); - mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; - mTransform = 0; - if (api == NATIVE_WINDOW_API_CPU) { - mConnectedToCpu = false; - } - } - return err; -} - -int GonkNativeWindowClient::setUsage(uint32_t reqUsage) -{ - ALOGV("GonkNativeWindowClient::setUsage"); - Mutex::Autolock lock(mMutex); - mReqUsage = reqUsage; - return OK; -} - -int GonkNativeWindowClient::setCrop(Rect const* rect) -{ - ATRACE_CALL(); - - Rect realRect; - if (rect == NULL || rect->isEmpty()) { - realRect.clear(); - } else { - realRect = *rect; - } - - ALOGV("GonkNativeWindowClient::setCrop rect=[%d %d %d %d]", - realRect.left, realRect.top, realRect.right, realRect.bottom); - - Mutex::Autolock lock(mMutex); - mCrop = realRect; - return NO_ERROR; -} - -int GonkNativeWindowClient::setBufferCount(int bufferCount) -{ - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::setBufferCount"); - Mutex::Autolock lock(mMutex); - - status_t err = mGraphicBufferProducer->setBufferCount(bufferCount); - ALOGE_IF(err, "IGraphicBufferProducer::setBufferCount(%d) returned %s", - bufferCount, strerror(-err)); - - if (err == NO_ERROR) { - freeAllBuffers(); - } - - return err; -} - -int GonkNativeWindowClient::setBuffersDimensions(int w, int h) -{ - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::setBuffersDimensions"); - - if (w<0 || h<0) - return BAD_VALUE; - - if ((w && !h) || (!w && h)) - return BAD_VALUE; - - Mutex::Autolock lock(mMutex); - mReqWidth = w; - mReqHeight = h; - return NO_ERROR; -} - -int GonkNativeWindowClient::setBuffersUserDimensions(int w, int h) -{ - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::setBuffersUserDimensions"); - - if (w<0 || h<0) - return BAD_VALUE; - - if ((w && !h) || (!w && h)) - return BAD_VALUE; - - Mutex::Autolock lock(mMutex); - mUserWidth = w; - mUserHeight = h; - return NO_ERROR; -} - -int GonkNativeWindowClient::setBuffersFormat(int format) -{ - ALOGV("GonkNativeWindowClient::setBuffersFormat"); - - if (format<0) - return BAD_VALUE; - - Mutex::Autolock lock(mMutex); - mReqFormat = format; - return NO_ERROR; -} - -int GonkNativeWindowClient::setScalingMode(int mode) -{ - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::setScalingMode(%d)", mode); - - switch (mode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: - case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: - break; - default: - ALOGE("unknown scaling mode: %d", mode); - return BAD_VALUE; - } - - Mutex::Autolock lock(mMutex); - mScalingMode = mode; - return NO_ERROR; -} - -int GonkNativeWindowClient::setBuffersTransform(int transform) -{ - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::setBuffersTransform"); - Mutex::Autolock lock(mMutex); - mTransform = transform; - return NO_ERROR; -} - -int GonkNativeWindowClient::setBuffersTimestamp(int64_t timestamp) -{ - ALOGV("GonkNativeWindowClient::setBuffersTimestamp"); - Mutex::Autolock lock(mMutex); - mTimestamp = timestamp; - return NO_ERROR; -} - -void GonkNativeWindowClient::freeAllBuffers() { - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - mSlots[i].buffer = 0; - } -} - -// ---------------------------------------------------------------------- -// the lock/unlock APIs must be used from the same thread - -// ---------------------------------------------------------------------------- - -status_t GonkNativeWindowClient::lock( - ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds) -{ - return INVALID_OPERATION; -} - -status_t GonkNativeWindowClient::unlockAndPost() -{ - return INVALID_OPERATION; -} - -}; // namespace android diff --git a/widget/gonk/nativewindow/GonkNativeWindowClientKK.h b/widget/gonk/nativewindow/GonkNativeWindowClientKK.h deleted file mode 100644 index 1364816101..0000000000 --- a/widget/gonk/nativewindow/GonkNativeWindowClientKK.h +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef NATIVEWINDOW_GONKNATIVEWINDOWCLIENT_KK_H -#define NATIVEWINDOW_GONKNATIVEWINDOWCLIENT_KK_H - -#include - -#include -#include - -#include -#include -#include - -#include "mozilla/Types.h" -#include "GonkBufferQueue.h" - -struct MOZ_EXPORT ANativeWindow_Buffer; - -namespace android { - -/* - * An implementation of ANativeWindow that feeds graphics buffers into a - * BufferQueue. - * - * This is typically used by programs that want to render frames through - * some means (maybe OpenGL, a software renderer, or a hardware decoder) - * and have the frames they create forwarded to SurfaceFlinger for - * compositing. For example, a video decoder could render a frame and call - * eglSwapBuffers(), which invokes ANativeWindow callbacks defined by - * GonkNativeWindowClient. GonkNativeWindowClient then forwards the buffers through Binder IPC - * to the BufferQueue's producer interface, providing the new frame to a - * consumer such as GLConsumer. - */ -class GonkNativeWindowClient - : public ANativeObjectBase -{ -public: - - /* - * creates a GonkNativeWindowClient from the given IGraphicBufferProducer (which concrete - * implementation is a BufferQueue). - * - * GonkNativeWindowClient is mainly state-less while it's disconnected, it can be - * viewed as a glorified IGraphicBufferProducer holder. It's therefore - * safe to create other GonkNativeWindowClients from the same IGraphicBufferProducer. - * - * However, once a GonkNativeWindowClient is connected, it'll prevent other GonkNativeWindowClients - * referring to the same IGraphicBufferProducer to become connected and - * therefore prevent them to be used as actual producers of buffers. - * - * the controlledByApp flag indicates that this Surface (producer) is - * controlled by the application. This flag is used at connect time. - */ - GonkNativeWindowClient(const sp& bufferProducer, bool controlledByApp = false); - - /* getIGraphicBufferProducer() returns the IGraphicBufferProducer this - * GonkNativeWindowClient was created with. Usually it's an error to use the - * IGraphicBufferProducer while the GonkNativeWindowClient is connected. - */ - sp getIGraphicBufferProducer() const; - - /* convenience function to check that the given surface is non NULL as - * well as its IGraphicBufferProducer */ - static bool isValid(const sp& surface) { - return surface != NULL && surface->getIGraphicBufferProducer() != NULL; - } - -protected: - virtual ~GonkNativeWindowClient(); - -private: - // can't be copied - GonkNativeWindowClient& operator = (const GonkNativeWindowClient& rhs); - GonkNativeWindowClient(const GonkNativeWindowClient& rhs); - - // ANativeWindow hooks - static int hook_cancelBuffer(ANativeWindow* window, - ANativeWindowBuffer* buffer, int fenceFd); - static int hook_dequeueBuffer(ANativeWindow* window, - ANativeWindowBuffer** buffer, int* fenceFd); - static int hook_perform(ANativeWindow* window, int operation, ...); - static int hook_query(const ANativeWindow* window, int what, int* value); - static int hook_queueBuffer(ANativeWindow* window, - ANativeWindowBuffer* buffer, int fenceFd); - static int hook_setSwapInterval(ANativeWindow* window, int interval); - - static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer); - static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer** buffer); - static int hook_lockBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer); - static int hook_queueBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer); - - int dispatchConnect(va_list args); - int dispatchDisconnect(va_list args); - int dispatchSetBufferCount(va_list args); - int dispatchSetBuffersGeometry(va_list args); - int dispatchSetBuffersDimensions(va_list args); - int dispatchSetBuffersUserDimensions(va_list args); - int dispatchSetBuffersFormat(va_list args); - int dispatchSetScalingMode(va_list args); - int dispatchSetBuffersTransform(va_list args); - int dispatchSetBuffersTimestamp(va_list args); - int dispatchSetCrop(va_list args); - int dispatchSetPostTransformCrop(va_list args); - int dispatchSetUsage(va_list args); - int dispatchLock(va_list args); - int dispatchUnlockAndPost(va_list args); - -protected: - virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); - virtual int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd); - virtual int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd); - virtual int perform(int operation, va_list args); - virtual int query(int what, int* value) const; - virtual int setSwapInterval(int interval); - - virtual int lockBuffer_DEPRECATED(ANativeWindowBuffer* buffer); - - virtual int connect(int api); - virtual int disconnect(int api); - virtual int setBufferCount(int bufferCount); - virtual int setBuffersDimensions(int w, int h); - virtual int setBuffersUserDimensions(int w, int h); - virtual int setBuffersFormat(int format); - virtual int setScalingMode(int mode); - virtual int setBuffersTransform(int transform); - virtual int setBuffersTimestamp(int64_t timestamp); - virtual int setCrop(Rect const* rect); - virtual int setUsage(uint32_t reqUsage); - -public: - virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds); - virtual int unlockAndPost(); - -protected: - enum { NUM_BUFFER_SLOTS = GonkBufferQueue::NUM_BUFFER_SLOTS }; - enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 }; - -private: - void freeAllBuffers(); - int getSlotFromBufferLocked(android_native_buffer_t* buffer) const; - - struct BufferSlot { - sp buffer; - Region dirtyRegion; - }; - - // mSurfaceTexture is the interface to the surface texture server. All - // operations on the surface texture client ultimately translate into - // interactions with the server using this interface. - // TODO: rename to mBufferProducer - sp mGraphicBufferProducer; - - // mSlots stores the buffers that have been allocated for each buffer slot. - // It is initialized to null pointers, and gets filled in with the result of - // IGraphicBufferProducer::requestBuffer when the client dequeues a buffer from a - // slot that has not yet been used. The buffer allocated to a slot will also - // be replaced if the requested buffer usage or geometry differs from that - // of the buffer allocated to a slot. - BufferSlot mSlots[NUM_BUFFER_SLOTS]; - - // mReqWidth is the buffer width that will be requested at the next dequeue - // operation. It is initialized to 1. - uint32_t mReqWidth; - - // mReqHeight is the buffer height that will be requested at the next - // dequeue operation. It is initialized to 1. - uint32_t mReqHeight; - - // mReqFormat is the buffer pixel format that will be requested at the next - // deuque operation. It is initialized to PIXEL_FORMAT_RGBA_8888. - uint32_t mReqFormat; - - // mReqUsage is the set of buffer usage flags that will be requested - // at the next deuque operation. It is initialized to 0. - uint32_t mReqUsage; - - // mTimestamp is the timestamp that will be used for the next buffer queue - // operation. It defaults to NATIVE_WINDOW_TIMESTAMP_AUTO, which means that - // a timestamp is auto-generated when queueBuffer is called. - int64_t mTimestamp; - - // mCrop is the crop rectangle that will be used for the next buffer - // that gets queued. It is set by calling setCrop. - Rect mCrop; - - // mScalingMode is the scaling mode that will be used for the next - // buffers that get queued. It is set by calling setScalingMode. - int mScalingMode; - - // mTransform is the transform identifier that will be used for the next - // buffer that gets queued. It is set by calling setTransform. - uint32_t mTransform; - - // mDefaultWidth is default width of the buffers, regardless of the - // native_window_set_buffers_dimensions call. - uint32_t mDefaultWidth; - - // mDefaultHeight is default height of the buffers, regardless of the - // native_window_set_buffers_dimensions call. - uint32_t mDefaultHeight; - - // mUserWidth, if non-zero, is an application-specified override - // of mDefaultWidth. This is lower priority than the width set by - // native_window_set_buffers_dimensions. - uint32_t mUserWidth; - - // mUserHeight, if non-zero, is an application-specified override - // of mDefaultHeight. This is lower priority than the height set - // by native_window_set_buffers_dimensions. - uint32_t mUserHeight; - - // mTransformHint is the transform probably applied to buffers of this - // window. this is only a hint, actual transform may differ. - uint32_t mTransformHint; - - // mProducerControlledByApp whether this buffer producer is controlled - // by the application - bool mProducerControlledByApp; - - // mSwapIntervalZero set if we should drop buffers at queue() time to - // achieve an asynchronous swap interval - bool mSwapIntervalZero; - - // mConsumerRunningBehind whether the consumer is running more than - // one buffer behind the producer. - mutable bool mConsumerRunningBehind; - - // mMutex is the mutex used to prevent concurrent access to the member - // variables of GonkNativeWindowClient objects. It must be locked whenever the - // member variables are accessed. - mutable Mutex mMutex; - - // must be used from the lock/unlock thread - sp mLockedBuffer; - sp mPostedBuffer; - bool mConnectedToCpu; - - // must be accessed from lock/unlock thread only - Region mDirtyRegion; -}; - -}; // namespace android - -#endif // NATIVEWINDOW_GONKNATIVEWINDOWCLIENT_JB_H diff --git a/widget/gonk/nativewindow/GonkNativeWindowClientLL.cpp b/widget/gonk/nativewindow/GonkNativeWindowClientLL.cpp deleted file mode 100644 index 2eb73f987d..0000000000 --- a/widget/gonk/nativewindow/GonkNativeWindowClientLL.cpp +++ /dev/null @@ -1,743 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "GonkNativeWindowClient" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#include - -#include - -#include -#include -#include - -#include - -#include -#include "GonkNativeWindowClientLL.h" - -namespace android { - -GonkNativeWindowClient::GonkNativeWindowClient( - const sp& bufferProducer, - bool controlledByApp) - : mGraphicBufferProducer(bufferProducer) -{ - // Initialize the ANativeWindow function pointers. - ANativeWindow::setSwapInterval = hook_setSwapInterval; - ANativeWindow::dequeueBuffer = hook_dequeueBuffer; - ANativeWindow::cancelBuffer = hook_cancelBuffer; - ANativeWindow::queueBuffer = hook_queueBuffer; - ANativeWindow::query = hook_query; - ANativeWindow::perform = hook_perform; - - ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED; - ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED; - ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED; - ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED; - - const_cast(ANativeWindow::minSwapInterval) = 0; - const_cast(ANativeWindow::maxSwapInterval) = 1; - - mReqWidth = 0; - mReqHeight = 0; - mReqFormat = 0; - mReqUsage = 0; - mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO; - mCrop.clear(); - mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; - mTransform = 0; - mStickyTransform = 0; - mDefaultWidth = 0; - mDefaultHeight = 0; - mUserWidth = 0; - mUserHeight = 0; - mTransformHint = 0; - mConsumerRunningBehind = false; - mConnectedToCpu = false; - mProducerControlledByApp = controlledByApp; - mSwapIntervalZero = false; -} - -GonkNativeWindowClient::~GonkNativeWindowClient() { - if (mConnectedToCpu) { - GonkNativeWindowClient::disconnect(NATIVE_WINDOW_API_CPU); - } -} - -sp GonkNativeWindowClient::getIGraphicBufferProducer() const { - return mGraphicBufferProducer; -} - -void GonkNativeWindowClient::setSidebandStream(const sp& stream) { - mGraphicBufferProducer->setSidebandStream(stream); -} - -void GonkNativeWindowClient::allocateBuffers() { - uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth; - uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight; - mGraphicBufferProducer->allocateBuffers(mSwapIntervalZero, reqWidth, - reqHeight, mReqFormat, mReqUsage); -} - -int GonkNativeWindowClient::hook_setSwapInterval(ANativeWindow* window, int interval) { - GonkNativeWindowClient* c = getSelf(window); - return c->setSwapInterval(interval); -} - -int GonkNativeWindowClient::hook_dequeueBuffer(ANativeWindow* window, - ANativeWindowBuffer** buffer, int* fenceFd) { - GonkNativeWindowClient* c = getSelf(window); - return c->dequeueBuffer(buffer, fenceFd); -} - -int GonkNativeWindowClient::hook_cancelBuffer(ANativeWindow* window, - ANativeWindowBuffer* buffer, int fenceFd) { - GonkNativeWindowClient* c = getSelf(window); - return c->cancelBuffer(buffer, fenceFd); -} - -int GonkNativeWindowClient::hook_queueBuffer(ANativeWindow* window, - ANativeWindowBuffer* buffer, int fenceFd) { - GonkNativeWindowClient* c = getSelf(window); - return c->queueBuffer(buffer, fenceFd); -} - -int GonkNativeWindowClient::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer** buffer) { - GonkNativeWindowClient* c = getSelf(window); - ANativeWindowBuffer* buf; - int fenceFd = -1; - int result = c->dequeueBuffer(&buf, &fenceFd); - sp fence(new Fence(fenceFd)); - int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED"); - if (waitResult != OK) { - ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d", - waitResult); - c->cancelBuffer(buf, -1); - return waitResult; - } - *buffer = buf; - return result; -} - -int GonkNativeWindowClient::hook_cancelBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer) { - GonkNativeWindowClient* c = getSelf(window); - return c->cancelBuffer(buffer, -1); -} - -int GonkNativeWindowClient::hook_lockBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer) { - GonkNativeWindowClient* c = getSelf(window); - return c->lockBuffer_DEPRECATED(buffer); -} - -int GonkNativeWindowClient::hook_queueBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer) { - GonkNativeWindowClient* c = getSelf(window); - return c->queueBuffer(buffer, -1); -} - -int GonkNativeWindowClient::hook_query(const ANativeWindow* window, - int what, int* value) { - const GonkNativeWindowClient* c = getSelf(window); - return c->query(what, value); -} - -int GonkNativeWindowClient::hook_perform(ANativeWindow* window, int operation, ...) { - va_list args; - va_start(args, operation); - GonkNativeWindowClient* c = getSelf(window); - return c->perform(operation, args); -} - -int GonkNativeWindowClient::setSwapInterval(int interval) { - ATRACE_CALL(); - // EGL specification states: - // interval is silently clamped to minimum and maximum implementation - // dependent values before being stored. - - if (interval < minSwapInterval) - interval = minSwapInterval; - - if (interval > maxSwapInterval) - interval = maxSwapInterval; - - return NO_ERROR; -} - -int GonkNativeWindowClient::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::dequeueBuffer"); - - int reqW; - int reqH; - bool swapIntervalZero; - uint32_t reqFormat; - uint32_t reqUsage; - - { - Mutex::Autolock lock(mMutex); - - reqW = mReqWidth ? mReqWidth : mUserWidth; - reqH = mReqHeight ? mReqHeight : mUserHeight; - - swapIntervalZero = mSwapIntervalZero; - reqFormat = mReqFormat; - reqUsage = mReqUsage; - } // Drop the lock so that we can still touch the GonkNativeWindowClient while blocking in IGBP::dequeueBuffer - - int buf = -1; - sp fence; - status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, swapIntervalZero, - reqW, reqH, reqFormat, reqUsage); - - if (result < 0) { - ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d, %d)" - "failed: %d", swapIntervalZero, reqW, reqH, reqFormat, reqUsage, - result); - return result; - } - - Mutex::Autolock lock(mMutex); - - sp& gbuf(mSlots[buf].buffer); - - // this should never happen - ALOGE_IF(fence == NULL, "GonkNativeWindowClient::dequeueBuffer: received null Fence! buf=%d", buf); - - if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) { - freeAllBuffers(); - } - - if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) { - result = mGraphicBufferProducer->requestBuffer(buf, &gbuf); - if (result != NO_ERROR) { - ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result); - mGraphicBufferProducer->cancelBuffer(buf, fence); - return result; - } - } - - if (fence->isValid()) { - *fenceFd = fence->dup(); - if (*fenceFd == -1) { - ALOGE("dequeueBuffer: error duping fence: %d", errno); - // dup() should never fail; something is badly wrong. Soldier on - // and hope for the best; the worst that should happen is some - // visible corruption that lasts until the next frame. - } - } else { - *fenceFd = -1; - } - - *buffer = gbuf.get(); - return OK; -} - -int GonkNativeWindowClient::cancelBuffer(android_native_buffer_t* buffer, - int fenceFd) { - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::cancelBuffer"); - Mutex::Autolock lock(mMutex); - int i = getSlotFromBufferLocked(buffer); - if (i < 0) { - return i; - } - sp fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); - mGraphicBufferProducer->cancelBuffer(i, fence); - return OK; -} - -int GonkNativeWindowClient::getSlotFromBufferLocked( - android_native_buffer_t* buffer) const { - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].buffer != NULL && - mSlots[i].buffer->handle == buffer->handle) { - return i; - } - } - ALOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle); - return BAD_VALUE; -} - -int GonkNativeWindowClient::lockBuffer_DEPRECATED(android_native_buffer_t* buffer __attribute__((unused))) { - ALOGV("GonkNativeWindowClient::lockBuffer"); - Mutex::Autolock lock(mMutex); - return OK; -} - -int GonkNativeWindowClient::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::queueBuffer"); - Mutex::Autolock lock(mMutex); - int64_t timestamp; - bool isAutoTimestamp = false; - if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) { - timestamp = systemTime(SYSTEM_TIME_MONOTONIC); - isAutoTimestamp = true; - ALOGV("GonkNativeWindowClient::queueBuffer making up timestamp: %.2f ms", - timestamp / 1000000.f); - } else { - timestamp = mTimestamp; - } - int i = getSlotFromBufferLocked(buffer); - if (i < 0) { - return i; - } - - - // Make sure the crop rectangle is entirely inside the buffer. - Rect crop; - mCrop.intersect(Rect(buffer->width, buffer->height), &crop); - - sp fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); - IGraphicBufferProducer::QueueBufferOutput output; - IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp, - crop, mScalingMode, mTransform ^ mStickyTransform, mSwapIntervalZero, - fence, mStickyTransform); - status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output); - if (err != OK) { - ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err); - } - uint32_t numPendingBuffers = 0; - uint32_t hint = 0; - output.deflate(&mDefaultWidth, &mDefaultHeight, &hint, - &numPendingBuffers); - - // Disable transform hint if sticky transform is set. - if (mStickyTransform == 0) { - mTransformHint = hint; - } - - mConsumerRunningBehind = (numPendingBuffers >= 2); - - return err; -} - -int GonkNativeWindowClient::query(int what, int* value) const { - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::query"); - { // scope for the lock - Mutex::Autolock lock(mMutex); - switch (what) { - case NATIVE_WINDOW_FORMAT: - if (mReqFormat) { - *value = mReqFormat; - return NO_ERROR; - } - break; - case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: { - *value = 0; - return NO_ERROR; - } - case NATIVE_WINDOW_CONCRETE_TYPE: - *value = NATIVE_WINDOW_SURFACE; - return NO_ERROR; - case NATIVE_WINDOW_DEFAULT_WIDTH: - *value = mUserWidth ? mUserWidth : mDefaultWidth; - return NO_ERROR; - case NATIVE_WINDOW_DEFAULT_HEIGHT: - *value = mUserHeight ? mUserHeight : mDefaultHeight; - return NO_ERROR; - case NATIVE_WINDOW_TRANSFORM_HINT: - *value = mTransformHint; - return NO_ERROR; - case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: { - status_t err = NO_ERROR; - if (!mConsumerRunningBehind) { - *value = 0; - } else { - err = mGraphicBufferProducer->query(what, value); - if (err == NO_ERROR) { - mConsumerRunningBehind = *value; - } - } - return err; - } - } - } - return mGraphicBufferProducer->query(what, value); -} - -int GonkNativeWindowClient::perform(int operation, va_list args) -{ - int res = NO_ERROR; - switch (operation) { - case NATIVE_WINDOW_CONNECT: - // deprecated. must return NO_ERROR. - break; - case NATIVE_WINDOW_DISCONNECT: - // deprecated. must return NO_ERROR. - break; - case NATIVE_WINDOW_SET_USAGE: - res = dispatchSetUsage(args); - break; - case NATIVE_WINDOW_SET_CROP: - res = dispatchSetCrop(args); - break; - case NATIVE_WINDOW_SET_BUFFER_COUNT: - res = dispatchSetBufferCount(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY: - res = dispatchSetBuffersGeometry(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: - res = dispatchSetBuffersTransform(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM: - res = dispatchSetBuffersStickyTransform(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP: - res = dispatchSetBuffersTimestamp(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: - res = dispatchSetBuffersDimensions(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS: - res = dispatchSetBuffersUserDimensions(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_FORMAT: - res = dispatchSetBuffersFormat(args); - break; - case NATIVE_WINDOW_LOCK: - res = dispatchLock(args); - break; - case NATIVE_WINDOW_UNLOCK_AND_POST: - res = dispatchUnlockAndPost(args); - break; - case NATIVE_WINDOW_SET_SCALING_MODE: - res = dispatchSetScalingMode(args); - break; - case NATIVE_WINDOW_API_CONNECT: - res = dispatchConnect(args); - break; - case NATIVE_WINDOW_API_DISCONNECT: - res = dispatchDisconnect(args); - break; - case NATIVE_WINDOW_SET_SIDEBAND_STREAM: - res = dispatchSetSidebandStream(args); - break; - default: - res = NAME_NOT_FOUND; - break; - } - return res; -} - -int GonkNativeWindowClient::dispatchConnect(va_list args) { - int api = va_arg(args, int); - return connect(api); -} - -int GonkNativeWindowClient::dispatchDisconnect(va_list args) { - int api = va_arg(args, int); - return disconnect(api); -} - -int GonkNativeWindowClient::dispatchSetUsage(va_list args) { - int usage = va_arg(args, int); - return setUsage(usage); -} - -int GonkNativeWindowClient::dispatchSetCrop(va_list args) { - android_native_rect_t const* rect = va_arg(args, android_native_rect_t*); - return setCrop(reinterpret_cast(rect)); -} - -int GonkNativeWindowClient::dispatchSetBufferCount(va_list args) { - size_t bufferCount = va_arg(args, size_t); - return setBufferCount(bufferCount); -} - -int GonkNativeWindowClient::dispatchSetBuffersGeometry(va_list args) { - int w = va_arg(args, int); - int h = va_arg(args, int); - int f = va_arg(args, int); - int err = setBuffersDimensions(w, h); - if (err != 0) { - return err; - } - return setBuffersFormat(f); -} - -int GonkNativeWindowClient::dispatchSetBuffersDimensions(va_list args) { - int w = va_arg(args, int); - int h = va_arg(args, int); - return setBuffersDimensions(w, h); -} - -int GonkNativeWindowClient::dispatchSetBuffersUserDimensions(va_list args) { - int w = va_arg(args, int); - int h = va_arg(args, int); - return setBuffersUserDimensions(w, h); -} - -int GonkNativeWindowClient::dispatchSetBuffersFormat(va_list args) { - int f = va_arg(args, int); - return setBuffersFormat(f); -} - -int GonkNativeWindowClient::dispatchSetScalingMode(va_list args) { - int m = va_arg(args, int); - return setScalingMode(m); -} - -int GonkNativeWindowClient::dispatchSetBuffersTransform(va_list args) { - int transform = va_arg(args, int); - return setBuffersTransform(transform); -} - -int GonkNativeWindowClient::dispatchSetBuffersStickyTransform(va_list args) { - int transform = va_arg(args, int); - return setBuffersStickyTransform(transform); -} - -int GonkNativeWindowClient::dispatchSetBuffersTimestamp(va_list args) { - int64_t timestamp = va_arg(args, int64_t); - return setBuffersTimestamp(timestamp); -} - -int GonkNativeWindowClient::dispatchLock(va_list args) { - ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*); - ARect* inOutDirtyBounds = va_arg(args, ARect*); - return lock(outBuffer, inOutDirtyBounds); -} - -int GonkNativeWindowClient::dispatchUnlockAndPost(va_list args __attribute__((unused))) { - return unlockAndPost(); -} - -int GonkNativeWindowClient::dispatchSetSidebandStream(va_list args) { - native_handle_t* sH = va_arg(args, native_handle_t*); - sp sidebandHandle = NativeHandle::create(sH, false); - setSidebandStream(sidebandHandle); - return OK; -} - -int GonkNativeWindowClient::connect(int api) { - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::connect"); - static sp listener = new DummyProducerListener(); - Mutex::Autolock lock(mMutex); - IGraphicBufferProducer::QueueBufferOutput output; - int err = mGraphicBufferProducer->connect(listener, api, true, &output); - if (err == NO_ERROR) { - uint32_t numPendingBuffers = 0; - uint32_t hint = 0; - output.deflate(&mDefaultWidth, &mDefaultHeight, &hint, - &numPendingBuffers); - - // Disable transform hint if sticky transform is set. - if (mStickyTransform == 0) { - mTransformHint = hint; - } - - mConsumerRunningBehind = (numPendingBuffers >= 2); - } - if (!err && api == NATIVE_WINDOW_API_CPU) { - mConnectedToCpu = true; - } - return err; -} - - -int GonkNativeWindowClient::disconnect(int api) { - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::disconnect"); - Mutex::Autolock lock(mMutex); - freeAllBuffers(); - int err = mGraphicBufferProducer->disconnect(api); - if (!err) { - mReqFormat = 0; - mReqWidth = 0; - mReqHeight = 0; - mReqUsage = 0; - mCrop.clear(); - mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; - mTransform = 0; - mStickyTransform = 0; - - if (api == NATIVE_WINDOW_API_CPU) { - mConnectedToCpu = false; - } - } - return err; -} - -int GonkNativeWindowClient::setUsage(uint32_t reqUsage) -{ - ALOGV("GonkNativeWindowClient::setUsage"); - Mutex::Autolock lock(mMutex); - mReqUsage = reqUsage; - return OK; -} - -int GonkNativeWindowClient::setCrop(Rect const* rect) -{ - ATRACE_CALL(); - - Rect realRect; - if (rect == NULL || rect->isEmpty()) { - realRect.clear(); - } else { - realRect = *rect; - } - - ALOGV("GonkNativeWindowClient::setCrop rect=[%d %d %d %d]", - realRect.left, realRect.top, realRect.right, realRect.bottom); - - Mutex::Autolock lock(mMutex); - mCrop = realRect; - return NO_ERROR; -} - -int GonkNativeWindowClient::setBufferCount(int bufferCount) -{ - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::setBufferCount"); - Mutex::Autolock lock(mMutex); - - status_t err = mGraphicBufferProducer->setBufferCount(bufferCount); - ALOGE_IF(err, "IGraphicBufferProducer::setBufferCount(%d) returned %s", - bufferCount, strerror(-err)); - - if (err == NO_ERROR) { - freeAllBuffers(); - } - - return err; -} - -int GonkNativeWindowClient::setBuffersDimensions(int w, int h) -{ - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::setBuffersDimensions"); - - if (w<0 || h<0) - return BAD_VALUE; - - if ((w && !h) || (!w && h)) - return BAD_VALUE; - - Mutex::Autolock lock(mMutex); - mReqWidth = w; - mReqHeight = h; - return NO_ERROR; -} - -int GonkNativeWindowClient::setBuffersUserDimensions(int w, int h) -{ - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::setBuffersUserDimensions"); - - if (w<0 || h<0) - return BAD_VALUE; - - if ((w && !h) || (!w && h)) - return BAD_VALUE; - - Mutex::Autolock lock(mMutex); - mUserWidth = w; - mUserHeight = h; - return NO_ERROR; -} - -int GonkNativeWindowClient::setBuffersFormat(int format) -{ - ALOGV("GonkNativeWindowClient::setBuffersFormat"); - - if (format<0) - return BAD_VALUE; - - Mutex::Autolock lock(mMutex); - mReqFormat = format; - return NO_ERROR; -} - -int GonkNativeWindowClient::setScalingMode(int mode) -{ - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::setScalingMode(%d)", mode); - - switch (mode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: - case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: - break; - default: - ALOGE("unknown scaling mode: %d", mode); - return BAD_VALUE; - } - - Mutex::Autolock lock(mMutex); - mScalingMode = mode; - return NO_ERROR; -} - -int GonkNativeWindowClient::setBuffersTransform(int transform) -{ - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::setBuffersTransform"); - Mutex::Autolock lock(mMutex); - mTransform = transform; - return NO_ERROR; -} - -int GonkNativeWindowClient::setBuffersStickyTransform(int transform) -{ - ATRACE_CALL(); - ALOGV("GonkNativeWindowClient::setBuffersStickyTransform"); - Mutex::Autolock lock(mMutex); - mStickyTransform = transform; - return NO_ERROR; -} - -int GonkNativeWindowClient::setBuffersTimestamp(int64_t timestamp) -{ - ALOGV("GonkNativeWindowClient::setBuffersTimestamp"); - Mutex::Autolock lock(mMutex); - mTimestamp = timestamp; - return NO_ERROR; -} - -void GonkNativeWindowClient::freeAllBuffers() { - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - mSlots[i].buffer = 0; - } -} - -// ---------------------------------------------------------------------- -// the lock/unlock APIs must be used from the same thread - -// ---------------------------------------------------------------------------- - -status_t GonkNativeWindowClient::lock( - ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds) -{ - return INVALID_OPERATION; -} - -status_t GonkNativeWindowClient::unlockAndPost() -{ - return INVALID_OPERATION; -} - -}; // namespace android diff --git a/widget/gonk/nativewindow/GonkNativeWindowClientLL.h b/widget/gonk/nativewindow/GonkNativeWindowClientLL.h deleted file mode 100644 index d20314524c..0000000000 --- a/widget/gonk/nativewindow/GonkNativeWindowClientLL.h +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef NATIVEWINDOW_GONKNATIVEWINDOWCLIENT_LL_H -#define NATIVEWINDOW_GONKNATIVEWINDOWCLIENT_LL_H - -#include - -#include -#include - -#include -#include -#include - -#include "GonkBufferQueueLL.h" - -struct ANativeWindow_Buffer; - -namespace android { - -/* - * An implementation of ANativeWindow that feeds graphics buffers into a - * GonkBufferQueue. - * - * This is typically used by programs that want to render frames through - * some means (maybe OpenGL, a software renderer, or a hardware decoder) - * and have the frames they create forwarded to SurfaceFlinger for - * compositing. For example, a video decoder could render a frame and call - * eglSwapBuffers(), which invokes ANativeWindow callbacks defined by - * GonkNativeWindowClient. GonkNativeWindowClient then forwards the buffers through Binder IPC - * to the GonkBufferQueue's producer interface, providing the new frame to a - * consumer such as GLConsumer. - */ -class GonkNativeWindowClient - : public ANativeObjectBase -{ -public: - - /* - * creates a GonkNativeWindowClient from the given IGraphicBufferProducer (which concrete - * implementation is a GonkBufferQueue). - * - * GonkNativeWindowClient is mainly state-less while it's disconnected, it can be - * viewed as a glorified IGraphicBufferProducer holder. It's therefore - * safe to create other GonkNativeWindowClients from the same IGraphicBufferProducer. - * - * However, once a GonkNativeWindowClient is connected, it'll prevent other GonkNativeWindowClients - * referring to the same IGraphicBufferProducer to become connected and - * therefore prevent them to be used as actual producers of buffers. - * - * the controlledByApp flag indicates that this GonkNativeWindowClient (producer) is - * controlled by the application. This flag is used at connect time. - */ - GonkNativeWindowClient(const sp& bufferProducer, bool controlledByApp = false); - - /* getIGraphicBufferProducer() returns the IGraphicBufferProducer this - * GonkNativeWindowClient was created with. Usually it's an error to use the - * IGraphicBufferProducer while the GonkNativeWindowClient is connected. - */ - sp getIGraphicBufferProducer() const; - - /* convenience function to check that the given surface is non NULL as - * well as its IGraphicBufferProducer */ - static bool isValid(const sp& surface) { - return surface != NULL && surface->getIGraphicBufferProducer() != NULL; - } - - /* Attaches a sideband buffer stream to the GonkNativeWindowClient's IGraphicBufferProducer. - * - * A sideband stream is a device-specific mechanism for passing buffers - * from the producer to the consumer without using dequeueBuffer/ - * queueBuffer. If a sideband stream is present, the consumer can choose - * whether to acquire buffers from the sideband stream or from the queued - * buffers. - * - * Passing NULL or a different stream handle will detach the previous - * handle if any. - */ - void setSidebandStream(const sp& stream); - - /* Allocates buffers based on the current dimensions/format. - * - * This function will allocate up to the maximum number of buffers - * permitted by the current GonkBufferQueue configuration. It will use the - * default format and dimensions. This is most useful to avoid an allocation - * delay during dequeueBuffer. If there are already the maximum number of - * buffers allocated, this function has no effect. - */ - void allocateBuffers(); - -protected: - virtual ~GonkNativeWindowClient(); - -private: - // can't be copied - GonkNativeWindowClient& operator = (const GonkNativeWindowClient& rhs); - GonkNativeWindowClient(const GonkNativeWindowClient& rhs); - - // ANativeWindow hooks - static int hook_cancelBuffer(ANativeWindow* window, - ANativeWindowBuffer* buffer, int fenceFd); - static int hook_dequeueBuffer(ANativeWindow* window, - ANativeWindowBuffer** buffer, int* fenceFd); - static int hook_perform(ANativeWindow* window, int operation, ...); - static int hook_query(const ANativeWindow* window, int what, int* value); - static int hook_queueBuffer(ANativeWindow* window, - ANativeWindowBuffer* buffer, int fenceFd); - static int hook_setSwapInterval(ANativeWindow* window, int interval); - - static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer); - static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer** buffer); - static int hook_lockBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer); - static int hook_queueBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer); - - int dispatchConnect(va_list args); - int dispatchDisconnect(va_list args); - int dispatchSetBufferCount(va_list args); - int dispatchSetBuffersGeometry(va_list args); - int dispatchSetBuffersDimensions(va_list args); - int dispatchSetBuffersUserDimensions(va_list args); - int dispatchSetBuffersFormat(va_list args); - int dispatchSetScalingMode(va_list args); - int dispatchSetBuffersTransform(va_list args); - int dispatchSetBuffersStickyTransform(va_list args); - int dispatchSetBuffersTimestamp(va_list args); - int dispatchSetCrop(va_list args); - int dispatchSetPostTransformCrop(va_list args); - int dispatchSetUsage(va_list args); - int dispatchLock(va_list args); - int dispatchUnlockAndPost(va_list args); - int dispatchSetSidebandStream(va_list args); - -protected: - virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); - virtual int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd); - virtual int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd); - virtual int perform(int operation, va_list args); - virtual int query(int what, int* value) const; - virtual int setSwapInterval(int interval); - - virtual int lockBuffer_DEPRECATED(ANativeWindowBuffer* buffer); - - virtual int connect(int api); - virtual int disconnect(int api); - virtual int setBufferCount(int bufferCount); - virtual int setBuffersDimensions(int w, int h); - virtual int setBuffersUserDimensions(int w, int h); - virtual int setBuffersFormat(int format); - virtual int setScalingMode(int mode); - virtual int setBuffersTransform(int transform); - virtual int setBuffersStickyTransform(int transform); - virtual int setBuffersTimestamp(int64_t timestamp); - virtual int setCrop(Rect const* rect); - virtual int setUsage(uint32_t reqUsage); - -public: - virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds); - virtual int unlockAndPost(); - -protected: - enum { NUM_BUFFER_SLOTS = GonkBufferQueue::NUM_BUFFER_SLOTS }; - enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 }; - -private: - void freeAllBuffers(); - int getSlotFromBufferLocked(android_native_buffer_t* buffer) const; - - struct BufferSlot { - sp buffer; - Region dirtyRegion; - }; - - // mSurfaceTexture is the interface to the surface texture server. All - // operations on the surface texture client ultimately translate into - // interactions with the server using this interface. - // TODO: rename to mBufferProducer - sp mGraphicBufferProducer; - - // mSlots stores the buffers that have been allocated for each buffer slot. - // It is initialized to null pointers, and gets filled in with the result of - // IGraphicBufferProducer::requestBuffer when the client dequeues a buffer from a - // slot that has not yet been used. The buffer allocated to a slot will also - // be replaced if the requested buffer usage or geometry differs from that - // of the buffer allocated to a slot. - BufferSlot mSlots[NUM_BUFFER_SLOTS]; - - // mReqWidth is the buffer width that will be requested at the next dequeue - // operation. It is initialized to 1. - uint32_t mReqWidth; - - // mReqHeight is the buffer height that will be requested at the next - // dequeue operation. It is initialized to 1. - uint32_t mReqHeight; - - // mReqFormat is the buffer pixel format that will be requested at the next - // deuque operation. It is initialized to PIXEL_FORMAT_RGBA_8888. - uint32_t mReqFormat; - - // mReqUsage is the set of buffer usage flags that will be requested - // at the next deuque operation. It is initialized to 0. - uint32_t mReqUsage; - - // mTimestamp is the timestamp that will be used for the next buffer queue - // operation. It defaults to NATIVE_WINDOW_TIMESTAMP_AUTO, which means that - // a timestamp is auto-generated when queueBuffer is called. - int64_t mTimestamp; - - // mCrop is the crop rectangle that will be used for the next buffer - // that gets queued. It is set by calling setCrop. - Rect mCrop; - - // mScalingMode is the scaling mode that will be used for the next - // buffers that get queued. It is set by calling setScalingMode. - int mScalingMode; - - // mTransform is the transform identifier that will be used for the next - // buffer that gets queued. It is set by calling setTransform. - uint32_t mTransform; - - // mStickyTransform is a transform that is applied on top of mTransform - // in each buffer that is queued. This is typically used to force the - // compositor to apply a transform, and will prevent the transform hint - // from being set by the compositor. - uint32_t mStickyTransform; - - // mDefaultWidth is default width of the buffers, regardless of the - // native_window_set_buffers_dimensions call. - uint32_t mDefaultWidth; - - // mDefaultHeight is default height of the buffers, regardless of the - // native_window_set_buffers_dimensions call. - uint32_t mDefaultHeight; - - // mUserWidth, if non-zero, is an application-specified override - // of mDefaultWidth. This is lower priority than the width set by - // native_window_set_buffers_dimensions. - uint32_t mUserWidth; - - // mUserHeight, if non-zero, is an application-specified override - // of mDefaultHeight. This is lower priority than the height set - // by native_window_set_buffers_dimensions. - uint32_t mUserHeight; - - // mTransformHint is the transform probably applied to buffers of this - // window. this is only a hint, actual transform may differ. - uint32_t mTransformHint; - - // mProducerControlledByApp whether this buffer producer is controlled - // by the application - bool mProducerControlledByApp; - - // mSwapIntervalZero set if we should drop buffers at queue() time to - // achieve an asynchronous swap interval - bool mSwapIntervalZero; - - // mConsumerRunningBehind whether the consumer is running more than - // one buffer behind the producer. - mutable bool mConsumerRunningBehind; - - // mMutex is the mutex used to prevent concurrent access to the member - // variables of GonkNativeWindowClient objects. It must be locked whenever the - // member variables are accessed. - mutable Mutex mMutex; - - // must be used from the lock/unlock thread - sp mLockedBuffer; - sp mPostedBuffer; - bool mConnectedToCpu; - - // must be accessed from lock/unlock thread only - Region mDirtyRegion; -}; - -}; // namespace android - -#endif // NATIVEWINDOW_GONKNATIVEWINDOWCLIENT_LL_H diff --git a/widget/gonk/nativewindow/moz.build b/widget/gonk/nativewindow/moz.build index 96fe175d2c..df64ad5202 100644 --- a/widget/gonk/nativewindow/moz.build +++ b/widget/gonk/nativewindow/moz.build @@ -17,7 +17,6 @@ EXPORTS += [ 'GonkBufferQueue.h', 'GonkNativeWindow.h', - 'GonkNativeWindowClient.h', ] if CONFIG['ANDROID_VERSION'] >= '19': @@ -32,7 +31,6 @@ if CONFIG['ANDROID_VERSION'] >= '21': 'GonkBufferQueueLL/GonkBufferQueueProducer.h', 'GonkBufferQueueLL/GonkBufferSlot.h', 'GonkConsumerBaseLL.h', - 'GonkNativeWindowClientLL.h', 'GonkNativeWindowLL.h', 'IGonkGraphicBufferConsumerLL.h', ] @@ -40,7 +38,6 @@ elif CONFIG['ANDROID_VERSION'] >= '19': EXPORTS += [ 'GonkBufferQueueKK.h', 'GonkConsumerBaseKK.h', - 'GonkNativeWindowClientKK.h', 'GonkNativeWindowKK.h', 'IGonkGraphicBufferConsumerKK.h', ] @@ -48,12 +45,10 @@ elif CONFIG['ANDROID_VERSION'] in ('17', '18'): EXPORTS += [ 'GonkBufferQueueJB.h', 'GonkConsumerBaseJB.h', - 'GonkNativeWindowClientJB.h', 'GonkNativeWindowJB.h', ] elif CONFIG['ANDROID_VERSION'] == '15': EXPORTS += [ - 'GonkNativeWindowClientICS.h', 'GonkNativeWindowICS.h', ] @@ -67,7 +62,6 @@ if CONFIG['MOZ_B2G_CAMERA'] or CONFIG['MOZ_OMX_DECODER'] or CONFIG['MOZ_WEBRTC'] 'GonkBufferQueueLL/GonkBufferQueueProducer.cpp', 'GonkBufferQueueLL/GonkBufferSlot.cpp', 'GonkConsumerBaseLL.cpp', - 'GonkNativeWindowClientLL.cpp', 'GonkNativeWindowLL.cpp', 'IGonkGraphicBufferConsumerLL.cpp', ] @@ -75,7 +69,6 @@ if CONFIG['MOZ_B2G_CAMERA'] or CONFIG['MOZ_OMX_DECODER'] or CONFIG['MOZ_WEBRTC'] SOURCES += [ 'GonkBufferQueueKK.cpp', 'GonkConsumerBaseKK.cpp', - 'GonkNativeWindowClientKK.cpp', 'GonkNativeWindowKK.cpp', 'IGonkGraphicBufferConsumerKK.cpp', ] @@ -83,12 +76,10 @@ if CONFIG['MOZ_B2G_CAMERA'] or CONFIG['MOZ_OMX_DECODER'] or CONFIG['MOZ_WEBRTC'] SOURCES += [ 'GonkBufferQueueJB.cpp', 'GonkConsumerBaseJB.cpp', - 'GonkNativeWindowClientJB.cpp', 'GonkNativeWindowJB.cpp', ] elif CONFIG['ANDROID_VERSION'] == '15': SOURCES += [ - 'GonkNativeWindowClientICS.cpp', 'GonkNativeWindowICS.cpp', ] diff --git a/widget/nsIGfxInfo.idl b/widget/nsIGfxInfo.idl index d55ba5086e..df596695f5 100644 --- a/widget/nsIGfxInfo.idl +++ b/widget/nsIGfxInfo.idl @@ -7,8 +7,7 @@ #include "nsISupports.idl" /* NOTE: this interface is completely undesigned, not stable and likely to change */ - -[scriptable, uuid(4b5ea59e-af89-44f7-8c1c-2dea47a170d1)] +[scriptable, uuid(1accd618-4c80-4703-9d29-ecf257d397c8)] interface nsIGfxInfo : nsISupports { /* @@ -108,6 +107,10 @@ interface nsIGfxInfo : nsISupports const long FEATURE_WEBRTC_HW_ACCELERATION_DECODE = 15; /* Whether Canvas acceleration is supported, starting in 45 */ const long FEATURE_CANVAS2D_ACCELERATION = 16; + /* Whether hardware VP8 decoding is supported. */ + const long FEATURE_VP8_HW_DECODE = 17; + /* Whether hardware VP9 decoding is supported. */ + const long FEATURE_VP9_HW_DECODE = 18; /* * A set of return values from GetFeatureStatus diff --git a/xpcom/reflect/xptcall/md/unix/moz.build b/xpcom/reflect/xptcall/md/unix/moz.build index d79e2ae73f..b8234b16bd 100644 --- a/xpcom/reflect/xptcall/md/unix/moz.build +++ b/xpcom/reflect/xptcall/md/unix/moz.build @@ -211,12 +211,12 @@ if CONFIG['OS_TEST'] in ('powerpc64', 'powerpc64le'): 'xptcstubs_ppc64_linux.cpp', ] -if CONFIG['OS_TEST'] in ('macppc', 'bebox', 'ofppc', 'prep', 'amigappc'): +if CONFIG['OS_TEST'] in ('powerpc', 'macppc', 'bebox', 'ofppc', 'prep', 'amigappc'): if CONFIG['OS_ARCH'] == 'NetBSD': SOURCES += [ - 'xptcinvoke_asm_ppc_netbsd.s', + 'xptcinvoke_asm_ppc_netbsd.S', 'xptcinvoke_ppc_netbsd.cpp', - 'xptcstubs_asm_ppc_netbsd.s', + 'xptcstubs_asm_ppc_netbsd.S', 'xptcstubs_ppc_netbsd.cpp', ] diff --git a/xpcom/typelib/xpt/tools/xpt.py b/xpcom/typelib/xpt/tools/xpt.py index 8d275f6b9f..67d40f7b2d 100755 --- a/xpcom/typelib/xpt/tools/xpt.py +++ b/xpcom/typelib/xpt/tools/xpt.py @@ -66,21 +66,24 @@ InterfaceType() - construct a new object representing a type that """ from __future__ import with_statement -import os, sys +import os +import sys import struct import operator -import itertools # header magic XPT_MAGIC = "XPCOM\nTypeLib\r\n\x1a" TYPELIB_VERSION = (1, 2) + class FileFormatError(Exception): pass + class DataError(Exception): pass + # Magic for creating enums def M_add_class_attribs(attribs): def foo(name, bases, dict_): @@ -89,19 +92,22 @@ def M_add_class_attribs(attribs): return type(name, bases, dict_) return foo + def enum(*names): class Foo(object): __metaclass__ = M_add_class_attribs(enumerate(names)) + def __setattr__(self, name, value): # this makes it read-only raise NotImplementedError return Foo() + # Descriptor types as described in the spec class Type(object): """ Data type of a method parameter or return value. Do not instantiate this class directly. Rather, use one of its subclasses. - + """ _prefixdescriptor = struct.Struct(">B") Tags = enum( @@ -135,7 +141,7 @@ class Type(object): 'StringWithSize', # WideStringWithSizeTypeDescriptor 'WideStringWithSize', - #XXX: These are also SimpleTypes (but not in the spec) + # XXX: These are also SimpleTypes (but not in the spec) # http://hg.mozilla.org/mozilla-central/annotate/0e0e2516f04e/xpcom/typelib/xpt/tools/xpt_dump.c#l69 'UTF8String', 'CString', @@ -149,6 +155,14 @@ class Type(object): if reference and not pointer: raise Exception("If reference is True pointer must be True too") + def __cmp__(self, other): + return ( + # First make sure we have two Types of the same type (no pun intended!) + cmp(type(self), type(other)) or + cmp(self.pointer, other.pointer) or + cmp(self.reference, other.reference) + ) + @staticmethod def decodeflags(byte): """ @@ -157,7 +171,7 @@ class Type(object): http://www.mozilla.org/scriptable/typelib_file.html#TypeDescriptor and return a dict of flagname: (True|False) suitable for passing to Type.__init__ as **kwargs. - + """ return {'pointer': bool(byte & 0x80), 'reference': bool(byte & 0x20), @@ -182,7 +196,7 @@ class Type(object): data pool offset |data_pool|. Returns (Type, next offset), where |next offset| is an offset suitable for reading the data following this TypeDescriptor. - + """ start = data_pool + offset - 1 (data,) = Type._prefixdescriptor.unpack_from(map, start) @@ -217,6 +231,7 @@ class Type(object): """ file.write(Type._prefixdescriptor.pack(self.encodeflags() | self.tag)) + class SimpleType(Type): """ A simple data type. (SimpleTypeDescriptor from the typelib specification.) @@ -228,13 +243,19 @@ class SimpleType(Type): Type.__init__(self, **kwargs) self.tag = tag + def __cmp__(self, other): + return ( + Type.__cmp__(self, other) or + cmp(self.tag, other.tag) + ) + @staticmethod def get(data, tag, flags): """ Get a SimpleType object representing |data| (a TypeDescriptorPrefix). May return an already-created object. If no cached object is found, construct one with |tag| and |flags|. - + """ if data not in SimpleType._cache: SimpleType._cache[data] = SimpleType(tag, **flags) @@ -258,6 +279,7 @@ class SimpleType(Type): s += " *" return s + class InterfaceType(Type): """ A type representing a pointer to an IDL-defined interface. @@ -268,11 +290,19 @@ class InterfaceType(Type): def __init__(self, iface, pointer=True, **kwargs): if not pointer: - raise DataError, "InterfaceType is not valid with pointer=False" + raise DataError("InterfaceType is not valid with pointer=False") Type.__init__(self, pointer=pointer, **kwargs) self.iface = iface self.tag = Type.Tags.Interface + def __cmp__(self, other): + return ( + Type.__cmp__(self, other) or + # When comparing interface types, only look at the name. + cmp(self.iface.name, other.iface.name) or + cmp(self.tag, other.tag) + ) + @staticmethod def read(typelib, map, data_pool, offset, flags): """ @@ -281,7 +311,7 @@ class InterfaceType(Type): Returns (InterfaceType, next offset), where |next offset| is an offset suitable for reading the data following this InterfaceTypeDescriptor. - + """ if not flags['pointer']: return None, offset @@ -309,23 +339,31 @@ class InterfaceType(Type): return self.iface.name return "unknown interface" + class InterfaceIsType(Type): """ A type representing an interface described by one of the other arguments to the method. (InterfaceIsTypeDescriptor from the typelib specification.) - + """ _descriptor = struct.Struct(">B") _cache = {} def __init__(self, param_index, pointer=True, **kwargs): if not pointer: - raise DataError, "InterfaceIsType is not valid with pointer=False" + raise DataError("InterfaceIsType is not valid with pointer=False") Type.__init__(self, pointer=pointer, **kwargs) self.param_index = param_index self.tag = Type.Tags.InterfaceIs + def __cmp__(self, other): + return ( + Type.__cmp__(self, other) or + cmp(self.param_index, other.param_index) or + cmp(self.tag, other.tag) + ) + @staticmethod def read(typelib, map, data_pool, offset, flags): """ @@ -335,7 +373,7 @@ class InterfaceIsType(Type): where |next offset| is an offset suitable for reading the data following this InterfaceIsTypeDescriptor. May return a cached value. - + """ if not flags['pointer']: return None, offset @@ -358,25 +396,35 @@ class InterfaceIsType(Type): def __str__(self): return "InterfaceIs *" + class ArrayType(Type): """ A type representing an Array of elements of another type, whose size and length are passed as separate parameters to a method. (ArrayTypeDescriptor from the typelib specification.) - + """ _descriptor = struct.Struct(">BB") def __init__(self, element_type, size_is_arg_num, length_is_arg_num, pointer=True, **kwargs): if not pointer: - raise DataError, "ArrayType is not valid with pointer=False" + raise DataError("ArrayType is not valid with pointer=False") Type.__init__(self, pointer=pointer, **kwargs) self.element_type = element_type self.size_is_arg_num = size_is_arg_num self.length_is_arg_num = length_is_arg_num self.tag = Type.Tags.Array + def __cmp__(self, other): + return ( + Type.__cmp__(self, other) or + cmp(self.element_type, other.element_type) or + cmp(self.size_is_arg_num, other.size_is_arg_num) or + cmp(self.length_is_arg_num, other.length_is_arg_num) or + cmp(self.tag, other.tag) + ) + @staticmethod def read(typelib, map, data_pool, offset, flags): """ @@ -408,6 +456,7 @@ class ArrayType(Type): def __str__(self): return "%s []" % str(self.element_type) + class StringWithSizeType(Type): """ A type representing a UTF-8 encoded string whose size and length @@ -420,12 +469,20 @@ class StringWithSizeType(Type): def __init__(self, size_is_arg_num, length_is_arg_num, pointer=True, **kwargs): if not pointer: - raise DataError, "StringWithSizeType is not valid with pointer=False" + raise DataError("StringWithSizeType is not valid with pointer=False") Type.__init__(self, pointer=pointer, **kwargs) self.size_is_arg_num = size_is_arg_num self.length_is_arg_num = length_is_arg_num self.tag = Type.Tags.StringWithSize + def __cmp__(self, other): + return ( + Type.__cmp__(self, other) or + cmp(self.size_is_arg_num, other.size_is_arg_num) or + cmp(self.length_is_arg_num, other.length_is_arg_num) or + cmp(self.tag, other.tag) + ) + @staticmethod def read(typelib, map, data_pool, offset, flags): """ @@ -455,6 +512,7 @@ class StringWithSizeType(Type): def __str__(self): return "string_s" + class WideStringWithSizeType(Type): """ A type representing a UTF-16 encoded string whose size and length @@ -467,12 +525,20 @@ class WideStringWithSizeType(Type): def __init__(self, size_is_arg_num, length_is_arg_num, pointer=True, **kwargs): if not pointer: - raise DataError, "WideStringWithSizeType is not valid with pointer=False" + raise DataError("WideStringWithSizeType is not valid with pointer=False") Type.__init__(self, pointer=pointer, **kwargs) self.size_is_arg_num = size_is_arg_num self.length_is_arg_num = length_is_arg_num self.tag = Type.Tags.WideStringWithSize + def __cmp__(self, other): + return ( + Type.__cmp__(self, other) or + cmp(self.size_is_arg_num, other.size_is_arg_num) or + cmp(self.length_is_arg_num, other.length_is_arg_num) or + cmp(self.tag, other.tag) + ) + @staticmethod def read(typelib, map, data_pool, offset, flags): """ @@ -502,6 +568,7 @@ class WideStringWithSizeType(Type): def __str__(self): return "wstring_s" + class Param(object): """ A parameter to a method, or the return value of a method. @@ -526,6 +593,17 @@ class Param(object): self.dipper = dipper self.optional = optional + def __cmp__(self, other): + return ( + cmp(self.type, other.type) or + cmp(self.in_, other.in_) or + cmp(self.out, other.out) or + cmp(self.retval, other.retval) or + cmp(self.shared, other.shared) or + cmp(self.dipper, other.dipper) or + cmp(self.optional, other.optional) + ) + @staticmethod def decodeflags(byte): """ @@ -540,7 +618,7 @@ class Param(object): 'retval': bool(byte & 0x20), 'shared': bool(byte & 0x10), 'dipper': bool(byte & 0x08), - #XXX: Not in the spec, see: + # XXX: Not in the spec, see: # http://hg.mozilla.org/mozilla-central/annotate/0e0e2516f04e/xpcom/typelib/xpt/public/xpt_struct.h#l456 'optional': bool(byte & 0x04), } @@ -620,12 +698,13 @@ class Param(object): def __str__(self): return self.prefix() + str(self.type) + class Method(object): """ A method of an interface, defining its associated parameters and return value. (MethodDescriptor from the typelib specification.) - + """ _descriptorstart = struct.Struct(">BIB") @@ -647,13 +726,27 @@ class Method(object): raise Exception("result must be a Param!") self.result = result + def __cmp__(self, other): + return ( + cmp(self.name, other.name) or + cmp(self.getter, other.getter) or + cmp(self.setter, other.setter) or + cmp(self.notxpcom, other.notxpcom) or + cmp(self.constructor, other.constructor) or + cmp(self.hidden, other.hidden) or + cmp(self.optargc, other.optargc) or + cmp(self.implicit_jscontext, other.implicit_jscontext) or + cmp(self.params, other.params) or + cmp(self.result, other.result) + ) + def read_params(self, typelib, map, data_pool, offset, num_args): """ Read |num_args| ParamDescriptors representing this Method's arguments from the mmaped file |map| with data pool at the offset |data_pool|, starting at |offset| into self.params. Returns the offset suitable for reading the data following the ParamDescriptor array. - + """ for i in range(num_args): p, offset = Param.read(typelib, map, data_pool, offset) @@ -666,7 +759,7 @@ class Method(object): from the mmaped file |map| with data pool at the offset |data_pool|, starting at |offset| into self.result. Returns the offset suitable for reading the data following the ParamDescriptor. - + """ self.result, offset = Param.read(typelib, map, data_pool, offset) return offset @@ -679,7 +772,7 @@ class Method(object): http://www.mozilla.org/scriptable/typelib_file.html#MethodDescriptor and return a dict of flagname: (True|False) suitable for passing to Method.__init__ as **kwargs - + """ return {'getter': bool(byte & 0x80), 'setter': bool(byte & 0x40), @@ -722,7 +815,7 @@ class Method(object): data pool offset |data_pool|. Returns (Method, next offset), where |next offset| is an offset suitable for reading the data following this MethodDescriptor. - + """ start = data_pool + offset - 1 flags, name_offset, num_args = Method._descriptorstart.unpack_from(map, start) @@ -762,6 +855,7 @@ class Method(object): else: self._name_offset = 0 + class Constant(object): """ A constant value of a specific type defined on an interface. @@ -770,7 +864,7 @@ class Constant(object): """ _descriptorstart = struct.Struct(">I") # Actual value is restricted to this set of types - #XXX: the spec lies, the source allows a bunch more + # XXX: the spec lies, the source allows a bunch more # http://hg.mozilla.org/mozilla-central/annotate/9c85f9aaec8c/xpcom/typelib/xpt/src/xpt_struct.c#l689 typemap = {Type.Tags.int16: '>h', Type.Tags.uint16: '>H', @@ -783,6 +877,13 @@ class Constant(object): self.type = type self.value = value + def __cmp__(self, other): + return ( + cmp(self.name, other.name) or + cmp(self.type, other.type) or + cmp(self.value, other.value) + ) + @staticmethod def read(typelib, map, data_pool, offset): """ @@ -790,7 +891,7 @@ class Constant(object): data pool offset |data_pool|. Returns (Constant, next offset), where |next offset| is an offset suitable for reading the data following this ConstDescriptor. - + """ start = data_pool + offset - 1 (name_offset,) = Constant._descriptorstart.unpack_from(map, start) @@ -834,12 +935,13 @@ class Constant(object): def __repr__(self): return "Constant(%s, %s, %d)" % (self.name, str(self.type), self.value) + class Interface(object): """ An Interface represents an object, with its associated methods and constant values. (InterfaceDescriptor from the typelib specification.) - + """ _direntry = struct.Struct(">16sIII") _descriptorstart = struct.Struct(">HH") @@ -851,7 +953,7 @@ class Interface(object): scriptable=False, function=False, builtinclass=False, main_process_scriptable_only=False): self.resolved = resolved - #TODO: should validate IIDs! + # TODO: should validate IIDs! self.iid = iid self.name = name self.namespace = namespace @@ -868,7 +970,7 @@ class Interface(object): if self.methods or self.constants: # make sure it has a valid IID if self.iid == Interface.UNRESOLVED_IID: - raise DataError, "Cannot instantiate Interface %s containing methods or constants with an unresolved IID" % self.name + raise DataError("Cannot instantiate Interface %s containing methods or constants with an unresolved IID" % self.name) self.resolved = True # These are only used for writing out the interface self._descriptor_offset = 0 @@ -902,10 +1004,27 @@ class Interface(object): else: return 1 else: - # both unresolved, but names and IIDs are the same, so equal - return 0 - #TODO: actually compare methods etc - return 0 + if not self.resolved: + # both unresolved, but names and IIDs are the same, so equal + return 0 + # When comparing parents, only look at the name. + if (self.parent is None) != (other.parent is None): + if self.parent is None: + return -1 + else: + return 1 + elif self.parent is not None: + c = cmp(self.parent.name, other.parent.name) + if c != 0: + return c + return ( + cmp(self.methods, other.methods) or + cmp(self.constants, other.constants) or + cmp(self.scriptable, other.scriptable) or + cmp(self.function, other.function) or + cmp(self.builtinclass, other.builtinclass) or + cmp(self.main_process_scriptable_only, other.main_process_scriptable_only) + ) def read_descriptor(self, typelib, map, data_pool): offset = self._descriptor_offset @@ -1008,6 +1127,7 @@ class Interface(object): for c in self.constants: c.write_name(file, data_pool_offset) + class Typelib(object): """ A typelib represents one entire typelib file and all the interfaces @@ -1049,7 +1169,7 @@ class Typelib(object): Convert a UUID string into a 16-byte IID. """ - s = iid_str.replace('-','') + s = iid_str.replace('-', '') return ''.join([chr(int(s[i:i+2], 16)) for i in range(0, len(s), 2)]) @staticmethod @@ -1089,12 +1209,12 @@ class Typelib(object): interface_directory_offset, data_pool_offset) = Typelib._header.unpack_from(data) if magic != XPT_MAGIC: - raise FileFormatError, "Bad magic: %s" % magic + raise FileFormatError("Bad magic: %s" % magic) xpt = Typelib((major_ver, minor_ver)) xpt.filename = filename if expected_size and file_length != expected_size: - raise FileFormatError, "File is of wrong length, got %d bytes, expected %d" % (expected_size, file_length) - #XXX: by spec this is a zero-based file offset. however, + raise FileFormatError("File is of wrong length, got %d bytes, expected %d" % (expected_size, file_length)) + # XXX: by spec this is a zero-based file offset. however, # the xpt_xdr code always subtracts 1 from data offsets # (because that's what you do in the data pool) so it # winds up accidentally treating this as 1-based. @@ -1104,9 +1224,8 @@ class Typelib(object): # since XPIDL doesn't produce any anyway. start = Typelib._header.size (anno, ) = struct.unpack_from(">B", data, start) - islast = anno & 0x80 tag = anno & 0x7F - if tag == 0: # EmptyAnnotation + if tag == 0: # EmptyAnnotation xpt.annotations.append(None) # We don't bother handling PrivateAnnotations or anything @@ -1138,14 +1257,14 @@ class Typelib(object): self.interfaces.sort() for i in self.interfaces: if i.parent and i.parent not in self.interfaces: - raise DataError, "Interface %s has parent %s not present in typelib!" % (i.name, i.parent.name) + raise DataError("Interface %s has parent %s not present in typelib!" % (i.name, i.parent.name)) for m in i.methods: for n, p in enumerate(m.params): if isinstance(p, InterfaceType) and \ - p.iface not in self.interfaces: - raise DataError, "Interface method %s::%s, parameter %d references interface %s not present in typelib!" % (i.name, m.name, n, p.iface.name) + p.iface not in self.interfaces: + raise DataError("Interface method %s::%s, parameter %d references interface %s not present in typelib!" % (i.name, m.name, n, p.iface.name)) if isinstance(m.result, InterfaceType) and m.result.iface not in self.interfaces: - raise DataError, "Interface method %s::%s, result references interface %s not present in typelib!" % (i.name, m.name, m.result.iface.name) + raise DataError("Interface method %s::%s, result references interface %s not present in typelib!" % (i.name, m.name, m.result.iface.name)) def writefd(self, fd): # write out space for a header + one empty annotation, @@ -1177,7 +1296,7 @@ class Typelib(object): # write an empty annotation fd.write(struct.pack(">B", 0x80)) # now write the interface directory - #XXX: bug-compatible with existing xpt lib, put it one byte + # XXX: bug-compatible with existing xpt lib, put it one byte # ahead of where it's supposed to be. fd.seek(interface_directory_offset - 1) for i in self.interfaces: @@ -1200,7 +1319,7 @@ class Typelib(object): """ Print a human-readable listing of the contents of this typelib to |out|, in the format of xpt_dump. - + """ out.write("""Header: Major version: %d @@ -1218,7 +1337,7 @@ class Typelib(object): else: if i.parent: out.write(" Parent: %s::%s\n" % (i.parent.namespace, - i.parent.name)) + i.parent.name)) out.write(""" Flags: Scriptable: %s BuiltinClass: %s @@ -1249,6 +1368,7 @@ class Typelib(object): for c in i.constants: out.write(" %s %s = %d;\n" % (c.type, c.name, c.value)) + def xpt_dump(file): """ Dump the contents of |file| to stdout in the format of xpt_dump. @@ -1257,6 +1377,7 @@ def xpt_dump(file): t = Typelib.read(file) t.dump(sys.stdout) + def xpt_link(inputs): """ Link all of the xpt files in |inputs| together and return the result @@ -1287,9 +1408,9 @@ def xpt_link(inputs): Result = enum('Equal', # Interfaces the same, doesn't matter 'NotEqual', # Interfaces differ, keep both - 'KeepFirst', # Replace second interface with first - 'KeepSecond')# Replace first interface with second - + 'KeepFirst', # Replace second interface with first + 'KeepSecond') # Replace first interface with second + def compare(i, j): """ Compare two interfaces, determine if they're equal or @@ -1303,10 +1424,10 @@ def xpt_link(inputs): if i.name != j.name: if i.iid == j.iid and i.iid != Interface.UNRESOLVED_IID: # Same IID but different names: raise an exception. - raise DataError, \ - "Typelibs contain definitions of interface %s" \ - " with different names (%s (%s) vs %s (%s))!" % \ - (i.iid, i.name, i.xpt_filename, j.name, j.xpt_filename) + raise DataError( + "Typelibs contain definitions of interface %s" + " with different names (%s (%s) vs %s (%s))!" % + (i.iid, i.name, i.xpt_filename, j.name, j.xpt_filename)) # Otherwise just different interfaces. return Result.NotEqual # Interfaces have the same name, so either they need to be merged @@ -1333,14 +1454,14 @@ def xpt_link(inputs): return Result.KeepSecond else: # Same name but different IIDs: raise an exception. - raise DataError, \ - "Typelibs contain definitions of interface %s" \ - " with different IIDs (%s (%s) vs %s (%s))!" % \ - (i.name, i.iid, i.xpt_filename, \ - j.iid, j.xpt_filename) - raise DataError, "No idea what happened here: %s:%s (%s), %s:%s (%s)" % \ - (i.name, i.iid, i.xpt_filename, j.name, j.iid, j.xpt_filename) - + raise DataError( + "Typelibs contain definitions of interface %s" + " with different IIDs (%s (%s) vs %s (%s))!" % + (i.name, i.iid, i.xpt_filename, + j.iid, j.xpt_filename)) + raise DataError("No idea what happened here: %s:%s (%s), %s:%s (%s)" % + (i.name, i.iid, i.xpt_filename, j.name, j.iid, j.xpt_filename)) + # Compare interfaces pairwise to find duplicates that should be merged. i = 1 while i < len(interfaces): @@ -1356,15 +1477,15 @@ def xpt_link(inputs): elif res == Result.KeepSecond: merged_interfaces[interfaces[i-1]] = interfaces[i] del interfaces[i-1] - + # Now fixup any merged interfaces def checkType(t): if isinstance(t, InterfaceType) and t.iface in merged_interfaces: t.iface = merged_interfaces[t.iface] elif isinstance(t, ArrayType) and \ - isinstance(t.element_type, InterfaceType) and \ - t.element_type.iface in merged_interfaces: - t.element_type.iface = merged_interfaces[t.element_type.iface] + isinstance(t.element_type, InterfaceType) and \ + t.element_type.iface in merged_interfaces: + t.element_type.iface = merged_interfaces[t.element_type.iface] for i in interfaces: # Replace parent references @@ -1383,6 +1504,7 @@ def xpt_link(inputs): # scriptable interfaces. worklist = set(i for i in interfaces if i.scriptable) required_interfaces = set() + def maybe_add_to_worklist(iface): if iface in required_interfaces or iface in worklist: return @@ -1416,4 +1538,3 @@ if __name__ == '__main__': xpt_dump(sys.argv[2]) elif sys.argv[1] == 'link': xpt_link(sys.argv[3:]).write(sys.argv[2]) - diff --git a/xpcom/typelib/xpt/xpt_struct.cpp b/xpcom/typelib/xpt/xpt_struct.cpp index 53332efde7..05281b0435 100644 --- a/xpcom/typelib/xpt/xpt_struct.cpp +++ b/xpcom/typelib/xpt/xpt_struct.cpp @@ -208,6 +208,7 @@ DoInterfaceDescriptor(XPTArena *arena, XPTCursor *outer, if (!XPT_Do32(outer, &cursor->offset)) return PR_FALSE; if (!cursor->offset) { + *idp = NULL; return PR_TRUE; } if(!XPT_Do16(cursor, &id->parent_interface) ||