Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/html/nsGenericHTMLFrameElement.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 file,
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "nsGenericHTMLFrameElement.h"
8
9
#include "mozilla/dom/ContentChild.h"
10
#include "mozilla/dom/HTMLIFrameElement.h"
11
#include "mozilla/dom/XULFrameElement.h"
12
#include "mozilla/Preferences.h"
13
#include "mozilla/ErrorResult.h"
14
#include "GeckoProfiler.h"
15
#include "nsAttrValueInlines.h"
16
#include "nsContentUtils.h"
17
#include "nsIDocShell.h"
18
#include "nsIFrame.h"
19
#include "nsIInterfaceRequestorUtils.h"
20
#include "nsIPermissionManager.h"
21
#include "nsIPresShell.h"
22
#include "nsIScrollable.h"
23
#include "nsPresContext.h"
24
#include "nsServiceManagerUtils.h"
25
#include "nsSubDocumentFrame.h"
26
#include "nsAttrValueOrString.h"
27
28
using namespace mozilla;
29
using namespace mozilla::dom;
30
31
NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericHTMLFrameElement)
32
33
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGenericHTMLFrameElement,
34
0
                                                  nsGenericHTMLElement)
35
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameLoader)
36
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOpenerWindow)
37
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserElementAPI)
38
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
39
40
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGenericHTMLFrameElement,
41
0
                                                nsGenericHTMLElement)
42
0
  if (tmp->mFrameLoader) {
43
0
    tmp->mFrameLoader->Destroy();
44
0
  }
45
0
46
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameLoader)
47
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOpenerWindow)
48
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserElementAPI)
49
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
50
51
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(nsGenericHTMLFrameElement,
52
                                             nsGenericHTMLElement,
53
                                             nsIFrameLoaderOwner,
54
                                             nsIDOMMozBrowserFrame,
55
                                             nsIMozBrowserFrame,
56
                                             nsGenericHTMLFrameElement)
