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
4 : *
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/
9 : *
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.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Daniel Glazman <glazman@netscape.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : /*
40 : * representation of a declaration block (or style attribute) in a CSS
41 : * stylesheet
42 : */
43 :
44 : #ifndef mozilla_css_Declaration_h
45 : #define mozilla_css_Declaration_h
46 :
47 : #include "mozilla/Attributes.h"
48 :
49 : // This header is in EXPORTS because it's used in several places in content/,
50 : // but it's not really a public interface.
51 : #ifndef _IMPL_NS_LAYOUT
52 : #error "This file should only be included within the layout library"
53 : #endif
54 :
55 : #include "nsCSSDataBlock.h"
56 : #include "nsCSSProperty.h"
57 : #include "nsCSSProps.h"
58 : #include "nsStringFwd.h"
59 : #include "nsTArray.h"
60 : #include <stdio.h>
61 :
62 : namespace mozilla {
63 : namespace css {
64 :
65 : // Declaration objects have unusual lifetime rules. Every declaration
66 : // begins life in an invalid state which ends when InitializeEmpty or
67 : // CompressFrom is called upon it. After that, it can be attached to
68 : // exactly one style rule, and will be destroyed when that style rule
69 : // is destroyed. A declaration becomes immutable when its style rule's
70 : // |RuleMatched| method is called; after that, it must be copied before
71 : // it can be modified, which is taken care of by |EnsureMutable|.
72 :
73 : class Declaration {
74 : public:
75 : /**
76 : * Construct an |Declaration| that is in an invalid state (null
77 : * |mData|) and cannot be used until its |CompressFrom| method or
78 : * |InitializeEmpty| method is called.
79 : */
80 : Declaration();
81 :
82 : Declaration(const Declaration& aCopy);
83 :
84 : ~Declaration();
85 :
86 : /**
87 : * |ValueAppended| must be called to maintain this declaration's
88 : * |mOrder| whenever a property is parsed into an expanded data block
89 : * for this declaration. aProperty must not be a shorthand.
90 : */
91 : void ValueAppended(nsCSSProperty aProperty);
92 :
93 : void RemoveProperty(nsCSSProperty aProperty);
94 :
95 : bool HasProperty(nsCSSProperty aProperty) const;
96 :
97 : void GetValue(nsCSSProperty aProperty, nsAString& aValue) const;
98 :
99 0 : bool HasImportantData() const { return mImportantData != nsnull; }
100 : bool GetValueIsImportant(nsCSSProperty aProperty) const;
101 : bool GetValueIsImportant(const nsAString& aProperty) const;
102 :
103 0 : PRUint32 Count() const {
104 0 : return mOrder.Length();
105 : }
106 : void GetNthProperty(PRUint32 aIndex, nsAString& aReturn) const;
107 :
108 : void ToString(nsAString& aString) const;
109 :
110 0 : nsCSSCompressedDataBlock* GetNormalBlock() const { return mData; }
111 : nsCSSCompressedDataBlock* GetImportantBlock() const { return mImportantData; }
112 :
113 : /**
114 : * Initialize this declaration as holding no data. Cannot fail.
115 : */
116 : void InitializeEmpty();
117 :
118 : /**
119 : * Transfer all of the state from |aExpandedData| into this declaration.
120 : * After calling, |aExpandedData| should be in its initial state.
121 : * Callers must make sure mOrder is updated as necessary.
122 : */
123 0 : void CompressFrom(nsCSSExpandedDataBlock *aExpandedData) {
124 0 : NS_ABORT_IF_FALSE(!mData, "oops");
125 0 : NS_ABORT_IF_FALSE(!mImportantData, "oops");
126 0 : aExpandedData->Compress(getter_Transfers(mData),
127 0 : getter_Transfers(mImportantData));
128 0 : aExpandedData->AssertInitialState();
129 0 : }
130 :
131 : /**
132 : * Transfer all of the state from this declaration into
133 : * |aExpandedData| and put this declaration temporarily into an
134 : * invalid state (ended by |CompressFrom| or |InitializeEmpty|) that
135 : * should last only during parsing. During this time only
136 : * |ValueAppended| should be called.
137 : */
138 0 : void ExpandTo(nsCSSExpandedDataBlock *aExpandedData) {
139 0 : AssertMutable();
140 0 : aExpandedData->AssertInitialState();
141 :
142 0 : NS_ABORT_IF_FALSE(mData, "oops");
143 0 : aExpandedData->Expand(mData.forget(), mImportantData.forget());
144 0 : }
145 :
146 : /**
147 : * Do what |nsIStyleRule::MapRuleInfoInto| needs to do for a style
148 : * rule using this declaration for storage.
149 : */
150 0 : void MapNormalRuleInfoInto(nsRuleData *aRuleData) const {
151 0 : NS_ABORT_IF_FALSE(mData, "called while expanded");
152 0 : mData->MapRuleInfoInto(aRuleData);
153 0 : }
154 0 : void MapImportantRuleInfoInto(nsRuleData *aRuleData) const {
155 0 : NS_ABORT_IF_FALSE(mData, "called while expanded");
156 0 : NS_ABORT_IF_FALSE(mImportantData, "must have important data");
157 0 : mImportantData->MapRuleInfoInto(aRuleData);
158 0 : }
159 :
160 : /**
161 : * Attempt to replace the value for |aProperty| stored in this
162 : * declaration with the matching value from |aFromBlock|.
163 : * This method may only be called on a mutable declaration.
164 : * It will fail (returning false) if |aProperty| is shorthand,
165 : * is not already in this declaration, or does not have the indicated
166 : * importance level. If it returns true, it erases the value in
167 : * |aFromBlock|. |aChanged| is set to true if the declaration
168 : * changed as a result of the call, and to false otherwise.
169 : */
170 : bool TryReplaceValue(nsCSSProperty aProperty, bool aIsImportant,
171 : nsCSSExpandedDataBlock& aFromBlock,
172 : bool* aChanged)
173 : {
174 : AssertMutable();
175 : NS_ABORT_IF_FALSE(mData, "called while expanded");
176 :
177 : if (nsCSSProps::IsShorthand(aProperty)) {
178 : *aChanged = false;
179 : return false;
180 : }
181 : nsCSSCompressedDataBlock *block = aIsImportant ? mImportantData : mData;
182 : // mImportantData might be null
183 : if (!block) {
184 : *aChanged = false;
185 : return false;
186 : }
187 :
188 : #ifdef DEBUG
189 : {
190 : nsCSSCompressedDataBlock *other = aIsImportant ? mData : mImportantData;
191 : NS_ABORT_IF_FALSE(!other || !other->ValueFor(aProperty) ||
192 : !block->ValueFor(aProperty),
193 : "Property both important and not?");
194 : }
195 : #endif
196 : return block->TryReplaceValue(aProperty, aFromBlock, aChanged);
197 : }
198 :
199 0 : bool HasNonImportantValueFor(nsCSSProperty aProperty) const {
200 0 : NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(aProperty), "must be longhand");
201 0 : return !!mData->ValueFor(aProperty);
202 : }
203 :
204 : /**
205 : * Return whether |this| may be modified.
206 : */
207 0 : bool IsMutable() const {
208 0 : return !mImmutable;
209 : }
210 :
211 : /**
212 : * Copy |this|, if necessary to ensure that it can be modified.
213 : */
214 : Declaration* EnsureMutable();
215 :
216 : /**
217 : * Crash if |this| cannot be modified.
218 : */
219 0 : void AssertMutable() const {
220 0 : NS_ABORT_IF_FALSE(IsMutable(), "someone forgot to call EnsureMutable");
221 0 : }
222 :
223 : /**
224 : * Mark this declaration as unmodifiable. It's 'const' so it can
225 : * be called from ToString.
226 : */
227 0 : void SetImmutable() const { mImmutable = true; }
228 :
229 : /**
230 : * Clear the data, in preparation for its replacement with entirely
231 : * new data by a call to |CompressFrom|.
232 : */
233 : void ClearData() {
234 : AssertMutable();
235 : mData = nsnull;
236 : mImportantData = nsnull;
237 : mOrder.Clear();
238 : }
239 :
240 : #ifdef DEBUG
241 : void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
242 : #endif
243 :
244 : private:
245 : Declaration& operator=(const Declaration& aCopy) MOZ_DELETE;
246 : bool operator==(const Declaration& aCopy) const MOZ_DELETE;
247 :
248 : static void AppendImportanceToString(bool aIsImportant, nsAString& aString);
249 : // return whether there was a value in |aValue| (i.e., it had a non-null unit)
250 : bool AppendValueToString(nsCSSProperty aProperty, nsAString& aResult) const;
251 : // Helper for ToString with strange semantics regarding aValue.
252 : void AppendPropertyAndValueToString(nsCSSProperty aProperty,
253 : nsAutoString& aValue,
254 : nsAString& aResult) const;
255 :
256 : public:
257 0 : nsCSSProperty OrderValueAt(PRUint32 aValue) const {
258 0 : return nsCSSProperty(mOrder.ElementAt(aValue));
259 : }
260 :
261 : size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
262 :
263 : private:
264 : nsAutoTArray<PRUint8, 8> mOrder;
265 :
266 : // never null, except while expanded, or before the first call to
267 : // InitializeEmpty or CompressFrom.
268 : nsAutoPtr<nsCSSCompressedDataBlock> mData;
269 :
270 : // may be null
271 : nsAutoPtr<nsCSSCompressedDataBlock> mImportantData;
272 :
273 : // set by style rules when |RuleMatched| is called;
274 : // also by ToString (hence the 'mutable').
275 : mutable bool mImmutable;
276 : };
277 :
278 : } // namespace css
279 : } // namespace mozilla
280 :
281 : #endif /* mozilla_css_Declaration_h */
|