Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/html/HTMLLinkElement.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 "mozilla/dom/HTMLLinkElement.h"
8
9
#include "mozilla/AsyncEventDispatcher.h"
10
#include "mozilla/Attributes.h"
11
#include "mozilla/EventDispatcher.h"
12
#include "mozilla/EventStates.h"
13
#include "mozilla/MemoryReporting.h"
14
#include "mozilla/Preferences.h"
15
#include "mozilla/dom/HTMLLinkElementBinding.h"
16
#include "nsContentUtils.h"
17
#include "nsGenericHTMLElement.h"
18
#include "nsGkAtoms.h"
19
#include "nsDOMTokenList.h"
20
#include "nsIContentInlines.h"
21
#include "nsIDocument.h"
22
#include "nsINode.h"
23
#include "nsIStyleSheetLinkingElement.h"
24
#include "nsIURL.h"
25
#include "nsPIDOMWindow.h"
26
#include "nsReadableUtils.h"
27
#include "nsStyleConsts.h"
28
#include "nsStyleLinkElement.h"
29
#include "nsUnicharUtils.h"
30
#include "nsWindowSizes.h"
31
#include "nsIContentPolicy.h"
32
#include "nsMimeTypes.h"
33
#include "imgLoader.h"
34
#include "MediaContainerType.h"
35
#include "DecoderDoctorDiagnostics.h"
36
#include "DecoderTraits.h"
37
#include "MediaList.h"
38
#include "nsAttrValueInlines.h"
39
40
#define LINK_ELEMENT_FLAG_BIT(n_) \
41
  NODE_FLAG_BIT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + (n_))
42
43
// Link element specific bits
44
enum {
45
  // Indicates that a DNS Prefetch has been requested from this Link element.
46
  HTML_LINK_DNS_PREFETCH_REQUESTED = LINK_ELEMENT_FLAG_BIT(0),
47
48
  // Indicates that a DNS Prefetch was added to the deferral queue
49
  HTML_LINK_DNS_PREFETCH_DEFERRED =  LINK_ELEMENT_FLAG_BIT(1)
50
};
51
52
#undef LINK_ELEMENT_FLAG_BIT
53
54
ASSERT_NODE_FLAGS_SPACE(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 2);
55
56
NS_IMPL_NS_NEW_HTML_ELEMENT(Link)
57
58
namespace mozilla {
59
namespace dom {
60
61
HTMLLinkElement::HTMLLinkElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
62
  : nsGenericHTMLElement(std::move(aNodeInfo))
63
  , Link(this)
64
0
{
65
0
}
66
67
HTMLLinkElement::~HTMLLinkElement()
68
0
{
69
0
}
70
71
NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLLinkElement)
72
73
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLLinkElement,
74
0
                                                  nsGenericHTMLElement)
75
0
  tmp->nsStyleLinkElement::Traverse(cb);
76
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRelList)
77
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
78
79
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLLinkElement,
80
0
                                                nsGenericHTMLElement)
81
0
  tmp->nsStyleLinkElement::Unlink();
82
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mRelList)
83
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
84
85
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLLinkElement,
86
                                             nsGenericHTMLElement,
87
                                             nsIStyleSheetLinkingElement,
88
                                             Link)
89
90
NS_IMPL_ELEMENT_CLONE(HTMLLinkElement)
91
92
bool
93
HTMLLinkElement::Disabled()
94
0
{
95
0
  StyleSheet* ss = GetSheet();
96
0
  return ss && ss->Disabled();
97
0
}
98
99
void
100
HTMLLinkElement::SetDisabled(bool aDisabled)
101
0
{
102
0
  if (StyleSheet* ss = GetSheet()) {
103
0
    ss->SetDisabled(aDisabled);
104
0
  }
105
0
}
106
107
void
108
HTMLLinkElement::OnDNSPrefetchRequested()
109
0
{
110
0
  UnsetFlags(HTML_LINK_DNS_PREFETCH_DEFERRED);
111
0
  SetFlags(HTML_LINK_DNS_PREFETCH_REQUESTED);
112
0
}
113
114
void
115
HTMLLinkElement::OnDNSPrefetchDeferred()
116
0
{
117
0
  UnsetFlags(HTML_LINK_DNS_PREFETCH_REQUESTED);
118
0
  SetFlags(HTML_LINK_DNS_PREFETCH_DEFERRED);
119
0
}
120
121
bool
122
HTMLLinkElement::HasDeferredDNSPrefetchRequest()
123
0
{
124
0
  return HasFlag(HTML_LINK_DNS_PREFETCH_DEFERRED);
125
0
}
126
127
nsresult
128
HTMLLinkElement::BindToTree(nsIDocument* aDocument,
129
                            nsIContent* aParent,
130
                            nsIContent* aBindingParent)
