Merge mozilla-central and tracemonkey. (a=blockers)
[mozilla-central.git] / layout / style / Loader.h
blob5d05f751cb65756aa88af065f16b0fc101b1e6c9
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1999
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 /* loading of CSS style sheets using the network APIs */
40 #ifndef mozilla_css_Loader_h
41 #define mozilla_css_Loader_h
43 #include "nsIPrincipal.h"
44 #include "nsAString.h"
45 #include "nsAutoPtr.h"
46 #include "nsCompatibility.h"
47 #include "nsDataHashtable.h"
48 #include "nsInterfaceHashtable.h"
49 #include "nsRefPtrHashtable.h"
50 #include "nsTArray.h"
51 #include "nsTObserverArray.h"
52 #include "nsURIHashKey.h"
54 class nsIAtom;
55 class nsICSSImportRule;
56 class nsICSSLoaderObserver;
57 class nsCSSStyleSheet;
58 class nsIContent;
59 class nsIDocument;
60 class nsIUnicharInputStream;
61 class nsCSSParser;
62 class nsMediaList;
64 namespace mozilla {
66 class URIAndPrincipalHashKey : public nsURIHashKey
68 public:
69 typedef URIAndPrincipalHashKey* KeyType;
70 typedef const URIAndPrincipalHashKey* KeyTypePointer;
72 URIAndPrincipalHashKey(const URIAndPrincipalHashKey* aKey)
73 : nsURIHashKey(aKey->mKey), mPrincipal(aKey->mPrincipal)
75 MOZ_COUNT_CTOR(URIAndPrincipalHashKey);
77 URIAndPrincipalHashKey(nsIURI* aURI, nsIPrincipal* aPrincipal)
78 : nsURIHashKey(aURI), mPrincipal(aPrincipal)
80 MOZ_COUNT_CTOR(URIAndPrincipalHashKey);
82 URIAndPrincipalHashKey(const URIAndPrincipalHashKey& toCopy)
83 : nsURIHashKey(toCopy), mPrincipal(toCopy.mPrincipal)
85 MOZ_COUNT_CTOR(URIAndPrincipalHashKey);
87 ~URIAndPrincipalHashKey()
89 MOZ_COUNT_DTOR(URIAndPrincipalHashKey);
92 URIAndPrincipalHashKey* GetKey() const {
93 return const_cast<URIAndPrincipalHashKey*>(this);
95 const URIAndPrincipalHashKey* GetKeyPointer() const { return this; }
97 PRBool KeyEquals(const URIAndPrincipalHashKey* aKey) const {
98 if (!nsURIHashKey::KeyEquals(aKey->mKey)) {
99 return PR_FALSE;
102 if (!mPrincipal != !aKey->mPrincipal) {
103 // One or the other has a principal, but not both... not equal
104 return PR_FALSE;
107 PRBool eq;
108 return !mPrincipal ||
109 (NS_SUCCEEDED(mPrincipal->Equals(aKey->mPrincipal, &eq)) && eq);
112 static const URIAndPrincipalHashKey*
113 KeyToPointer(URIAndPrincipalHashKey* aKey) { return aKey; }
114 static PLDHashNumber HashKey(const URIAndPrincipalHashKey* aKey) {
115 return nsURIHashKey::HashKey(aKey->mKey);
118 enum { ALLOW_MEMMOVE = PR_TRUE };
120 protected:
121 nsCOMPtr<nsIPrincipal> mPrincipal;
126 namespace css {
128 class SheetLoadData;
130 /***********************************************************************
131 * Enum that describes the state of the sheet returned by CreateSheet. *
132 ***********************************************************************/
133 enum StyleSheetState {
134 eSheetStateUnknown = 0,
135 eSheetNeedsParser,
136 eSheetPending,
137 eSheetLoading,
138 eSheetComplete
141 class Loader {
142 public:
143 Loader();
144 Loader(nsIDocument*);
145 ~Loader();
147 // This isn't a COM class but it's reference-counted like one.
148 NS_IMETHOD_(nsrefcnt) AddRef();
149 NS_IMETHOD_(nsrefcnt) Release();
151 void DropDocumentReference(); // notification that doc is going away
153 void SetCompatibilityMode(nsCompatibility aCompatMode)
154 { mCompatMode = aCompatMode; }
155 nsCompatibility GetCompatibilityMode() { return mCompatMode; }
156 nsresult SetPreferredSheet(const nsAString& aTitle);
158 // XXXbz sort out what the deal is with events! When should they fire?
161 * Load an inline style sheet. If a successful result is returned and
162 * *aCompleted is false, then aObserver is guaranteed to be notified
163 * asynchronously once the sheet is marked complete. If an error is
164 * returned, or if *aCompleted is true, aObserver will not be notified. In
165 * addition to parsing the sheet, this method will insert it into the
166 * stylesheet list of this CSSLoader's document.
168 * @param aElement the element linking to the stylesheet. This must not be
169 * null and must implement nsIStyleSheetLinkingElement.
170 * @param aStream the character stream that holds the stylesheet data.
171 * @param aLineNumber the line number at which the stylesheet data started.
172 * @param aTitle the title of the sheet.
173 * @param aMedia the media string for the sheet.
174 * @param aObserver the observer to notify when the load completes.
175 * May be null.
176 * @param [out] aCompleted whether parsing of the sheet completed.
177 * @param [out] aIsAlternate whether the stylesheet ended up being an
178 * alternate sheet.
180 nsresult LoadInlineStyle(nsIContent* aElement,
181 nsIUnicharInputStream* aStream,
182 PRUint32 aLineNumber,
183 const nsAString& aTitle,
184 const nsAString& aMedia,
185 nsICSSLoaderObserver* aObserver,
186 PRBool* aCompleted,
187 PRBool* aIsAlternate);
190 * Load a linked (document) stylesheet. If a successful result is returned,
191 * aObserver is guaranteed to be notified asynchronously once the sheet is
192 * loaded and marked complete. If an error is returned, aObserver will not
193 * be notified. In addition to loading the sheet, this method will insert it
194 * into the stylesheet list of this CSSLoader's document.
196 * @param aElement the element linking to the the stylesheet. May be null.
197 * @param aURL the URL of the sheet.
198 * @param aTitle the title of the sheet.
199 * @param aMedia the media string for the sheet.
200 * @param aHasAlternateRel whether the rel for this link included
201 * "alternate".
202 * @param aObserver the observer to notify when the load completes.
203 * May be null.
204 * @param [out] aIsAlternate whether the stylesheet actually ended up beinga
205 * an alternate sheet. Note that this need not match
206 * aHasAlternateRel.
208 nsresult LoadStyleLink(nsIContent* aElement,
209 nsIURI* aURL,
210 const nsAString& aTitle,
211 const nsAString& aMedia,
212 PRBool aHasAlternateRel,
213 nsICSSLoaderObserver* aObserver,
214 PRBool* aIsAlternate);
217 * Load a child (@import-ed) style sheet. In addition to loading the sheet,
218 * this method will insert it into the child sheet list of aParentSheet. If
219 * there is no sheet currently being parsed and the child sheet is not
220 * complete when this method returns, then when the child sheet becomes
221 * complete aParentSheet will be QIed to nsICSSLoaderObserver and
222 * asynchronously notified, just like for LoadStyleLink. Note that if the
223 * child sheet is already complete when this method returns, no
224 * nsICSSLoaderObserver notification will be sent.
226 * @param aParentSheet the parent of this child sheet
227 * @param aURL the URL of the child sheet
228 * @param aMedia the already-parsed media list for the child sheet
229 * @param aRule the @import rule importing this child. This is used to
230 * properly order the child sheet list of aParentSheet.
232 nsresult LoadChildSheet(nsCSSStyleSheet* aParentSheet,
233 nsIURI* aURL,
234 nsMediaList* aMedia,
235 nsICSSImportRule* aRule);
238 * Synchronously load and return the stylesheet at aURL. Any child sheets
239 * will also be loaded synchronously. Note that synchronous loads over some
240 * protocols may involve spinning up a new event loop, so use of this method
241 * does NOT guarantee not receiving any events before the sheet loads. This
242 * method can be used to load sheets not associated with a document.
244 * @param aURL the URL of the sheet to load
245 * @param aEnableUnsafeRules whether unsafe rules are enabled for this
246 * sheet load
247 * Unsafe rules are rules that can violate key Gecko invariants if misused.
248 * In particular, most anonymous box pseudoelements must be very carefully
249 * styled or we will have severe problems. Therefore unsafe rules should
250 * never be enabled for stylesheets controlled by untrusted sites; preferably
251 * unsafe rules should only be enabled for agent sheets.
252 * @param aUseSystemPrincipal if true, give the resulting sheet the system
253 * principal no matter where it's being loaded from.
254 * @param [out] aSheet the loaded, complete sheet.
256 * NOTE: At the moment, this method assumes the sheet will be UTF-8, but
257 * ideally it would allow arbitrary encodings. Callers should NOT depend on
258 * non-UTF8 sheets being treated as UTF-8 by this method.
260 * NOTE: A successful return from this method doesn't indicate anything about
261 * whether the data could be parsed as CSS and doesn't indicate anything
262 * about the status of child sheets of the returned sheet.
264 nsresult LoadSheetSync(nsIURI* aURL, PRBool aEnableUnsafeRules,
265 PRBool aUseSystemPrincipal,
266 nsCSSStyleSheet** aSheet);
269 * As above, but aUseSystemPrincipal and aEnableUnsafeRules are assumed false.
271 nsresult LoadSheetSync(nsIURI* aURL, nsCSSStyleSheet** aSheet) {
272 return LoadSheetSync(aURL, PR_FALSE, PR_FALSE, aSheet);
276 * Asynchronously load the stylesheet at aURL. If a successful result is
277 * returned, aObserver is guaranteed to be notified asynchronously once the
278 * sheet is loaded and marked complete. This method can be used to load
279 * sheets not associated with a document.
281 * @param aURL the URL of the sheet to load
282 * @param aOriginPrincipal the principal to use for security checks. This
283 * can be null to indicate that these checks should
284 * be skipped.
285 * @param aCharset the encoding to use for converting the sheet data
286 * from bytes to Unicode. May be empty to indicate that the
287 * charset of the CSSLoader's document should be used. This
288 * is only used if neither the network transport nor the
289 * sheet itself indicate an encoding.
290 * @param aObserver the observer to notify when the load completes.
291 * Must not be null.
292 * @param [out] aSheet the sheet to load. Note that the sheet may well
293 * not be loaded by the time this method returns.
295 nsresult LoadSheet(nsIURI* aURL,
296 nsIPrincipal* aOriginPrincipal,
297 const nsCString& aCharset,
298 nsICSSLoaderObserver* aObserver,
299 nsCSSStyleSheet** aSheet);
302 * Same as above, to be used when the caller doesn't care about the
303 * not-yet-loaded sheet.
305 nsresult LoadSheet(nsIURI* aURL,
306 nsIPrincipal* aOriginPrincipal,
307 const nsCString& aCharset,
308 nsICSSLoaderObserver* aObserver);
311 * Stop loading all sheets. All nsICSSLoaderObservers involved will be
312 * notified with NS_BINDING_ABORTED as the status, possibly synchronously.
314 nsresult Stop(void);
317 * nsresult Loader::StopLoadingSheet(nsIURI* aURL), which notifies the
318 * nsICSSLoaderObserver with NS_BINDING_ABORTED, was removed in Bug 556446.
319 * It can be found in revision 2c44a32052ad.
323 * Whether the loader is enabled or not.
324 * When disabled, processing of new styles is disabled and an attempt
325 * to do so will fail with a return code of
326 * NS_ERROR_NOT_AVAILABLE. Note that this DOES NOT disable
327 * currently loading styles or already processed styles.
329 PRBool GetEnabled() { return mEnabled; }
330 void SetEnabled(PRBool aEnabled) { mEnabled = aEnabled; }
333 * Get the document we live for. May return null.
335 nsIDocument* GetDocument() const { return mDocument; }
338 * Return true if this loader has pending loads (ones that would send
339 * notifications to an nsICSSLoaderObserver attached to this loader).
340 * If called from inside nsICSSLoaderObserver::StyleSheetLoaded, this will
341 * return PR_FALSE if and only if that is the last StyleSheetLoaded
342 * notification the CSSLoader knows it's going to send. In other words, if
343 * two sheets load at once (via load coalescing, e.g.), HasPendingLoads()
344 * will return PR_TRUE during notification for the first one, and PR_FALSE
345 * during notification for the second one.
347 PRBool HasPendingLoads();
350 * Add an observer to this loader. The observer will be notified
351 * for all loads that would have notified their own observers (even
352 * if those loads don't have observers attached to them).
353 * Load-specific observers will be notified before generic
354 * observers. The loader holds a reference to the observer.
356 * aObserver must not be null.
358 nsresult AddObserver(nsICSSLoaderObserver* aObserver);
361 * Remove an observer added via AddObserver.
363 void RemoveObserver(nsICSSLoaderObserver* aObserver);
365 // These interfaces are public only for the benefit of static functions
366 // within nsCSSLoader.cpp.
368 // IsAlternate can change our currently selected style set if none
369 // is selected and aHasAlternateRel is false.
370 PRBool IsAlternate(const nsAString& aTitle, PRBool aHasAlternateRel);
372 typedef nsTArray<nsRefPtr<SheetLoadData> > LoadDataArray;
374 private:
375 friend class SheetLoadData;
377 // Note: null aSourcePrincipal indicates that the content policy and
378 // CheckLoadURI checks should be skipped.
379 nsresult CheckLoadAllowed(nsIPrincipal* aSourcePrincipal,
380 nsIURI* aTargetURI,
381 nsISupports* aContext);
384 // For inline style, the aURI param is null, but the aLinkingContent
385 // must be non-null then. The loader principal must never be null
386 // if aURI is not null.
387 nsresult CreateSheet(nsIURI* aURI,
388 nsIContent* aLinkingContent,
389 nsIPrincipal* aLoaderPrincipal,
390 PRBool aSyncLoad,
391 StyleSheetState& aSheetState,
392 nsCSSStyleSheet** aSheet);
394 // Pass in either a media string or the nsMediaList from the
395 // CSSParser. Don't pass both.
396 // If aIsAlternate is non-null, this method will set *aIsAlternate to
397 // correspond to the sheet's enabled state (which it will set no matter what)
398 nsresult PrepareSheet(nsCSSStyleSheet* aSheet,
399 const nsAString& aTitle,
400 const nsAString& aMediaString,
401 nsMediaList* aMediaList,
402 PRBool aHasAlternateRel = PR_FALSE,
403 PRBool *aIsAlternate = nsnull);
405 nsresult InsertSheetInDoc(nsCSSStyleSheet* aSheet,
406 nsIContent* aLinkingContent,
407 nsIDocument* aDocument);
409 nsresult InsertChildSheet(nsCSSStyleSheet* aSheet,
410 nsCSSStyleSheet* aParentSheet,
411 nsICSSImportRule* aParentRule);
413 nsresult InternalLoadNonDocumentSheet(nsIURI* aURL,
414 PRBool aAllowUnsafeRules,
415 PRBool aUseSystemPrincipal,
416 nsIPrincipal* aOriginPrincipal,
417 const nsCString& aCharset,
418 nsCSSStyleSheet** aSheet,
419 nsICSSLoaderObserver* aObserver);
421 // Post a load event for aObserver to be notified about aSheet. The
422 // notification will be sent with status NS_OK unless the load event is
423 // canceled at some point (in which case it will be sent with
424 // NS_BINDING_ABORTED). aWasAlternate indicates the state when the load was
425 // initiated, not the state at some later time. aURI should be the URI the
426 // sheet was loaded from (may be null for inline sheets).
427 nsresult PostLoadEvent(nsIURI* aURI,
428 nsCSSStyleSheet* aSheet,
429 nsICSSLoaderObserver* aObserver,
430 PRBool aWasAlternate);
432 // Start the loads of all the sheets in mPendingDatas
433 void StartAlternateLoads();
435 // Handle an event posted by PostLoadEvent
436 void HandleLoadEvent(SheetLoadData* aEvent);
438 // Note: LoadSheet is responsible for releasing aLoadData and setting the
439 // sheet to complete on failure.
440 nsresult LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState);
442 // Parse the stylesheet in aLoadData. The sheet data comes from aStream.
443 // Set aCompleted to true if the parse finished, false otherwise (e.g. if the
444 // sheet had an @import). If aCompleted is true when this returns, then
445 // ParseSheet also called SheetComplete on aLoadData
446 nsresult ParseSheet(nsIUnicharInputStream* aStream,
447 SheetLoadData* aLoadData,
448 PRBool& aCompleted);
450 // The load of the sheet in aLoadData is done, one way or another. Do final
451 // cleanup, including releasing aLoadData.
452 void SheetComplete(SheetLoadData* aLoadData, nsresult aStatus);
454 // The guts of SheetComplete. This may be called recursively on parent datas
455 // or datas that had glommed on to a single load. The array is there so load
456 // datas whose observers need to be notified can be added to it.
457 void DoSheetComplete(SheetLoadData* aLoadData, nsresult aStatus,
458 LoadDataArray& aDatasToNotify);
460 nsRefPtrHashtable<URIAndPrincipalHashKey, nsCSSStyleSheet>
461 mCompleteSheets;
462 nsDataHashtable<URIAndPrincipalHashKey, SheetLoadData*>
463 mLoadingDatas; // weak refs
464 nsDataHashtable<URIAndPrincipalHashKey, SheetLoadData*>
465 mPendingDatas; // weak refs
467 // We're not likely to have many levels of @import... But likely to have
468 // some. Allocate some storage, what the hell.
469 nsAutoTArray<SheetLoadData*, 8> mParsingDatas;
471 // The array of posted stylesheet loaded events (SheetLoadDatas) we have.
472 // Note that these are rare.
473 LoadDataArray mPostedEvents;
475 // Our array of "global" observers
476 nsTObserverArray<nsCOMPtr<nsICSSLoaderObserver> > mObservers;
478 // the load data needs access to the document...
479 nsIDocument* mDocument; // the document we live for
481 // Refcounting
482 nsAutoRefCnt mRefCnt;
483 NS_DECL_OWNINGTHREAD
485 // Number of datas still waiting to be notified on if we're notifying on a
486 // whole bunch at once (e.g. in one of the stop methods). This is used to
487 // make sure that HasPendingLoads() won't return false until we're notifying
488 // on the last data we're working with.
489 PRUint32 mDatasToNotifyOn;
491 nsCompatibility mCompatMode;
492 nsString mPreferredSheet; // title of preferred sheet
494 PRPackedBool mEnabled; // is enabled to load new styles
496 #ifdef DEBUG
497 PRPackedBool mSyncCallback;
498 #endif
501 } // namespace css
502 } // namespace mozilla
504 #endif /* mozilla_css_Loader_h */