Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/xbl/nsXBLResourceLoader.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 "nsCSSFrameConstructor.h"
8
#include "nsTArray.h"
9
#include "nsString.h"
10
#include "nsIDocument.h"
11
#include "nsIContent.h"
12
#include "nsIPresShell.h"
13
#include "nsXBLService.h"
14
#include "nsIServiceManager.h"
15
#include "nsXBLResourceLoader.h"
16
#include "nsXBLPrototypeResources.h"
17
#include "nsIDocumentObserver.h"
18
#include "imgILoader.h"
19
#include "imgRequestProxy.h"
20
#include "mozilla/ComputedStyle.h"
21
#include "mozilla/StyleSheet.h"
22
#include "mozilla/StyleSheetInlines.h"
23
#include "mozilla/css/Loader.h"
24
#include "nsIURI.h"
25
#include "nsNetUtil.h"
26
#include "nsGkAtoms.h"
27
#include "nsXBLPrototypeBinding.h"
28
#include "nsContentUtils.h"
29
#include "nsIScriptSecurityManager.h"
30
31
using namespace mozilla;
32
33
NS_IMPL_CYCLE_COLLECTION(nsXBLResourceLoader, mBoundElements)
34
35
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXBLResourceLoader)
36
0
  NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
37
0
  NS_INTERFACE_MAP_ENTRY(nsISupports)
38
0
NS_INTERFACE_MAP_END
39
40
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXBLResourceLoader)
41
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXBLResourceLoader)
42
43
struct nsXBLResource
44
{
45
  nsXBLResource* mNext;
46
  nsAtom* mType;
47
  nsString mSrc;
48
49
  nsXBLResource(nsAtom* aType, const nsAString& aSrc)
50
0
  {
51
0
    MOZ_COUNT_CTOR(nsXBLResource);
52
0
    mNext = nullptr;
53
0
    mType = aType;
54
0
    mSrc = aSrc;
55
0
  }
56
57
  ~nsXBLResource()
58
0
  {
59
0
    MOZ_COUNT_DTOR(nsXBLResource);
60
0
    NS_CONTENT_DELETE_LIST_MEMBER(nsXBLResource, this, mNext);
61
0
  }
62
};
63
64
nsXBLResourceLoader::nsXBLResourceLoader(nsXBLPrototypeBinding* aBinding,
65
                                         nsXBLPrototypeResources* aResources)
66
:mBinding(aBinding),
67
 mResources(aResources),
68
 mResourceList(nullptr),
69
 mLastResource(nullptr),
70
 mLoadingResources(false),
71
 mInLoadResourcesFunc(false),
72
 mPendingSheets(0),
73
 mBoundDocument(nullptr)
74
0
{
75
0
}
76
77
nsXBLResourceLoader::~nsXBLResourceLoader()
78
0
{
79
0
  delete mResourceList;
80
0
}
81
82
bool
83
nsXBLResourceLoader::LoadResources(nsIContent* aBoundElement)
84
0
{
85
0
  mInLoadResourcesFunc = true;
86
0
87
0
  if (mLoadingResources) {
88
0
    mInLoadResourcesFunc = false;
89
0
    return mPendingSheets == 0;
90
0
  }
91
0
92
0
  mLoadingResources = true;
93
0
94
0
  // Declare our loaders.
95
0
  nsCOMPtr<nsIDocument> doc = mBinding->XBLDocumentInfo()->GetDocument();
96
0
  mBoundDocument = aBoundElement->OwnerDoc();
97
0
98
0
  mozilla::css::Loader* cssLoader = doc->CSSLoader();
99
0
  MOZ_ASSERT(cssLoader->GetDocument(), "Loader must have document");
100
0
101
0
  nsIURI *docURL = doc->GetDocumentURI();
102
0
  nsIPrincipal* docPrincipal = doc->NodePrincipal();
103
0
104
0
  nsCOMPtr<nsIURI> url;
105
0
106
0
  for (nsXBLResource* curr = mResourceList; curr; curr = curr->mNext) {
107
0
    if (curr->mSrc.IsEmpty())
108
0
      continue;
109
0
110
0
    if (NS_FAILED(NS_NewURI(getter_AddRefs(url), curr->mSrc,
111
0
                            doc->GetDocumentCharacterSet(), docURL)))
112
0
      continue;
113
0
114
0
    if (curr->mType == nsGkAtoms::image) {
115
0
      // Now kick off the image load...
116
0
      // Passing nullptr for pretty much everything -- cause we don't care!
117
0
      // XXX: initialDocumentURI is nullptr!
118
0
      RefPtr<imgRequestProxy> req;
119
0
      nsContentUtils::LoadImage(url, doc, doc, docPrincipal, 0, docURL,
120
0
                                doc->GetReferrerPolicy(), nullptr,
121
0
                                nsIRequest::LOAD_BACKGROUND, EmptyString(),
122
0
                                getter_AddRefs(req));
123
0
    }
124
0
    else if (curr->mType == nsGkAtoms::stylesheet) {
125
0
      // Kick off the load of the stylesheet.
126
0
127
0
      // Always load chrome synchronously
128
0
      // XXXbz should that still do a content policy check?
129
0
      bool chrome;
130
0
      nsresult rv;
131
0
      if (NS_SUCCEEDED(url->SchemeIs("chrome", &chrome)) && chrome)
132
0
      {
133
0
        rv = nsContentUtils::GetSecurityManager()->
134
0
          CheckLoadURIWithPrincipal(docPrincipal, url,
135
0
                                    nsIScriptSecurityManager::ALLOW_CHROME);
136
0
        if (NS_SUCCEEDED(rv)) {
137
0
          RefPtr<StyleSheet> sheet;
138
0
          rv = cssLoader->LoadSheetSync(url, &sheet);
139
0
          NS_ASSERTION(NS_SUCCEEDED(rv), "Load failed!!!");
140
0
          if (NS_SUCCEEDED(rv))
141
0
          {
142
0
            rv = StyleSheetLoaded(sheet, false, NS_OK);
143
0
            NS_ASSERTION(NS_SUCCEEDED(rv), "Processing the style sheet failed!!!");
144
0
          }
145
0
        }
146
0
      }
147
0
      else
148
0
      {
149
0
        rv = cssLoader->LoadSheet(url, false, docPrincipal, nullptr, this);
150
0
        if (NS_SUCCEEDED(rv))
151
0
          ++mPendingSheets;
152
0
      }
153
0
    }
154
0
  }
155
0
156
0
  mInLoadResourcesFunc = false;
157
0
158
0
  // Destroy our resource list.
159
0
  delete mResourceList;
160
0
  mResourceList = nullptr;
161
0
162
0
  return mPendingSheets == 0;
163
0
}
164
165
// nsICSSLoaderObserver
166
NS_IMETHODIMP
167
nsXBLResourceLoader::StyleSheetLoaded(StyleSheet* aSheet,
168
                                      bool aWasDeferred,
169
                                      nsresult aStatus)