131
0
{
132
0
  Link::ResetLinkState(false, Link::ElementHasHref());
133
0
134
0
  nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
135
0
                                                 aBindingParent);
136
0
  NS_ENSURE_SUCCESS(rv, rv);
137
0
138
0
  if (nsIDocument* doc = GetComposedDoc()) {
139
0
    doc->RegisterPendingLinkUpdate(this);
140
0
    TryDNSPrefetchOrPreconnectOrPrefetchOrPreloadOrPrerender();
141
0
  }
142
0
143
0
  void (HTMLLinkElement::*update)() = &HTMLLinkElement::UpdateStyleSheetInternal;
144
0
  nsContentUtils::AddScriptRunner(
145
0
    NewRunnableMethod("dom::HTMLLinkElement::BindToTree", this, update));
146
0
147
0
  if (aDocument && this->AttrValueIs(kNameSpaceID_None, nsGkAtoms::rel, nsGkAtoms::localization, eIgnoreCase)) {
148
0
    aDocument->LocalizationLinkAdded(this);
149
0
  }
150
0
151
0
  CreateAndDispatchEvent(aDocument, NS_LITERAL_STRING("DOMLinkAdded"));
152
0
153
0
  return rv;
154
0
}
155
156
void
157
HTMLLinkElement::LinkAdded()
158
0
{
159
0
  CreateAndDispatchEvent(OwnerDoc(), NS_LITERAL_STRING("DOMLinkAdded"));
160
0
}
161
162
void
163
HTMLLinkElement::LinkRemoved()
164
0
{
165
0
  CreateAndDispatchEvent(OwnerDoc(), NS_LITERAL_STRING("DOMLinkRemoved"));
166
0
}
167
168
void
169
HTMLLinkElement::UnbindFromTree(bool aDeep, bool aNullParent)
170
0
{
171
0
  // Cancel any DNS prefetches
172
0
  // Note: Must come before ResetLinkState.  If called after, it will recreate
173
0
  // mCachedURI based on data that is invalid - due to a call to GetHostname.
174
0
  CancelDNSPrefetch(HTML_LINK_DNS_PREFETCH_DEFERRED,
175
0
                    HTML_LINK_DNS_PREFETCH_REQUESTED);
176
0
  CancelPrefetchOrPreload();
177
0
178
0
  // If this link is ever reinserted into a document, it might
179
0
  // be under a different xml:base, so forget the cached state now.
180
0
  Link::ResetLinkState(false, Link::ElementHasHref());
181
0
182
0
  // If this is reinserted back into the document it will not be
183
0
  // from the parser.
184
0
  nsIDocument* oldDoc = GetUncomposedDoc();
185
0
  ShadowRoot* oldShadowRoot = GetContainingShadow();
186
0
187
0
  if (oldDoc && this->AttrValueIs(kNameSpaceID_None, nsGkAtoms::rel, nsGkAtoms::localization, eIgnoreCase)) {
188
0
    oldDoc->LocalizationLinkRemoved(this);
189
0
  }
190
0
191
0
  CreateAndDispatchEvent(oldDoc, NS_LITERAL_STRING("DOMLinkRemoved"));
192
0
  nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
193
0
194
0
  Unused << UpdateStyleSheetInternal(oldDoc, oldShadowRoot);
195
0
}
196
197
bool
198
HTMLLinkElement::ParseAttribute(int32_t aNamespaceID,
199
                                nsAtom* aAttribute,
200
                                const nsAString& aValue,
201
                                nsIPrincipal* aMaybeScriptedPrincipal,
202
                                nsAttrValue& aResult)
203
0
{
204
0
  if (aNamespaceID == kNameSpaceID_None) {
205
0
    if (aAttribute == nsGkAtoms::crossorigin) {
206
0
      ParseCORSValue(aValue, aResult);
207
0
      return true;
208
0
    }
209
0
210
0
    if (aAttribute == nsGkAtoms::as) {
211
0
      ParseAsValue(aValue, aResult);
212
0
      return true;
213
0
    }
214
0
215
0
    if (aAttribute == nsGkAtoms::sizes) {
216
0
      aResult.ParseAtomArray(aValue);
217
0
      return true;
218
0
    }
219
0
220
0
    if (aAttribute == nsGkAtoms::integrity) {
221
0
      aResult.ParseStringOrAtom(aValue);
222
0
      return true;
223
0
    }
224
0
  }
225
0
226
0
  return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
227
0
                                              aMaybeScriptedPrincipal, aResult);
