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
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.
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__
56 class nsICSSStyleSheet
;
57 class nsIStyleSheetLinkingElement
;
58 class nsICSSLoaderObserver
;
60 class nsICSSImportRule
;
63 #include "nsICSSLoader.h"
64 #include "nsIRunnable.h"
65 #include "nsIUnicharStreamLoader.h"
67 #include "nsCOMArray.h"
69 #include "nsURIHashKey.h"
70 #include "nsInterfaceHashtable.h"
71 #include "nsDataHashtable.h"
72 #include "nsAutoPtr.h"
74 #include "nsIPrincipal.h"
75 #include "nsTObserverArray.h"
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
105 /*********************************************
106 * Data needed to properly load a stylesheet *
107 *********************************************/
109 class SheetLoadData
: public nsIRunnable
,
110 public nsIUnicharStreamLoaderObserver
113 virtual ~SheetLoadData(void);
114 // Data for loading a sheet linked from a document
115 SheetLoadData(CSSLoaderImpl
* aLoader
,
116 const nsSubstring
& aTitle
,
118 nsICSSStyleSheet
* aSheet
,
119 nsIStyleSheetLinkingElement
* aOwningElement
,
121 nsICSSLoaderObserver
* aObserver
,
122 nsIPrincipal
* aLoaderPrincipal
);
124 // Data for loading a sheet linked from an @import rule
125 SheetLoadData(CSSLoaderImpl
* aLoader
,
127 nsICSSStyleSheet
* aSheet
,
128 SheetLoadData
* aParentData
,
129 nsICSSLoaderObserver
* aObserver
,
130 nsIPrincipal
* aLoaderPrincipal
);
132 // Data for loading a non-document sheet
133 SheetLoadData(CSSLoaderImpl
* aLoader
,
135 nsICSSStyleSheet
* aSheet
,
137 PRBool aAllowUnsafeRules
,
138 nsICSSLoaderObserver
* aObserver
,
139 nsIPrincipal
* aLoaderPrincipal
);
141 already_AddRefed
<nsIURI
> GetReferrerURI();
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
155 // Charset we decided to use for the sheet
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
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
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
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
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
)) {
258 if (!mPrincipal
!= !aKey
->mPrincipal
) {
259 // One or the other has a principal, but not both... not equal
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
};
277 nsCOMPtr
<nsIPrincipal
> mPrincipal
;
280 /***********************************************************************
281 * Enum that describes the state of the sheet returned by CreateSheet. *
282 ***********************************************************************/
283 enum StyleSheetState
{
284 eSheetStateUnknown
= 0,
292 /**********************
293 * Loader Declaration *
294 **********************/
296 class CSSLoaderImpl
: public nsICSSLoader
300 virtual ~CSSLoaderImpl(void);
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
,
326 PRBool
* aIsAlternate
);
328 NS_IMETHOD
LoadStyleLink(nsIContent
* aElement
,
330 const nsSubstring
& aTitle
,
331 const nsSubstring
& aMedia
,
332 PRBool aHasAlternateRel
,
333 nsICSSLoaderObserver
* aObserver
,
334 PRBool
* aIsAlternate
);
336 NS_IMETHOD
LoadChildSheet(nsICSSStyleSheet
* aParentSheet
,
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
);
380 // Note: null aSourcePrincipal indicates that the content policy and
381 // CheckLoadURI checks should be skipped.
382 nsresult
CheckLoadAllowed(nsIPrincipal
* aSourcePrincipal
,
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
,
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();
437 // Handle an event posted by PostLoadEvent
438 void HandleLoadEvent(SheetLoadData
* aEvent
);
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
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
,
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
);
463 typedef nsTArray
<nsRefPtr
<SheetLoadData
> > LoadDataArray
;
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
478 PRPackedBool mSyncCallback
;
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__