|
1 <!-- This Source Code Form is subject to the terms of the Mozilla Public |
|
2 - License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> |
|
4 |
|
5 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head> |
|
6 <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"> |
|
7 <meta name="author" content="Marc Attinasi"><title>Adding a new style property - layout cookbook</title></head> |
|
8 |
|
9 <body> |
|
10 <h1>Adding a new style property</h1> |
|
11 <blockquote> |
|
12 <h4>Document history:</h4> |
|
13 <ul> |
|
14 <li>03/21/2002: Marc Attinasi (attinasi@netscape.com) created document |
|
15 / implementing -moz-force-broken-image-icon for bug <a href="http://bugzilla.mozilla.org/show_bug.cgi?id=58646"> |
|
16 58646</a></li> |
|
17 <li> |
|
18 6/18/2002: David Baron (dbaron@dbaron.org): corrected support |
|
19 for 'inherit' and 'initial' (didn't test with code, though), |
|
20 and explained what the final boolean in CheckPropertyData is for. |
|
21 </li> |
|
22 <li> |
|
23 11/09/2002: Christopher Aillon (caillon@returnzero.com): updated |
|
24 nsCSSPropList.h macro description and added information about |
|
25 nsIDOMCSS2Properties.idl. |
|
26 </li> |
|
27 </ul> |
|
28 <p> |
|
29 <b>NOTE</b>: This document is still missing a few pieces. I need to |
|
30 add information on adding to <code>nsComputedDOMStyle</code>. |
|
31 </p> |
|
32 </blockquote> |
|
33 <h2>Overview</h2> |
|
34 When a new style property is needed there are many places in the code that |
|
35 need to be updated. This document outlines the procedure used to add a new |
|
36 property, in this case the property is a proprietary one called '-moz-force-broken-image-icons' |
|
37 and is used as a way for a stylesheet to force broken image icons to be displayed. |
|
38 This is all being done in the context of <a href="http://bugzilla.mozilla.org/show_bug.cgi?id=58646"> |
|
39 bug 58646</a>. |
|
40 |
|
41 <h2>Analysis</h2> |
|
42 <p>Up front you have to decide some things about the new property:</p> |
|
43 |
|
44 <p><b>Questions:</b></p> |
|
45 <ol> |
|
46 <li>Is the property proprietary or specified by the CSS standard?</li> |
|
47 <li>Is the property inherited?</li> |
|
48 <li>What types of values can the property have?</li> |
|
49 <li>Does it logically fit with other existing properties?</li> |
|
50 <li>What is the impact to the layout of a page if that property changes?</li> |
|
51 <li>What do you want to name it?</li> |
|
52 </ol> |
|
53 <p><b>Answers:</b></p> |
|
54 <ol> |
|
55 <li>In our specific case, we want a property that is used internally, |
|
56 so it is a proprietary property.</li> |
|
57 <li>The property is to be used for images, which are leaf elements, so |
|
58 there is no need to inherit it.</li> |
|
59 <li>The property is used simply to force a broken image to be represented |
|
60 by an icon, so it only supports the values '0' and '1' as numerics. </li> |
|
61 <li>It is hard to see how this property fits logically in with other |
|
62 properties, but if we stretch our imaginations we could say that it is a |
|
63 sort of UI property.</li> |
|
64 <li>If this property changes, the image frame has to be recreated. This |
|
65 is because the decision about whether to display the icon or not will impact |
|
66 the decision to replace the image frame with an inline text frame for the |
|
67 ALT text, so if the ALT text inline is already made, there is no image frame |
|
68 left around to reflow or otherwise modify.</li> |
|
69 <li>Finally, the name will be '-moz-force-broken-image-icons' - that |
|
70 should be pretty self-describing (by convention we start proprietary property |
|
71 names with '-moz-').</li> |
|
72 </ol> |
|
73 <h2>Implementation</h2> |
|
74 |
|
75 <p>There are several places that need to be educated about a new style property. |
|
76 They are: |
|
77 </p> |
|
78 <ul> |
|
79 <li><a href="#CSSPropList">CSS Property Names and Hint Tables</a>: the new |
|
80 property name must be made formally know to the system</li> |
|
81 <li><a href="#CSSDeclaration">CSS Declaration</a>: the declaration must be |
|
82 able to hold the property and its value(s)</li> |
|
83 <li><a href="#Parser">CSS Parser</a>: the parser must be able to parse the |
|
84 property name, validate the values, and provide a declaration for the property |
|
85 and value</li> |
|
86 <li><a href="#StyleContext">Style Context</a>: the StyleContext must be able |
|
87 to hold the resolved value of the property, and provide a means to retrieve the |
|
88 property value. Additionally, the StyleContext has to know what kind of impact a |
|
89 change to this property causes.</li> |
|
90 <li><a href="#RuleNode">Rule Nodes</a>: the RuleNodes need to know how the |
|
91 property is inherited and how it is shared by other elements.</li> |
|
92 <li><a href="#DOM">DOM</a>: Your style should be accessible from the DOM so |
|
93 users may dynamically set/get its property value.</li> |
|
94 <li><a href="#Layout">Layout</a>: layout has to know what to do with the |
|
95 property, in other words, the meaning of the property.</li> |
|
96 </ul> |
|
97 <h3><a name="CSSPropList">CSS Property Name / Constants / Hints</a></h3> |
|
98 |
|
99 <p> |
|
100 First, add the new name to the property list in <a href="http://lxr.mozilla.org/seamonkey/source/content/shared/public/nsCSSPropList.h"> |
|
101 nsCSSPropList.h</a> |
|
102 Insert the property in the list alphabetically, using the existing |
|
103 property names as a template. The format of the entry you will create is: |
|
104 </p> |
|
105 <pre>CSS_PROP(-moz-force-broken-image-icons, force_broken_image_icons, MozForceBrokenImageIcons, NS_STYLE_HINT_FRAMECHANGE) // bug 58646</pre> |
|
106 |
|
107 <p>The first value is the formal property name, in other words the property |
|
108 name as it is seen by the CSS parser.<br> |
|
109 The second value is the name of the property as it will appear internally.<br> |
|
110 The third value is the name of the DOM property used to access your style.<br> |
|
111 The last value indicates what must change when the value of the property |
|
112 changes. It should be an |
|
113 <a href="http://lxr.mozilla.org/seamonkey/source/content/shared/public/nsChangeHint.h">nsChangeHint</a>.</p> |
|
114 |
|
115 <p>If you need to introduce new constants for the values of the property, they |
|
116 must be added to <a href="http://lxr.mozilla.org/seamonkey/source/layout/base/public/nsStyleConsts.h"> |
|
117 nsStyleConsts.h</a> |
|
118 and to the appropriate keyword tables in <a href="http://lxr.mozilla.org/seamonkey/source/content/shared/src/nsCSSProps.cpp"> |
|
119 nsCSSProps.cpp</a> |
|
120 (note: this cookbook does not do this since the new property does not require |
|
121 any new keywords for the property values). |
|
122 <h3><a name="CSSDeclaration">CSS Declaration</a></h3> |
|
123 Changes will need to be made to the structs and classes defined in <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSDeclaration.h"> |
|
124 nsCSSDeclaration.h </a> |
|
125 and <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSDeclaration.cpp"> |
|
126 nsCSSDeclaration.cpp</a> |
|
127 <br> |
|
128 <br> |
|
129 First, find the declaration of the struct that will hold the new property |
|
130 value (in the header file). For this example it is the struct <b>nsCSSUserInterface</b> |
|
131 . Modify the struct declaration to include a new data member for the new |
|
132 property, of the type CSSValue. Next, open the implementation file (the cpp) |
|
133 and modify the struct's constructors. <br> |
|
134 <br> |
|
135 Next, the <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSDeclaration.cpp#1410"> |
|
136 AppendValue</a> |
|
137 method must be updated to support your new property. The CSSParser will |
|
138 call this to build up a declaration. Find the portion of that method that |
|
139 deals with the other properties in the struct that you are adding your property |
|
140 to (or create a new section if you are creating a new style struct). For |
|
141 this example we will find the 'UserInterface' section and add our new property |
|
142 <a href="#AppendValueCase">there</a> |
|
143 .<br> |
|
144 <pre> // nsCSSUserInterface |
|
145 case eCSSProperty_user_input: |
|
146 case eCSSProperty_user_modify: |
|
147 case eCSSProperty_user_select: |
|
148 case eCSSProperty_key_equivalent: |
|
149 case eCSSProperty_user_focus: |
|
150 case eCSSProperty_resizer: |
|
151 case eCSSProperty_cursor: |
|
152 case eCSSProperty_force_broken_image_icons: { |
|
153 CSS_ENSURE(UserInterface) { |
|
154 switch (aProperty) { |
|
155 case eCSSProperty_user_input: theUserInterface->mUserInput = aValue; break; |
|
156 case eCSSProperty_user_modify: theUserInterface->mUserModify = aValue; break; |
|
157 case eCSSProperty_user_select: theUserInterface->mUserSelect = aValue; break; |
|
158 case eCSSProperty_key_equivalent: |
|
159 CSS_ENSURE_DATA(theUserInterface->mKeyEquivalent, nsCSSValueList) { |
|
160 theUserInterface->mKeyEquivalent->mValue = aValue; |
|
161 CSS_IF_DELETE(theUserInterface->mKeyEquivalent->mNext); |
|
162 } |
|
163 break; |
|
164 case eCSSProperty_user_focus: theUserInterface->mUserFocus = aValue; break; |
|
165 case eCSSProperty_resizer: theUserInterface->mResizer = aValue; break; |
|
166 case eCSSProperty_cursor: |
|
167 CSS_ENSURE_DATA(theUserInterface->mCursor, nsCSSValueList) { |
|
168 theUserInterface->mCursor->mValue = aValue; |
|
169 CSS_IF_DELETE(theUserInterface->mCursor->mNext); |
|
170 } |
|
171 break; |
|
172 <b> <a name="AppendValueCase"></a>case eCSSProperty_force_broken_image_icons: theUserInterface->mForceBrokenImageIcon = aValue; break; |
|
173 </b> |
|
174 CSS_BOGUS_DEFAULT; // make compiler happy |
|
175 } |
|
176 } |
|
177 break; |
|
178 } |
|
179 |
|
180 </pre> |
|
181 The GetValue method must be similarly <a href="#GetValueCase">modified</a> |
|
182 :<br> |
|
183 <pre> // nsCSSUserInterface |
|
184 case eCSSProperty_user_input: |
|
185 case eCSSProperty_user_modify: |
|
186 case eCSSProperty_user_select: |
|
187 case eCSSProperty_key_equivalent: |
|
188 case eCSSProperty_user_focus: |
|
189 case eCSSProperty_resizer: |
|
190 case eCSSProperty_cursor: |
|
191 case eCSSProperty_force_broken_image_icons: { |
|
192 CSS_VARONSTACK_GET(UserInterface); |
|
193 if (nullptr != theUserInterface) { |
|
194 switch (aProperty) { |
|
195 case eCSSProperty_user_input: aValue = theUserInterface->mUserInput; break; |
|
196 case eCSSProperty_user_modify: aValue = theUserInterface->mUserModify; break; |
|
197 case eCSSProperty_user_select: aValue = theUserInterface->mUserSelect; break; |
|
198 case eCSSProperty_key_equivalent: |
|
199 if (nullptr != theUserInterface->mKeyEquivalent) { |
|
200 aValue = theUserInterface->mKeyEquivalent->mValue; |
|
201 } |
|
202 break; |
|
203 case eCSSProperty_user_focus: aValue = theUserInterface->mUserFocus; break; |
|
204 case eCSSProperty_resizer: aValue = theUserInterface->mResizer; break; |
|
205 case eCSSProperty_cursor: |
|
206 if (nullptr != theUserInterface->mCursor) { |
|
207 aValue = theUserInterface->mCursor->mValue; |
|
208 } |
|
209 break; |
|
210 <b> <a name="GetValueCase"></a>case eCSSProperty_force_broken_image_icons: aValue = theUserInterface->mForceBrokenImageIcons; break; |
|
211 </b> |
|
212 CSS_BOGUS_DEFAULT; // make compiler happy |
|
213 } |
|
214 } |
|
215 else { |
|
216 aValue.Reset(); |
|
217 } |
|
218 break; |
|
219 } |
|
220 |
|
221 </pre> |
|
222 Finally <a href="#ListCase">modify </a> |
|
223 the 'List' method to output the property value.<br> |
|
224 <pre>void nsCSSUserInterface::List(FILE* out, int32_t aIndent) const |
|
225 { |
|
226 for (int32_t index = aIndent; --index >= 0; ) fputs(" ", out); |
|
227 |
|
228 nsAutoString buffer; |
|
229 |
|
230 mUserInput.AppendToString(buffer, eCSSProperty_user_input); |
|
231 mUserModify.AppendToString(buffer, eCSSProperty_user_modify); |
|
232 mUserSelect.AppendToString(buffer, eCSSProperty_user_select); |
|
233 nsCSSValueList* keyEquiv = mKeyEquivalent; |
|
234 while (nullptr != keyEquiv) { |
|
235 keyEquiv->mValue.AppendToString(buffer, eCSSProperty_key_equivalent); |
|
236 keyEquiv= keyEquiv->mNext; |
|
237 } |
|
238 mUserFocus.AppendToString(buffer, eCSSProperty_user_focus); |
|
239 mResizer.AppendToString(buffer, eCSSProperty_resizer); |
|
240 |
|
241 nsCSSValueList* cursor = mCursor; |
|
242 while (nullptr != cursor) { |
|
243 cursor->mValue.AppendToString(buffer, eCSSProperty_cursor); |
|
244 cursor = cursor->mNext; |
|
245 } |
|
246 |
|
247 <b> <a name="ListCase"></a>mForceBrokenImageIcon.AppendToString(buffer,eCSSProperty_force_broken_image_icons);</b> |
|
248 |
|
249 fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out); |
|
250 } |
|
251 |
|
252 </pre> |
|
253 |
|
254 <h3><a name="Parser">CSS Parser</a></h3> |
|
255 Next, the CSSParser must be educated about this new property so that it can |
|
256 read in the formal declarations and build up the internal declarations that |
|
257 will be used to build the rules. If you are adding a simple property that |
|
258 takes a single value, you simply add your new property to the ParseSingleProperty |
|
259 method. If a more complex parsing is required you will have to write a new |
|
260 method to handle it, modeling it off of one of the existing parsing helper |
|
261 methods (see <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSParser.cpp#4151"> |
|
262 ParseBackground</a> |
|
263 , for and example). We are just adding a simple single-value property here.<br> |
|
264 <br> |
|
265 Open nsCSSParser.cpp and look for the method <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSParser.cpp#3580"> |
|
266 ParseSingleProperty</a> |
|
267 . This method is responsible for calling the relevant helper routine to parse |
|
268 the value(s). Find an existing property that is similar to the property you |
|
269 are adding. For our example we are adding a property that takes a numeric |
|
270 value so we will model it after the 'height' property and call ParsePositiveVariant. |
|
271 Add a new case for the new property and call the appropriate parser-helper |
|
272 and make a call to ParseVariant passing the <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSParser.cpp#2754"> |
|
273 variant flag</a> |
|
274 that makes sense for your property. In our case<br> |
|
275 <br> |
|
276 <pre> case eCSSProperty_force_broken_image_icons:</pre> |
|
277 <pre> return ParsePositiveVariant(aErrorCode, aValue, VARIANT_INTEGER, nullptr);</pre> |
|
278 This will parse the value as a positive integer value, which is what we want.<br> |
|
279 <br> |
|
280 <h3><a name="StyleContext">Style Context</a></h3> |
|
281 Having implemented support for the new property in the CSS Parser and CSS |
|
282 Declaration classes in the content module, it is now time to provide support |
|
283 for the new property in layout. The Style Context must be given a new data |
|
284 member corresponding to the declaration's new data member, so the computed |
|
285 value can be held for the layout objects to use.<br> |
|
286 <br> |
|
287 First look into <a href="http://lxr.mozilla.org/seamonkey/source/content/shared/public/nsStyleStruct.h"> |
|
288 nsStyleStruct.h</a> |
|
289 to see the existing style strucs. Find the one that you want to store the |
|
290 data on. In this example, we want to put it on the nsStyleUserInterface struct, |
|
291 however there is also a class nsStyleUIReset that holds the non-inherited |
|
292 values, so we will use that one (remember, our property is not inherited). |
|
293 Add a <a href="#StyleContextMember">data member</a> |
|
294 to hold the value: |
|
295 <pre>struct nsStyleUIReset { |
|
296 nsStyleUIReset(void); |
|
297 nsStyleUIReset(const nsStyleUIReset& aOther); |
|
298 ~nsStyleUIReset(void); |
|
299 |
|
300 NS_DEFINE_STATIC_STYLESTRUCTID_ACCESSOR(eStyleStruct_UIReset) |
|
301 |
|
302 void* operator new(size_t sz, nsPresContext* aContext) { |
|
303 return aContext->AllocateFromShell(sz); |
|
304 } |
|
305 void Destroy(nsPresContext* aContext) { |
|
306 this->~nsStyleUIReset(); |
|
307 aContext->FreeToShell(sizeof(nsStyleUIReset), this); |
|
308 }; |
|
309 |
|
310 int32_t CalcDifference(const nsStyleUIReset& aOther) const; |
|
311 |
|
312 uint8_t mUserSelect; // [reset] (selection-style) |
|
313 PRUnichar mKeyEquivalent; // [reset] XXX what type should this be? |
|
314 uint8_t mResizer; // [reset] |
|
315 <b><a name="StyleContextMember"></a>uint8_t mForceBrokenImageIcon; // [reset] (0 if not forcing, otherwise forcing)</b> |
|
316 }; |
|
317 </pre> |
|
318 In the implementation file <a href="http://lxr.mozilla.org/seamonkey/source/content/shared/src/nsStyleStruct.cpp"> |
|
319 nsStyleContext.cpp </a> |
|
320 add the new data member to the constructors of the style struct and the CalcDifference |
|
321 method, which must return the correct style-change hint when a change to |
|
322 your new property is detected. The constructor changes are obvious, but here |
|
323 is the CalcDifference change for our example:<br> |
|
324 <pre>int32_t nsStyleUIReset::CalcDifference(const nsStyleUIReset& aOther) const |
|
325 { |
|
326 <b> if (mForceBrokenImageIcon == aOther.mForceBrokenImageIcon) {</b> |
|
327 if (mResizer == aOther.mResizer) { |
|
328 if (mUserSelect == aOther.mUserSelect) { |
|
329 if (mKeyEquivalent == aOther.mKeyEquivalent) { |
|
330 return NS_STYLE_HINT_NONE; |
|
331 } |
|
332 return NS_STYLE_HINT_CONTENT; |
|
333 } |
|
334 return NS_STYLE_HINT_VISUAL; |
|
335 } |
|
336 return NS_STYLE_HINT_VISUAL; |
|
337 } |
|
338 <b>return NS_STYLE_HINT_FRAMECHANGE; |
|
339 </b>} |
|
340 </pre> |
|
341 <h3>CSSStyleRule</h3> |
|
342 The nsCSSStyleRule must be updated to manage mapping the declaration to the |
|
343 style struct. In the file <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSStyleRule.cpp"> |
|
344 nsCSSStyleRule.cpp</a> |
|
345 , locate the Declaration mapping function corresponding to the style struct |
|
346 you have added your property to. For example, we <a href="http://bugzilla.mozilla.org/MapUIForDeclChange"> |
|
347 update </a> |
|
348 MapUIForDeclaration:<br> |
|
349 <pre>static nsresult |
|
350 MapUIForDeclaration(nsCSSDeclaration* aDecl, const nsStyleStructID& aID, nsCSSUserInterface& aUI) |
|
351 { |
|
352 if (!aDecl) |
|
353 return NS_OK; // The rule must have a declaration. |
|
354 |
|
355 nsCSSUserInterface* ourUI = (nsCSSUserInterface*)aDecl->GetData(kCSSUserInterfaceSID); |
|
356 if (!ourUI) |
|
357 return NS_OK; // We don't have any rules for UI. |
|
358 |
|
359 if (aID == eStyleStruct_UserInterface) { |
|
360 if (aUI.mUserFocus.GetUnit() == eCSSUnit_Null && ourUI->mUserFocus.GetUnit() != eCSSUnit_Null) |
|
361 aUI.mUserFocus = ourUI->mUserFocus; |
|
362 |
|
363 if (aUI.mUserInput.GetUnit() == eCSSUnit_Null && ourUI->mUserInput.GetUnit() != eCSSUnit_Null) |
|
364 aUI.mUserInput = ourUI->mUserInput; |
|
365 |
|
366 if (aUI.mUserModify.GetUnit() == eCSSUnit_Null && ourUI->mUserModify.GetUnit() != eCSSUnit_Null) |
|
367 aUI.mUserModify = ourUI->mUserModify; |
|
368 |
|
369 if (!aUI.mCursor && ourUI->mCursor) |
|
370 aUI.mCursor = ourUI->mCursor; |
|
371 |
|
372 |
|
373 } |
|
374 else if (aID == eStyleStruct_UIReset) { |
|
375 if (aUI.mUserSelect.GetUnit() == eCSSUnit_Null && ourUI->mUserSelect.GetUnit() != eCSSUnit_Null) |
|
376 aUI.mUserSelect = ourUI->mUserSelect; |
|
377 |
|
378 if (!aUI.mKeyEquivalent && ourUI->mKeyEquivalent) |
|
379 aUI.mKeyEquivalent = ourUI->mKeyEquivalent; |
|
380 |
|
381 if (aUI.mResizer.GetUnit() == eCSSUnit_Null && ourUI->mResizer.GetUnit() != eCSSUnit_Null) |
|
382 aUI.mResizer = ourUI->mResizer; |
|
383 <b> |
|
384 <a name="MapUIForDeclChange"></a>if (aUI.mForceBrokenImageIcon.GetUnit() == eCSSUnit_Null && ourUI->mForceBrokenImageIcon.GetUnit() == eCSSUnit_Integer) |
|
385 aUI.mForceBrokenImageIcon = ourUI->mForceBrokenImageIcon;</b> |
|
386 } |
|
387 |
|
388 return NS_OK; |
|
389 |
|
390 } |
|
391 </pre> |
|
392 <h3><a name="RuleNode">Rule Node</a></h3> |
|
393 Now we have to update the RuleNode code to know about the new property. First, |
|
394 locate the PropertyCheckData array for the data that you added the new property |
|
395 to. For this example, we add the following:<br> |
|
396 <pre>static const PropertyCheckData UIResetCheckProperties[] = { |
|
397 CHECKDATA_PROP(nsCSSUserInterface, mUserSelect, CHECKDATA_VALUE, PR_FALSE), |
|
398 CHECKDATA_PROP(nsCSSUserInterface, mResizer, CHECKDATA_VALUE, PR_FALSE), |
|
399 CHECKDATA_PROP(nsCSSUserInterface, mKeyEquivalent, CHECKDATA_VALUELIST, PR_FALSE) |
|
400 <b>CHECKDATA_PROP(nsCSSUserInterface, mForceBrokenImageIcon, CHECKDATA_VALUE, PR_FALSE)</b> |
|
401 }; |
|
402 </pre> |
|
403 The first two arguments correspond to the structure and data member from |
|
404 the CSSDeclaration, the third is the data type, the fourth indicates |
|
405 whether it is a coord value that uses an explicit inherit value on the |
|
406 style data struct that must be computed by layout.<br> |
|
407 <br> |
|
408 Next, we have to make sure the ComputeXXX method for the structure the property |
|
409 was added to is updated to mange the new value. In this example we need to |
|
410 modify the nsRuleNode::ComputeUIResetData method to handle the CSS Declaration |
|
411 to the style struct:<br> |
|
412 <pre> ... |
|
413 // resizer: auto, none, enum, inherit |
|
414 if (eCSSUnit_Enumerated == uiData.mResizer.GetUnit()) { |
|
415 ui->mResizer = uiData.mResizer.GetIntValue(); |
|
416 } |
|
417 else if (eCSSUnit_Auto == uiData.mResizer.GetUnit()) { |
|
418 ui->mResizer = NS_STYLE_RESIZER_AUTO; |
|
419 } |
|
420 else if (eCSSUnit_None == uiData.mResizer.GetUnit()) { |
|
421 ui->mResizer = NS_STYLE_RESIZER_NONE; |
|
422 } |
|
423 else if (eCSSUnit_Inherit == uiData.mResizer.GetUnit()) { |
|
424 inherited = PR_TRUE; |
|
425 ui->mResizer = parentUI->mResizer; |
|
426 } |
|
427 |
|
428 <b>// force-broken-image-icons: integer, inherit, initial |
|
429 if (eCSSUnit_Integer == uiData.mForceBrokenImageIcons.GetUnit()) { |
|
430 ui->mForceBrokenImageIcons = uiData.mForceBrokenImageIcons.GetIntValue(); |
|
431 } else if (eCSSUnit_Inherit == uiData.mForceBrokenImageIcons.GetUnit()) { |
|
432 inherited = PR_TRUE; |
|
433 ui->mForceBrokenImageIcons = parentUI->mForceBrokenImageIcons; |
|
434 } else if (eCSSUnit_Initial == uiData.mForceBrokenImageIcons.GetUnit()) { |
|
435 ui->mForceBrokenImageIcons = 0; |
|
436 }</b> |
|
437 |
|
438 if (inherited) |
|
439 // We inherited, and therefore can't be cached in the rule node. We have to be put right on the |
|
440 // style context. |
|
441 aContext->SetStyle(eStyleStruct_UIReset, *ui); |
|
442 else { |
|
443 // We were fully specified and can therefore be cached right on the rule node. |
|
444 if (!aHighestNode->mStyleData.mResetData) |
|
445 aHighestNode->mStyleData.mResetData = new (mPresContext) nsResetStyleData; |
|
446 aHighestNode->mStyleData.mResetData->mUIData = ui; |
|
447 // Propagate the bit down. |
|
448 PropagateDependentBit(NS_STYLE_INHERIT_UI_RESET, aHighestNode); |
|
449 } |
|
450 ... |
|
451 </pre> |
|
452 <h3><a name="DOM">DOM</a></h3> |
|
453 Users in scripts, or anywhere outside of layout/ or content/ may need to access |
|
454 the new property. This is done using the CSS OM, specifically |
|
455 <code>nsIDOMCSSStyleDeclaration</code> and <code>CSS2Properties</code>. |
|
456 By the magic of C++ pre-processing, the |
|
457 CSS2Properties bits will be implemented automatically when you |
|
458 <a href="#CSSPropList">add your property</a> to <a href="http://lxr.mozilla.org/seamonkey/source/content/shared/public/nsCSSPropList.h"> |
|
459 nsCSSPropList.h</a>. |
|
460 <h3><a name="Layout">Layout</a></h3> |
|
461 OK, finally the style system is supporting the new property. It is time to |
|
462 actually make use of it now.<br> |
|
463 <br> |
|
464 In layout, retrieve the styleStruct that has the new property from the frame's |
|
465 style context. Access the new property and get its value. It is that simple. |
|
466 For this example, it looks like this, in nsImageFrame:<br> |
|
467 <pre> PRBool forceIcon = PR_FALSE; |
|
468 |
|
469 if (StyleUIReset()->mForceBrokenImageIcon) { |
|
470 forceIcon = PR_TRUE; |
|
471 } |
|
472 |
|
473 </pre> |
|
474 Create some testcases with style rules that use the new property, make sure |
|
475 it is being parsed correctly. Test it in an external stylesheet and in inline |
|
476 style. Test that it is inherited correctly, or not inherited as appropriate |
|
477 to your property. Update this document with any further details, or correcting |
|
478 any errors.<br> |
|
479 </body></html> |