michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 sw=2 et tw=79: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsMimeTypeArray.h" michael@0: michael@0: #include "mozilla/dom/MimeTypeArrayBinding.h" michael@0: #include "mozilla/dom/MimeTypeBinding.h" michael@0: #include "nsIDOMNavigator.h" michael@0: #include "nsPluginArray.h" michael@0: #include "nsIMIMEService.h" michael@0: #include "nsIMIMEInfo.h" michael@0: #include "Navigator.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::dom; michael@0: michael@0: NS_IMPL_CYCLE_COLLECTING_ADDREF(nsMimeTypeArray) michael@0: NS_IMPL_CYCLE_COLLECTING_RELEASE(nsMimeTypeArray) michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsMimeTypeArray) michael@0: NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY michael@0: NS_INTERFACE_MAP_ENTRY(nsISupports) michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_3(nsMimeTypeArray, michael@0: mWindow, michael@0: mMimeTypes, michael@0: mHiddenMimeTypes) michael@0: michael@0: nsMimeTypeArray::nsMimeTypeArray(nsPIDOMWindow* aWindow) michael@0: : mWindow(aWindow) michael@0: { michael@0: SetIsDOMBinding(); michael@0: } michael@0: michael@0: nsMimeTypeArray::~nsMimeTypeArray() michael@0: { michael@0: } michael@0: michael@0: JSObject* michael@0: nsMimeTypeArray::WrapObject(JSContext* aCx) michael@0: { michael@0: return MimeTypeArrayBinding::Wrap(aCx, this); michael@0: } michael@0: michael@0: void michael@0: nsMimeTypeArray::Refresh() michael@0: { michael@0: mMimeTypes.Clear(); michael@0: mHiddenMimeTypes.Clear(); michael@0: } michael@0: michael@0: nsPIDOMWindow* michael@0: nsMimeTypeArray::GetParentObject() const michael@0: { michael@0: MOZ_ASSERT(mWindow); michael@0: return mWindow; michael@0: } michael@0: michael@0: nsMimeType* michael@0: nsMimeTypeArray::Item(uint32_t aIndex) michael@0: { michael@0: bool unused; michael@0: return IndexedGetter(aIndex, unused); michael@0: } michael@0: michael@0: nsMimeType* michael@0: nsMimeTypeArray::NamedItem(const nsAString& aName) michael@0: { michael@0: bool unused; michael@0: return NamedGetter(aName, unused); michael@0: } michael@0: michael@0: nsMimeType* michael@0: nsMimeTypeArray::IndexedGetter(uint32_t aIndex, bool &aFound) michael@0: { michael@0: aFound = false; michael@0: michael@0: EnsurePluginMimeTypes(); michael@0: michael@0: if (aIndex >= mMimeTypes.Length()) { michael@0: return nullptr; michael@0: } michael@0: michael@0: aFound = true; michael@0: michael@0: return mMimeTypes[aIndex]; michael@0: } michael@0: michael@0: static nsMimeType* michael@0: FindMimeType(const nsTArray >& aMimeTypes, michael@0: const nsAString& aType) michael@0: { michael@0: for (uint32_t i = 0; i < aMimeTypes.Length(); ++i) { michael@0: nsMimeType* mimeType = aMimeTypes[i]; michael@0: if (aType.Equals(mimeType->Type())) { michael@0: return mimeType; michael@0: } michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: nsMimeType* michael@0: nsMimeTypeArray::NamedGetter(const nsAString& aName, bool &aFound) michael@0: { michael@0: aFound = false; michael@0: michael@0: EnsurePluginMimeTypes(); michael@0: michael@0: nsString lowerName(aName); michael@0: ToLowerCase(lowerName); michael@0: michael@0: nsMimeType* mimeType = FindMimeType(mMimeTypes, lowerName); michael@0: if (!mimeType) { michael@0: mimeType = FindMimeType(mHiddenMimeTypes, lowerName); michael@0: } michael@0: michael@0: if (mimeType) { michael@0: aFound = true; michael@0: return mimeType; michael@0: } michael@0: michael@0: // Now let's check with the MIME service. michael@0: nsCOMPtr mimeSrv = do_GetService("@mozilla.org/mime;1"); michael@0: if (!mimeSrv) { michael@0: return nullptr; michael@0: } michael@0: michael@0: nsCOMPtr mimeInfo; michael@0: mimeSrv->GetFromTypeAndExtension(NS_ConvertUTF16toUTF8(lowerName), michael@0: EmptyCString(), getter_AddRefs(mimeInfo)); michael@0: if (!mimeInfo) { michael@0: return nullptr; michael@0: } michael@0: michael@0: // Now we check whether we can really claim to support this type michael@0: nsHandlerInfoAction action = nsIHandlerInfo::saveToDisk; michael@0: mimeInfo->GetPreferredAction(&action); michael@0: if (action != nsIMIMEInfo::handleInternally) { michael@0: bool hasHelper = false; michael@0: mimeInfo->GetHasDefaultHandler(&hasHelper); michael@0: michael@0: if (!hasHelper) { michael@0: nsCOMPtr helper; michael@0: mimeInfo->GetPreferredApplicationHandler(getter_AddRefs(helper)); michael@0: michael@0: if (!helper) { michael@0: // mime info from the OS may not have a PreferredApplicationHandler michael@0: // so just check for an empty default description michael@0: nsAutoString defaultDescription; michael@0: mimeInfo->GetDefaultDescription(defaultDescription); michael@0: michael@0: if (defaultDescription.IsEmpty()) { michael@0: // no support; just leave michael@0: return nullptr; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: // If we got here, we support this type! Say so. michael@0: aFound = true; michael@0: michael@0: // We don't want navigator.mimeTypes enumeration to expose MIME types with michael@0: // application handlers, so add them to the list of hidden MIME types. michael@0: nsMimeType *mt = new nsMimeType(mWindow, lowerName); michael@0: mHiddenMimeTypes.AppendElement(mt); michael@0: michael@0: return mt; michael@0: } michael@0: michael@0: bool michael@0: nsMimeTypeArray::NameIsEnumerable(const nsAString& aName) michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: uint32_t michael@0: nsMimeTypeArray::Length() michael@0: { michael@0: EnsurePluginMimeTypes(); michael@0: michael@0: return mMimeTypes.Length(); michael@0: } michael@0: michael@0: void michael@0: nsMimeTypeArray::GetSupportedNames(unsigned, nsTArray< nsString >& aRetval) michael@0: { michael@0: EnsurePluginMimeTypes(); michael@0: michael@0: for (uint32_t i = 0; i < mMimeTypes.Length(); ++i) { michael@0: aRetval.AppendElement(mMimeTypes[i]->Type()); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsMimeTypeArray::EnsurePluginMimeTypes() michael@0: { michael@0: if (!mMimeTypes.IsEmpty() || !mHiddenMimeTypes.IsEmpty() || !mWindow) { michael@0: return; michael@0: } michael@0: michael@0: nsCOMPtr navigator; michael@0: mWindow->GetNavigator(getter_AddRefs(navigator)); michael@0: michael@0: if (!navigator) { michael@0: return; michael@0: } michael@0: michael@0: ErrorResult rv; michael@0: nsPluginArray *pluginArray = michael@0: static_cast(navigator.get())->GetPlugins(rv); michael@0: if (!pluginArray) { michael@0: return; michael@0: } michael@0: michael@0: pluginArray->GetMimeTypes(mMimeTypes, mHiddenMimeTypes); michael@0: } michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsMimeType, AddRef) michael@0: NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsMimeType, Release) michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(nsMimeType, mWindow, mPluginElement) michael@0: michael@0: nsMimeType::nsMimeType(nsPIDOMWindow* aWindow, nsPluginElement* aPluginElement, michael@0: uint32_t aPluginTagMimeIndex, const nsAString& aType) michael@0: : mWindow(aWindow), michael@0: mPluginElement(aPluginElement), michael@0: mPluginTagMimeIndex(aPluginTagMimeIndex), michael@0: mType(aType) michael@0: { michael@0: SetIsDOMBinding(); michael@0: } michael@0: michael@0: nsMimeType::nsMimeType(nsPIDOMWindow* aWindow, const nsAString& aType) michael@0: : mWindow(aWindow), michael@0: mPluginElement(nullptr), michael@0: mPluginTagMimeIndex(0), michael@0: mType(aType) michael@0: { michael@0: SetIsDOMBinding(); michael@0: } michael@0: michael@0: nsMimeType::~nsMimeType() michael@0: { michael@0: } michael@0: michael@0: nsPIDOMWindow* michael@0: nsMimeType::GetParentObject() const michael@0: { michael@0: MOZ_ASSERT(mWindow); michael@0: return mWindow; michael@0: } michael@0: michael@0: JSObject* michael@0: nsMimeType::WrapObject(JSContext* aCx) michael@0: { michael@0: return MimeTypeBinding::Wrap(aCx, this); michael@0: } michael@0: michael@0: void michael@0: nsMimeType::GetDescription(nsString& retval) const michael@0: { michael@0: retval.Truncate(); michael@0: michael@0: if (mPluginElement) { michael@0: CopyUTF8toUTF16(mPluginElement->PluginTag()-> michael@0: mMimeDescriptions[mPluginTagMimeIndex], retval); michael@0: } michael@0: } michael@0: michael@0: nsPluginElement* michael@0: nsMimeType::GetEnabledPlugin() const michael@0: { michael@0: return (mPluginElement && mPluginElement->PluginTag()->IsEnabled()) ? michael@0: mPluginElement : nullptr; michael@0: } michael@0: michael@0: void michael@0: nsMimeType::GetSuffixes(nsString& retval) const michael@0: { michael@0: retval.Truncate(); michael@0: michael@0: if (mPluginElement) { michael@0: CopyUTF8toUTF16(mPluginElement->PluginTag()-> michael@0: mExtensions[mPluginTagMimeIndex], retval); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsMimeType::GetType(nsString& aRetval) const michael@0: { michael@0: aRetval = mType; michael@0: }