228
0
}
229
230
void
231
HTMLLinkElement::CreateAndDispatchEvent(nsIDocument* aDoc,
232
                                        const nsAString& aEventName)
233
0
{
234
0
  if (!aDoc)
235
0
    return;
236
0
237
0
  // In the unlikely case that both rev is specified *and* rel=stylesheet,
238
0
  // this code will cause the event to fire, on the principle that maybe the
239
0
  // page really does want to specify that its author is a stylesheet. Since
240
0
  // this should never actually happen and the performance hit is minimal,
241
0
  // doing the "right" thing costs virtually nothing here, even if it doesn't
242
0
  // make much sense.
243
0
  static Element::AttrValuesArray strings[] =
244
0
    {&nsGkAtoms::_empty, &nsGkAtoms::stylesheet, nullptr};
245
0
246
0
  if (!nsContentUtils::HasNonEmptyAttr(this, kNameSpaceID_None,
247
0
                                       nsGkAtoms::rev) &&
248
0
      FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::rel,
249
0
                      strings, eIgnoreCase) != ATTR_VALUE_NO_MATCH)
250
0
    return;
251
0
252
0
  RefPtr<AsyncEventDispatcher> asyncDispatcher =
253
0
    new AsyncEventDispatcher(this,
254
0
                             aEventName,
255
0
                             CanBubble::eYes,
256
0
                             ChromeOnlyDispatch::eYes);
257
0
  // Always run async in order to avoid running script when the content
258
0
  // sink isn't expecting it.
259
0
  asyncDispatcher->PostDOMEvent();
260
0
}
261
262
nsresult
263
HTMLLinkElement::BeforeSetAttr(int32_t aNameSpaceID, nsAtom* aName,
264
                               const nsAttrValueOrString* aValue, bool aNotify)
265
0
{
266
0
  if (aNameSpaceID == kNameSpaceID_None &&
267
0
      (aName == nsGkAtoms::href || aName == nsGkAtoms::rel)) {
268
0
    CancelDNSPrefetch(HTML_LINK_DNS_PREFETCH_DEFERRED,
269
0
                      HTML_LINK_DNS_PREFETCH_REQUESTED);
270
0
    CancelPrefetchOrPreload();
271
0
  }
272
0
273
0
  return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName,
274
0
                                             aValue, aNotify);
275
0
}
276
277
nsresult
278
HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
279
                              const nsAttrValue* aValue,
280
                              const nsAttrValue* aOldValue,
281
                              nsIPrincipal* aSubjectPrincipal,
282
                              bool aNotify)
283
0
{
284
0
  // It's safe to call ResetLinkState here because our new attr value has
285
0
  // already been set or unset.  ResetLinkState needs the updated attribute
286
0
  // value because notifying the document that content states have changed will
287
0
  // call IntrinsicState, which will try to get updated information about the
288
0
  // visitedness from Link.
289
0
  if (aName == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID) {
290
0
    bool hasHref = aValue;
291
0
    Link::ResetLinkState(!!aNotify, hasHref);
292
0
    if (IsInUncomposedDoc()) {
293
0
      CreateAndDispatchEvent(OwnerDoc(), NS_LITERAL_STRING("DOMLinkChanged"));
294
0
    }
295
0
  }
296
0
297
0
  if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::href) {
298
0
    mTriggeringPrincipal = nsContentUtils::GetAttrTriggeringPrincipal(
299
0
        this, aValue ? aValue->GetStringValue() : EmptyString(),
300
0
        aSubjectPrincipal);
301
0
  }
302
0
303
0
  // If a link's `rel` attribute was changed from or to `localization`,
304
0
  // update the list of localization links.
305
0
  if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::rel) {
306
0
    nsIDocument* doc = GetComposedDoc();
307
0
    if (doc) {
308
0
      if ((aValue && aValue->Equals(nsGkAtoms::localization, eIgnoreCase)) &&
309
0
          (!aOldValue || !aOldValue->Equals(nsGkAtoms::localization, eIgnoreCase))) {
310
0
        doc->LocalizationLinkAdded(this);
311
0
      } else if ((aOldValue && aOldValue->Equals(nsGkAtoms::localization, eIgnoreCase)) &&
312
0
                 (!aValue || !aValue->Equals(nsGkAtoms::localization, eIgnoreCase))) {
313
0
        doc->LocalizationLinkRemoved(this);
314
0
      }
315
0
    }
316
0
  }