57
58
NS_IMETHODIMP
59
nsGenericHTMLFrameElement::GetMozbrowser(bool* aValue)
60
0
{
61
0
  *aValue = GetBoolAttr(nsGkAtoms::mozbrowser);
62
0
  return NS_OK;
63
0
}
64
NS_IMETHODIMP
65
nsGenericHTMLFrameElement::SetMozbrowser(bool aValue)
66
0
{
67
0
  return SetBoolAttr(nsGkAtoms::mozbrowser, aValue);
68
0
}
69
70
int32_t
71
nsGenericHTMLFrameElement::TabIndexDefault()
72
0
{
73
0
  return 0;
74
0
}
75
76
nsGenericHTMLFrameElement::~nsGenericHTMLFrameElement()
77
0
{
78
0
  if (mFrameLoader) {
79
0
    mFrameLoader->Destroy();
80
0
  }
81
0
}
82
83
nsIDocument*
84
nsGenericHTMLFrameElement::GetContentDocument(nsIPrincipal& aSubjectPrincipal)
85
0
{
86
0
  nsCOMPtr<nsPIDOMWindowOuter> win = GetContentWindow();
87
0
  if (!win) {
88
0
    return nullptr;
89
0
  }
90
0
91
0
  nsIDocument *doc = win->GetDoc();
92
0
  if (!doc) {
93
0
    return nullptr;
94
0
  }
95
0
96
0
  // Return null for cross-origin contentDocument.
97
0
  if (!aSubjectPrincipal.SubsumesConsideringDomain(doc->NodePrincipal())) {
98
0
    return nullptr;
99
0
  }
100
0
  return doc;
101
0
}
102
103
already_AddRefed<nsPIDOMWindowOuter>
104
nsGenericHTMLFrameElement::GetContentWindow()
105
0
{
106
0
  EnsureFrameLoader();
107
0
108
0
  if (!mFrameLoader) {
109
0
    return nullptr;
110
0
  }
111
0
112
0
  if (mFrameLoader->DepthTooGreat()) {
113
0
    // Claim to have no contentWindow
114
0
    return nullptr;
115
0
  }
116
0
117
0
  nsCOMPtr<nsIDocShell> doc_shell = mFrameLoader->GetDocShell(IgnoreErrors());
118
0
  if (!doc_shell) {
119
0
    return nullptr;
120
0
  }
121
0
122
0
  nsCOMPtr<nsPIDOMWindowOuter> win = doc_shell->GetWindow();
123
0
124
0
  if (!win) {
125
0
    return nullptr;
126
0
  }
127
0
128
0
  return win.forget();
129
0
}
130
131
void
132
nsGenericHTMLFrameElement::EnsureFrameLoader()
133
0
{
134
0
  if (!IsInComposedDoc() || mFrameLoader || mFrameLoaderCreationDisallowed) {
135
0
    // If frame loader is there, we just keep it around, cached
136
0
    return;
137
0
  }
138
0
139
0
  // Strangely enough, this method doesn't actually ensure that the
140
0
  // frameloader exists.  It's more of a best-effort kind of thing.
141
0
  mFrameLoader = nsFrameLoader::Create(this,
142
0
                                       nsPIDOMWindowOuter::From(mOpenerWindow),
143
0
                                       mNetworkCreated);
144
0
}
145
146
nsresult
147
nsGenericHTMLFrameElement::CreateRemoteFrameLoader(nsITabParent* aTabParent)
148
0
{
149
0
  MOZ_ASSERT(!mFrameLoader);
150
0
  EnsureFrameLoader();
151
0
  NS_ENSURE_STATE(mFrameLoader);
152
0
  mFrameLoader->SetRemoteBrowser(aTabParent);
153
0
154
0
  if (nsSubDocumentFrame* subdocFrame = do_QueryFrame(GetPrimaryFrame())) {
155
0
    // The reflow for this element already happened while we were waiting
156
0
    // for the iframe creation. Therefore the subdoc frame didn't have a
157
0
    // frameloader when UpdatePositionAndSize was supposed to be called in
158
0
    // ReflowFinished, and we need to do it properly now.
159
0
    mFrameLoader->UpdatePositionAndSize(subdocFrame);
160
0
  }
161
0
  return NS_OK;
162
0
}
163
164
NS_IMETHODIMP_(already_AddRefed<nsFrameLoader>)
165
nsGenericHTMLFrameElement::GetFrameLoader()
166
0
{
167
0
  RefPtr<nsFrameLoader> loader = mFrameLoader;
168
0
  return loader.forget();
169
0
}
170
171
void
172
nsGenericHTMLFrameElement::PresetOpenerWindow(mozIDOMWindowProxy* aWindow, ErrorResult& aRv)
173
0
{
174
0
  MOZ_ASSERT(!mFrameLoader);
175
0
  mOpenerWindow = nsPIDOMWindowOuter::From(aWindow);
176
0
}
177
178
void
179
nsGenericHTMLFrameElement::InternalSetFrameLoader(nsFrameLoader* aNewFrameLoader)
180
0
{
181
0
  mFrameLoader = aNewFrameLoader;
182
0
}
183
184
void
185
nsGenericHTMLFrameElement::SwapFrameLoaders(HTMLIFrameElement& aOtherLoaderOwner,
186
                                            ErrorResult& rv)
187
0
{
188
0
  if (&aOtherLoaderOwner == this) {
189
0
    // nothing to do
190
0
    return;
191
0
  }
192
0
193
0
  aOtherLoaderOwner.SwapFrameLoaders(this, rv);
194
0
}
195
196
void
197
nsGenericHTMLFrameElement::SwapFrameLoaders(XULFrameElement& aOtherLoaderOwner,
198
                                            ErrorResult& rv)
199
0
{
200
0
  aOtherLoaderOwner.SwapFrameLoaders(this, rv);
201
0
}
202
203
void
204
nsGenericHTMLFrameElement::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherLoaderOwner,
205
                                            mozilla::ErrorResult& rv)
206
0
{
207
0
  RefPtr<nsFrameLoader> loader = GetFrameLoader();
208
0
  RefPtr<nsFrameLoader> otherLoader = aOtherLoaderOwner->GetFrameLoader();
209
0
  if (!loader || !otherLoader) {
210
0
    rv.Throw(NS_ERROR_NOT_IMPLEMENTED);
211
0
    return;
212
0
  }
213
0
214
0
  rv = loader->SwapWithOtherLoader(otherLoader, this, aOtherLoaderOwner);
215
0
}
216
217
void
218
nsGenericHTMLFrameElement::LoadSrc()
219
0
{
220
0
  EnsureFrameLoader();
221
0
222
0
  if (!mFrameLoader) {
223
0
    return;
224
0
  }
225
0
226
0
  bool origSrc = !mSrcLoadHappened;
227
0
  mSrcLoadHappened = true;
228
0
  mFrameLoader->LoadFrame(origSrc);
229
0
}
230
231
nsresult
232
nsGenericHTMLFrameElement::BindToTree(nsIDocument* aDocument,
233
                                      nsIContent* aParent,
234
                                      nsIContent* aBindingParent)
