summaryrefslogtreecommitdiffstats
path: root/layout/doc/adding-style-props.html
diff options
context:
space:
mode:
Diffstat (limited to 'layout/doc/adding-style-props.html')
-rw-r--r--layout/doc/adding-style-props.html479
1 files changed, 479 insertions, 0 deletions
diff --git a/layout/doc/adding-style-props.html b/layout/doc/adding-style-props.html
new file mode 100644
index 000000000..c654a55d5
--- /dev/null
+++ b/layout/doc/adding-style-props.html
@@ -0,0 +1,479 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head>
+ <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Marc Attinasi"><title>Adding a new style property - layout cookbook</title></head>
+
+<body>
+<h1>Adding a new style property</h1>
+<blockquote>
+ <h4>Document history:</h4>
+ <ul>
+ <li>03/21/2002: Marc Attinasi (attinasi@netscape.com) created document
+/ implementing -moz-force-broken-image-icon for bug <a href="http://bugzilla.mozilla.org/show_bug.cgi?id=58646">
+58646</a></li>
+ <li>
+ 6/18/2002: David Baron (dbaron@dbaron.org): corrected support
+ for 'inherit' and 'initial' (didn't test with code, though),
+ and explained what the final boolean in CheckPropertyData is for.
+ </li>
+ <li>
+ 11/09/2002: Christopher Aillon (caillon@returnzero.com): updated
+ nsCSSPropList.h macro description and added information about
+ nsIDOMCSS2Properties.idl.
+ </li>
+ </ul>
+ <p>
+ <b>NOTE</b>: This document is still missing a few pieces. I need to
+ add information on adding to <code>nsComputedDOMStyle</code>.
+ </p>
+ </blockquote>
+ <h2>Overview</h2>
+When a new style property is needed there are many places in the code that
+need to be updated. This document outlines the procedure used to add a new
+property, in this case the property is a proprietary one called '-moz-force-broken-image-icons'
+and is used as a way for a stylesheet to force broken image icons to be displayed.
+This is all being done in the context of <a href="http://bugzilla.mozilla.org/show_bug.cgi?id=58646">
+bug 58646</a>.
+
+ <h2>Analysis</h2>
+<p>Up front you have to decide some things about the new property:</p>
+
+<p><b>Questions:</b></p>
+ <ol>
+ <li>Is the property proprietary or specified by the CSS standard?</li>
+ <li>Is the property inherited?</li>
+ <li>What types of values can the property have?</li>
+ <li>Does it logically fit with other existing properties?</li>
+ <li>What is the impact to the layout of a page if that property changes?</li>
+ <li>What do you want to name it?</li>
+ </ol>
+<p><b>Answers:</b></p>
+ <ol>
+ <li>In our specific case, we want a property that is used internally,
+so it is a proprietary property.</li>
+ <li>The property is to be used for images, which are leaf elements, so
+there is no need to inherit it.</li>
+ <li>The property is used simply to force a broken image to be represented
+by an icon, so it only supports the values '0' and '1' as numerics. </li>
+ <li>It is hard to see how this property fits logically in with other
+properties, but if we stretch our imaginations we could say that it is a
+sort of UI property.</li>
+ <li>If this property changes, the image frame has to be recreated. This
+is because the decision about whether to display the icon or not will impact
+the decision to replace the image frame with an inline text frame for the
+ALT text, so if the ALT text inline is already made, there is no image frame
+left around to reflow or otherwise modify.</li>
+ <li>Finally, the name will be '-moz-force-broken-image-icons' - that
+should be pretty self-describing (by convention we start proprietary property
+names with '-moz-').</li>
+ </ol>
+ <h2>Implementation</h2>
+
+<p>There are several places that need to be educated about a new style property.
+They are:
+</p>
+ <ul>
+ <li><a href="#CSSPropList">CSS Property Names and Hint Tables</a>: the new
+property name must be made formally know to the system</li>
+ <li><a href="#CSSDeclaration">CSS Declaration</a>: the declaration must be
+able to hold the property and its value(s)</li>
+ <li><a href="#Parser">CSS Parser</a>: the parser must be able to parse the
+property name, validate the values, and provide a declaration for the property
+and value</li>
+ <li><a href="#StyleContext">Style Context</a>: the StyleContext must be able
+to hold the resolved value of the property, and provide a means to retrieve the
+property value. Additionally, the StyleContext has to know what kind of impact a
+change to this property causes.</li>
+ <li><a href="#RuleNode">Rule Nodes</a>: the RuleNodes need to know how the
+property is inherited and how it is shared by other elements.</li>
+ <li><a href="#DOM">DOM</a>: Your style should be accessible from the DOM so
+users may dynamically set/get its property value.</li>
+ <li><a href="#Layout">Layout</a>: layout has to know what to do with the
+property, in other words, the meaning of the property.</li>
+ </ul>
+ <h3><a name="CSSPropList">CSS Property Name / Constants / Hints</a></h3>
+
+<p>
+First, add the new name to the property list in <a href="http://lxr.mozilla.org/seamonkey/source/content/shared/public/nsCSSPropList.h">
+nsCSSPropList.h</a>
+  Insert the property in the list alphabetically, using the existing
+property names as a template. The format of the entry you will create is:
+</p>
+ <pre>CSS_PROP(-moz-force-broken-image-icons, force_broken_image_icons, MozForceBrokenImageIcons, nsChangeHint_ReconstructFrame) // bug 58646</pre>
+
+<p>The first value is the formal property name, in other words the property
+name as it is seen by the CSS parser.<br>
+The second value is the name of the property as it will appear internally.<br>
+The third value is the name of the DOM property used to access your style.<br>
+The last value indicates what must change when the value of the property
+changes. It should be an
+<a href="http://lxr.mozilla.org/seamonkey/source/content/shared/public/nsChangeHint.h">nsChangeHint</a>.</p>
+
+<p>If you need to introduce new constants for the values of the property, they
+must be added to <a href="http://lxr.mozilla.org/seamonkey/source/layout/base/public/nsStyleConsts.h">
+nsStyleConsts.h</a>
+ and to the appropriate keyword tables in <a href="http://lxr.mozilla.org/seamonkey/source/content/shared/src/nsCSSProps.cpp">
+nsCSSProps.cpp</a>
+ (note: this cookbook does not do this since the new property does not require
+any new keywords for the property values).
+ <h3><a name="CSSDeclaration">CSS Declaration</a></h3>
+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">
+nsCSSDeclaration.h </a>
+and <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSDeclaration.cpp">
+nsCSSDeclaration.cpp</a>
+ <br>
+ <br>
+First, find the declaration of the struct that will hold the new property
+value (in the header file). For this example it is the struct <b>nsCSSUserInterface</b>
+. Modify the struct declaration to include a new data member for the new
+property, of the type CSSValue. Next, open the implementation file (the cpp)
+and modify the struct's constructors. <br>
+ <br>
+Next, the <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSDeclaration.cpp#1410">
+AppendValue</a>
+ method must be updated to support your new property. The CSSParser will
+call this to build up a declaration. Find the portion of that method that
+deals with the other properties in the struct that you are adding your property
+to (or create a new section if you are creating a new style struct). For
+this example we will find the 'UserInterface' section and add our new property
+ <a href="#AppendValueCase">there</a>
+.<br>
+ <pre> // nsCSSUserInterface
+ case eCSSProperty_user_input:
+ case eCSSProperty_user_modify:
+ case eCSSProperty_user_select:
+ case eCSSProperty_key_equivalent:
+ case eCSSProperty_user_focus:
+ case eCSSProperty_resizer:
+ case eCSSProperty_cursor:
+ case eCSSProperty_force_broken_image_icons: {
+ CSS_ENSURE(UserInterface) {
+ switch (aProperty) {
+ case eCSSProperty_user_input: theUserInterface-&gt;mUserInput = aValue; break;
+ case eCSSProperty_user_modify: theUserInterface-&gt;mUserModify = aValue; break;
+ case eCSSProperty_user_select: theUserInterface-&gt;mUserSelect = aValue; break;
+ case eCSSProperty_key_equivalent:
+ CSS_ENSURE_DATA(theUserInterface-&gt;mKeyEquivalent, nsCSSValueList) {
+ theUserInterface-&gt;mKeyEquivalent-&gt;mValue = aValue;
+ CSS_IF_DELETE(theUserInterface-&gt;mKeyEquivalent-&gt;mNext);
+ }
+ break;
+ case eCSSProperty_user_focus: theUserInterface-&gt;mUserFocus = aValue; break;
+ case eCSSProperty_resizer: theUserInterface-&gt;mResizer = aValue; break;
+ case eCSSProperty_cursor:
+ CSS_ENSURE_DATA(theUserInterface-&gt;mCursor, nsCSSValueList) {
+ theUserInterface-&gt;mCursor-&gt;mValue = aValue;
+ CSS_IF_DELETE(theUserInterface-&gt;mCursor-&gt;mNext);
+ }
+ break;
+<b> <a name="AppendValueCase"></a>case eCSSProperty_force_broken_image_icons: theUserInterface-&gt;mForceBrokenImageIcon = aValue; break;
+</b>
+ CSS_BOGUS_DEFAULT; // make compiler happy
+ }
+ }
+ break;
+ }
+
+</pre>
+The GetValue method must be similarly <a href="#GetValueCase">modified</a>
+:<br>
+ <pre> // nsCSSUserInterface
+ case eCSSProperty_user_input:
+ case eCSSProperty_user_modify:
+ case eCSSProperty_user_select:
+ case eCSSProperty_key_equivalent:
+ case eCSSProperty_user_focus:
+ case eCSSProperty_resizer:
+ case eCSSProperty_cursor:
+ case eCSSProperty_force_broken_image_icons: {
+ CSS_VARONSTACK_GET(UserInterface);
+ if (nullptr != theUserInterface) {
+ switch (aProperty) {
+ case eCSSProperty_user_input: aValue = theUserInterface-&gt;mUserInput; break;
+ case eCSSProperty_user_modify: aValue = theUserInterface-&gt;mUserModify; break;
+ case eCSSProperty_user_select: aValue = theUserInterface-&gt;mUserSelect; break;
+ case eCSSProperty_key_equivalent:
+ if (nullptr != theUserInterface-&gt;mKeyEquivalent) {
+ aValue = theUserInterface-&gt;mKeyEquivalent-&gt;mValue;
+ }
+ break;
+ case eCSSProperty_user_focus: aValue = theUserInterface-&gt;mUserFocus; break;
+ case eCSSProperty_resizer: aValue = theUserInterface-&gt;mResizer; break;
+ case eCSSProperty_cursor:
+ if (nullptr != theUserInterface-&gt;mCursor) {
+ aValue = theUserInterface-&gt;mCursor-&gt;mValue;
+ }
+ break;
+<b> <a name="GetValueCase"></a>case eCSSProperty_force_broken_image_icons: aValue = theUserInterface-&gt;mForceBrokenImageIcons; break;
+</b>
+ CSS_BOGUS_DEFAULT; // make compiler happy
+ }
+ }
+ else {
+ aValue.Reset();
+ }
+ break;
+ }
+
+</pre>
+Finally <a href="#ListCase">modify </a>
+the 'List' method to output the property value.<br>
+ <pre>void nsCSSUserInterface::List(FILE* out, int32_t aIndent) const
+{
+ for (int32_t index = aIndent; --index &gt;= 0; ) fputs(" ", out);
+
+ nsAutoString buffer;
+
+ mUserInput.AppendToString(buffer, eCSSProperty_user_input);
+ mUserModify.AppendToString(buffer, eCSSProperty_user_modify);
+ mUserSelect.AppendToString(buffer, eCSSProperty_user_select);
+ nsCSSValueList* keyEquiv = mKeyEquivalent;
+ while (nullptr != keyEquiv) {
+ keyEquiv-&gt;mValue.AppendToString(buffer, eCSSProperty_key_equivalent);
+ keyEquiv= keyEquiv-&gt;mNext;
+ }
+ mUserFocus.AppendToString(buffer, eCSSProperty_user_focus);
+ mResizer.AppendToString(buffer, eCSSProperty_resizer);
+
+ nsCSSValueList* cursor = mCursor;
+ while (nullptr != cursor) {
+ cursor-&gt;mValue.AppendToString(buffer, eCSSProperty_cursor);
+ cursor = cursor-&gt;mNext;
+ }
+
+ <b> <a name="ListCase"></a>mForceBrokenImageIcon.AppendToString(buffer,eCSSProperty_force_broken_image_icons);</b>
+
+ fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out);
+}
+
+</pre>
+
+ <h3><a name="Parser">CSS Parser</a></h3>
+Next, the CSSParser must be educated about this new property so that it can
+read in the formal declarations and build up the internal declarations that
+will be used to build the rules. If you are adding a simple property that
+takes a single value, you simply add your new property to the ParseSingleProperty
+method. If a more complex parsing is required you will have to write a new
+method to handle it, modeling it off of one of the existing parsing helper
+methods (see <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSParser.cpp#4151">
+ParseBackground</a>
+, for and example). We are just adding a simple single-value property here.<br>
+ <br>
+Open nsCSSParser.cpp and look for the method <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSParser.cpp#3580">
+ParseSingleProperty</a>
+. This method is responsible for calling the relevant helper routine to parse
+the value(s). Find an existing property that is similar to the property you
+are adding. For our example we are adding a property that takes a numeric
+value so we will model it after the 'height' property and call ParsePositiveVariant.
+Add a new case for the new property and call the appropriate parser-helper
+and make a call to ParseVariant passing the <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSParser.cpp#2754">
+variant flag</a>
+ that makes sense for your property. In our case<br>
+ <br>
+ <pre>  case eCSSProperty_force_broken_image_icons:</pre>
+ <pre>    return ParsePositiveVariant(aErrorCode, aValue, VARIANT_INTEGER, nullptr);</pre>
+This will parse the value as a positive integer value, which is what we want.<br>
+ <br>
+ <h3><a name="StyleContext">Style Context</a></h3>
+Having implemented support for the new property in the CSS Parser and CSS
+Declaration classes in the content module, it is now time to provide support
+for the new property in layout. The Style Context must be given a new data
+member corresponding to the declaration's new data member, so the computed
+value can be held for the layout objects to use.<br>
+ <br>
+First look into <a href="http://lxr.mozilla.org/seamonkey/source/content/shared/public/nsStyleStruct.h">
+nsStyleStruct.h</a>
+ to see the existing style strucs. Find the one that you want to store the
+data on. In this example, we want to put it on the nsStyleUserInterface struct,
+however there is also a class nsStyleUIReset that holds the non-inherited
+values, so we will use that one (remember, our property is not inherited).
+Add a <a href="#StyleContextMember">data member</a>
+ to hold the value:
+ <pre>struct nsStyleUIReset {
+ nsStyleUIReset(void);
+ nsStyleUIReset(const nsStyleUIReset&amp; aOther);
+ ~nsStyleUIReset(void);
+
+ NS_DEFINE_STATIC_STYLESTRUCTID_ACCESSOR(eStyleStruct_UIReset)
+
+ void* operator new(size_t sz, nsPresContext* aContext) {
+ return aContext->AllocateFromShell(sz);
+ }
+ void Destroy(nsPresContext* aContext) {
+ this-&gt;~nsStyleUIReset();
+ aContext-&gt;FreeToShell(sizeof(nsStyleUIReset), this);
+ };
+
+ int32_t CalcDifference(const nsStyleUIReset&amp; aOther) const;
+
+ uint8_t mUserSelect; // [reset] (selection-style)
+ PRUnichar mKeyEquivalent; // [reset] XXX what type should this be?
+ uint8_t mResizer; // [reset]
+ <b><a name="StyleContextMember"></a>uint8_t mForceBrokenImageIcon; // [reset] (0 if not forcing, otherwise forcing)</b>
+};
+</pre>
+In the implementation file <a href="http://lxr.mozilla.org/seamonkey/source/content/shared/src/nsStyleStruct.cpp">
+nsStyleContext.cpp </a>
+add the new data member to the constructors of the style struct and the CalcDifference
+method, which must return the correct style-change hint when a change to
+your new property is detected. The constructor changes are obvious, but here
+is the CalcDifference change for our example:<br>
+ <pre>int32_t nsStyleUIReset::CalcDifference(const nsStyleUIReset&amp; aOther) const
+{
+ <b> if (mForceBrokenImageIcon == aOther.mForceBrokenImageIcon) {</b>
+ if (mResizer == aOther.mResizer) {
+ if (mUserSelect == aOther.mUserSelect) {
+ if (mKeyEquivalent == aOther.mKeyEquivalent) {
+ return NS_STYLE_HINT_NONE;
+ }
+ return NS_STYLE_HINT_CONTENT;
+ }
+ return NS_STYLE_HINT_VISUAL;
+ }
+ return NS_STYLE_HINT_VISUAL;
+ }
+ <b>return nsChangeHint_ReconstructFrame;
+</b>}
+</pre>
+ <h3>CSSStyleRule</h3>
+The nsCSSStyleRule must be updated to manage mapping the declaration to the
+style struct. In the file <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSStyleRule.cpp">
+nsCSSStyleRule.cpp</a>
+, locate the Declaration mapping function corresponding to the style struct
+you have added your property to. For example, we <a href="http://bugzilla.mozilla.org/MapUIForDeclChange">
+update </a>
+MapUIForDeclaration:<br>
+ <pre>static nsresult
+MapUIForDeclaration(nsCSSDeclaration* aDecl, const nsStyleStructID&amp; aID, nsCSSUserInterface&amp; aUI)
+{
+ if (!aDecl)
+ return NS_OK; // The rule must have a declaration.
+
+ nsCSSUserInterface* ourUI = (nsCSSUserInterface*)aDecl-&gt;GetData(kCSSUserInterfaceSID);
+ if (!ourUI)
+ return NS_OK; // We don't have any rules for UI.
+
+ if (aID == eStyleStruct_UserInterface) {
+ if (aUI.mUserFocus.GetUnit() == eCSSUnit_Null &amp;&amp; ourUI-&gt;mUserFocus.GetUnit() != eCSSUnit_Null)
+ aUI.mUserFocus = ourUI-&gt;mUserFocus;
+
+ if (aUI.mUserInput.GetUnit() == eCSSUnit_Null &amp;&amp; ourUI-&gt;mUserInput.GetUnit() != eCSSUnit_Null)
+ aUI.mUserInput = ourUI-&gt;mUserInput;
+
+ if (aUI.mUserModify.GetUnit() == eCSSUnit_Null &amp;&amp; ourUI-&gt;mUserModify.GetUnit() != eCSSUnit_Null)
+ aUI.mUserModify = ourUI-&gt;mUserModify;
+
+ if (!aUI.mCursor &amp;&amp; ourUI-&gt;mCursor)
+ aUI.mCursor = ourUI-&gt;mCursor;
+
+
+ }
+ else if (aID == eStyleStruct_UIReset) {
+ if (aUI.mUserSelect.GetUnit() == eCSSUnit_Null &amp;&amp; ourUI-&gt;mUserSelect.GetUnit() != eCSSUnit_Null)
+ aUI.mUserSelect = ourUI-&gt;mUserSelect;
+
+ if (!aUI.mKeyEquivalent &amp;&amp; ourUI-&gt;mKeyEquivalent)
+ aUI.mKeyEquivalent = ourUI-&gt;mKeyEquivalent;
+
+ if (aUI.mResizer.GetUnit() == eCSSUnit_Null &amp;&amp; ourUI-&gt;mResizer.GetUnit() != eCSSUnit_Null)
+ aUI.mResizer = ourUI-&gt;mResizer;
+ <b>
+ <a name="MapUIForDeclChange"></a>if (aUI.mForceBrokenImageIcon.GetUnit() == eCSSUnit_Null &amp;&amp; ourUI-&gt;mForceBrokenImageIcon.GetUnit() == eCSSUnit_Integer)
+ aUI.mForceBrokenImageIcon = ourUI-&gt;mForceBrokenImageIcon;</b>
+ }
+
+ return NS_OK;
+
+}
+</pre>
+ <h3><a name="RuleNode">Rule Node</a></h3>
+Now we have to update the RuleNode code to know about the new property. First,
+locate the PropertyCheckData array for the data that you added the new property
+to. For this example, we add the following:<br>
+ <pre>static const PropertyCheckData UIResetCheckProperties[] = {
+ CHECKDATA_PROP(nsCSSUserInterface, mUserSelect, CHECKDATA_VALUE, PR_FALSE),
+ CHECKDATA_PROP(nsCSSUserInterface, mResizer, CHECKDATA_VALUE, PR_FALSE),
+ CHECKDATA_PROP(nsCSSUserInterface, mKeyEquivalent, CHECKDATA_VALUELIST, PR_FALSE)
+ <b>CHECKDATA_PROP(nsCSSUserInterface, mForceBrokenImageIcon, CHECKDATA_VALUE, PR_FALSE)</b>
+};
+</pre>
+The first two arguments correspond to the structure and data member from
+the CSSDeclaration, the third is the data type, the fourth indicates
+whether it is a coord value that uses an explicit inherit value on the
+style data struct that must be computed by layout.<br>
+ <br>
+Next, we have to make sure the ComputeXXX method for the structure the property
+was added to is updated to mange the new value. In this example we need to
+modify the nsRuleNode::ComputeUIResetData method to handle the CSS Declaration
+to the style struct:<br>
+ <pre> ...
+ // resizer: auto, none, enum, inherit
+ if (eCSSUnit_Enumerated == uiData.mResizer.GetUnit()) {
+ ui-&gt;mResizer = uiData.mResizer.GetIntValue();
+ }
+ else if (eCSSUnit_Auto == uiData.mResizer.GetUnit()) {
+ ui-&gt;mResizer = NS_STYLE_RESIZER_AUTO;
+ }
+ else if (eCSSUnit_None == uiData.mResizer.GetUnit()) {
+ ui-&gt;mResizer = NS_STYLE_RESIZER_NONE;
+ }
+ else if (eCSSUnit_Inherit == uiData.mResizer.GetUnit()) {
+ inherited = PR_TRUE;
+ ui-&gt;mResizer = parentUI-&gt;mResizer;
+ }
+
+ <b>// force-broken-image-icons: integer, inherit, initial
+ if (eCSSUnit_Integer == uiData.mForceBrokenImageIcons.GetUnit()) {
+ ui-&gt;mForceBrokenImageIcons = uiData.mForceBrokenImageIcons.GetIntValue();
+ } else if (eCSSUnit_Inherit == uiData.mForceBrokenImageIcons.GetUnit()) {
+ inherited = PR_TRUE;
+ ui-&gt;mForceBrokenImageIcons = parentUI-&gt;mForceBrokenImageIcons;
+ } else if (eCSSUnit_Initial == uiData.mForceBrokenImageIcons.GetUnit()) {
+ ui-&gt;mForceBrokenImageIcons = 0;
+ }</b>
+
+ if (inherited)
+ // We inherited, and therefore can't be cached in the rule node. We have to be put right on the
+ // style context.
+ aContext-&gt;SetStyle(eStyleStruct_UIReset, *ui);
+ else {
+ // We were fully specified and can therefore be cached right on the rule node.
+ if (!aHighestNode-&gt;mStyleData.mResetData)
+ aHighestNode-&gt;mStyleData.mResetData = new (mPresContext) nsResetStyleData;
+ aHighestNode-&gt;mStyleData.mResetData-&gt;mUIData = ui;
+ // Propagate the bit down.
+ PropagateDependentBit(NS_STYLE_INHERIT_UI_RESET, aHighestNode);
+ }
+ ...
+</pre>
+ <h3><a name="DOM">DOM</a></h3>
+Users in scripts, or anywhere outside of layout/ or content/ may need to access
+the new property. This is done using the CSS OM, specifically
+<code>nsIDOMCSSStyleDeclaration</code> and <code>CSS2Properties</code>.
+By the magic of C++ pre-processing, the
+CSS2Properties bits will be implemented automatically when you
+<a href="#CSSPropList">add your property</a> to <a href="http://lxr.mozilla.org/seamonkey/source/content/shared/public/nsCSSPropList.h">
+nsCSSPropList.h</a>.
+ <h3><a name="Layout">Layout</a></h3>
+OK, finally the style system is supporting the new property. It is time to
+actually make use of it now.<br>
+ <br>
+In layout, retrieve the styleStruct that has the new property from the frame's
+style context. Access the new property and get its value. It is that simple.
+For this example, it looks like this, in nsImageFrame:<br>
+ <pre> PRBool forceIcon = PR_FALSE;
+
+ if (StyleUIReset()-&gt;mForceBrokenImageIcon) {
+ forceIcon = PR_TRUE;
+ }
+
+</pre>
+Create some testcases with style rules that use the new property, make sure
+it is being parsed correctly. Test it in an external stylesheet and in inline
+style. Test that it is inherited correctly, or not inherited as appropriate
+to your property. Update this document with any further details, or correcting
+any errors.<br>
+ </body></html>