317
0
318
0
  // If the link has `rel=localization` and its `href` attribute is changed,
319
0
  // update the list of localization links.
320
0
  if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::href && 
321
0
      AttrValueIs(kNameSpaceID_None, nsGkAtoms::rel, nsGkAtoms::localization, eIgnoreCase)) {
322
0
    nsIDocument* doc = GetComposedDoc();
323
0
    if (doc) {
324
0
      if (aOldValue) {
325
0
        doc->LocalizationLinkRemoved(this);
326
0
      }
327
0
      if (aValue) {
328
0
        doc->LocalizationLinkAdded(this);
329
0
      }
330
0
    }
331
0
  }
332
0
333
0
  if (aValue) {
334
0
    if (aNameSpaceID == kNameSpaceID_None &&
335
0
        (aName == nsGkAtoms::href ||
336
0
         aName == nsGkAtoms::rel ||
337
0
         aName == nsGkAtoms::title ||
338
0
         aName == nsGkAtoms::media ||
339
0
         aName == nsGkAtoms::type ||
340
0
         aName == nsGkAtoms::as ||
341
0
         aName == nsGkAtoms::crossorigin)) {
342
0
      bool dropSheet = false;
343
0
      if (aName == nsGkAtoms::rel) {
344
0
        nsAutoString value;
345
0
        aValue->ToString(value);
346
0
        uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(value);
347
0
        if (GetSheet()) {
348
0
          dropSheet = !(linkTypes & nsStyleLinkElement::eSTYLESHEET);
349
0
        }
350
0
      }
351
0
352
0
      if ((aName == nsGkAtoms::rel || aName == nsGkAtoms::href) &&
353
0
          IsInComposedDoc()) {
354
0
        TryDNSPrefetchOrPreconnectOrPrefetchOrPreloadOrPrerender();
355
0
      }
356
0
357
0
      if ((aName == nsGkAtoms::as || aName == nsGkAtoms::type ||
358
0
           aName == nsGkAtoms::crossorigin || aName == nsGkAtoms::media) &&
359
0
          IsInComposedDoc()) {
360
0
        UpdatePreload(aName, aValue, aOldValue);
361
0
      }
362
0
363
0
      const bool forceUpdate = dropSheet ||
364
0
        aName == nsGkAtoms::title ||
365
0
        aName == nsGkAtoms::media ||
366
0
        aName == nsGkAtoms::type;
367
0
368
0
      Unused << UpdateStyleSheetInternal(
369
0
          nullptr, nullptr, forceUpdate ? ForceUpdate::Yes : ForceUpdate::No);
370
0
    }
371
0
  } else {
372
0
    // Since removing href or rel makes us no longer link to a
373
0
    // stylesheet, force updates for those too.
374
0
    if (aNameSpaceID == kNameSpaceID_None) {
375
0
      if (aName == nsGkAtoms::href ||
376
0
          aName == nsGkAtoms::rel ||
377
0
          aName == nsGkAtoms::title ||
378
0
          aName == nsGkAtoms::media ||
379
0
          aName == nsGkAtoms::type) {
380
0
        Unused << UpdateStyleSheetInternal(nullptr, nullptr, ForceUpdate::Yes);
381
0
      }
382
0
      if ((aName == nsGkAtoms::as || aName == nsGkAtoms::type ||
383
0
           aName == nsGkAtoms::crossorigin || aName == nsGkAtoms::media) &&
384
0
          IsInComposedDoc()) {
385
0
        UpdatePreload(aName, aValue, aOldValue);
386
0
      }
387
0
    }
388
0
  }
389
0
390
0
  return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
391
0
                                            aOldValue, aSubjectPrincipal, aNotify);
