nsXBLResourceLoader.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. /* -*- Mode: C++; tab-width: 8; 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 "nsTArray.h"
  6. #include "nsString.h"
  7. #include "nsIStyleRuleProcessor.h"
  8. #include "nsIDocument.h"
  9. #include "nsIContent.h"
  10. #include "nsIPresShell.h"
  11. #include "nsXBLService.h"
  12. #include "nsIServiceManager.h"
  13. #include "nsXBLResourceLoader.h"
  14. #include "nsXBLPrototypeResources.h"
  15. #include "nsIDocumentObserver.h"
  16. #include "imgILoader.h"
  17. #include "imgRequestProxy.h"
  18. #include "mozilla/StyleSheet.h"
  19. #include "mozilla/StyleSheetInlines.h"
  20. #include "mozilla/css/Loader.h"
  21. #include "nsIURI.h"
  22. #include "nsNetUtil.h"
  23. #include "nsGkAtoms.h"
  24. #include "nsFrameManager.h"
  25. #include "nsStyleContext.h"
  26. #include "nsXBLPrototypeBinding.h"
  27. #include "nsCSSRuleProcessor.h"
  28. #include "nsContentUtils.h"
  29. #include "nsStyleSet.h"
  30. #include "nsIScriptSecurityManager.h"
  31. using namespace mozilla;
  32. NS_IMPL_CYCLE_COLLECTION(nsXBLResourceLoader, mBoundElements)
  33. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXBLResourceLoader)
  34. NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
  35. NS_INTERFACE_MAP_ENTRY(nsISupports)
  36. NS_INTERFACE_MAP_END
  37. NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXBLResourceLoader)
  38. NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXBLResourceLoader)
  39. struct nsXBLResource
  40. {
  41. nsXBLResource* mNext;
  42. nsIAtom* mType;
  43. nsString mSrc;
  44. nsXBLResource(nsIAtom* aType, const nsAString& aSrc)
  45. {
  46. MOZ_COUNT_CTOR(nsXBLResource);
  47. mNext = nullptr;
  48. mType = aType;
  49. mSrc = aSrc;
  50. }
  51. ~nsXBLResource()
  52. {
  53. MOZ_COUNT_DTOR(nsXBLResource);
  54. NS_CONTENT_DELETE_LIST_MEMBER(nsXBLResource, this, mNext);
  55. }
  56. };
  57. nsXBLResourceLoader::nsXBLResourceLoader(nsXBLPrototypeBinding* aBinding,
  58. nsXBLPrototypeResources* aResources)
  59. :mBinding(aBinding),
  60. mResources(aResources),
  61. mResourceList(nullptr),
  62. mLastResource(nullptr),
  63. mLoadingResources(false),
  64. mInLoadResourcesFunc(false),
  65. mPendingSheets(0)
  66. {
  67. }
  68. nsXBLResourceLoader::~nsXBLResourceLoader()
  69. {
  70. delete mResourceList;
  71. }
  72. void
  73. nsXBLResourceLoader::LoadResources(bool* aResult)
  74. {
  75. mInLoadResourcesFunc = true;
  76. if (mLoadingResources) {
  77. *aResult = (mPendingSheets == 0);
  78. mInLoadResourcesFunc = false;
  79. return;
  80. }
  81. mLoadingResources = true;
  82. *aResult = true;
  83. // Declare our loaders.
  84. nsCOMPtr<nsIDocument> doc = mBinding->XBLDocumentInfo()->GetDocument();
  85. mozilla::css::Loader* cssLoader = doc->CSSLoader();
  86. nsIURI *docURL = doc->GetDocumentURI();
  87. nsIPrincipal* docPrincipal = doc->NodePrincipal();
  88. nsCOMPtr<nsIURI> url;
  89. for (nsXBLResource* curr = mResourceList; curr; curr = curr->mNext) {
  90. if (curr->mSrc.IsEmpty())
  91. continue;
  92. if (NS_FAILED(NS_NewURI(getter_AddRefs(url), curr->mSrc,
  93. doc->GetDocumentCharacterSet().get(), docURL)))
  94. continue;
  95. if (curr->mType == nsGkAtoms::image) {
  96. // Now kick off the image load...
  97. // Passing nullptr for pretty much everything -- cause we don't care!
  98. // XXX: initialDocumentURI is nullptr!
  99. RefPtr<imgRequestProxy> req;
  100. nsContentUtils::LoadImage(url, doc, doc, docPrincipal, docURL,
  101. doc->GetReferrerPolicy(), nullptr,
  102. nsIRequest::LOAD_BACKGROUND, EmptyString(),
  103. getter_AddRefs(req));
  104. }
  105. else if (curr->mType == nsGkAtoms::stylesheet) {
  106. // Kick off the load of the stylesheet.
  107. // Always load chrome synchronously
  108. // XXXbz should that still do a content policy check?
  109. bool chrome;
  110. nsresult rv;
  111. if (NS_SUCCEEDED(url->SchemeIs("chrome", &chrome)) && chrome)
  112. {
  113. rv = nsContentUtils::GetSecurityManager()->
  114. CheckLoadURIWithPrincipal(docPrincipal, url,
  115. nsIScriptSecurityManager::ALLOW_CHROME);
  116. if (NS_SUCCEEDED(rv)) {
  117. RefPtr<StyleSheet> sheet;
  118. rv = cssLoader->LoadSheetSync(url, &sheet);
  119. NS_ASSERTION(NS_SUCCEEDED(rv), "Load failed!!!");
  120. if (NS_SUCCEEDED(rv))
  121. {
  122. rv = StyleSheetLoaded(sheet, false, NS_OK);
  123. NS_ASSERTION(NS_SUCCEEDED(rv), "Processing the style sheet failed!!!");
  124. }
  125. }
  126. }
  127. else
  128. {
  129. rv = cssLoader->LoadSheet(url, false, docPrincipal, EmptyCString(), this);
  130. if (NS_SUCCEEDED(rv))
  131. ++mPendingSheets;
  132. }
  133. }
  134. }
  135. *aResult = (mPendingSheets == 0);
  136. mInLoadResourcesFunc = false;
  137. // Destroy our resource list.
  138. delete mResourceList;
  139. mResourceList = nullptr;
  140. }
  141. // nsICSSLoaderObserver
  142. NS_IMETHODIMP
  143. nsXBLResourceLoader::StyleSheetLoaded(StyleSheet* aSheet,
  144. bool aWasAlternate,
  145. nsresult aStatus)
  146. {
  147. if (!mResources) {
  148. // Our resources got destroyed -- just bail out
  149. return NS_OK;
  150. }
  151. mResources->AppendStyleSheet(aSheet);
  152. if (!mInLoadResourcesFunc)
  153. mPendingSheets--;
  154. if (mPendingSheets == 0) {
  155. // All stylesheets are loaded.
  156. mResources->GatherRuleProcessor();
  157. // XXX Check for mPendingScripts when scripts also come online.
  158. if (!mInLoadResourcesFunc)
  159. NotifyBoundElements();
  160. }
  161. return NS_OK;
  162. }
  163. void
  164. nsXBLResourceLoader::AddResource(nsIAtom* aResourceType, const nsAString& aSrc)
  165. {
  166. nsXBLResource* res = new nsXBLResource(aResourceType, aSrc);
  167. if (!mResourceList)
  168. mResourceList = res;
  169. else
  170. mLastResource->mNext = res;
  171. mLastResource = res;
  172. }
  173. void
  174. nsXBLResourceLoader::AddResourceListener(nsIContent* aBoundElement)
  175. {
  176. if (aBoundElement) {
  177. mBoundElements.AppendObject(aBoundElement);
  178. }
  179. }
  180. void
  181. nsXBLResourceLoader::NotifyBoundElements()
  182. {
  183. nsXBLService* xblService = nsXBLService::GetInstance();
  184. if (!xblService)
  185. return;
  186. nsIURI* bindingURI = mBinding->BindingURI();
  187. uint32_t eltCount = mBoundElements.Count();
  188. for (uint32_t j = 0; j < eltCount; j++) {
  189. nsCOMPtr<nsIContent> content = mBoundElements.ObjectAt(j);
  190. bool ready = false;
  191. xblService->BindingReady(content, bindingURI, &ready);
  192. if (ready) {
  193. // We need the document to flush out frame construction and
  194. // such, so we want to use the current document.
  195. nsIDocument* doc = content->GetUncomposedDoc();
  196. if (doc) {
  197. // Flush first to make sure we can get the frame for content
  198. doc->FlushPendingNotifications(Flush_Frames);
  199. // If |content| is (in addition to having binding |mBinding|)
  200. // also a descendant of another element with binding |mBinding|,
  201. // then we might have just constructed it due to the
  202. // notification of its parent. (We can know about both if the
  203. // binding loads were triggered from the DOM rather than frame
  204. // construction.) So we have to check both whether the element
  205. // has a primary frame and whether it's in the undisplayed map
  206. // before sending a ContentInserted notification, or bad things
  207. // will happen.
  208. nsIPresShell *shell = doc->GetShell();
  209. if (shell) {
  210. nsIFrame* childFrame = content->GetPrimaryFrame();
  211. if (!childFrame) {
  212. // Check to see if it's in the undisplayed content map.
  213. nsStyleContext* sc =
  214. shell->FrameManager()->GetUndisplayedContent(content);
  215. if (!sc) {
  216. shell->RecreateFramesFor(content);
  217. }
  218. }
  219. }
  220. // Flush again
  221. // XXXbz why is this needed?
  222. doc->FlushPendingNotifications(Flush_ContentAndNotify);
  223. }
  224. }
  225. }
  226. // Clear out the whole array.
  227. mBoundElements.Clear();
  228. // Delete ourselves.
  229. mResources->ClearLoader();
  230. }
  231. nsresult
  232. nsXBLResourceLoader::Write(nsIObjectOutputStream* aStream)
  233. {
  234. nsresult rv;
  235. for (nsXBLResource* curr = mResourceList; curr; curr = curr->mNext) {
  236. if (curr->mType == nsGkAtoms::image)
  237. rv = aStream->Write8(XBLBinding_Serialize_Image);
  238. else if (curr->mType == nsGkAtoms::stylesheet)
  239. rv = aStream->Write8(XBLBinding_Serialize_Stylesheet);
  240. else
  241. continue;
  242. NS_ENSURE_SUCCESS(rv, rv);
  243. rv = aStream->WriteWStringZ(curr->mSrc.get());
  244. NS_ENSURE_SUCCESS(rv, rv);
  245. }
  246. return NS_OK;
  247. }