layout/doc/adding-style-props.html

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/doc/adding-style-props.html	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,479 @@
     1.4 +<!-- This Source Code Form is subject to the terms of the Mozilla Public
     1.5 +   - License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 +   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
     1.7 +
     1.8 +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head>
     1.9 +  <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
    1.10 +  <meta name="author" content="Marc Attinasi"><title>Adding a new style property - layout cookbook</title></head>
    1.11 +
    1.12 +<body>
    1.13 +<h1>Adding a new style property</h1>
    1.14 +<blockquote>
    1.15 +  <h4>Document history:</h4>
    1.16 +  <ul>
    1.17 +    <li>03/21/2002: Marc Attinasi (attinasi@netscape.com) created document
    1.18 +/ implementing -moz-force-broken-image-icon for bug <a href="http://bugzilla.mozilla.org/show_bug.cgi?id=58646">
    1.19 +58646</a></li>
    1.20 +    <li>
    1.21 +      6/18/2002: David Baron (dbaron@dbaron.org): corrected support
    1.22 +      for 'inherit' and 'initial' (didn't test with code, though),
    1.23 +      and explained what the final boolean in CheckPropertyData is for.
    1.24 +    </li>
    1.25 +    <li>
    1.26 +      11/09/2002: Christopher Aillon (caillon@returnzero.com): updated
    1.27 +      nsCSSPropList.h macro description and added information about
    1.28 +      nsIDOMCSS2Properties.idl.
    1.29 +    </li>
    1.30 +  </ul>
    1.31 +    <p>
    1.32 +      <b>NOTE</b>:  This document is still missing a few pieces.  I need to
    1.33 +      add information on adding to <code>nsComputedDOMStyle</code>.
    1.34 +    </p>
    1.35 +  </blockquote>
    1.36 +  <h2>Overview</h2>
    1.37 +When a new style property is needed there are many places in the code that
    1.38 +need to be updated. This document outlines the procedure used to add a new
    1.39 +property, in this case the property is a proprietary one called '-moz-force-broken-image-icons'
    1.40 +and is used as a way for a stylesheet to force broken image icons to be displayed.
    1.41 +This is all being done in the context of <a href="http://bugzilla.mozilla.org/show_bug.cgi?id=58646">
    1.42 +bug 58646</a>.
    1.43 +
    1.44 +  <h2>Analysis</h2>
    1.45 +<p>Up front you have to decide some things about the new property:</p>
    1.46 +
    1.47 +<p><b>Questions:</b></p>
    1.48 +  <ol>
    1.49 +    <li>Is the property proprietary or specified by the CSS standard?</li>
    1.50 +    <li>Is the property inherited?</li>
    1.51 +    <li>What types of values can the property have?</li>
    1.52 +    <li>Does it logically fit with other existing properties?</li>
    1.53 +    <li>What is the impact to the layout of a page if that property changes?</li>
    1.54 +    <li>What do you want to name it?</li>
    1.55 +  </ol>
    1.56 +<p><b>Answers:</b></p>
    1.57 +  <ol>
    1.58 +    <li>In our specific case, we want a property that is used internally,
    1.59 +so it is a proprietary property.</li>
    1.60 +    <li>The property is to be used for images, which are leaf elements, so
    1.61 +there is no need to inherit it.</li>
    1.62 +    <li>The property is used simply to force a broken image to be represented
    1.63 +by an icon, so it only supports the values '0' and '1' as numerics. </li>
    1.64 +    <li>It is hard to see how this property fits logically in with other
    1.65 +properties, but if we stretch our imaginations we could say that it is a
    1.66 +sort of UI property.</li>
    1.67 +    <li>If this property changes, the image frame has to be recreated. This
    1.68 +is because the decision about whether to display the icon or not will impact
    1.69 +the decision to replace the image frame with an inline text frame for the
    1.70 +ALT text, so if the ALT text inline is already made, there is no image frame
    1.71 +left around to reflow or otherwise modify.</li>
    1.72 +    <li>Finally, the name will be '-moz-force-broken-image-icons' - that
    1.73 +should be pretty self-describing (by convention we start proprietary property
    1.74 +names with '-moz-').</li>
    1.75 +  </ol>
    1.76 +  <h2>Implementation</h2>
    1.77 +
    1.78 +<p>There are several places that need to be educated about a new style property.
    1.79 +They are:
    1.80 +</p>
    1.81 +  <ul>
    1.82 +    <li><a href="#CSSPropList">CSS Property Names and Hint Tables</a>: the new
    1.83 +property name must be made formally know to the system</li>
    1.84 +    <li><a href="#CSSDeclaration">CSS Declaration</a>: the declaration must be
    1.85 +able to hold the property and its value(s)</li>
    1.86 +    <li><a href="#Parser">CSS Parser</a>: the parser must be able to parse the
    1.87 +property name, validate the values, and provide a declaration for the property
    1.88 +and value</li>
    1.89 +    <li><a href="#StyleContext">Style Context</a>: the StyleContext must be able
    1.90 +to hold the resolved value of the property, and provide a means to retrieve the
    1.91 +property value. Additionally, the StyleContext has to know what kind of impact a
    1.92 +change to this property causes.</li>
    1.93 +    <li><a href="#RuleNode">Rule Nodes</a>: the RuleNodes need to know how the
    1.94 +property is inherited and how it is shared by other elements.</li>
    1.95 +    <li><a href="#DOM">DOM</a>: Your style should be accessible from the DOM so
    1.96 +users may dynamically set/get its property value.</li>
    1.97 +    <li><a href="#Layout">Layout</a>: layout has to know what to do with the
    1.98 +property, in other words, the meaning of the property.</li>
    1.99 +  </ul>
   1.100 +  <h3><a name="CSSPropList">CSS Property Name / Constants / Hints</a></h3>
   1.101 +
   1.102 +<p>
   1.103 +First, add the new name to the property list in <a href="http://lxr.mozilla.org/seamonkey/source/content/shared/public/nsCSSPropList.h">
   1.104 +nsCSSPropList.h</a>
   1.105 +  Insert the property in the list alphabetically, using the existing
   1.106 +property names as a template. The format of the entry you will create is:
   1.107 +</p>
   1.108 +  <pre>CSS_PROP(-moz-force-broken-image-icons, force_broken_image_icons, MozForceBrokenImageIcons, NS_STYLE_HINT_FRAMECHANGE) // bug 58646</pre>
   1.109 +
   1.110 +<p>The first value is the formal property name, in other words the property
   1.111 +name as it is seen by the CSS parser.<br>
   1.112 +The second value is the name of the property as it will appear internally.<br>
   1.113 +The third value is the name of the DOM property used to access your style.<br>
   1.114 +The last value indicates what must change when the value of the property
   1.115 +changes. It should be an
   1.116 +<a href="http://lxr.mozilla.org/seamonkey/source/content/shared/public/nsChangeHint.h">nsChangeHint</a>.</p>
   1.117 + 
   1.118 +<p>If you need to introduce new constants for the values of the property, they
   1.119 +must be added to <a href="http://lxr.mozilla.org/seamonkey/source/layout/base/public/nsStyleConsts.h">
   1.120 +nsStyleConsts.h</a>
   1.121 + and to the appropriate keyword tables in <a href="http://lxr.mozilla.org/seamonkey/source/content/shared/src/nsCSSProps.cpp">
   1.122 +nsCSSProps.cpp</a>
   1.123 + (note: this cookbook does not do this since the new property does not require
   1.124 +any new keywords for the property values).
   1.125 +  <h3><a name="CSSDeclaration">CSS Declaration</a></h3>
   1.126 +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">
   1.127 +nsCSSDeclaration.h </a>
   1.128 +and <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSDeclaration.cpp">
   1.129 +nsCSSDeclaration.cpp</a>
   1.130 +  <br>
   1.131 +  <br>
   1.132 +First, find the declaration of the struct that will hold the new property
   1.133 +value (in the header file). For this example it is the struct <b>nsCSSUserInterface</b>
   1.134 +. Modify the struct declaration to include a new data member for the new
   1.135 +property, of the type CSSValue. Next, open the implementation file (the cpp)
   1.136 +and modify the struct's constructors. <br>
   1.137 +  <br>
   1.138 +Next, the <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSDeclaration.cpp#1410">
   1.139 +AppendValue</a>
   1.140 + method must be updated to support your new property. The CSSParser will
   1.141 +call this to build up a declaration. Find the portion of that method that
   1.142 +deals with the other properties in the struct that you are adding your property
   1.143 +to (or create a new section if you are creating a new style struct). For
   1.144 +this example we will find the 'UserInterface' section and add our new property
   1.145 +  <a href="#AppendValueCase">there</a>
   1.146 +.<br>
   1.147 +  <pre>    // nsCSSUserInterface
   1.148 +    case eCSSProperty_user_input:
   1.149 +    case eCSSProperty_user_modify:
   1.150 +    case eCSSProperty_user_select:
   1.151 +    case eCSSProperty_key_equivalent:
   1.152 +    case eCSSProperty_user_focus:
   1.153 +    case eCSSProperty_resizer:
   1.154 +    case eCSSProperty_cursor:
   1.155 +    case eCSSProperty_force_broken_image_icons: {
   1.156 +      CSS_ENSURE(UserInterface) {
   1.157 +        switch (aProperty) {
   1.158 +          case eCSSProperty_user_input:       theUserInterface-&gt;mUserInput = aValue;      break;
   1.159 +          case eCSSProperty_user_modify:      theUserInterface-&gt;mUserModify = aValue;     break;
   1.160 +          case eCSSProperty_user_select:      theUserInterface-&gt;mUserSelect = aValue;     break;
   1.161 +          case eCSSProperty_key_equivalent: 
   1.162 +            CSS_ENSURE_DATA(theUserInterface-&gt;mKeyEquivalent, nsCSSValueList) {
   1.163 +              theUserInterface-&gt;mKeyEquivalent-&gt;mValue = aValue;
   1.164 +              CSS_IF_DELETE(theUserInterface-&gt;mKeyEquivalent-&gt;mNext);
   1.165 +            }
   1.166 +            break;
   1.167 +          case eCSSProperty_user_focus:       theUserInterface-&gt;mUserFocus = aValue;      break;
   1.168 +          case eCSSProperty_resizer:          theUserInterface-&gt;mResizer = aValue;        break;
   1.169 +          case eCSSProperty_cursor:
   1.170 +            CSS_ENSURE_DATA(theUserInterface-&gt;mCursor, nsCSSValueList) {
   1.171 +              theUserInterface-&gt;mCursor-&gt;mValue = aValue;
   1.172 +              CSS_IF_DELETE(theUserInterface-&gt;mCursor-&gt;mNext);
   1.173 +            }
   1.174 +            break;
   1.175 +<b>          <a name="AppendValueCase"></a>case eCSSProperty_force_broken_image_icons: theUserInterface-&gt;mForceBrokenImageIcon = aValue; break;
   1.176 +</b>
   1.177 +          CSS_BOGUS_DEFAULT; // make compiler happy
   1.178 +        }
   1.179 +      }
   1.180 +      break;
   1.181 +    }
   1.182 +
   1.183 +</pre>
   1.184 +The GetValue method must be similarly <a href="#GetValueCase">modified</a>
   1.185 +:<br>
   1.186 +  <pre>    // nsCSSUserInterface
   1.187 +    case eCSSProperty_user_input:
   1.188 +    case eCSSProperty_user_modify:
   1.189 +    case eCSSProperty_user_select:
   1.190 +    case eCSSProperty_key_equivalent:
   1.191 +    case eCSSProperty_user_focus:
   1.192 +    case eCSSProperty_resizer:
   1.193 +    case eCSSProperty_cursor:
   1.194 +    case eCSSProperty_force_broken_image_icons: {
   1.195 +      CSS_VARONSTACK_GET(UserInterface);
   1.196 +      if (nullptr != theUserInterface) {
   1.197 +        switch (aProperty) {
   1.198 +          case eCSSProperty_user_input:       aValue = theUserInterface-&gt;mUserInput;       break;
   1.199 +          case eCSSProperty_user_modify:      aValue = theUserInterface-&gt;mUserModify;      break;
   1.200 +          case eCSSProperty_user_select:      aValue = theUserInterface-&gt;mUserSelect;      break;
   1.201 +          case eCSSProperty_key_equivalent:
   1.202 +            if (nullptr != theUserInterface-&gt;mKeyEquivalent) {
   1.203 +              aValue = theUserInterface-&gt;mKeyEquivalent-&gt;mValue;
   1.204 +            }
   1.205 +            break;
   1.206 +          case eCSSProperty_user_focus:       aValue = theUserInterface-&gt;mUserFocus;       break;
   1.207 +          case eCSSProperty_resizer:          aValue = theUserInterface-&gt;mResizer;         break;
   1.208 +          case eCSSProperty_cursor:
   1.209 +            if (nullptr != theUserInterface-&gt;mCursor) {
   1.210 +              aValue = theUserInterface-&gt;mCursor-&gt;mValue;
   1.211 +            }
   1.212 +            break;
   1.213 +<b>          <a name="GetValueCase"></a>case eCSSProperty_force_broken_image_icons: aValue = theUserInterface-&gt;mForceBrokenImageIcons; break;
   1.214 +</b>
   1.215 +          CSS_BOGUS_DEFAULT; // make compiler happy
   1.216 +        }
   1.217 +      }
   1.218 +      else {
   1.219 +        aValue.Reset();
   1.220 +      }
   1.221 +      break;
   1.222 +    }
   1.223 +
   1.224 +</pre>
   1.225 +Finally <a href="#ListCase">modify </a>
   1.226 +the 'List' method to output the property value.<br>
   1.227 +  <pre>void nsCSSUserInterface::List(FILE* out, int32_t aIndent) const
   1.228 +{
   1.229 +  for (int32_t index = aIndent; --index &gt;= 0; ) fputs("  ", out);
   1.230 +
   1.231 +  nsAutoString buffer;
   1.232 +
   1.233 +  mUserInput.AppendToString(buffer, eCSSProperty_user_input);
   1.234 +  mUserModify.AppendToString(buffer, eCSSProperty_user_modify);
   1.235 +  mUserSelect.AppendToString(buffer, eCSSProperty_user_select);
   1.236 +  nsCSSValueList*  keyEquiv = mKeyEquivalent;
   1.237 +  while (nullptr != keyEquiv) {
   1.238 +    keyEquiv-&gt;mValue.AppendToString(buffer, eCSSProperty_key_equivalent);
   1.239 +    keyEquiv= keyEquiv-&gt;mNext;
   1.240 +  }
   1.241 +  mUserFocus.AppendToString(buffer, eCSSProperty_user_focus);
   1.242 +  mResizer.AppendToString(buffer, eCSSProperty_resizer);
   1.243 +  
   1.244 +  nsCSSValueList*  cursor = mCursor;
   1.245 +  while (nullptr != cursor) {
   1.246 +    cursor-&gt;mValue.AppendToString(buffer, eCSSProperty_cursor);
   1.247 +    cursor = cursor-&gt;mNext;
   1.248 +  }
   1.249 +
   1.250 + <b> <a name="ListCase"></a>mForceBrokenImageIcon.AppendToString(buffer,eCSSProperty_force_broken_image_icons);</b>
   1.251 +
   1.252 +  fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out);
   1.253 +}
   1.254 +
   1.255 +</pre>
   1.256 + 
   1.257 +  <h3><a name="Parser">CSS Parser</a></h3>
   1.258 +Next, the CSSParser must be educated about this new property so that it can
   1.259 +read in the formal declarations and build up the internal declarations that
   1.260 +will be used to build the rules. If you are adding a simple property that
   1.261 +takes a single value, you simply add your new property to the ParseSingleProperty
   1.262 +method. If a more complex parsing is required you will have to write a new
   1.263 +method to handle it, modeling it off of one of the existing parsing helper
   1.264 +methods (see <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSParser.cpp#4151">
   1.265 +ParseBackground</a>
   1.266 +, for and example). We are just adding a simple single-value property here.<br>
   1.267 +  <br>
   1.268 +Open nsCSSParser.cpp and look for the method <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSParser.cpp#3580">
   1.269 +ParseSingleProperty</a>
   1.270 +. This method is responsible for calling the relevant helper routine to parse
   1.271 +the value(s). Find an existing property that is similar to the property you
   1.272 +are adding. For our example we are adding a property that takes a numeric
   1.273 +value so we will model it after the 'height' property and call ParsePositiveVariant.
   1.274 +Add a new case for the new property and call the appropriate parser-helper
   1.275 +and make a call to ParseVariant passing the <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSParser.cpp#2754">
   1.276 +variant flag</a>
   1.277 + that makes sense for your property. In our case<br>
   1.278 +  <br>
   1.279 +  <pre>  case eCSSProperty_force_broken_image_icons:</pre>
   1.280 +  <pre>    return ParsePositiveVariant(aErrorCode, aValue, VARIANT_INTEGER, nullptr);</pre>
   1.281 +This will parse the value as a positive integer value, which is what we want.<br>
   1.282 +  <br>
   1.283 +  <h3><a name="StyleContext">Style Context</a></h3>
   1.284 +Having implemented support for the new property in the CSS Parser and CSS
   1.285 +Declaration classes in the content module, it is now time to provide support
   1.286 +for the new property in layout. The Style Context must be given a new data
   1.287 +member corresponding to the declaration's new data member, so the computed
   1.288 +value can be held for the layout objects to use.<br>
   1.289 +  <br>
   1.290 +First look into <a href="http://lxr.mozilla.org/seamonkey/source/content/shared/public/nsStyleStruct.h">
   1.291 +nsStyleStruct.h</a>
   1.292 + to see the existing style strucs. Find the one that you want to store the
   1.293 +data on. In this example, we want to put it on the nsStyleUserInterface struct,
   1.294 +however there is also a class nsStyleUIReset that holds the non-inherited
   1.295 +values, so we will use that one (remember, our property is not inherited).
   1.296 +Add a <a href="#StyleContextMember">data member</a>
   1.297 + to hold the value:
   1.298 +  <pre>struct nsStyleUIReset {
   1.299 +  nsStyleUIReset(void);
   1.300 +  nsStyleUIReset(const nsStyleUIReset&amp; aOther);
   1.301 +  ~nsStyleUIReset(void);
   1.302 +
   1.303 +  NS_DEFINE_STATIC_STYLESTRUCTID_ACCESSOR(eStyleStruct_UIReset)
   1.304 +
   1.305 +  void* operator new(size_t sz, nsPresContext* aContext) {
   1.306 +    return aContext->AllocateFromShell(sz);
   1.307 +  }
   1.308 +  void Destroy(nsPresContext* aContext) {
   1.309 +    this-&gt;~nsStyleUIReset();
   1.310 +    aContext-&gt;FreeToShell(sizeof(nsStyleUIReset), this);
   1.311 +  };
   1.312 +
   1.313 +  int32_t CalcDifference(const nsStyleUIReset&amp; aOther) const;
   1.314 +
   1.315 +  uint8_t   mUserSelect;      // [reset] (selection-style)
   1.316 +  PRUnichar mKeyEquivalent;   // [reset] XXX what type should this be?
   1.317 +  uint8_t   mResizer;         // [reset]
   1.318 +  <b><a name="StyleContextMember"></a>uint8_t   mForceBrokenImageIcon; // [reset]  (0 if not forcing, otherwise forcing)</b>
   1.319 +};
   1.320 +</pre>
   1.321 +In the implementation file <a href="http://lxr.mozilla.org/seamonkey/source/content/shared/src/nsStyleStruct.cpp">
   1.322 +nsStyleContext.cpp </a>
   1.323 +add the new data member to the constructors of the style struct and the CalcDifference
   1.324 +method, which must return the correct style-change hint when a change to
   1.325 +your new property is detected. The constructor changes are obvious, but here
   1.326 +is the CalcDifference change for our example:<br>
   1.327 +  <pre>int32_t nsStyleUIReset::CalcDifference(const nsStyleUIReset&amp; aOther) const
   1.328 +{
   1.329 + <b> if (mForceBrokenImageIcon == aOther.mForceBrokenImageIcon) {</b>
   1.330 +    if (mResizer == aOther.mResizer) {
   1.331 +      if (mUserSelect == aOther.mUserSelect) {
   1.332 +        if (mKeyEquivalent == aOther.mKeyEquivalent) {
   1.333 +          return NS_STYLE_HINT_NONE;
   1.334 +        }
   1.335 +        return NS_STYLE_HINT_CONTENT;
   1.336 +      }
   1.337 +      return NS_STYLE_HINT_VISUAL;
   1.338 +    }
   1.339 +    return NS_STYLE_HINT_VISUAL;
   1.340 +  }
   1.341 +  <b>return NS_STYLE_HINT_FRAMECHANGE;
   1.342 +</b>}
   1.343 +</pre>
   1.344 +  <h3>CSSStyleRule</h3>
   1.345 +The nsCSSStyleRule must be updated to manage mapping the declaration to the
   1.346 +style struct. In the file <a href="http://lxr.mozilla.org/seamonkey/source/content/html/style/src/nsCSSStyleRule.cpp">
   1.347 +nsCSSStyleRule.cpp</a>
   1.348 +, locate the Declaration mapping function corresponding to the style struct
   1.349 +you have added your property to. For example, we <a href="http://bugzilla.mozilla.org/MapUIForDeclChange">
   1.350 +update </a>
   1.351 +MapUIForDeclaration:<br>
   1.352 +  <pre>static nsresult
   1.353 +MapUIForDeclaration(nsCSSDeclaration* aDecl, const nsStyleStructID&amp; aID, nsCSSUserInterface&amp; aUI)
   1.354 +{
   1.355 +  if (!aDecl)
   1.356 +    return NS_OK; // The rule must have a declaration.
   1.357 +
   1.358 +  nsCSSUserInterface* ourUI = (nsCSSUserInterface*)aDecl-&gt;GetData(kCSSUserInterfaceSID);
   1.359 +  if (!ourUI)
   1.360 +    return NS_OK; // We don't have any rules for UI.
   1.361 +
   1.362 +  if (aID == eStyleStruct_UserInterface) {
   1.363 +    if (aUI.mUserFocus.GetUnit() == eCSSUnit_Null &amp;&amp; ourUI-&gt;mUserFocus.GetUnit() != eCSSUnit_Null)
   1.364 +      aUI.mUserFocus = ourUI-&gt;mUserFocus;
   1.365 +    
   1.366 +    if (aUI.mUserInput.GetUnit() == eCSSUnit_Null &amp;&amp; ourUI-&gt;mUserInput.GetUnit() != eCSSUnit_Null)
   1.367 +      aUI.mUserInput = ourUI-&gt;mUserInput;
   1.368 +
   1.369 +    if (aUI.mUserModify.GetUnit() == eCSSUnit_Null &amp;&amp; ourUI-&gt;mUserModify.GetUnit() != eCSSUnit_Null)
   1.370 +      aUI.mUserModify = ourUI-&gt;mUserModify;
   1.371 +
   1.372 +    if (!aUI.mCursor &amp;&amp; ourUI-&gt;mCursor)
   1.373 +      aUI.mCursor = ourUI-&gt;mCursor;
   1.374 +
   1.375 +
   1.376 +  }
   1.377 +  else if (aID == eStyleStruct_UIReset) {
   1.378 +    if (aUI.mUserSelect.GetUnit() == eCSSUnit_Null &amp;&amp; ourUI-&gt;mUserSelect.GetUnit() != eCSSUnit_Null)
   1.379 +      aUI.mUserSelect = ourUI-&gt;mUserSelect;
   1.380 +   
   1.381 +    if (!aUI.mKeyEquivalent &amp;&amp; ourUI-&gt;mKeyEquivalent)
   1.382 +      aUI.mKeyEquivalent = ourUI-&gt;mKeyEquivalent;
   1.383 +
   1.384 +    if (aUI.mResizer.GetUnit() == eCSSUnit_Null &amp;&amp; ourUI-&gt;mResizer.GetUnit() != eCSSUnit_Null)
   1.385 +      aUI.mResizer = ourUI-&gt;mResizer;
   1.386 +    <b>
   1.387 +    <a name="MapUIForDeclChange"></a>if (aUI.mForceBrokenImageIcon.GetUnit() == eCSSUnit_Null &amp;&amp; ourUI-&gt;mForceBrokenImageIcon.GetUnit() == eCSSUnit_Integer)
   1.388 +      aUI.mForceBrokenImageIcon = ourUI-&gt;mForceBrokenImageIcon;</b>
   1.389 +  }
   1.390 +
   1.391 +  return NS_OK;
   1.392 +
   1.393 +}
   1.394 +</pre>
   1.395 +  <h3><a name="RuleNode">Rule Node</a></h3>
   1.396 +Now we have to update the RuleNode code to know about the new property. First,
   1.397 +locate the PropertyCheckData array for the data that you added the new property
   1.398 +to. For this example, we add the following:<br>
   1.399 +  <pre>static const PropertyCheckData UIResetCheckProperties[] = {
   1.400 +  CHECKDATA_PROP(nsCSSUserInterface, mUserSelect, CHECKDATA_VALUE, PR_FALSE),
   1.401 +  CHECKDATA_PROP(nsCSSUserInterface, mResizer, CHECKDATA_VALUE, PR_FALSE),
   1.402 +  CHECKDATA_PROP(nsCSSUserInterface, mKeyEquivalent, CHECKDATA_VALUELIST, PR_FALSE)
   1.403 +  <b>CHECKDATA_PROP(nsCSSUserInterface, mForceBrokenImageIcon, CHECKDATA_VALUE, PR_FALSE)</b>
   1.404 +};
   1.405 +</pre>
   1.406 +The first two arguments correspond to the structure and data member from
   1.407 +the CSSDeclaration, the third is the data type, the fourth indicates
   1.408 +whether it is a coord value that uses an explicit inherit value on the
   1.409 +style data struct that must be computed by layout.<br>
   1.410 +  <br>
   1.411 +Next, we have to make sure the ComputeXXX method for the structure the property
   1.412 +was added to is updated to mange the new value. In this example we need to
   1.413 +modify the nsRuleNode::ComputeUIResetData method to handle the CSS Declaration
   1.414 +to the style struct:<br>
   1.415 +  <pre>  ...
   1.416 +  // resizer: auto, none, enum, inherit
   1.417 +  if (eCSSUnit_Enumerated == uiData.mResizer.GetUnit()) {
   1.418 +    ui-&gt;mResizer = uiData.mResizer.GetIntValue();
   1.419 +  }
   1.420 +  else if (eCSSUnit_Auto == uiData.mResizer.GetUnit()) {
   1.421 +    ui-&gt;mResizer = NS_STYLE_RESIZER_AUTO;
   1.422 +  }
   1.423 +  else if (eCSSUnit_None == uiData.mResizer.GetUnit()) {
   1.424 +    ui-&gt;mResizer = NS_STYLE_RESIZER_NONE;
   1.425 +  }
   1.426 +  else if (eCSSUnit_Inherit == uiData.mResizer.GetUnit()) {
   1.427 +    inherited = PR_TRUE;
   1.428 +    ui-&gt;mResizer = parentUI-&gt;mResizer;
   1.429 +  }
   1.430 +
   1.431 +  <b>// force-broken-image-icons: integer, inherit, initial
   1.432 +  if (eCSSUnit_Integer == uiData.mForceBrokenImageIcons.GetUnit()) {
   1.433 +    ui-&gt;mForceBrokenImageIcons = uiData.mForceBrokenImageIcons.GetIntValue();
   1.434 +  } else if (eCSSUnit_Inherit == uiData.mForceBrokenImageIcons.GetUnit()) {
   1.435 +    inherited = PR_TRUE;
   1.436 +    ui-&gt;mForceBrokenImageIcons = parentUI-&gt;mForceBrokenImageIcons;
   1.437 +  } else if (eCSSUnit_Initial == uiData.mForceBrokenImageIcons.GetUnit()) {
   1.438 +    ui-&gt;mForceBrokenImageIcons = 0;
   1.439 +  }</b>
   1.440 +  
   1.441 +  if (inherited)
   1.442 +    // We inherited, and therefore can't be cached in the rule node.  We have to be put right on the
   1.443 +    // style context.
   1.444 +    aContext-&gt;SetStyle(eStyleStruct_UIReset, *ui);
   1.445 +  else {
   1.446 +    // We were fully specified and can therefore be cached right on the rule node.
   1.447 +    if (!aHighestNode-&gt;mStyleData.mResetData)
   1.448 +      aHighestNode-&gt;mStyleData.mResetData = new (mPresContext) nsResetStyleData;
   1.449 +    aHighestNode-&gt;mStyleData.mResetData-&gt;mUIData = ui;
   1.450 +    // Propagate the bit down.
   1.451 +    PropagateDependentBit(NS_STYLE_INHERIT_UI_RESET, aHighestNode);
   1.452 +  }
   1.453 +  ...
   1.454 +</pre>
   1.455 +  <h3><a name="DOM">DOM</a></h3>
   1.456 +Users in scripts, or anywhere outside of layout/ or content/ may need to access
   1.457 +the new property.  This is done using the CSS OM, specifically
   1.458 +<code>nsIDOMCSSStyleDeclaration</code> and <code>CSS2Properties</code>.
   1.459 +By the magic of C++ pre-processing, the
   1.460 +CSS2Properties bits will be implemented automatically when you
   1.461 +<a href="#CSSPropList">add your property</a> to <a href="http://lxr.mozilla.org/seamonkey/source/content/shared/public/nsCSSPropList.h">
   1.462 +nsCSSPropList.h</a>.
   1.463 +  <h3><a name="Layout">Layout</a></h3>
   1.464 +OK, finally the style system is supporting the new property. It is time to
   1.465 +actually make use of it now.<br>
   1.466 +  <br>
   1.467 +In layout, retrieve the styleStruct that has the new property from the frame's
   1.468 +style context. Access the new property and get its value. It is that simple.
   1.469 +For this example, it looks like this, in nsImageFrame:<br>
   1.470 +  <pre>        PRBool forceIcon = PR_FALSE;
   1.471 +
   1.472 +        if (StyleUIReset()-&gt;mForceBrokenImageIcon) {
   1.473 +          forceIcon = PR_TRUE;
   1.474 +        }
   1.475 +
   1.476 +</pre>
   1.477 +Create some testcases with style rules that use the new property, make sure
   1.478 +it is being parsed correctly. Test it in an external stylesheet and in inline
   1.479 +style. Test that it is inherited correctly, or not inherited as appropriate
   1.480 +to your property. Update this document with any further details, or correcting
   1.481 +any errors.<br>
   1.482 +  </body></html>

mercurial