170
0
{
171
0
  if (!mResources) {
172
0
    // Our resources got destroyed -- just bail out
173
0
    return NS_OK;
174
0
  }
175
0
176
0
  mResources->AppendStyleSheet(aSheet);
177
0
178
0
  if (!mInLoadResourcesFunc)
179
0
    mPendingSheets--;
180
0
181
0
  if (mPendingSheets == 0) {
182
0
    // All stylesheets are loaded.
183
0
184
0
    // Our document might have been undisplayed after this sheet load
185
0
    // was started, so check before building the XBL cascade data.
186
0
    if (nsIPresShell* shell = mBoundDocument->GetShell()) {
187
0
      mResources->ComputeServoStyles(*shell->StyleSet());
188
0
    }
189
0
190
0
    // XXX Check for mPendingScripts when scripts also come online.
191
0
    if (!mInLoadResourcesFunc)
192
0
      NotifyBoundElements();
193
0
  }
194
0
  return NS_OK;
195
0
}
196
197
void
198
nsXBLResourceLoader::AddResource(nsAtom* aResourceType, const nsAString& aSrc)
199
0
{
200
0
  nsXBLResource* res = new nsXBLResource(aResourceType, aSrc);
201
0
  if (!mResourceList)
202
0
    mResourceList = res;
203
0
  else
204
0
    mLastResource->mNext = res;
205
0
206
0
  mLastResource = res;
207
0
}
208
209
void
210
nsXBLResourceLoader::AddResourceListener(nsIContent* aBoundElement)
211
0
{
212
0
  if (aBoundElement) {
213
0
    mBoundElements.AppendObject(aBoundElement);
214
0
    aBoundElement->OwnerDoc()->BlockOnload();
215
0
  }
216
0
}
217
218
void
219
nsXBLResourceLoader::NotifyBoundElements()
220
0
{
221
0
  nsXBLService* xblService = nsXBLService::GetInstance();
222
0
  if (!xblService)
223
0
    return;
224
0
225
0
  nsIURI* bindingURI = mBinding->BindingURI();
226
0
227
0
  uint32_t eltCount = mBoundElements.Count();
228
0
  for (uint32_t j = 0; j < eltCount; j++) {
229
0
    nsCOMPtr<nsIContent> content = mBoundElements.ObjectAt(j);
230
0
    MOZ_ASSERT(content->IsElement());
231
0
    content->OwnerDoc()->UnblockOnload(/* aFireSync = */ false);
232
0
233
0
    bool ready = false;
234
0
    xblService->BindingReady(content, bindingURI, &ready);
235
0
236
0
    if (!ready) {
237
0
      continue;
238
0
    }
239
0
240
0
    nsIDocument* doc = content->GetUncomposedDoc();
241
0
    if (!doc) {
242
0
      continue;
243
0
    }
244
0
245
0
    nsIPresShell* shell = doc->GetShell();
246
0
    if (!shell) {
247
0
      continue;
248
0
    }
249
0
250
0
    shell->PostRecreateFramesFor(content->AsElement());
251
0
  }
252
0
253
0
  // Clear out the whole array.
254
0
  mBoundElements.Clear();
255
0
256
0
  // Delete ourselves.
257
0
  mResources->ClearLoader();
258
0
}
259
260
nsresult
261
nsXBLResourceLoader::Write(nsIObjectOutputStream* aStream)
262
0
{
263
0
  nsresult rv;
264
0
265
0
  for (nsXBLResource* curr = mResourceList; curr; curr = curr->mNext) {
266
0
    if (curr->mType == nsGkAtoms::image)
267
0
      rv = aStream->Write8(XBLBinding_Serialize_Image);
268
0
    else if (curr->mType == nsGkAtoms::stylesheet)
269
0
      rv = aStream->Write8(XBLBinding_Serialize_Stylesheet);
270
0
    else
271
0
      continue;
272
0
273
0
    NS_ENSURE_SUCCESS(rv, rv);
274
0
275
0
    rv = aStream->WriteWStringZ(curr->mSrc.get());
276
0
    NS_ENSURE_SUCCESS(rv, rv);
277
0
  }
278
0
279
0
  return NS_OK;
280
0
}