235
0
{
236
0
  nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
237
0
                                                 aBindingParent);
238
0
  NS_ENSURE_SUCCESS(rv, rv);
239
0
240
0
  if (IsInComposedDoc()) {
241
0
    NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
242
0
                 "Missing a script blocker!");
243
0
244
0
    AUTO_PROFILER_LABEL("nsGenericHTMLFrameElement::BindToTree", OTHER);
245
0
246
0
    // We're in a document now.  Kick off the frame load.
247
0
    LoadSrc();
248
0
  }
249
0
250
0
  // We're now in document and scripts may move us, so clear
251
0
  // the mNetworkCreated flag.
252
0
  mNetworkCreated = false;
253
0
  return rv;
254
0
}
255
256
void
257
nsGenericHTMLFrameElement::UnbindFromTree(bool aDeep, bool aNullParent)
258
0
{
259
0
  if (mFrameLoader) {
260
0
    // This iframe is being taken out of the document, destroy the
261
0
    // iframe's frame loader (doing that will tear down the window in
262
0
    // this iframe).
263
0
    // XXXbz we really want to only partially destroy the frame
264
0
    // loader... we don't want to tear down the docshell.  Food for
265
0
    // later bug.
266
0
    mFrameLoader->Destroy();
267
0
    mFrameLoader = nullptr;
268
0
  }
269
0
270
0
  nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
271
0
}
272
273
/* static */ int32_t
274
nsGenericHTMLFrameElement::MapScrollingAttribute(const nsAttrValue* aValue)
275
0
{
276
0
  int32_t mappedValue = nsIScrollable::Scrollbar_Auto;
277
0
  if (aValue && aValue->Type() == nsAttrValue::eEnum) {
278
0
    switch (aValue->GetEnumValue()) {
279
0
      case NS_STYLE_FRAME_OFF:
280
0
      case NS_STYLE_FRAME_NOSCROLL:
281
0
      case NS_STYLE_FRAME_NO:
282
0
        mappedValue = nsIScrollable::Scrollbar_Never;
283
0
        break;
284
0
    }
285
0
  }
286
0
  return mappedValue;
287
0
}
288
289
static bool
290
PrincipalAllowsBrowserFrame(nsIPrincipal* aPrincipal)
291
0
{
292
0
  nsCOMPtr<nsIPermissionManager> permMgr = mozilla::services::GetPermissionManager();
293
0
  NS_ENSURE_TRUE(permMgr, false);
294
0
  uint32_t permission = nsIPermissionManager::DENY_ACTION;
295
0
  nsresult rv = permMgr->TestPermissionFromPrincipal(aPrincipal, "browser", &permission);
296
0
  NS_ENSURE_SUCCESS(rv, false);
297
0
  return permission == nsIPermissionManager::ALLOW_ACTION;
298
0
}
299
300
/* virtual */ nsresult
301
nsGenericHTMLFrameElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
302
                                        const nsAttrValue* aValue,
303
                                        const nsAttrValue* aOldValue,
304
                                        nsIPrincipal* aMaybeScriptedPrincipal,
305
                                        bool aNotify)
