Bug 461267, bump version to 3.0.5pre/1.9.0.5pre, p=joduinn, r=nthomas
[mozilla-1.9.git] / layout / style / nsCSSLoader.h
blobdc3c6605f39a5822026ecac1f8c13e39bf973a02
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: ft=cpp tw=78 sw=2 et ts=2
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
17 * The Original Code is mozilla.org code.
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1999
22 * the Initial Developer. All Rights Reserved.
24 * Contributor(s):
25 * Boris Zbarsky <bzbarsky@mit.edu>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK *****
41 * This Original Code has been modified by IBM Corporation. Modifications made by IBM
42 * described herein are Copyright (c) International Business Machines Corporation, 2000.
43 * Modifications to Mozilla code or documentation identified per MPL Section 3.3
45 * Date Modified by Description of modification
46 * 04/20/2000 IBM Corp. OS/2 VisualAge build.
49 /* loading of CSS style sheets using the network APIs */
51 #ifndef nsCSSLoader_h__
52 #define nsCSSLoader_h__
54 class CSSLoaderImpl;
55 class nsIURI;
56 class nsICSSStyleSheet;
57 class nsIStyleSheetLinkingElement;
58 class nsICSSLoaderObserver;
59 class nsICSSParser;
60 class nsICSSImportRule;
61 class nsMediaList;
63 #include "nsICSSLoader.h"
64 #include "nsIRunnable.h"
65 #include "nsIUnicharStreamLoader.h"
66 #include "nsCOMPtr.h"
67 #include "nsCOMArray.h"
68 #include "nsString.h"
69 #include "nsURIHashKey.h"
70 #include "nsInterfaceHashtable.h"
71 #include "nsDataHashtable.h"
72 #include "nsAutoPtr.h"
73 #include "nsTArray.h"
74 #include "nsIPrincipal.h"
75 #include "nsTObserverArray.h"
77 /**
78 * OVERALL ARCHITECTURE
80 * The CSS Loader gets requests to load various sorts of style sheets:
81 * inline style from <style> elements, linked style, @import-ed child
82 * sheets, non-document sheets. The loader handles the following tasks:
84 * 1) Checking whether the load is allowed: CheckLoadAllowed()
85 * 2) Creation of the actual style sheet objects: CreateSheet()
86 * 3) setting of the right media, title, enabled state, etc on the
87 * sheet: PrepareSheet()
88 * 4) Insertion of the sheet in the proper cascade order:
89 * InsertSheetInDoc() and InsertChildSheet()
90 * 5) Load of the sheet: LoadSheet()
91 * 6) Parsing of the sheet: ParseSheet()
92 * 7) Cleanup: SheetComplete()
94 * The detailed documentation for these functions is found with the
95 * function implementations.
97 * The following helper object is used:
98 * SheetLoadData -- a small class that is used to store all the
99 * information needed for the loading of a sheet;
100 * this class handles listening for the stream
101 * loader completion and also handles charset
102 * determination.
105 /*********************************************
106 * Data needed to properly load a stylesheet *
107 *********************************************/
109 class SheetLoadData : public nsIRunnable,
110 public nsIUnicharStreamLoaderObserver
112 public:
113 virtual ~SheetLoadData(void);
114 // Data for loading a sheet linked from a document
115 SheetLoadData(CSSLoaderImpl* aLoader,
116 const nsSubstring& aTitle,
117 nsIURI* aURI,
118 nsICSSStyleSheet* aSheet,
119 nsIStyleSheetLinkingElement* aOwningElement,
120 PRBool aIsAlternate,
121 nsICSSLoaderObserver* aObserver,
122 nsIPrincipal* aLoaderPrincipal);
124 // Data for loading a sheet linked from an @import rule
125 SheetLoadData(CSSLoaderImpl* aLoader,
126 nsIURI* aURI,
127 nsICSSStyleSheet* aSheet,
128 SheetLoadData* aParentData,
129 nsICSSLoaderObserver* aObserver,
130 nsIPrincipal* aLoaderPrincipal);
132 // Data for loading a non-document sheet
133 SheetLoadData(CSSLoaderImpl* aLoader,
134 nsIURI* aURI,
135 nsICSSStyleSheet* aSheet,
136 PRBool aSyncLoad,
137 PRBool aAllowUnsafeRules,
138 nsICSSLoaderObserver* aObserver,
139 nsIPrincipal* aLoaderPrincipal);
141 already_AddRefed<nsIURI> GetReferrerURI();
143 NS_DECL_ISUPPORTS
144 NS_DECL_NSIRUNNABLE
145 NS_DECL_NSIUNICHARSTREAMLOADEROBSERVER
147 // Hold a ref to the CSSLoader so we can call back to it to let it
148 // know the load finished
149 CSSLoaderImpl* mLoader; // strong ref
151 // Title needed to pull datas out of the pending datas table when
152 // the preferred title is changed
153 nsString mTitle;
155 // Charset we decided to use for the sheet
156 nsCString mCharset;
158 // URI we're loading. Null for inline sheets
159 nsCOMPtr<nsIURI> mURI;
161 // Should be 1 for non-inline sheets.
162 PRUint32 mLineNumber;
164 // The sheet we're loading data for
165 nsCOMPtr<nsICSSStyleSheet> mSheet;
167 // Linked list of datas for the same URI as us
168 SheetLoadData* mNext; // strong ref
170 // Load data for the sheet that @import-ed us if we were @import-ed
171 // during the parse
172 SheetLoadData* mParentData; // strong ref
174 // Number of sheets we @import-ed that are still loading
175 PRUint32 mPendingChildren;
177 // mSyncLoad is true when the load needs to be synchronous -- right
178 // now only for LoadSheetSync and children of sync loads.
179 PRPackedBool mSyncLoad : 1;
181 // mIsNonDocumentSheet is true if the load was triggered by LoadSheetSync or
182 // LoadSheet or an @import from such a sheet. Non-document sheet loads can
183 // proceed even if we have no document.
184 PRPackedBool mIsNonDocumentSheet : 1;
186 // mIsLoading is true from the moment we are placed in the loader's
187 // "loading datas" table (right after the async channel is opened)
188 // to the moment we are removed from said table (due to the load
189 // completing or being cancelled).
190 PRPackedBool mIsLoading : 1;
192 // mIsCancelled is set to true when a sheet load is stopped by
193 // Stop() or StopLoadingSheet(). SheetLoadData::OnStreamComplete()
194 // checks this to avoid parsing sheets that have been cancelled and
195 // such.
196 PRPackedBool mIsCancelled : 1;
198 // mMustNotify is true if the load data is being loaded async and
199 // the original function call that started the load has returned.
200 // XXXbz sort our relationship with load/error events!
201 PRPackedBool mMustNotify : 1;
203 // mWasAlternate is true if the sheet was an alternate when the load data was
204 // created.
205 PRPackedBool mWasAlternate : 1;
207 // mAllowUnsafeRules is true if we should allow unsafe rules to be parsed
208 // in the loaded sheet.
209 PRPackedBool mAllowUnsafeRules : 1;
211 // This is the element that imported the sheet. Needed to get the
212 // charset set on it.
213 nsCOMPtr<nsIStyleSheetLinkingElement> mOwningElement;
215 // The observer that wishes to be notified of load completion
216 nsCOMPtr<nsICSSLoaderObserver> mObserver;
218 // The principal that identifies who started loading us.
219 nsCOMPtr<nsIPrincipal> mLoaderPrincipal;
222 class nsURIAndPrincipalHashKey : public nsURIHashKey
224 public:
225 typedef nsURIAndPrincipalHashKey* KeyType;
226 typedef const nsURIAndPrincipalHashKey* KeyTypePointer;
228 nsURIAndPrincipalHashKey(const nsURIAndPrincipalHashKey* aKey)
229 : nsURIHashKey(aKey->mKey), mPrincipal(aKey->mPrincipal)
231 MOZ_COUNT_CTOR(nsURIAndPrincipalHashKey);
233 nsURIAndPrincipalHashKey(nsIURI* aURI, nsIPrincipal* aPrincipal)
234 : nsURIHashKey(aURI), mPrincipal(aPrincipal)
236 MOZ_COUNT_CTOR(nsURIAndPrincipalHashKey);
238 nsURIAndPrincipalHashKey(const nsURIAndPrincipalHashKey& toCopy)
239 : nsURIHashKey(toCopy), mPrincipal(toCopy.mPrincipal)
241 MOZ_COUNT_CTOR(nsURIAndPrincipalHashKey);
243 ~nsURIAndPrincipalHashKey()
245 MOZ_COUNT_DTOR(nsURIAndPrincipalHashKey);
248 nsURIAndPrincipalHashKey* GetKey() const {
249 return const_cast<nsURIAndPrincipalHashKey*>(this);
251 const nsURIAndPrincipalHashKey* GetKeyPointer() const { return this; }
253 PRBool KeyEquals(const nsURIAndPrincipalHashKey* aKey) const {
254 if (!nsURIHashKey::KeyEquals(aKey->mKey)) {
255 return PR_FALSE;
258 if (!mPrincipal != !aKey->mPrincipal) {
259 // One or the other has a principal, but not both... not equal
260 return PR_FALSE;
263 PRBool eq;
264 return !mPrincipal ||
265 NS_SUCCEEDED(mPrincipal->Equals(aKey->mPrincipal, &eq)) && eq;
268 static const nsURIAndPrincipalHashKey*
269 KeyToPointer(nsURIAndPrincipalHashKey* aKey) { return aKey; }
270 static PLDHashNumber HashKey(const nsURIAndPrincipalHashKey* aKey) {
271 return nsURIHashKey::HashKey(aKey->mKey);
274 enum { ALLOW_MEMMOVE = PR_TRUE };
276 protected:
277 nsCOMPtr<nsIPrincipal> mPrincipal;
280 /***********************************************************************
281 * Enum that describes the state of the sheet returned by CreateSheet. *
282 ***********************************************************************/
283 enum StyleSheetState {
284 eSheetStateUnknown = 0,
285 eSheetNeedsParser,
286 eSheetPending,
287 eSheetLoading,
288 eSheetComplete
292 /**********************
293 * Loader Declaration *
294 **********************/
296 class CSSLoaderImpl : public nsICSSLoader
298 public:
299 CSSLoaderImpl(void);
300 virtual ~CSSLoaderImpl(void);
302 NS_DECL_ISUPPORTS
304 static void Shutdown(); // called at app shutdown
306 // nsICSSLoader methods
307 NS_IMETHOD Init(nsIDocument* aDocument);
308 NS_IMETHOD DropDocumentReference(void);
310 NS_IMETHOD SetCaseSensitive(PRBool aCaseSensitive);
311 NS_IMETHOD SetCompatibilityMode(nsCompatibility aCompatMode);
312 NS_IMETHOD SetPreferredSheet(const nsAString& aTitle);
313 NS_IMETHOD GetPreferredSheet(nsAString& aTitle);
315 NS_IMETHOD GetParserFor(nsICSSStyleSheet* aSheet,
316 nsICSSParser** aParser);
317 NS_IMETHOD RecycleParser(nsICSSParser* aParser);
319 NS_IMETHOD LoadInlineStyle(nsIContent* aElement,
320 nsIUnicharInputStream* aStream,
321 PRUint32 aLineNumber,
322 const nsSubstring& aTitle,
323 const nsSubstring& aMedia,
324 nsICSSLoaderObserver* aObserver,
325 PRBool* aCompleted,
326 PRBool* aIsAlternate);
328 NS_IMETHOD LoadStyleLink(nsIContent* aElement,
329 nsIURI* aURL,
330 const nsSubstring& aTitle,
331 const nsSubstring& aMedia,
332 PRBool aHasAlternateRel,
333 nsICSSLoaderObserver* aObserver,
334 PRBool* aIsAlternate);
336 NS_IMETHOD LoadChildSheet(nsICSSStyleSheet* aParentSheet,
337 nsIURI* aURL,
338 nsMediaList* aMedia,
339 nsICSSImportRule* aRule);
341 NS_IMETHOD LoadSheetSync(nsIURI* aURL, PRBool aAllowUnsafeRules,
342 nsICSSStyleSheet** aSheet);
344 NS_IMETHOD LoadSheet(nsIURI* aURL,
345 nsIPrincipal* aOriginPrincipal,
346 nsICSSLoaderObserver* aObserver,
347 nsICSSStyleSheet** aSheet);
349 NS_IMETHOD LoadSheet(nsIURI* aURL,
350 nsIPrincipal* aOriginPrincipal,
351 nsICSSLoaderObserver* aObserver);
353 // stop loading all sheets
354 NS_IMETHOD Stop(void);
356 // stop loading one sheet
357 NS_IMETHOD StopLoadingSheet(nsIURI* aURL);
360 * Is the loader enabled or not.
361 * When disabled, processing of new styles is disabled and an attempt
362 * to do so will fail with a return code of
363 * NS_ERROR_NOT_AVAILABLE. Note that this DOES NOT disable
364 * currently loading styles or already processed styles.
366 NS_IMETHOD GetEnabled(PRBool *aEnabled);
367 NS_IMETHOD SetEnabled(PRBool aEnabled);
369 NS_IMETHOD_(PRBool) HasPendingLoads();
370 NS_IMETHOD AddObserver(nsICSSLoaderObserver* aObserver);
371 NS_IMETHOD_(void) RemoveObserver(nsICSSLoaderObserver* aObserver);
373 // local helper methods (some are public for access from statics)
375 // IsAlternate can change our currently selected style set if none
376 // is selected and aHasAlternateRel is false.
377 PRBool IsAlternate(const nsAString& aTitle, PRBool aHasAlternateRel);
379 private:
380 // Note: null aSourcePrincipal indicates that the content policy and
381 // CheckLoadURI checks should be skipped.
382 nsresult CheckLoadAllowed(nsIPrincipal* aSourcePrincipal,
383 nsIURI* aTargetURI,
384 nsISupports* aContext);
387 // For inline style, the aURI param is null, but the aLinkingContent
388 // must be non-null then. The loader principal must never be null
389 // if aURI is not null.
390 nsresult CreateSheet(nsIURI* aURI,
391 nsIContent* aLinkingContent,
392 nsIPrincipal* aLoaderPrincipal,
393 PRBool aSyncLoad,
394 StyleSheetState& aSheetState,
395 nsICSSStyleSheet** aSheet);
397 // Pass in either a media string or the nsMediaList from the
398 // CSSParser. Don't pass both.
399 // If aIsAlternate is non-null, this method will set *aIsAlternate to
400 // correspond to the sheet's enabled state (which it will set no matter what)
401 nsresult PrepareSheet(nsICSSStyleSheet* aSheet,
402 const nsSubstring& aTitle,
403 const nsSubstring& aMediaString,
404 nsMediaList* aMediaList,
405 PRBool aHasAlternateRel = PR_FALSE,
406 PRBool *aIsAlternate = nsnull);
408 nsresult InsertSheetInDoc(nsICSSStyleSheet* aSheet,
409 nsIContent* aLinkingContent,
410 nsIDocument* aDocument);
412 nsresult InsertChildSheet(nsICSSStyleSheet* aSheet,
413 nsICSSStyleSheet* aParentSheet,
414 nsICSSImportRule* aParentRule);
416 nsresult InternalLoadNonDocumentSheet(nsIURI* aURL,
417 PRBool aAllowUnsafeRules,
418 nsIPrincipal* aOriginPrincipal,
419 nsICSSStyleSheet** aSheet,
420 nsICSSLoaderObserver* aObserver);
422 // Post a load event for aObserver to be notified about aSheet. The
423 // notification will be sent with status NS_OK unless the load event is
424 // canceled at some point (in which case it will be sent with
425 // NS_BINDING_ABORTED). aWasAlternate indicates the state when the load was
426 // initiated, not the state at some later time. aURI should be the URI the
427 // sheet was loaded from (may be null for inline sheets).
428 nsresult PostLoadEvent(nsIURI* aURI,
429 nsICSSStyleSheet* aSheet,
430 nsICSSLoaderObserver* aObserver,
431 PRBool aWasAlternate);
433 // Start the loads of all the sheets in mPendingDatas
434 void StartAlternateLoads();
436 public:
437 // Handle an event posted by PostLoadEvent
438 void HandleLoadEvent(SheetLoadData* aEvent);
440 protected:
441 // Note: LoadSheet is responsible for releasing aLoadData and setting the
442 // sheet to complete on failure.
443 nsresult LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState);
445 friend class SheetLoadData;
447 // Protected functions and members are ones that SheetLoadData needs
448 // access to.
450 // Parse the stylesheet in aLoadData. The sheet data comes from aStream.
451 // Set aCompleted to true if the parse finished, false otherwise (e.g. if the
452 // sheet had an @import). If aCompleted is true when this returns, then
453 // ParseSheet also called SheetComplete on aLoadData
454 nsresult ParseSheet(nsIUnicharInputStream* aStream,
455 SheetLoadData* aLoadData,
456 PRBool& aCompleted);
458 // The load of the sheet in aLoadData is done, one way or another. Do final
459 // cleanup, including releasing aLoadData.
460 void SheetComplete(SheetLoadData* aLoadData, nsresult aStatus);
462 public:
463 typedef nsTArray<nsRefPtr<SheetLoadData> > LoadDataArray;
465 private:
466 // The guts of SheetComplete. This may be called recursively on parent datas
467 // or datas that had glommed on to a single load. The array is there so load
468 // datas whose observers need to be notified can be added to it.
469 void DoSheetComplete(SheetLoadData* aLoadData, nsresult aStatus,
470 LoadDataArray& aDatasToNotify);
472 static nsCOMArray<nsICSSParser>* gParsers; // array of idle CSS parsers
474 // the load data needs access to the document...
475 nsIDocument* mDocument; // the document we live for
477 #ifdef DEBUG
478 PRPackedBool mSyncCallback;
479 #endif
481 PRPackedBool mCaseSensitive; // is document CSS case sensitive
482 PRPackedBool mEnabled; // is enabled to load new styles
483 nsCompatibility mCompatMode;
484 nsString mPreferredSheet; // title of preferred sheet
486 nsInterfaceHashtable<nsURIAndPrincipalHashKey,
487 nsICSSStyleSheet> mCompleteSheets;
488 nsDataHashtable<nsURIAndPrincipalHashKey,
489 SheetLoadData*> mLoadingDatas; // weak refs
490 nsDataHashtable<nsURIAndPrincipalHashKey,
491 SheetLoadData*> mPendingDatas; // weak refs
493 // We're not likely to have many levels of @import... But likely to have
494 // some. Allocate some storage, what the hell.
495 nsAutoVoidArray mParsingDatas;
497 // The array of posted stylesheet loaded events (SheetLoadDatas) we have.
498 // Note that these are rare.
499 LoadDataArray mPostedEvents;
501 // Number of datas still waiting to be notified on if we're notifying on a
502 // whole bunch at once (e.g. in one of the stop methods). This is used to
503 // make sure that HasPendingLoads() won't return false until we're notifying
504 // on the last data we're working with.
505 PRUint32 mDatasToNotifyOn;
507 // Our array of "global" observers
508 nsTObserverArray<nsCOMPtr<nsICSSLoaderObserver> > mObservers;
511 #endif // nsCSSLoader_h__