1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "mozilla/dom/BrowsingContext.h"
6 #include "mozilla/dom/CanonicalBrowsingContext.h"
7 #include "mozilla/dom/Document.h"
8 #include "mozilla/dom/WindowGlobalChild.h"
9 #include "mozilla/dom/WindowGlobalParent.h"
10 #include "mozilla/Services.h"
11 #include "nsIObserverService.h"
12 #include "nsIURI.h"
13 #include "nsNetUtil.h"
14 #include "nsPIDOMWindow.h"
15 #include "nsReadableUtils.h"
16 #include "nsThreadUtils.h"
17 #include "RestoreTabContentObserver.h"
18 
19 using namespace mozilla::dom;
20 
21 NS_IMPL_ISUPPORTS(RestoreTabContentObserver, nsIObserver)
22 
23 const char* const kAboutReaderTopic = "AboutReader:Ready";
24 const char* const kContentDocumentLoaded = "content-document-loaded";
25 const char* const kChromeDocumentLoaded = "chrome-document-loaded";
26 
27 /* static */
Initialize()28 void RestoreTabContentObserver::Initialize() {
29   MOZ_ASSERT(!gRestoreTabContentObserver);
30   MOZ_ASSERT(NS_IsMainThread());
31 
32   RefPtr<RestoreTabContentObserver> observer = new RestoreTabContentObserver();
33 
34   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
35   if (NS_WARN_IF(!obs)) {
36     return;
37   }
38 
39   obs->AddObserver(observer, kAboutReaderTopic, false);
40   obs->AddObserver(observer, kContentDocumentLoaded, false);
41   obs->AddObserver(observer, kChromeDocumentLoaded, false);
42 
43   gRestoreTabContentObserver = observer;
44 }
45 
46 /* static */
Shutdown()47 void RestoreTabContentObserver::Shutdown() {
48   MOZ_ASSERT(NS_IsMainThread());
49 
50   if (!gRestoreTabContentObserver) {
51     return;
52   }
53 
54   RefPtr<RestoreTabContentObserver> observer = gRestoreTabContentObserver;
55   gRestoreTabContentObserver = nullptr;
56 
57   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
58   if (!obs) {
59     return;
60   }
61 
62   obs->RemoveObserver(observer, kAboutReaderTopic);
63   obs->RemoveObserver(observer, kContentDocumentLoaded);
64   obs->RemoveObserver(observer, kChromeDocumentLoaded);
65 }
66 
67 NS_IMETHODIMP
Observe(nsISupports * aSubject,const char * aTopic,const char16_t * aData)68 RestoreTabContentObserver::Observe(nsISupports* aSubject, const char* aTopic,
69                                    const char16_t* aData) {
70   nsCOMPtr<nsPIDOMWindowInner> inner;
71   if (!strcmp(aTopic, kAboutReaderTopic)) {
72     inner = do_QueryInterface(aSubject);
73   } else if (!strcmp(aTopic, kContentDocumentLoaded) ||
74              !strcmp(aTopic, kChromeDocumentLoaded)) {
75     nsCOMPtr<Document> doc = do_QueryInterface(aSubject);
76     inner = doc ? doc->GetInnerWindow() : nullptr;
77   }
78   if (!inner) {
79     return NS_OK;
80   }
81 
82   nsCOMPtr<nsIURI> uri = inner->GetDocumentURI();
83   if (!uri) {
84     return NS_OK;
85   }
86 
87   // We'll handle loading about:reader with "AboutReader:Ready"
88   // rather than "content-document-loaded".
89   if (uri->SchemeIs("about") &&
90       StringBeginsWith(uri->GetSpecOrDefault(), "about:reader"_ns) &&
91       strcmp(aTopic, kAboutReaderTopic) != 0) {
92     return NS_OK;
93   }
94 
95   RefPtr<BrowsingContext> bc = inner->GetBrowsingContext();
96   if (!bc || !bc->Top()->GetHasRestoreData()) {
97     return NS_OK;
98   }
99   if (XRE_IsParentProcess()) {
100     if (WindowGlobalParent* wgp = bc->Canonical()->GetCurrentWindowGlobal()) {
101       bc->Canonical()->Top()->RequestRestoreTabContent(wgp);
102     }
103   } else if (WindowContext* windowContext = bc->GetCurrentWindowContext()) {
104     if (WindowGlobalChild* wgc = windowContext->GetWindowGlobalChild()) {
105       wgc->SendRequestRestoreTabContent();
106     }
107   }
108   return NS_OK;
109 }
110 
111 mozilla::StaticRefPtr<RestoreTabContentObserver>
112     RestoreTabContentObserver::gRestoreTabContentObserver;
113