306
0
{
307
0
  if (aValue) {
308
0
    nsAttrValueOrString value(aValue);
309
0
    AfterMaybeChangeAttr(aNameSpaceID, aName, &value, aMaybeScriptedPrincipal, aNotify);
310
0
  } else {
311
0
    AfterMaybeChangeAttr(aNameSpaceID, aName, nullptr, aMaybeScriptedPrincipal, aNotify);
312
0
  }
313
0
314
0
  if (aNameSpaceID == kNameSpaceID_None) {
315
0
    if (aName == nsGkAtoms::scrolling) {
316
0
      if (mFrameLoader) {
317
0
        nsIDocShell* docshell = mFrameLoader->GetExistingDocShell();
318
0
        nsCOMPtr<nsIScrollable> scrollable = do_QueryInterface(docshell);
319
0
        if (scrollable) {
320
0
          int32_t cur;
321
0
          scrollable->GetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X, &cur);
322
0
          int32_t val = MapScrollingAttribute(aValue);
323
0
          if (cur != val) {
324
0
            scrollable->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X, val);
325
0
            scrollable->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_Y, val);
326
0
            RefPtr<nsPresContext> presContext;
327
0
            docshell->GetPresContext(getter_AddRefs(presContext));
328
0
            nsIPresShell* shell = presContext ? presContext->GetPresShell() : nullptr;
329
0
            nsIFrame* rootScroll = shell ? shell->GetRootScrollFrame() : nullptr;
330
0
            if (rootScroll) {
331
0
              shell->FrameNeedsReflow(rootScroll, nsIPresShell::eStyleChange,
332
0
                                      NS_FRAME_IS_DIRTY);
333
0
            }
334
0
          }
335
0
        }
336
0
      }
337
0
    } else if (aName == nsGkAtoms::mozbrowser) {
338
0
      mReallyIsBrowser = !!aValue && BrowserFramesEnabled() &&
339
0
                         PrincipalAllowsBrowserFrame(NodePrincipal());
340
0
    }
341
0
  }
342
0
343
0
  return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
344
0
                                            aOldValue, aMaybeScriptedPrincipal, aNotify);
345
0
}
346
347
nsresult
348
nsGenericHTMLFrameElement::OnAttrSetButNotChanged(int32_t aNamespaceID,
349
                                                  nsAtom* aName,
350
                                                  const nsAttrValueOrString& aValue,
351
                                                  bool aNotify)
352
0
{
353
0
  AfterMaybeChangeAttr(aNamespaceID, aName, &aValue, nullptr, aNotify);
354
0
355
0
  return nsGenericHTMLElement::OnAttrSetButNotChanged(aNamespaceID, aName,
356
0
                                                      aValue, aNotify);
357
0
}
358
359
void
360
nsGenericHTMLFrameElement::AfterMaybeChangeAttr(int32_t aNamespaceID,
361
                                                nsAtom* aName,
362
                                                const nsAttrValueOrString* aValue,
363
                                                nsIPrincipal* aMaybeScriptedPrincipal,
364
                                                bool aNotify)
365
0
{
366
0
  if (aNamespaceID == kNameSpaceID_None) {
367
0
    if (aName == nsGkAtoms::src) {
368
0
      mSrcTriggeringPrincipal = nsContentUtils::GetAttrTriggeringPrincipal(
369
0
          this, aValue ? aValue->String() : EmptyString(), aMaybeScriptedPrincipal);
370
0
      if (aValue && (!IsHTMLElement(nsGkAtoms::iframe) ||
371
0
          !HasAttr(kNameSpaceID_None, nsGkAtoms::srcdoc))) {
372
0
        // Don't propagate error here. The attribute was successfully set,
373
0
        // that's what we should reflect.
374
0
        LoadSrc();
375
0
      }
376
0
    } else if (aName == nsGkAtoms::name) {
377
0
      // Propagate "name" to the docshell to make browsing context names live,
378
0
      // per HTML5.
379
0
      nsIDocShell* docShell = mFrameLoader ? mFrameLoader->GetExistingDocShell()
380
0
                                           : nullptr;
381
0
      if (docShell) {
382
0
        if (aValue) {
383
0
          docShell->SetName(aValue->String());
384
0
        } else {
385
0
          docShell->SetName(EmptyString());
386
0
        }
387
0
      }
388
0
    }
389
0
  }
390
0
}
391
392
void
393
nsGenericHTMLFrameElement::DestroyContent()
394
0
{
395
0
  if (mFrameLoader) {
396
0
    mFrameLoader->Destroy();
397
0
    mFrameLoader = nullptr;
398
0
  }
399
0
400
0
  nsGenericHTMLElement::DestroyContent();
401
0
}
402
403
nsresult
404
nsGenericHTMLFrameElement::CopyInnerTo(Element* aDest)
405
0
{
406
0
  nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest);
407
0
  NS_ENSURE_SUCCESS(rv, rv);
408
0
409
0
  nsIDocument* doc = aDest->OwnerDoc();