392
0
}
393
394
void
395
HTMLLinkElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
396
0
{
397
0
  GetEventTargetParentForAnchors(aVisitor);
398
0
}
399
400
nsresult
401
HTMLLinkElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
402
0
{
403
0
  return PostHandleEventForAnchors(aVisitor);
404
0
}
405
406
bool
407
HTMLLinkElement::IsLink(nsIURI** aURI) const
408
0
{
409
0
  return IsHTMLLink(aURI);
410
0
}
411
412
void
413
HTMLLinkElement::GetLinkTarget(nsAString& aTarget)
414
0
{
415
0
  GetAttr(kNameSpaceID_None, nsGkAtoms::target, aTarget);
416
0
  if (aTarget.IsEmpty()) {
417
0
    GetBaseTarget(aTarget);
418
0
  }
419
0
}
420
421
static const DOMTokenListSupportedToken sSupportedRelValues[] = {
422
  // Keep this in sync with ToLinkMask in nsStyleLinkElement.cpp.
423
  // "preload" must come first because it can be disabled.
424
  "preload",
425
  "prefetch",
426
  "dns-prefetch",
427
  "stylesheet",
428
  "next",
429
  "alternate",
430
  "preconnect",
431
  "icon",
432
  "search",
433
  nullptr
434
};
435
436
nsDOMTokenList*
437
HTMLLinkElement::RelList()
438
0
{
439
0
  if (!mRelList) {
440
0
    if (Preferences::GetBool("network.preload")) {
441
0
      mRelList = new nsDOMTokenList(this, nsGkAtoms::rel, sSupportedRelValues);
442
0
    } else {
443
0
      mRelList = new nsDOMTokenList(this, nsGkAtoms::rel, &sSupportedRelValues[1]);
444
0
    }
445
0
  }
446
0
  return mRelList;
447
0
}
448
449
already_AddRefed<nsIURI>
450
HTMLLinkElement::GetHrefURI() const
451
0
{
452
0
  return GetHrefURIForAnchors();
453
0
}
454
455
Maybe<nsStyleLinkElement::SheetInfo>
456
HTMLLinkElement::GetStyleSheetInfo()
457
0
{
458
0
  nsAutoString rel;
459
0
  GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel);
460
0
  uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(rel);
461
0
  if (!(linkTypes & nsStyleLinkElement::eSTYLESHEET)) {
462
0
    return Nothing();
463
0
  }
464
0
465
0
  if (!IsCSSMimeTypeAttribute(*this)) {
466
0
    return Nothing();
467
0
  }
468
0
469
0
  nsAutoString title;
470
0
  nsAutoString media;
471
0
  GetTitleAndMediaForElement(*this, title, media);
472
0
473
0
  bool alternate = linkTypes & nsStyleLinkElement::eALTERNATE;
474
0
  if (alternate && title.IsEmpty()) {
475
0
    // alternates must have title.
476
0
    return Nothing();
477
0
  }
478
0
479
0
  nsAutoString href;
480
0
  GetAttr(kNameSpaceID_None, nsGkAtoms::href, href);
481
0
  if (href.IsEmpty()) {
482
0
    return Nothing();
483
0
  }
484
0
485
0
  nsCOMPtr<nsIURI> uri = Link::GetURI();
486
0
  nsCOMPtr<nsIPrincipal> prin = mTriggeringPrincipal;
487
0
  return Some(SheetInfo {
488
0
    *OwnerDoc(),
489
0
    this,
490
0
    uri.forget(),
491
0
    prin.forget(),
492
0
    GetReferrerPolicyAsEnum(),
493
0
    GetCORSMode(),
494
0
    title,
495
0
    media,
496
0
    alternate ? HasAlternateRel::Yes : HasAlternateRel::No,
497
0
    IsInline::No,
498
0
  });
499
0
}
500
501
EventStates
502
HTMLLinkElement::IntrinsicState() const
503
0
{
504
0
  return Link::LinkState() | nsGenericHTMLElement::IntrinsicState();
505
0
}
506
507
void
508
HTMLLinkElement::AddSizeOfExcludingThis(nsWindowSizes& aSizes,
509
                                        size_t* aNodeSize) const
