/src/mozilla-central/dom/base/nsPluginArray.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "nsPluginArray.h" |
8 | | |
9 | | #include "mozilla/dom/PluginArrayBinding.h" |
10 | | #include "mozilla/dom/PluginBinding.h" |
11 | | #include "mozilla/dom/HiddenPluginEvent.h" |
12 | | |
13 | | #include "nsMimeTypeArray.h" |
14 | | #include "Navigator.h" |
15 | | #include "nsIDocShell.h" |
16 | | #include "nsIWebNavigation.h" |
17 | | #include "nsPluginHost.h" |
18 | | #include "nsPluginTags.h" |
19 | | #include "nsIObserverService.h" |
20 | | #include "nsIWeakReference.h" |
21 | | #include "mozilla/Services.h" |
22 | | #include "nsIInterfaceRequestorUtils.h" |
23 | | #include "nsContentUtils.h" |
24 | | #include "nsIPermissionManager.h" |
25 | | #include "nsIDocument.h" |
26 | | #include "nsIBlocklistService.h" |
27 | | |
28 | | using namespace mozilla; |
29 | | using namespace mozilla::dom; |
30 | | |
31 | | nsPluginArray::nsPluginArray(nsPIDOMWindowInner* aWindow) |
32 | | : mWindow(aWindow) |
33 | 0 | { |
34 | 0 | } |
35 | | |
36 | | void |
37 | | nsPluginArray::Init() |
38 | 0 | { |
39 | 0 | nsCOMPtr<nsIObserverService> obsService = |
40 | 0 | mozilla::services::GetObserverService(); |
41 | 0 | if (obsService) { |
42 | 0 | obsService->AddObserver(this, "plugin-info-updated", true); |
43 | 0 | } |
44 | 0 | } |
45 | | |
46 | 0 | nsPluginArray::~nsPluginArray() = default; |
47 | | |
48 | | nsPIDOMWindowInner* |
49 | | nsPluginArray::GetParentObject() const |
50 | 0 | { |
51 | 0 | MOZ_ASSERT(mWindow); |
52 | 0 | return mWindow; |
53 | 0 | } |
54 | | |
55 | | JSObject* |
56 | | nsPluginArray::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) |
57 | 0 | { |
58 | 0 | return PluginArray_Binding::Wrap(aCx, this, aGivenProto); |
59 | 0 | } |
60 | | |
61 | | NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPluginArray) |
62 | | NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPluginArray) |
63 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPluginArray) |
64 | 0 | NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY |
65 | 0 | NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver) |
66 | 0 | NS_INTERFACE_MAP_ENTRY(nsIObserver) |
67 | 0 | NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) |
68 | 0 | NS_INTERFACE_MAP_END |
69 | | |
70 | | NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginArray, |
71 | | mWindow, |
72 | | mPlugins, |
73 | | mCTPPlugins) |
74 | | |
75 | | static void |
76 | | GetPluginMimeTypes(const nsTArray<RefPtr<nsPluginElement> >& aPlugins, |
77 | | nsTArray<RefPtr<nsMimeType> >& aMimeTypes) |
78 | 0 | { |
79 | 0 | for (uint32_t i = 0; i < aPlugins.Length(); ++i) { |
80 | 0 | nsPluginElement *plugin = aPlugins[i]; |
81 | 0 | aMimeTypes.AppendElements(plugin->MimeTypes()); |
82 | 0 | } |
83 | 0 | } |
84 | | |
85 | | static bool |
86 | | operator<(const RefPtr<nsMimeType>& lhs, const RefPtr<nsMimeType>& rhs) |
87 | 0 | { |
88 | 0 | // Sort MIME types alphabetically by type name. |
89 | 0 | return lhs->Type() < rhs->Type(); |
90 | 0 | } |
91 | | |
92 | | void |
93 | | nsPluginArray::GetMimeTypes(nsTArray<RefPtr<nsMimeType>>& aMimeTypes) |
94 | 0 | { |
95 | 0 | aMimeTypes.Clear(); |
96 | 0 |
|
97 | 0 | if (!AllowPlugins()) { |
98 | 0 | return; |
99 | 0 | } |
100 | 0 | |
101 | 0 | EnsurePlugins(); |
102 | 0 |
|
103 | 0 | GetPluginMimeTypes(mPlugins, aMimeTypes); |
104 | 0 |
|
105 | 0 | // Alphabetize the enumeration order of non-hidden MIME types to reduce |
106 | 0 | // fingerprintable entropy based on plugins' installation file times. |
107 | 0 | aMimeTypes.Sort(); |
108 | 0 | } |
109 | | |
110 | | void |
111 | | nsPluginArray::GetCTPMimeTypes(nsTArray<RefPtr<nsMimeType>>& aMimeTypes) |
112 | 0 | { |
113 | 0 | aMimeTypes.Clear(); |
114 | 0 |
|
115 | 0 | if (!AllowPlugins()) { |
116 | 0 | return; |
117 | 0 | } |
118 | 0 | |
119 | 0 | EnsurePlugins(); |
120 | 0 |
|
121 | 0 | GetPluginMimeTypes(mCTPPlugins, aMimeTypes); |
122 | 0 |
|
123 | 0 | // Alphabetize the enumeration order of non-hidden MIME types to reduce |
124 | 0 | // fingerprintable entropy based on plugins' installation file times. |
125 | 0 | aMimeTypes.Sort(); |
126 | 0 | } |
127 | | |
128 | | nsPluginElement* |
129 | | nsPluginArray::Item(uint32_t aIndex, CallerType aCallerType) |
130 | 0 | { |
131 | 0 | bool unused; |
132 | 0 | return IndexedGetter(aIndex, unused, aCallerType); |
133 | 0 | } |
134 | | |
135 | | nsPluginElement* |
136 | | nsPluginArray::NamedItem(const nsAString& aName, CallerType aCallerType) |
137 | 0 | { |
138 | 0 | bool unused; |
139 | 0 | return NamedGetter(aName, unused, aCallerType); |
140 | 0 | } |
141 | | |
142 | | void |
143 | | nsPluginArray::Refresh(bool aReloadDocuments) |
144 | 0 | { |
145 | 0 | RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst(); |
146 | 0 |
|
147 | 0 | if(!AllowPlugins() || !pluginHost) { |
148 | 0 | return; |
149 | 0 | } |
150 | 0 | |
151 | 0 | // NS_ERROR_PLUGINS_PLUGINSNOTCHANGED on reloading plugins indicates |
152 | 0 | // that plugins did not change and was not reloaded |
153 | 0 | if (pluginHost->ReloadPlugins() == |
154 | 0 | NS_ERROR_PLUGINS_PLUGINSNOTCHANGED) { |
155 | 0 | nsTArray<nsCOMPtr<nsIInternalPluginTag> > newPluginTags; |
156 | 0 | pluginHost->GetPlugins(newPluginTags); |
157 | 0 |
|
158 | 0 | // Check if the number of plugins we know about are different from |
159 | 0 | // the number of plugin tags the plugin host knows about. If the |
160 | 0 | // lengths are different, we refresh. This is safe because we're |
161 | 0 | // notified for every plugin enabling/disabling event that |
162 | 0 | // happens, and therefore the lengths will be in sync only when |
163 | 0 | // the both arrays contain the same plugin tags (though as |
164 | 0 | // different types). |
165 | 0 | if (newPluginTags.Length() == mPlugins.Length()) { |
166 | 0 | return; |
167 | 0 | } |
168 | 0 | } |
169 | 0 | |
170 | 0 | mPlugins.Clear(); |
171 | 0 | mCTPPlugins.Clear(); |
172 | 0 |
|
173 | 0 | RefPtr<Navigator> navigator = mWindow->Navigator(); |
174 | 0 | navigator->RefreshMIMEArray(); |
175 | 0 |
|
176 | 0 | nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(mWindow); |
177 | 0 | if (aReloadDocuments && webNav) { |
178 | 0 | webNav->Reload(nsIWebNavigation::LOAD_FLAGS_NONE); |
179 | 0 | } |
180 | 0 | } |
181 | | |
182 | | nsPluginElement* |
183 | | nsPluginArray::IndexedGetter(uint32_t aIndex, bool &aFound, CallerType aCallerType) |
184 | 0 | { |
185 | 0 | aFound = false; |
186 | 0 |
|
187 | 0 | if (!AllowPlugins() || nsContentUtils::ResistFingerprinting(aCallerType)) { |
188 | 0 | return nullptr; |
189 | 0 | } |
190 | 0 | |
191 | 0 | EnsurePlugins(); |
192 | 0 |
|
193 | 0 | aFound = aIndex < mPlugins.Length(); |
194 | 0 |
|
195 | 0 | if (!aFound) { |
196 | 0 | return nullptr; |
197 | 0 | } |
198 | 0 | |
199 | 0 | return mPlugins[aIndex]; |
200 | 0 | } |
201 | | |
202 | | void |
203 | | nsPluginArray::Invalidate() |
204 | 0 | { |
205 | 0 | nsCOMPtr<nsIObserverService> obsService = |
206 | 0 | mozilla::services::GetObserverService(); |
207 | 0 | if (obsService) { |
208 | 0 | obsService->RemoveObserver(this, "plugin-info-updated"); |
209 | 0 | } |
210 | 0 | } |
211 | | |
212 | | static nsPluginElement* |
213 | | FindPlugin(const nsTArray<RefPtr<nsPluginElement> >& aPlugins, |
214 | | const nsAString& aName) |
215 | 0 | { |
216 | 0 | for (uint32_t i = 0; i < aPlugins.Length(); ++i) { |
217 | 0 | nsAutoString pluginName; |
218 | 0 | nsPluginElement* plugin = aPlugins[i]; |
219 | 0 | plugin->GetName(pluginName); |
220 | 0 |
|
221 | 0 | if (pluginName.Equals(aName)) { |
222 | 0 | return plugin; |
223 | 0 | } |
224 | 0 | } |
225 | 0 |
|
226 | 0 | return nullptr; |
227 | 0 | } |
228 | | |
229 | | nsPluginElement* |
230 | | nsPluginArray::NamedGetter(const nsAString& aName, bool &aFound, |
231 | | CallerType aCallerType) |
232 | 0 | { |
233 | 0 | aFound = false; |
234 | 0 |
|
235 | 0 | if (!AllowPlugins() || nsContentUtils::ResistFingerprinting(aCallerType)) { |
236 | 0 | return nullptr; |
237 | 0 | } |
238 | 0 | |
239 | 0 | EnsurePlugins(); |
240 | 0 |
|
241 | 0 | nsPluginElement* plugin = FindPlugin(mPlugins, aName); |
242 | 0 | aFound = (plugin != nullptr); |
243 | 0 | if (!aFound) { |
244 | 0 | nsPluginElement* hiddenPlugin = FindPlugin(mCTPPlugins, aName); |
245 | 0 | if (hiddenPlugin) { |
246 | 0 | NotifyHiddenPluginTouched(hiddenPlugin); |
247 | 0 | } |
248 | 0 | } |
249 | 0 | return plugin; |
250 | 0 | } |
251 | | |
252 | | void nsPluginArray::NotifyHiddenPluginTouched(nsPluginElement* aHiddenElement) |
253 | 0 | { |
254 | 0 | HiddenPluginEventInit init; |
255 | 0 | init.mTag = aHiddenElement->PluginTag(); |
256 | 0 | nsCOMPtr<nsIDocument> doc = aHiddenElement->GetParentObject()->GetDoc(); |
257 | 0 | RefPtr<HiddenPluginEvent> event = |
258 | 0 | HiddenPluginEvent::Constructor(doc, NS_LITERAL_STRING("HiddenPlugin"), init); |
259 | 0 | event->SetTarget(doc); |
260 | 0 | event->SetTrusted(true); |
261 | 0 | event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true; |
262 | 0 | doc->DispatchEvent(*event); |
263 | 0 | } |
264 | | |
265 | | uint32_t |
266 | | nsPluginArray::Length(CallerType aCallerType) |
267 | 0 | { |
268 | 0 | if (!AllowPlugins() || nsContentUtils::ResistFingerprinting(aCallerType)) { |
269 | 0 | return 0; |
270 | 0 | } |
271 | 0 | |
272 | 0 | EnsurePlugins(); |
273 | 0 |
|
274 | 0 | return mPlugins.Length(); |
275 | 0 | } |
276 | | |
277 | | void |
278 | | nsPluginArray::GetSupportedNames(nsTArray<nsString>& aRetval, |
279 | | CallerType aCallerType) |
280 | 0 | { |
281 | 0 | aRetval.Clear(); |
282 | 0 |
|
283 | 0 | if (!AllowPlugins() || nsContentUtils::ResistFingerprinting(aCallerType)) { |
284 | 0 | return; |
285 | 0 | } |
286 | 0 | |
287 | 0 | for (uint32_t i = 0; i < mPlugins.Length(); ++i) { |
288 | 0 | nsAutoString pluginName; |
289 | 0 | mPlugins[i]->GetName(pluginName); |
290 | 0 |
|
291 | 0 | aRetval.AppendElement(pluginName); |
292 | 0 | } |
293 | 0 | } |
294 | | |
295 | | NS_IMETHODIMP |
296 | | nsPluginArray::Observe(nsISupports *aSubject, const char *aTopic, |
297 | 0 | const char16_t *aData) { |
298 | 0 | if (!nsCRT::strcmp(aTopic, "plugin-info-updated")) { |
299 | 0 | Refresh(false); |
300 | 0 | } |
301 | 0 |
|
302 | 0 | return NS_OK; |
303 | 0 | } |
304 | | |
305 | | bool |
306 | | nsPluginArray::AllowPlugins() const |
307 | 0 | { |
308 | 0 | if (!mWindow) { |
309 | 0 | return false; |
310 | 0 | } |
311 | 0 | nsCOMPtr<nsIDocument> doc = mWindow->GetDoc(); |
312 | 0 | if (!doc) { |
313 | 0 | return false; |
314 | 0 | } |
315 | 0 | |
316 | 0 | return doc->GetAllowPlugins(); |
317 | 0 | } |
318 | | |
319 | | static bool |
320 | | operator<(const RefPtr<nsPluginElement>& lhs, |
321 | | const RefPtr<nsPluginElement>& rhs) |
322 | 0 | { |
323 | 0 | // Sort plugins alphabetically by name. |
324 | 0 | return lhs->PluginTag()->Name() < rhs->PluginTag()->Name(); |
325 | 0 | } |
326 | | |
327 | | static bool |
328 | 0 | PluginShouldBeHidden(const nsCString& aName) { |
329 | 0 | // This only supports one hidden plugin |
330 | 0 | nsAutoCString value; |
331 | 0 | Preferences::GetCString("plugins.navigator.hidden_ctp_plugin", value); |
332 | 0 | return value.Equals(aName); |
333 | 0 | } |
334 | | |
335 | | void |
336 | | nsPluginArray::EnsurePlugins() |
337 | 0 | { |
338 | 0 | if (!mPlugins.IsEmpty() || !mCTPPlugins.IsEmpty()) { |
339 | 0 | // We already have an array of plugin elements. |
340 | 0 | return; |
341 | 0 | } |
342 | 0 | |
343 | 0 | RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst(); |
344 | 0 | if (!pluginHost) { |
345 | 0 | // We have no plugin host. |
346 | 0 | return; |
347 | 0 | } |
348 | 0 | |
349 | 0 | nsTArray<nsCOMPtr<nsIInternalPluginTag> > pluginTags; |
350 | 0 | pluginHost->GetPlugins(pluginTags); |
351 | 0 |
|
352 | 0 | // need to wrap each of these with a nsPluginElement, which is |
353 | 0 | // scriptable. |
354 | 0 | for (uint32_t i = 0; i < pluginTags.Length(); ++i) { |
355 | 0 | nsCOMPtr<nsPluginTag> pluginTag = do_QueryInterface(pluginTags[i]); |
356 | 0 | if (!pluginTag) { |
357 | 0 | mPlugins.AppendElement(new nsPluginElement(mWindow, pluginTags[i])); |
358 | 0 | } else if (pluginTag->IsActive()) { |
359 | 0 | uint32_t permission = nsIPermissionManager::ALLOW_ACTION; |
360 | 0 | uint32_t blocklistState; |
361 | 0 | if (pluginTag->IsClicktoplay() && |
362 | 0 | NS_SUCCEEDED(pluginTag->GetBlocklistState(&blocklistState)) && |
363 | 0 | blocklistState == nsIBlocklistService::STATE_NOT_BLOCKED) { |
364 | 0 | nsCString name; |
365 | 0 | pluginTag->GetName(name); |
366 | 0 | if (PluginShouldBeHidden(name)) { |
367 | 0 | RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst(); |
368 | 0 | nsCString permString; |
369 | 0 | nsresult rv = pluginHost->GetPermissionStringForTag(pluginTag, 0, permString); |
370 | 0 | if (rv == NS_OK) { |
371 | 0 | nsCOMPtr<nsIDocument> currentDoc = mWindow->GetExtantDoc(); |
372 | 0 |
|
373 | 0 | // The top-level content document gets the final say on whether or not |
374 | 0 | // a plugin is going to be hidden or not, regardless of the origin |
375 | 0 | // that a subframe is hosted at. This is to avoid spamming the user |
376 | 0 | // with the hidden plugin notification bar when third-party iframes |
377 | 0 | // attempt to access navigator.plugins after the user has already |
378 | 0 | // expressed that the top-level document has this permission. |
379 | 0 | nsCOMPtr<nsIDocument> topDoc = currentDoc->GetTopLevelContentDocument(); |
380 | 0 |
|
381 | 0 | if (topDoc) { |
382 | 0 | nsIPrincipal* principal = topDoc->NodePrincipal(); |
383 | 0 | nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager(); |
384 | 0 | permMgr->TestPermissionFromPrincipal(principal, permString.get(), &permission); |
385 | 0 | } |
386 | 0 | } |
387 | 0 | } |
388 | 0 | } |
389 | 0 | if (permission == nsIPermissionManager::ALLOW_ACTION) { |
390 | 0 | mPlugins.AppendElement(new nsPluginElement(mWindow, pluginTags[i])); |
391 | 0 | } else { |
392 | 0 | mCTPPlugins.AppendElement(new nsPluginElement(mWindow, pluginTags[i])); |
393 | 0 | } |
394 | 0 | } |
395 | 0 | } |
396 | 0 |
|
397 | 0 | if (mPlugins.Length() == 0 && mCTPPlugins.Length() != 0) { |
398 | 0 | nsCOMPtr<nsPluginTag> hiddenTag = new nsPluginTag("Hidden Plugin", nullptr, "dummy.plugin", nullptr, nullptr, |
399 | 0 | nullptr, nullptr, nullptr, 0, 0, false, |
400 | 0 | nsIBlocklistService::STATE_NOT_BLOCKED); |
401 | 0 | mPlugins.AppendElement(new nsPluginElement(mWindow, hiddenTag)); |
402 | 0 | } |
403 | 0 |
|
404 | 0 | // Alphabetize the enumeration order of non-hidden plugins to reduce |
405 | 0 | // fingerprintable entropy based on plugins' installation file times. |
406 | 0 | mPlugins.Sort(); |
407 | 0 | } |
408 | | // nsPluginElement implementation. |
409 | | |
410 | | NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPluginElement) |
411 | | NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPluginElement) |
412 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPluginElement) |
413 | 0 | NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY |
414 | 0 | NS_INTERFACE_MAP_ENTRY(nsISupports) |
415 | 0 | NS_INTERFACE_MAP_END |
416 | | |
417 | | NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginElement, mWindow, mMimeTypes) |
418 | | |
419 | | nsPluginElement::nsPluginElement(nsPIDOMWindowInner* aWindow, |
420 | | nsIInternalPluginTag* aPluginTag) |
421 | | : mWindow(aWindow), |
422 | | mPluginTag(aPluginTag) |
423 | 0 | { |
424 | 0 | } |
425 | | |
426 | 0 | nsPluginElement::~nsPluginElement() = default; |
427 | | |
428 | | nsPIDOMWindowInner* |
429 | | nsPluginElement::GetParentObject() const |
430 | 0 | { |
431 | 0 | MOZ_ASSERT(mWindow); |
432 | 0 | return mWindow; |
433 | 0 | } |
434 | | |
435 | | JSObject* |
436 | | nsPluginElement::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) |
437 | 0 | { |
438 | 0 | return Plugin_Binding::Wrap(aCx, this, aGivenProto); |
439 | 0 | } |
440 | | |
441 | | void |
442 | | nsPluginElement::GetDescription(nsString& retval) const |
443 | 0 | { |
444 | 0 | CopyUTF8toUTF16(mPluginTag->Description(), retval); |
445 | 0 | } |
446 | | |
447 | | void |
448 | | nsPluginElement::GetFilename(nsString& retval) const |
449 | 0 | { |
450 | 0 | CopyUTF8toUTF16(mPluginTag->FileName(), retval); |
451 | 0 | } |
452 | | |
453 | | void |
454 | | nsPluginElement::GetVersion(nsString& retval) const |
455 | 0 | { |
456 | 0 | CopyUTF8toUTF16(mPluginTag->Version(), retval); |
457 | 0 | } |
458 | | |
459 | | void |
460 | | nsPluginElement::GetName(nsString& retval) const |
461 | 0 | { |
462 | 0 | CopyUTF8toUTF16(mPluginTag->Name(), retval); |
463 | 0 | } |
464 | | |
465 | | nsMimeType* |
466 | | nsPluginElement::Item(uint32_t aIndex) |
467 | 0 | { |
468 | 0 | EnsurePluginMimeTypes(); |
469 | 0 |
|
470 | 0 | return mMimeTypes.SafeElementAt(aIndex); |
471 | 0 | } |
472 | | |
473 | | nsMimeType* |
474 | | nsPluginElement::NamedItem(const nsAString& aName) |
475 | 0 | { |
476 | 0 | bool unused; |
477 | 0 | return NamedGetter(aName, unused); |
478 | 0 | } |
479 | | |
480 | | nsMimeType* |
481 | | nsPluginElement::IndexedGetter(uint32_t aIndex, bool &aFound) |
482 | 0 | { |
483 | 0 | EnsurePluginMimeTypes(); |
484 | 0 |
|
485 | 0 | aFound = aIndex < mMimeTypes.Length(); |
486 | 0 |
|
487 | 0 | if (!aFound) { |
488 | 0 | return nullptr; |
489 | 0 | } |
490 | 0 | |
491 | 0 | return mMimeTypes[aIndex]; |
492 | 0 | } |
493 | | |
494 | | nsMimeType* |
495 | | nsPluginElement::NamedGetter(const nsAString& aName, bool &aFound) |
496 | 0 | { |
497 | 0 | EnsurePluginMimeTypes(); |
498 | 0 |
|
499 | 0 | aFound = false; |
500 | 0 |
|
501 | 0 | for (uint32_t i = 0; i < mMimeTypes.Length(); ++i) { |
502 | 0 | if (mMimeTypes[i]->Type().Equals(aName)) { |
503 | 0 | aFound = true; |
504 | 0 |
|
505 | 0 | return mMimeTypes[i]; |
506 | 0 | } |
507 | 0 | } |
508 | 0 |
|
509 | 0 | return nullptr; |
510 | 0 | } |
511 | | |
512 | | uint32_t |
513 | | nsPluginElement::Length() |
514 | 0 | { |
515 | 0 | EnsurePluginMimeTypes(); |
516 | 0 |
|
517 | 0 | return mMimeTypes.Length(); |
518 | 0 | } |
519 | | |
520 | | void |
521 | | nsPluginElement::GetSupportedNames(nsTArray<nsString>& retval) |
522 | 0 | { |
523 | 0 | EnsurePluginMimeTypes(); |
524 | 0 |
|
525 | 0 | for (uint32_t i = 0; i < mMimeTypes.Length(); ++i) { |
526 | 0 | retval.AppendElement(mMimeTypes[i]->Type()); |
527 | 0 | } |
528 | 0 | } |
529 | | |
530 | | nsTArray<RefPtr<nsMimeType> >& |
531 | | nsPluginElement::MimeTypes() |
532 | 0 | { |
533 | 0 | EnsurePluginMimeTypes(); |
534 | 0 |
|
535 | 0 | return mMimeTypes; |
536 | 0 | } |
537 | | |
538 | | void |
539 | | nsPluginElement::EnsurePluginMimeTypes() |
540 | 0 | { |
541 | 0 | if (!mMimeTypes.IsEmpty()) { |
542 | 0 | return; |
543 | 0 | } |
544 | 0 | |
545 | 0 | if (mPluginTag->MimeTypes().Length() != mPluginTag->MimeDescriptions().Length() || |
546 | 0 | mPluginTag->MimeTypes().Length() != mPluginTag->Extensions().Length()) { |
547 | 0 | MOZ_ASSERT(false, "mime type arrays expected to be the same length"); |
548 | 0 | return; |
549 | 0 | } |
550 | 0 |
|
551 | 0 | for (uint32_t i = 0; i < mPluginTag->MimeTypes().Length(); ++i) { |
552 | 0 | NS_ConvertUTF8toUTF16 type(mPluginTag->MimeTypes()[i]); |
553 | 0 | NS_ConvertUTF8toUTF16 description(mPluginTag->MimeDescriptions()[i]); |
554 | 0 | NS_ConvertUTF8toUTF16 extension(mPluginTag->Extensions()[i]); |
555 | 0 |
|
556 | 0 | mMimeTypes.AppendElement(new nsMimeType(mWindow, this, type, description, |
557 | 0 | extension)); |
558 | 0 | } |
559 | 0 | } |