410
0
  if (doc->IsStaticDocument() && mFrameLoader) {
411
0
    nsGenericHTMLFrameElement* dest =
412
0
      static_cast<nsGenericHTMLFrameElement*>(aDest);
413
0
    nsFrameLoader* fl = nsFrameLoader::Create(dest, nullptr, false);
414
0
    NS_ENSURE_STATE(fl);
415
0
    dest->mFrameLoader = fl;
416
0
    mFrameLoader->CreateStaticClone(fl);
417
0
  }
418
0
419
0
  return rv;
420
0
}
421
422
bool
423
nsGenericHTMLFrameElement::IsHTMLFocusable(bool aWithMouse,
424
                                           bool *aIsFocusable,
425
                                           int32_t *aTabIndex)
426
0
{
427
0
  if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable, aTabIndex)) {
428
0
    return true;
429
0
  }
430
0
431
0
  *aIsFocusable = nsContentUtils::IsSubDocumentTabbable(this);
432
0
433
0
  if (!*aIsFocusable && aTabIndex) {
434
0
    *aTabIndex = -1;
435
0
  }
436
0
437
0
  return false;
438
0
}
439
440
static bool sMozBrowserFramesEnabled = false;
441
#ifdef DEBUG
442
static bool sBoolVarCacheInitialized = false;
443
#endif
444
445
void
446
nsGenericHTMLFrameElement::InitStatics()
447
3
{
448
3
  MOZ_ASSERT(!sBoolVarCacheInitialized);
449
3
  MOZ_ASSERT(NS_IsMainThread());
450
3
  Preferences::AddBoolVarCache(&sMozBrowserFramesEnabled,
451
3
                               "dom.mozBrowserFramesEnabled");
452
#ifdef DEBUG
453
  sBoolVarCacheInitialized = true;
454
#endif
455
}
456
457
458
bool
459
nsGenericHTMLFrameElement::BrowserFramesEnabled()
460
0
{
461
0
  MOZ_ASSERT(sBoolVarCacheInitialized);
462
0
  return sMozBrowserFramesEnabled;
463
0
}
464
465
/**
466
 * Return true if this frame element really is a mozbrowser.  (It
467
 * needs to have the right attributes, and its creator must have the right
468
 * permissions.)
469
 */
470
/* [infallible] */ nsresult
471
nsGenericHTMLFrameElement::GetReallyIsBrowser(bool *aOut)
472
0
{
473
0
  *aOut = mReallyIsBrowser;
474
0
  return NS_OK;
475
0
}
476
477
/* [infallible] */ NS_IMETHODIMP
478
nsGenericHTMLFrameElement::GetIsolated(bool *aOut)
479
0
{
480
0
  *aOut = true;
481
0
482
0
  if (!nsContentUtils::IsSystemPrincipal(NodePrincipal())) {
483
0
    return NS_OK;
484
0
  }
485
0
486
0
  // Isolation is only disabled if the attribute is present
487
0
  *aOut = !HasAttr(kNameSpaceID_None, nsGkAtoms::noisolation);
488
0
  return NS_OK;
489
0
}
490
491
NS_IMETHODIMP
492
nsGenericHTMLFrameElement::DisallowCreateFrameLoader()
493
0
{
494
0
  MOZ_ASSERT(!mFrameLoader);
495
0
  MOZ_ASSERT(!mFrameLoaderCreationDisallowed);
496
0
  mFrameLoaderCreationDisallowed = true;
497
0
  return NS_OK;
498
0
}
499
500
NS_IMETHODIMP
501
nsGenericHTMLFrameElement::AllowCreateFrameLoader()
502
0
{
503
0
  MOZ_ASSERT(!mFrameLoader);
504
0
  MOZ_ASSERT(mFrameLoaderCreationDisallowed);
505
0
  mFrameLoaderCreationDisallowed = false;
506
0
  return NS_OK;
507
0
}
508
509
NS_IMETHODIMP
510
nsGenericHTMLFrameElement::InitializeBrowserAPI()
511
0
{
512
0
  MOZ_ASSERT(mFrameLoader);
513
0
  InitBrowserElementAPI();
514
0
  return NS_OK;
515
0
}
516
517
NS_IMETHODIMP
518
nsGenericHTMLFrameElement::DestroyBrowserFrameScripts()
519
0
{
520
0
  MOZ_ASSERT(mFrameLoader);
521
0
  DestroyBrowserElementFrameScripts();
522
0
  return NS_OK;
523
0
}