1use std::cell::Cell;
6use std::rc::Rc;
7
8use base::id::{BrowsingContextId, PipelineId, WebViewId};
9use constellation_traits::{
10 IFrameLoadInfo, IFrameLoadInfoWithData, JsEvalResult, LoadData, LoadOrigin,
11 NavigationHistoryBehavior, ScriptToConstellationMessage,
12};
13use content_security_policy::sandboxing_directive::{
14 SandboxingFlagSet, parse_a_sandboxing_directive,
15};
16use dom_struct::dom_struct;
17use embedder_traits::ViewportDetails;
18use html5ever::{LocalName, Prefix, local_name, ns};
19use js::rust::HandleObject;
20use net_traits::ReferrerPolicy;
21use net_traits::request::Destination;
22use profile_traits::ipc as ProfiledIpc;
23use script_traits::{NewLayoutInfo, UpdatePipelineIdReason};
24use servo_url::ServoUrl;
25use style::attr::{AttrValue, LengthOrPercentageOrAuto};
26use stylo_atoms::Atom;
27
28use crate::document_loader::{LoadBlocker, LoadType};
29use crate::dom::attr::Attr;
30use crate::dom::bindings::cell::DomRefCell;
31use crate::dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElementMethods;
32use crate::dom::bindings::codegen::Bindings::WindowBinding::Window_Binding::WindowMethods;
33use crate::dom::bindings::codegen::UnionTypes::TrustedHTMLOrString;
34use crate::dom::bindings::error::Fallible;
35use crate::dom::bindings::inheritance::Castable;
36use crate::dom::bindings::reflector::DomGlobal;
37use crate::dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom};
38use crate::dom::bindings::str::{DOMString, USVString};
39use crate::dom::document::Document;
40use crate::dom::domtokenlist::DOMTokenList;
41use crate::dom::element::{
42 AttributeMutation, Element, LayoutElementHelpers, reflect_referrer_policy_attribute,
43};
44use crate::dom::eventtarget::EventTarget;
45use crate::dom::globalscope::GlobalScope;
46use crate::dom::html::htmlelement::HTMLElement;
47use crate::dom::node::{BindContext, Node, NodeDamage, NodeTraits, UnbindContext};
48use crate::dom::trustedhtml::TrustedHTML;
49use crate::dom::virtualmethods::VirtualMethods;
50use crate::dom::windowproxy::WindowProxy;
51use crate::script_runtime::CanGc;
52use crate::script_thread::ScriptThread;
53use crate::script_window_proxies::ScriptWindowProxies;
54
55#[derive(PartialEq)]
56enum PipelineType {
57 InitialAboutBlank,
58 Navigation,
59}
60
61#[derive(PartialEq)]
62enum ProcessingMode {
63 FirstTime,
64 NotFirstTime,
65}
66
67#[dom_struct]
68pub(crate) struct HTMLIFrameElement {
69 htmlelement: HTMLElement,
70 #[no_trace]
71 webview_id: Cell<Option<WebViewId>>,
72 #[no_trace]
73 browsing_context_id: Cell<Option<BrowsingContextId>>,
74 #[no_trace]
75 pipeline_id: Cell<Option<PipelineId>>,
76 #[no_trace]
77 pending_pipeline_id: Cell<Option<PipelineId>>,
78 #[no_trace]
79 about_blank_pipeline_id: Cell<Option<PipelineId>>,
80 sandbox: MutNullableDom<DOMTokenList>,
81 #[no_trace]
82 sandboxing_flag_set: Cell<Option<SandboxingFlagSet>>,
83 load_blocker: DomRefCell<Option<LoadBlocker>>,
84 throttled: Cell<bool>,
85 #[conditional_malloc_size_of]
86 script_window_proxies: Rc<ScriptWindowProxies>,
87}
88
89impl HTMLIFrameElement {
90 fn get_url(&self) -> ServoUrl {
93 let element = self.upcast::<Element>();
94 element
95 .get_attribute(&ns!(), &local_name!("src"))
96 .and_then(|src| {
97 let url = src.value();
98 if url.is_empty() {
99 None
100 } else {
101 self.owner_document().base_url().join(&url).ok()
102 }
103 })
104 .unwrap_or_else(|| ServoUrl::parse("about:blank").unwrap())
105 }
106
107 pub(crate) fn navigate_or_reload_child_browsing_context(
108 &self,
109 load_data: LoadData,
110 history_handling: NavigationHistoryBehavior,
111 can_gc: CanGc,
112 ) {
113 self.start_new_pipeline(
114 load_data,
115 PipelineType::Navigation,
116 history_handling,
117 can_gc,
118 );
119 }
120
121 fn start_new_pipeline(
122 &self,
123 mut load_data: LoadData,
124 pipeline_type: PipelineType,
125 history_handling: NavigationHistoryBehavior,
126 can_gc: CanGc,
127 ) {
128 let browsing_context_id = match self.browsing_context_id() {
129 None => return warn!("Attempted to start a new pipeline on an unattached iframe."),
130 Some(id) => id,
131 };
132
133 let webview_id = match self.webview_id() {
134 None => return warn!("Attempted to start a new pipeline on an unattached iframe."),
135 Some(id) => id,
136 };
137
138 let document = self.owner_document();
139
140 {
141 let load_blocker = &self.load_blocker;
142 LoadBlocker::terminate(load_blocker, can_gc);
145 }
146
147 if load_data.url.scheme() == "javascript" {
148 let window_proxy = self.GetContentWindow();
149 if let Some(window_proxy) = window_proxy {
150 if !ScriptThread::navigate_to_javascript_url(
151 &document.global(),
152 &window_proxy.global(),
153 &mut load_data,
154 Some(self.upcast()),
155 can_gc,
156 ) {
157 return;
158 }
159 }
160 }
161
162 match load_data.js_eval_result {
163 Some(JsEvalResult::NoContent) => (),
164 _ => {
165 let mut load_blocker = self.load_blocker.borrow_mut();
166 *load_blocker = Some(LoadBlocker::new(
167 &document,
168 LoadType::Subframe(load_data.url.clone()),
169 ));
170 },
171 };
172
173 let window = self.owner_window();
174 let old_pipeline_id = self.pipeline_id();
175 let new_pipeline_id = PipelineId::new();
176 self.pending_pipeline_id.set(Some(new_pipeline_id));
177
178 let load_info = IFrameLoadInfo {
179 parent_pipeline_id: window.pipeline_id(),
180 browsing_context_id,
181 webview_id,
182 new_pipeline_id,
183 is_private: false, inherited_secure_context: load_data.inherited_secure_context,
185 history_handling,
186 };
187
188 let viewport_details = window
189 .get_iframe_viewport_details_if_known(browsing_context_id)
190 .unwrap_or_else(|| ViewportDetails {
191 hidpi_scale_factor: window.device_pixel_ratio(),
192 ..Default::default()
193 });
194
195 match pipeline_type {
196 PipelineType::InitialAboutBlank => {
197 self.about_blank_pipeline_id.set(Some(new_pipeline_id));
198
199 let load_info = IFrameLoadInfoWithData {
200 info: load_info,
201 load_data: load_data.clone(),
202 old_pipeline_id,
203 viewport_details,
204 theme: window.theme(),
205 };
206 window
207 .as_global_scope()
208 .script_to_constellation_chan()
209 .send(ScriptToConstellationMessage::ScriptNewIFrame(load_info))
210 .unwrap();
211
212 let new_layout_info = NewLayoutInfo {
213 parent_info: Some(window.pipeline_id()),
214 new_pipeline_id,
215 browsing_context_id,
216 webview_id,
217 opener: None,
218 load_data,
219 viewport_details,
220 theme: window.theme(),
221 };
222
223 self.pipeline_id.set(Some(new_pipeline_id));
224 ScriptThread::process_attach_layout(new_layout_info, document.origin().clone());
225 },
226 PipelineType::Navigation => {
227 let load_info = IFrameLoadInfoWithData {
228 info: load_info,
229 load_data,
230 old_pipeline_id,
231 viewport_details,
232 theme: window.theme(),
233 };
234 window
235 .as_global_scope()
236 .script_to_constellation_chan()
237 .send(ScriptToConstellationMessage::ScriptLoadedURLInIFrame(
238 load_info,
239 ))
240 .unwrap();
241 },
242 }
243 }
244
245 fn process_the_iframe_attributes(&self, mode: ProcessingMode, can_gc: CanGc) {
247 if self
249 .upcast::<Element>()
250 .has_attribute(&local_name!("srcdoc"))
251 {
252 let url = ServoUrl::parse("about:srcdoc").unwrap();
253 let document = self.owner_document();
254 let window = self.owner_window();
255 let pipeline_id = Some(window.pipeline_id());
256 let mut load_data = LoadData::new(
257 LoadOrigin::Script(document.origin().immutable().clone()),
258 url,
259 pipeline_id,
260 window.as_global_scope().get_referrer(),
261 document.get_referrer_policy(),
262 Some(window.as_global_scope().is_secure_context()),
263 Some(document.insecure_requests_policy()),
264 document.has_trustworthy_ancestor_or_current_origin(),
265 self.sandboxing_flag_set(),
266 );
267 load_data.destination = Destination::IFrame;
268 load_data.policy_container = Some(window.as_global_scope().policy_container());
269 let element = self.upcast::<Element>();
270 load_data.srcdoc = String::from(element.get_string_attribute(&local_name!("srcdoc")));
271 self.navigate_or_reload_child_browsing_context(
272 load_data,
273 NavigationHistoryBehavior::Push,
274 can_gc,
275 );
276 return;
277 }
278
279 let window = self.owner_window();
280
281 if mode == ProcessingMode::FirstTime {
286 if let Some(window) = self.GetContentWindow() {
287 window.set_name(
288 self.upcast::<Element>()
289 .get_name()
290 .map_or(DOMString::from(""), |n| DOMString::from(&*n)),
291 );
292 }
293 }
294
295 if mode == ProcessingMode::FirstTime &&
296 !self.upcast::<Element>().has_attribute(&local_name!("src"))
297 {
298 return;
299 }
300
301 let url = self.get_url();
306
307 let document = self.owner_document();
310 let referrer_policy_token = self.ReferrerPolicy();
311
312 let referrer_policy = match ReferrerPolicy::from(&*referrer_policy_token.str()) {
316 ReferrerPolicy::EmptyString => document.get_referrer_policy(),
317 policy => policy,
318 };
319
320 let mut ancestor = window.GetParent();
329 while let Some(a) = ancestor {
330 if let Some(ancestor_url) = a.document().map(|d| d.url()) {
331 if ancestor_url.scheme() == url.scheme() &&
332 ancestor_url.username() == url.username() &&
333 ancestor_url.password() == url.password() &&
334 ancestor_url.host() == url.host() &&
335 ancestor_url.port() == url.port() &&
336 ancestor_url.path() == url.path() &&
337 ancestor_url.query() == url.query()
338 {
339 return;
340 }
341 }
342 ancestor = a.parent().map(DomRoot::from_ref);
343 }
344
345 let creator_pipeline_id = if url.as_str() == "about:blank" {
346 Some(window.pipeline_id())
347 } else {
348 None
349 };
350
351 let mut load_data = LoadData::new(
352 LoadOrigin::Script(document.origin().immutable().clone()),
353 url,
354 creator_pipeline_id,
355 window.as_global_scope().get_referrer(),
356 referrer_policy,
357 Some(window.as_global_scope().is_secure_context()),
358 Some(document.insecure_requests_policy()),
359 document.has_trustworthy_ancestor_or_current_origin(),
360 self.sandboxing_flag_set(),
361 );
362 load_data.destination = Destination::IFrame;
363 load_data.policy_container = Some(window.as_global_scope().policy_container());
364
365 let pipeline_id = self.pipeline_id();
366 let is_about_blank =
369 pipeline_id.is_some() && pipeline_id == self.about_blank_pipeline_id.get();
370
371 let history_handling = if is_about_blank {
372 NavigationHistoryBehavior::Replace
373 } else {
374 NavigationHistoryBehavior::Push
375 };
376
377 self.navigate_or_reload_child_browsing_context(load_data, history_handling, can_gc);
378 }
379
380 fn create_nested_browsing_context(&self, can_gc: CanGc) {
381 let url = ServoUrl::parse("about:blank").unwrap();
397 let document = self.owner_document();
398 let window = self.owner_window();
399 let pipeline_id = Some(window.pipeline_id());
400 let mut load_data = LoadData::new(
401 LoadOrigin::Script(document.origin().immutable().clone()),
402 url,
403 pipeline_id,
404 window.as_global_scope().get_referrer(),
405 document.get_referrer_policy(),
406 Some(window.as_global_scope().is_secure_context()),
407 Some(document.insecure_requests_policy()),
408 document.has_trustworthy_ancestor_or_current_origin(),
409 self.sandboxing_flag_set(),
410 );
411 load_data.destination = Destination::IFrame;
412 load_data.policy_container = Some(window.as_global_scope().policy_container());
413 let browsing_context_id = BrowsingContextId::new();
414 let webview_id = window.window_proxy().webview_id();
415 self.pipeline_id.set(None);
416 self.pending_pipeline_id.set(None);
417 self.webview_id.set(Some(webview_id));
418 self.browsing_context_id.set(Some(browsing_context_id));
419 self.start_new_pipeline(
420 load_data,
421 PipelineType::InitialAboutBlank,
422 NavigationHistoryBehavior::Push,
423 can_gc,
424 );
425 }
426
427 fn destroy_nested_browsing_context(&self) {
428 self.pipeline_id.set(None);
429 self.pending_pipeline_id.set(None);
430 self.about_blank_pipeline_id.set(None);
431 self.webview_id.set(None);
432 self.browsing_context_id.set(None);
433 }
434
435 pub(crate) fn update_pipeline_id(
436 &self,
437 new_pipeline_id: PipelineId,
438 reason: UpdatePipelineIdReason,
439 can_gc: CanGc,
440 ) {
441 if self.pending_pipeline_id.get() != Some(new_pipeline_id) &&
442 reason == UpdatePipelineIdReason::Navigation
443 {
444 return;
445 }
446
447 self.pipeline_id.set(Some(new_pipeline_id));
448
449 if reason == UpdatePipelineIdReason::Traversal {
452 let blocker = &self.load_blocker;
453 LoadBlocker::terminate(blocker, can_gc);
454 }
455
456 self.upcast::<Node>().dirty(NodeDamage::Other);
457 }
458
459 fn new_inherited(
460 local_name: LocalName,
461 prefix: Option<Prefix>,
462 document: &Document,
463 ) -> HTMLIFrameElement {
464 HTMLIFrameElement {
465 htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
466 browsing_context_id: Cell::new(None),
467 webview_id: Cell::new(None),
468 pipeline_id: Cell::new(None),
469 pending_pipeline_id: Cell::new(None),
470 about_blank_pipeline_id: Cell::new(None),
471 sandbox: Default::default(),
472 sandboxing_flag_set: Cell::new(None),
473 load_blocker: DomRefCell::new(None),
474 throttled: Cell::new(false),
475 script_window_proxies: ScriptThread::window_proxies(),
476 }
477 }
478
479 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
480 pub(crate) fn new(
481 local_name: LocalName,
482 prefix: Option<Prefix>,
483 document: &Document,
484 proto: Option<HandleObject>,
485 can_gc: CanGc,
486 ) -> DomRoot<HTMLIFrameElement> {
487 Node::reflect_node_with_proto(
488 Box::new(HTMLIFrameElement::new_inherited(
489 local_name, prefix, document,
490 )),
491 document,
492 proto,
493 can_gc,
494 )
495 }
496
497 #[inline]
498 pub(crate) fn pipeline_id(&self) -> Option<PipelineId> {
499 self.pipeline_id.get()
500 }
501
502 #[inline]
503 pub(crate) fn browsing_context_id(&self) -> Option<BrowsingContextId> {
504 self.browsing_context_id.get()
505 }
506
507 #[inline]
508 pub(crate) fn webview_id(&self) -> Option<WebViewId> {
509 self.webview_id.get()
510 }
511
512 #[inline]
513 pub(crate) fn sandboxing_flag_set(&self) -> SandboxingFlagSet {
514 self.sandboxing_flag_set
515 .get()
516 .unwrap_or_else(SandboxingFlagSet::empty)
517 }
518
519 pub(crate) fn set_throttled(&self, throttled: bool) {
520 if self.throttled.get() != throttled {
521 self.throttled.set(throttled);
522 }
523 }
524
525 pub(crate) fn iframe_load_event_steps(&self, loaded_pipeline: PipelineId, can_gc: CanGc) {
527 if Some(loaded_pipeline) != self.pending_pipeline_id.get() {
530 return;
531 }
532
533 self.upcast::<EventTarget>()
541 .fire_event(atom!("load"), can_gc);
542
543 let blocker = &self.load_blocker;
544 LoadBlocker::terminate(blocker, can_gc);
545
546 }
548
549 fn parse_sandbox_attribute(&self) {
553 let attribute = self
554 .upcast::<Element>()
555 .get_attribute(&ns!(), &local_name!("sandbox"));
556 self.sandboxing_flag_set
557 .set(attribute.map(|attribute_value| {
558 let tokens: Vec<_> = attribute_value
559 .value()
560 .as_tokens()
561 .iter()
562 .map(|atom| atom.to_string().to_ascii_lowercase())
563 .collect();
564 parse_a_sandboxing_directive(&tokens)
565 }));
566 }
567}
568
569pub(crate) trait HTMLIFrameElementLayoutMethods {
570 fn pipeline_id(self) -> Option<PipelineId>;
571 fn browsing_context_id(self) -> Option<BrowsingContextId>;
572 fn get_width(self) -> LengthOrPercentageOrAuto;
573 fn get_height(self) -> LengthOrPercentageOrAuto;
574}
575
576impl HTMLIFrameElementLayoutMethods for LayoutDom<'_, HTMLIFrameElement> {
577 #[inline]
578 fn pipeline_id(self) -> Option<PipelineId> {
579 (self.unsafe_get()).pipeline_id.get()
580 }
581
582 #[inline]
583 fn browsing_context_id(self) -> Option<BrowsingContextId> {
584 (self.unsafe_get()).browsing_context_id.get()
585 }
586
587 fn get_width(self) -> LengthOrPercentageOrAuto {
588 self.upcast::<Element>()
589 .get_attr_for_layout(&ns!(), &local_name!("width"))
590 .map(AttrValue::as_dimension)
591 .cloned()
592 .unwrap_or(LengthOrPercentageOrAuto::Auto)
593 }
594
595 fn get_height(self) -> LengthOrPercentageOrAuto {
596 self.upcast::<Element>()
597 .get_attr_for_layout(&ns!(), &local_name!("height"))
598 .map(AttrValue::as_dimension)
599 .cloned()
600 .unwrap_or(LengthOrPercentageOrAuto::Auto)
601 }
602}
603
604impl HTMLIFrameElementMethods<crate::DomTypeHolder> for HTMLIFrameElement {
605 make_url_getter!(Src, "src");
607
608 make_url_setter!(SetSrc, "src");
610
611 fn Srcdoc(&self) -> TrustedHTMLOrString {
613 let element = self.upcast::<Element>();
614 element.get_trusted_html_attribute(&local_name!("srcdoc"))
615 }
616
617 fn SetSrcdoc(&self, value: TrustedHTMLOrString, can_gc: CanGc) -> Fallible<()> {
619 let element = self.upcast::<Element>();
623 let value = TrustedHTML::get_trusted_script_compliant_string(
624 &element.owner_global(),
625 value,
626 "HTMLIFrameElement srcdoc",
627 can_gc,
628 )?;
629 element.set_attribute(
631 &local_name!("srcdoc"),
632 AttrValue::String(value.str().to_owned()),
633 can_gc,
634 );
635 Ok(())
636 }
637
638 fn Sandbox(&self, can_gc: CanGc) -> DomRoot<DOMTokenList> {
644 self.sandbox.or_init(|| {
645 DOMTokenList::new(
646 self.upcast::<Element>(),
647 &local_name!("sandbox"),
648 Some(vec![
649 Atom::from("allow-downloads"),
650 Atom::from("allow-forms"),
651 Atom::from("allow-modals"),
652 Atom::from("allow-orientation-lock"),
653 Atom::from("allow-pointer-lock"),
654 Atom::from("allow-popups"),
655 Atom::from("allow-popups-to-escape-sandbox"),
656 Atom::from("allow-presentation"),
657 Atom::from("allow-same-origin"),
658 Atom::from("allow-scripts"),
659 Atom::from("allow-top-navigation"),
660 Atom::from("allow-top-navigation-by-user-activation"),
661 Atom::from("allow-top-navigation-to-custom-protocols"),
662 ]),
663 can_gc,
664 )
665 })
666 }
667
668 fn GetContentWindow(&self) -> Option<DomRoot<WindowProxy>> {
670 self.browsing_context_id
671 .get()
672 .and_then(|id| self.script_window_proxies.find_window_proxy(id))
673 }
674
675 fn GetContentDocument(&self) -> Option<DomRoot<Document>> {
678 let pipeline_id = self.pipeline_id.get()?;
680
681 let document = ScriptThread::find_document(pipeline_id)?;
685
686 let current = GlobalScope::current()
688 .expect("No current global object")
689 .as_window()
690 .Document();
691 if !current.origin().same_origin_domain(document.origin()) {
692 return None;
693 }
694 Some(document)
696 }
697
698 fn ReferrerPolicy(&self) -> DOMString {
700 reflect_referrer_policy_attribute(self.upcast::<Element>())
701 }
702
703 make_setter!(SetReferrerPolicy, "referrerpolicy");
705
706 make_bool_getter!(AllowFullscreen, "allowfullscreen");
708 make_bool_setter!(SetAllowFullscreen, "allowfullscreen");
710
711 make_getter!(Width, "width");
713 make_dimension_setter!(SetWidth, "width");
715
716 make_getter!(Height, "height");
718 make_dimension_setter!(SetHeight, "height");
720
721 make_getter!(FrameBorder, "frameborder");
723 make_setter!(SetFrameBorder, "frameborder");
725
726 make_atomic_setter!(SetName, "name");
730
731 make_getter!(Name, "name");
735}
736
737impl VirtualMethods for HTMLIFrameElement {
738 fn super_type(&self) -> Option<&dyn VirtualMethods> {
739 Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
740 }
741
742 fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
743 self.super_type()
744 .unwrap()
745 .attribute_mutated(attr, mutation, can_gc);
746 match *attr.local_name() {
747 local_name!("sandbox") if self.browsing_context_id.get().is_some() => {
758 self.parse_sandbox_attribute();
759 },
760 local_name!("srcdoc") => {
761 if self.upcast::<Node>().is_connected_with_browsing_context() {
772 debug!("iframe srcdoc modified while in browsing context.");
773 self.process_the_iframe_attributes(ProcessingMode::NotFirstTime, can_gc);
774 }
775 },
776 local_name!("src") => {
777 if self.upcast::<Node>().is_connected_with_browsing_context() {
786 debug!("iframe src set while in browsing context.");
787 self.process_the_iframe_attributes(ProcessingMode::NotFirstTime, can_gc);
788 }
789 },
790 _ => {},
791 }
792 }
793
794 fn attribute_affects_presentational_hints(&self, attr: &Attr) -> bool {
795 match attr.local_name() {
796 &local_name!("width") | &local_name!("height") => true,
797 _ => self
798 .super_type()
799 .unwrap()
800 .attribute_affects_presentational_hints(attr),
801 }
802 }
803
804 fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
805 match *name {
806 local_name!("sandbox") => AttrValue::from_serialized_tokenlist(value.into()),
807 local_name!("width") => AttrValue::from_dimension(value.into()),
808 local_name!("height") => AttrValue::from_dimension(value.into()),
809 _ => self
810 .super_type()
811 .unwrap()
812 .parse_plain_attribute(name, value),
813 }
814 }
815
816 fn post_connection_steps(&self) {
818 if let Some(s) = self.super_type() {
819 s.post_connection_steps();
820 }
821
822 if !self.upcast::<Node>().is_connected_with_browsing_context() {
826 return;
827 }
828
829 debug!("<iframe> running post connection steps");
830
831 self.create_nested_browsing_context(CanGc::note());
833
834 self.parse_sandbox_attribute();
837
838 self.process_the_iframe_attributes(ProcessingMode::FirstTime, CanGc::note());
840 }
841
842 fn bind_to_tree(&self, context: &BindContext, can_gc: CanGc) {
843 if let Some(s) = self.super_type() {
844 s.bind_to_tree(context, can_gc);
845 }
846 self.owner_document().invalidate_iframes_collection();
847 }
848
849 fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
850 self.super_type().unwrap().unbind_from_tree(context, can_gc);
851
852 let blocker = &self.load_blocker;
853 LoadBlocker::terminate(blocker, CanGc::note());
854
855 let window = self.owner_window();
857 let (sender, receiver) =
858 ProfiledIpc::channel(self.global().time_profiler_chan().clone()).unwrap();
859
860 let browsing_context_id = match self.browsing_context_id() {
863 None => return warn!("Unbinding already unbound iframe."),
864 Some(id) => id,
865 };
866 debug!("Unbinding frame {}.", browsing_context_id);
867
868 let msg = ScriptToConstellationMessage::RemoveIFrame(browsing_context_id, sender);
869 window
870 .as_global_scope()
871 .script_to_constellation_chan()
872 .send(msg)
873 .unwrap();
874 let exited_pipeline_ids = receiver.recv().unwrap();
875
876 for exited_pipeline_id in exited_pipeline_ids {
880 if let Some(exited_document) = ScriptThread::find_document(exited_pipeline_id) {
882 debug!(
883 "Discarding browsing context for pipeline {}",
884 exited_pipeline_id
885 );
886 let exited_window = exited_document.window();
887 exited_window.discard_browsing_context();
888 for exited_iframe in exited_document.iframes().iter() {
889 debug!("Discarding nested browsing context");
890 exited_iframe.destroy_nested_browsing_context();
891 }
892 }
893 }
894
895 self.destroy_nested_browsing_context();
901
902 self.owner_document().invalidate_iframes_collection();
903 }
904}