510
0
{
511
0
  nsGenericHTMLElement::AddSizeOfExcludingThis(aSizes, aNodeSize);
512
0
  *aNodeSize += Link::SizeOfExcludingThis(aSizes.mState);
513
0
}
514
515
JSObject*
516
HTMLLinkElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
517
0
{
518
0
  return HTMLLinkElement_Binding::Wrap(aCx, this, aGivenProto);
519
0
}
520
521
void
522
HTMLLinkElement::GetAs(nsAString& aResult)
523
0
{
524
0
  GetEnumAttr(nsGkAtoms::as, EmptyCString().get(), aResult);
525
0
}
526
527
// We will use official mime-types from:
528
// https://www.iana.org/assignments/media-types/media-types.xhtml#font
529
// We do not support old deprecated mime-types for preload feature.
530
// (We currectly do not support font/collection)
531
static uint32_t StyleLinkElementFontMimeTypesNum = 5;
532
static const char* StyleLinkElementFontMimeTypes[] = {
533
  "font/otf",
534
  "font/sfnt",
535
  "font/ttf",
536
  "font/woff",
537
  "font/woff2"
538
};
539
540
bool
541
IsFontMimeType(const nsAString& aType)
542
0
{
543
0
  if (aType.IsEmpty()) {
544
0
    return true;
545
0
  }
546
0
  for (uint32_t i = 0; i < StyleLinkElementFontMimeTypesNum; i++) {
547
0
    if (aType.EqualsASCII(StyleLinkElementFontMimeTypes[i])) {
548
0
      return true;
549
0
    }
550
0
  }
551
0
  return false;
552
0
}
553
554
bool
555
HTMLLinkElement::CheckPreloadAttrs(const nsAttrValue& aAs,
556
                                   const nsAString& aType,
557
                                   const nsAString& aMedia,
558
                                   nsIDocument* aDocument)
559
0
{
560
0
  nsContentPolicyType policyType = Link::AsValueToContentPolicy(aAs);
561
0
  if (policyType == nsIContentPolicy::TYPE_INVALID) {
562
0
    return false;
563
0
  }
564
0
565
0
  // Check if media attribute is valid.
566
0
  if (!aMedia.IsEmpty()) {
567
0
    RefPtr<MediaList> mediaList = MediaList::Create(aMedia);
568
0
    nsPresContext* presContext = aDocument->GetPresContext();
569
0
    if (!presContext) {
570
0
      return false;
571
0
    }
572
0
    if (!mediaList->Matches(presContext)) {
573
0
      return false;
574
0
    }
575
0
  }
576
0
577
0
  if (aType.IsEmpty()) {
578
0
    return true;
579
0
  }
580
0
581
0
  nsString type = nsString(aType);
582
0
  ToLowerCase(type);
583
0
584
0
  if (policyType == nsIContentPolicy::TYPE_OTHER) {
585
0
    return true;
586
0
587
0
  } else if (policyType == nsIContentPolicy::TYPE_MEDIA) {
588
0
    if (aAs.GetEnumValue() == DESTINATION_TRACK) {
589
0
      if (type.EqualsASCII("text/vtt")) {
590
0
        return true;
591
0
      } else {
592
0
        return false;
593
0
      }
594
0
    }
595
0
    Maybe<MediaContainerType> mimeType = MakeMediaContainerType(aType);
596
0
    if (!mimeType) {
597
0
      return false;
598
0
    }
599
0
    DecoderDoctorDiagnostics diagnostics;
600
0
    CanPlayStatus status = DecoderTraits::CanHandleContainerType(*mimeType,
601
0
                                                                 &diagnostics);
602
0
    // Preload if this return CANPLAY_YES and CANPLAY_MAYBE.
603
0
    if (status == CANPLAY_NO) {
604
0
      return false;
605
0
    } else {
606
0
      return true;
607
0
    }
608
0
609
0
  } else if (policyType == nsIContentPolicy::TYPE_FONT) {
610
0
    if (IsFontMimeType(type)) {
611
0
      return true;
612
0
    } else {
613
0
      return false;
614
0
    }
615
0
616
0
  } else if (policyType == nsIContentPolicy::TYPE_IMAGE) {
617
0
    if (imgLoader::SupportImageWithMimeType(NS_ConvertUTF16toUTF8(type).get(),
618
0
                                            AcceptedMimeTypes::IMAGES_AND_DOCUMENTS)) {
619
0
      return true;
620
0
    } else {
621
0
      return false;
622
0
    }
623
0
624
0
  } else if (policyType == nsIContentPolicy::TYPE_SCRIPT) {
625
0
    if (nsContentUtils::IsJavascriptMIMEType(type)) {
626
0
      return true;
627
0
    } else {
628
0
      return false;
629
0
    }
630
0
631
0
  } else if (policyType == nsIContentPolicy::TYPE_STYLESHEET) {
632
0
    if (type.EqualsASCII("text/css")) {
633
0
      return true;
634
0
    } else {
635
0
      return false;
636
0
    }
637
0
  }
638
0
  return false;
639
0
}
640
641
} // namespace dom
642
} // namespace mozilla