diff -r 000000000000 -r 6474c204b198 layout/doc/adding-style-props.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/layout/doc/adding-style-props.html Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,479 @@ + + +
+ +++Document history:
++
+- 03/21/2002: Marc Attinasi (attinasi@netscape.com) created document +/ implementing -moz-force-broken-image-icon for bug +58646
+- + 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. +
+- + 11/09/2002: Christopher Aillon (caillon@returnzero.com): updated + nsCSSPropList.h macro description and added information about + nsIDOMCSS2Properties.idl. +
++ NOTE: This document is still missing a few pieces. I need to + add information on adding to
+nsComputedDOMStyle
. +
Up front you have to decide some things about the new property:
+ +Questions:
+Answers:
+There are several places that need to be educated about a new style property. +They are: +
++First, add the new name to the property list in +nsCSSPropList.h + Insert the property in the list alphabetically, using the existing +property names as a template. The format of the entry you will create is: +
+CSS_PROP(-moz-force-broken-image-icons, force_broken_image_icons, MozForceBrokenImageIcons, NS_STYLE_HINT_FRAMECHANGE) // bug 58646+ +
The first value is the formal property name, in other words the property
+name as it is seen by the CSS parser.
+The second value is the name of the property as it will appear internally.
+The third value is the name of the DOM property used to access your style.
+The last value indicates what must change when the value of the property
+changes. It should be an
+nsChangeHint.
If you need to introduce new constants for the values of the property, they +must be added to +nsStyleConsts.h + and to the appropriate keyword tables in +nsCSSProps.cpp + (note: this cookbook does not do this since the new property does not require +any new keywords for the property values). +
// 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->mUserInput = aValue; break; + case eCSSProperty_user_modify: theUserInterface->mUserModify = aValue; break; + case eCSSProperty_user_select: theUserInterface->mUserSelect = aValue; break; + case eCSSProperty_key_equivalent: + CSS_ENSURE_DATA(theUserInterface->mKeyEquivalent, nsCSSValueList) { + theUserInterface->mKeyEquivalent->mValue = aValue; + CSS_IF_DELETE(theUserInterface->mKeyEquivalent->mNext); + } + break; + case eCSSProperty_user_focus: theUserInterface->mUserFocus = aValue; break; + case eCSSProperty_resizer: theUserInterface->mResizer = aValue; break; + case eCSSProperty_cursor: + CSS_ENSURE_DATA(theUserInterface->mCursor, nsCSSValueList) { + theUserInterface->mCursor->mValue = aValue; + CSS_IF_DELETE(theUserInterface->mCursor->mNext); + } + break; + case eCSSProperty_force_broken_image_icons: theUserInterface->mForceBrokenImageIcon = aValue; break; + + CSS_BOGUS_DEFAULT; // make compiler happy + } + } + break; + } + ++The GetValue method must be similarly modified +:
// 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->mUserInput; break; + case eCSSProperty_user_modify: aValue = theUserInterface->mUserModify; break; + case eCSSProperty_user_select: aValue = theUserInterface->mUserSelect; break; + case eCSSProperty_key_equivalent: + if (nullptr != theUserInterface->mKeyEquivalent) { + aValue = theUserInterface->mKeyEquivalent->mValue; + } + break; + case eCSSProperty_user_focus: aValue = theUserInterface->mUserFocus; break; + case eCSSProperty_resizer: aValue = theUserInterface->mResizer; break; + case eCSSProperty_cursor: + if (nullptr != theUserInterface->mCursor) { + aValue = theUserInterface->mCursor->mValue; + } + break; + case eCSSProperty_force_broken_image_icons: aValue = theUserInterface->mForceBrokenImageIcons; break; + + CSS_BOGUS_DEFAULT; // make compiler happy + } + } + else { + aValue.Reset(); + } + break; + } + ++Finally modify +the 'List' method to output the property value.
void nsCSSUserInterface::List(FILE* out, int32_t aIndent) const +{ + for (int32_t index = aIndent; --index >= 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->mValue.AppendToString(buffer, eCSSProperty_key_equivalent); + keyEquiv= keyEquiv->mNext; + } + mUserFocus.AppendToString(buffer, eCSSProperty_user_focus); + mResizer.AppendToString(buffer, eCSSProperty_resizer); + + nsCSSValueList* cursor = mCursor; + while (nullptr != cursor) { + cursor->mValue.AppendToString(buffer, eCSSProperty_cursor); + cursor = cursor->mNext; + } + + mForceBrokenImageIcon.AppendToString(buffer,eCSSProperty_force_broken_image_icons); + + fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out); +} + ++ +
case eCSSProperty_force_broken_image_icons:+
return ParsePositiveVariant(aErrorCode, aValue, VARIANT_INTEGER, nullptr);+This will parse the value as a positive integer value, which is what we want.
struct nsStyleUIReset { + nsStyleUIReset(void); + nsStyleUIReset(const nsStyleUIReset& 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->~nsStyleUIReset(); + aContext->FreeToShell(sizeof(nsStyleUIReset), this); + }; + + int32_t CalcDifference(const nsStyleUIReset& aOther) const; + + uint8_t mUserSelect; // [reset] (selection-style) + PRUnichar mKeyEquivalent; // [reset] XXX what type should this be? + uint8_t mResizer; // [reset] + uint8_t mForceBrokenImageIcon; // [reset] (0 if not forcing, otherwise forcing) +}; ++In the implementation file +nsStyleContext.cpp +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:
int32_t nsStyleUIReset::CalcDifference(const nsStyleUIReset& aOther) const +{ + if (mForceBrokenImageIcon == aOther.mForceBrokenImageIcon) { + 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; + } + return NS_STYLE_HINT_FRAMECHANGE; +} ++
static nsresult +MapUIForDeclaration(nsCSSDeclaration* aDecl, const nsStyleStructID& aID, nsCSSUserInterface& aUI) +{ + if (!aDecl) + return NS_OK; // The rule must have a declaration. + + nsCSSUserInterface* ourUI = (nsCSSUserInterface*)aDecl->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 && ourUI->mUserFocus.GetUnit() != eCSSUnit_Null) + aUI.mUserFocus = ourUI->mUserFocus; + + if (aUI.mUserInput.GetUnit() == eCSSUnit_Null && ourUI->mUserInput.GetUnit() != eCSSUnit_Null) + aUI.mUserInput = ourUI->mUserInput; + + if (aUI.mUserModify.GetUnit() == eCSSUnit_Null && ourUI->mUserModify.GetUnit() != eCSSUnit_Null) + aUI.mUserModify = ourUI->mUserModify; + + if (!aUI.mCursor && ourUI->mCursor) + aUI.mCursor = ourUI->mCursor; + + + } + else if (aID == eStyleStruct_UIReset) { + if (aUI.mUserSelect.GetUnit() == eCSSUnit_Null && ourUI->mUserSelect.GetUnit() != eCSSUnit_Null) + aUI.mUserSelect = ourUI->mUserSelect; + + if (!aUI.mKeyEquivalent && ourUI->mKeyEquivalent) + aUI.mKeyEquivalent = ourUI->mKeyEquivalent; + + if (aUI.mResizer.GetUnit() == eCSSUnit_Null && ourUI->mResizer.GetUnit() != eCSSUnit_Null) + aUI.mResizer = ourUI->mResizer; + + if (aUI.mForceBrokenImageIcon.GetUnit() == eCSSUnit_Null && ourUI->mForceBrokenImageIcon.GetUnit() == eCSSUnit_Integer) + aUI.mForceBrokenImageIcon = ourUI->mForceBrokenImageIcon; + } + + return NS_OK; + +} ++
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) + CHECKDATA_PROP(nsCSSUserInterface, mForceBrokenImageIcon, CHECKDATA_VALUE, PR_FALSE) +}; ++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.
... + // resizer: auto, none, enum, inherit + if (eCSSUnit_Enumerated == uiData.mResizer.GetUnit()) { + ui->mResizer = uiData.mResizer.GetIntValue(); + } + else if (eCSSUnit_Auto == uiData.mResizer.GetUnit()) { + ui->mResizer = NS_STYLE_RESIZER_AUTO; + } + else if (eCSSUnit_None == uiData.mResizer.GetUnit()) { + ui->mResizer = NS_STYLE_RESIZER_NONE; + } + else if (eCSSUnit_Inherit == uiData.mResizer.GetUnit()) { + inherited = PR_TRUE; + ui->mResizer = parentUI->mResizer; + } + + // force-broken-image-icons: integer, inherit, initial + if (eCSSUnit_Integer == uiData.mForceBrokenImageIcons.GetUnit()) { + ui->mForceBrokenImageIcons = uiData.mForceBrokenImageIcons.GetIntValue(); + } else if (eCSSUnit_Inherit == uiData.mForceBrokenImageIcons.GetUnit()) { + inherited = PR_TRUE; + ui->mForceBrokenImageIcons = parentUI->mForceBrokenImageIcons; + } else if (eCSSUnit_Initial == uiData.mForceBrokenImageIcons.GetUnit()) { + ui->mForceBrokenImageIcons = 0; + } + + 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->SetStyle(eStyleStruct_UIReset, *ui); + else { + // We were fully specified and can therefore be cached right on the rule node. + if (!aHighestNode->mStyleData.mResetData) + aHighestNode->mStyleData.mResetData = new (mPresContext) nsResetStyleData; + aHighestNode->mStyleData.mResetData->mUIData = ui; + // Propagate the bit down. + PropagateDependentBit(NS_STYLE_INHERIT_UI_RESET, aHighestNode); + } + ... ++
nsIDOMCSSStyleDeclaration
and CSS2Properties
.
+By the magic of C++ pre-processing, the
+CSS2Properties bits will be implemented automatically when you
+add your property to
+nsCSSPropList.h.
+ PRBool forceIcon = PR_FALSE; + + if (StyleUIReset()->mForceBrokenImageIcon) { + forceIcon = PR_TRUE; + } + ++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.