michael@0: michael@0: michael@0:
michael@0: michael@0:michael@0:michael@0:Document history:
michael@0:michael@0:
michael@0:- 03/21/2002: Marc Attinasi (attinasi@netscape.com) created document michael@0: / implementing -moz-force-broken-image-icon for bug michael@0: 58646
michael@0:- michael@0: 6/18/2002: David Baron (dbaron@dbaron.org): corrected support michael@0: for 'inherit' and 'initial' (didn't test with code, though), michael@0: and explained what the final boolean in CheckPropertyData is for. michael@0:
michael@0:- michael@0: 11/09/2002: Christopher Aillon (caillon@returnzero.com): updated michael@0: nsCSSPropList.h macro description and added information about michael@0: nsIDOMCSS2Properties.idl. michael@0:
michael@0:michael@0: NOTE: This document is still missing a few pieces. I need to michael@0: add information on adding to
michael@0:nsComputedDOMStyle
. michael@0:
Up front you have to decide some things about the new property:
michael@0: michael@0:Questions:
michael@0:Answers:
michael@0:There are several places that need to be educated about a new style property. michael@0: They are: michael@0:
michael@0:michael@0: First, add the new name to the property list in michael@0: nsCSSPropList.h michael@0: Insert the property in the list alphabetically, using the existing michael@0: property names as a template. The format of the entry you will create is: michael@0:
michael@0:CSS_PROP(-moz-force-broken-image-icons, force_broken_image_icons, MozForceBrokenImageIcons, NS_STYLE_HINT_FRAMECHANGE) // bug 58646michael@0: michael@0:
The first value is the formal property name, in other words the property
michael@0: name as it is seen by the CSS parser.
michael@0: The second value is the name of the property as it will appear internally.
michael@0: The third value is the name of the DOM property used to access your style.
michael@0: The last value indicates what must change when the value of the property
michael@0: changes. It should be an
michael@0: nsChangeHint.
If you need to introduce new constants for the values of the property, they michael@0: must be added to michael@0: nsStyleConsts.h michael@0: and to the appropriate keyword tables in michael@0: nsCSSProps.cpp michael@0: (note: this cookbook does not do this since the new property does not require michael@0: any new keywords for the property values). michael@0:
// nsCSSUserInterface michael@0: case eCSSProperty_user_input: michael@0: case eCSSProperty_user_modify: michael@0: case eCSSProperty_user_select: michael@0: case eCSSProperty_key_equivalent: michael@0: case eCSSProperty_user_focus: michael@0: case eCSSProperty_resizer: michael@0: case eCSSProperty_cursor: michael@0: case eCSSProperty_force_broken_image_icons: { michael@0: CSS_ENSURE(UserInterface) { michael@0: switch (aProperty) { michael@0: case eCSSProperty_user_input: theUserInterface->mUserInput = aValue; break; michael@0: case eCSSProperty_user_modify: theUserInterface->mUserModify = aValue; break; michael@0: case eCSSProperty_user_select: theUserInterface->mUserSelect = aValue; break; michael@0: case eCSSProperty_key_equivalent: michael@0: CSS_ENSURE_DATA(theUserInterface->mKeyEquivalent, nsCSSValueList) { michael@0: theUserInterface->mKeyEquivalent->mValue = aValue; michael@0: CSS_IF_DELETE(theUserInterface->mKeyEquivalent->mNext); michael@0: } michael@0: break; michael@0: case eCSSProperty_user_focus: theUserInterface->mUserFocus = aValue; break; michael@0: case eCSSProperty_resizer: theUserInterface->mResizer = aValue; break; michael@0: case eCSSProperty_cursor: michael@0: CSS_ENSURE_DATA(theUserInterface->mCursor, nsCSSValueList) { michael@0: theUserInterface->mCursor->mValue = aValue; michael@0: CSS_IF_DELETE(theUserInterface->mCursor->mNext); michael@0: } michael@0: break; michael@0: case eCSSProperty_force_broken_image_icons: theUserInterface->mForceBrokenImageIcon = aValue; break; michael@0: michael@0: CSS_BOGUS_DEFAULT; // make compiler happy michael@0: } michael@0: } michael@0: break; michael@0: } michael@0: michael@0:michael@0: The GetValue method must be similarly modified michael@0: :
// nsCSSUserInterface michael@0: case eCSSProperty_user_input: michael@0: case eCSSProperty_user_modify: michael@0: case eCSSProperty_user_select: michael@0: case eCSSProperty_key_equivalent: michael@0: case eCSSProperty_user_focus: michael@0: case eCSSProperty_resizer: michael@0: case eCSSProperty_cursor: michael@0: case eCSSProperty_force_broken_image_icons: { michael@0: CSS_VARONSTACK_GET(UserInterface); michael@0: if (nullptr != theUserInterface) { michael@0: switch (aProperty) { michael@0: case eCSSProperty_user_input: aValue = theUserInterface->mUserInput; break; michael@0: case eCSSProperty_user_modify: aValue = theUserInterface->mUserModify; break; michael@0: case eCSSProperty_user_select: aValue = theUserInterface->mUserSelect; break; michael@0: case eCSSProperty_key_equivalent: michael@0: if (nullptr != theUserInterface->mKeyEquivalent) { michael@0: aValue = theUserInterface->mKeyEquivalent->mValue; michael@0: } michael@0: break; michael@0: case eCSSProperty_user_focus: aValue = theUserInterface->mUserFocus; break; michael@0: case eCSSProperty_resizer: aValue = theUserInterface->mResizer; break; michael@0: case eCSSProperty_cursor: michael@0: if (nullptr != theUserInterface->mCursor) { michael@0: aValue = theUserInterface->mCursor->mValue; michael@0: } michael@0: break; michael@0: case eCSSProperty_force_broken_image_icons: aValue = theUserInterface->mForceBrokenImageIcons; break; michael@0: michael@0: CSS_BOGUS_DEFAULT; // make compiler happy michael@0: } michael@0: } michael@0: else { michael@0: aValue.Reset(); michael@0: } michael@0: break; michael@0: } michael@0: michael@0:michael@0: Finally modify michael@0: the 'List' method to output the property value.
void nsCSSUserInterface::List(FILE* out, int32_t aIndent) const michael@0: { michael@0: for (int32_t index = aIndent; --index >= 0; ) fputs(" ", out); michael@0: michael@0: nsAutoString buffer; michael@0: michael@0: mUserInput.AppendToString(buffer, eCSSProperty_user_input); michael@0: mUserModify.AppendToString(buffer, eCSSProperty_user_modify); michael@0: mUserSelect.AppendToString(buffer, eCSSProperty_user_select); michael@0: nsCSSValueList* keyEquiv = mKeyEquivalent; michael@0: while (nullptr != keyEquiv) { michael@0: keyEquiv->mValue.AppendToString(buffer, eCSSProperty_key_equivalent); michael@0: keyEquiv= keyEquiv->mNext; michael@0: } michael@0: mUserFocus.AppendToString(buffer, eCSSProperty_user_focus); michael@0: mResizer.AppendToString(buffer, eCSSProperty_resizer); michael@0: michael@0: nsCSSValueList* cursor = mCursor; michael@0: while (nullptr != cursor) { michael@0: cursor->mValue.AppendToString(buffer, eCSSProperty_cursor); michael@0: cursor = cursor->mNext; michael@0: } michael@0: michael@0: mForceBrokenImageIcon.AppendToString(buffer,eCSSProperty_force_broken_image_icons); michael@0: michael@0: fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out); michael@0: } michael@0: michael@0:michael@0: michael@0:
case eCSSProperty_force_broken_image_icons:michael@0:
return ParsePositiveVariant(aErrorCode, aValue, VARIANT_INTEGER, nullptr);michael@0: This will parse the value as a positive integer value, which is what we want.
struct nsStyleUIReset { michael@0: nsStyleUIReset(void); michael@0: nsStyleUIReset(const nsStyleUIReset& aOther); michael@0: ~nsStyleUIReset(void); michael@0: michael@0: NS_DEFINE_STATIC_STYLESTRUCTID_ACCESSOR(eStyleStruct_UIReset) michael@0: michael@0: void* operator new(size_t sz, nsPresContext* aContext) { michael@0: return aContext->AllocateFromShell(sz); michael@0: } michael@0: void Destroy(nsPresContext* aContext) { michael@0: this->~nsStyleUIReset(); michael@0: aContext->FreeToShell(sizeof(nsStyleUIReset), this); michael@0: }; michael@0: michael@0: int32_t CalcDifference(const nsStyleUIReset& aOther) const; michael@0: michael@0: uint8_t mUserSelect; // [reset] (selection-style) michael@0: PRUnichar mKeyEquivalent; // [reset] XXX what type should this be? michael@0: uint8_t mResizer; // [reset] michael@0: uint8_t mForceBrokenImageIcon; // [reset] (0 if not forcing, otherwise forcing) michael@0: }; michael@0:michael@0: In the implementation file michael@0: nsStyleContext.cpp michael@0: add the new data member to the constructors of the style struct and the CalcDifference michael@0: method, which must return the correct style-change hint when a change to michael@0: your new property is detected. The constructor changes are obvious, but here michael@0: is the CalcDifference change for our example:
int32_t nsStyleUIReset::CalcDifference(const nsStyleUIReset& aOther) const michael@0: { michael@0: if (mForceBrokenImageIcon == aOther.mForceBrokenImageIcon) { michael@0: if (mResizer == aOther.mResizer) { michael@0: if (mUserSelect == aOther.mUserSelect) { michael@0: if (mKeyEquivalent == aOther.mKeyEquivalent) { michael@0: return NS_STYLE_HINT_NONE; michael@0: } michael@0: return NS_STYLE_HINT_CONTENT; michael@0: } michael@0: return NS_STYLE_HINT_VISUAL; michael@0: } michael@0: return NS_STYLE_HINT_VISUAL; michael@0: } michael@0: return NS_STYLE_HINT_FRAMECHANGE; michael@0: } michael@0:michael@0:
static nsresult michael@0: MapUIForDeclaration(nsCSSDeclaration* aDecl, const nsStyleStructID& aID, nsCSSUserInterface& aUI) michael@0: { michael@0: if (!aDecl) michael@0: return NS_OK; // The rule must have a declaration. michael@0: michael@0: nsCSSUserInterface* ourUI = (nsCSSUserInterface*)aDecl->GetData(kCSSUserInterfaceSID); michael@0: if (!ourUI) michael@0: return NS_OK; // We don't have any rules for UI. michael@0: michael@0: if (aID == eStyleStruct_UserInterface) { michael@0: if (aUI.mUserFocus.GetUnit() == eCSSUnit_Null && ourUI->mUserFocus.GetUnit() != eCSSUnit_Null) michael@0: aUI.mUserFocus = ourUI->mUserFocus; michael@0: michael@0: if (aUI.mUserInput.GetUnit() == eCSSUnit_Null && ourUI->mUserInput.GetUnit() != eCSSUnit_Null) michael@0: aUI.mUserInput = ourUI->mUserInput; michael@0: michael@0: if (aUI.mUserModify.GetUnit() == eCSSUnit_Null && ourUI->mUserModify.GetUnit() != eCSSUnit_Null) michael@0: aUI.mUserModify = ourUI->mUserModify; michael@0: michael@0: if (!aUI.mCursor && ourUI->mCursor) michael@0: aUI.mCursor = ourUI->mCursor; michael@0: michael@0: michael@0: } michael@0: else if (aID == eStyleStruct_UIReset) { michael@0: if (aUI.mUserSelect.GetUnit() == eCSSUnit_Null && ourUI->mUserSelect.GetUnit() != eCSSUnit_Null) michael@0: aUI.mUserSelect = ourUI->mUserSelect; michael@0: michael@0: if (!aUI.mKeyEquivalent && ourUI->mKeyEquivalent) michael@0: aUI.mKeyEquivalent = ourUI->mKeyEquivalent; michael@0: michael@0: if (aUI.mResizer.GetUnit() == eCSSUnit_Null && ourUI->mResizer.GetUnit() != eCSSUnit_Null) michael@0: aUI.mResizer = ourUI->mResizer; michael@0: michael@0: if (aUI.mForceBrokenImageIcon.GetUnit() == eCSSUnit_Null && ourUI->mForceBrokenImageIcon.GetUnit() == eCSSUnit_Integer) michael@0: aUI.mForceBrokenImageIcon = ourUI->mForceBrokenImageIcon; michael@0: } michael@0: michael@0: return NS_OK; michael@0: michael@0: } michael@0:michael@0:
static const PropertyCheckData UIResetCheckProperties[] = { michael@0: CHECKDATA_PROP(nsCSSUserInterface, mUserSelect, CHECKDATA_VALUE, PR_FALSE), michael@0: CHECKDATA_PROP(nsCSSUserInterface, mResizer, CHECKDATA_VALUE, PR_FALSE), michael@0: CHECKDATA_PROP(nsCSSUserInterface, mKeyEquivalent, CHECKDATA_VALUELIST, PR_FALSE) michael@0: CHECKDATA_PROP(nsCSSUserInterface, mForceBrokenImageIcon, CHECKDATA_VALUE, PR_FALSE) michael@0: }; michael@0:michael@0: The first two arguments correspond to the structure and data member from michael@0: the CSSDeclaration, the third is the data type, the fourth indicates michael@0: whether it is a coord value that uses an explicit inherit value on the michael@0: style data struct that must be computed by layout.
... michael@0: // resizer: auto, none, enum, inherit michael@0: if (eCSSUnit_Enumerated == uiData.mResizer.GetUnit()) { michael@0: ui->mResizer = uiData.mResizer.GetIntValue(); michael@0: } michael@0: else if (eCSSUnit_Auto == uiData.mResizer.GetUnit()) { michael@0: ui->mResizer = NS_STYLE_RESIZER_AUTO; michael@0: } michael@0: else if (eCSSUnit_None == uiData.mResizer.GetUnit()) { michael@0: ui->mResizer = NS_STYLE_RESIZER_NONE; michael@0: } michael@0: else if (eCSSUnit_Inherit == uiData.mResizer.GetUnit()) { michael@0: inherited = PR_TRUE; michael@0: ui->mResizer = parentUI->mResizer; michael@0: } michael@0: michael@0: // force-broken-image-icons: integer, inherit, initial michael@0: if (eCSSUnit_Integer == uiData.mForceBrokenImageIcons.GetUnit()) { michael@0: ui->mForceBrokenImageIcons = uiData.mForceBrokenImageIcons.GetIntValue(); michael@0: } else if (eCSSUnit_Inherit == uiData.mForceBrokenImageIcons.GetUnit()) { michael@0: inherited = PR_TRUE; michael@0: ui->mForceBrokenImageIcons = parentUI->mForceBrokenImageIcons; michael@0: } else if (eCSSUnit_Initial == uiData.mForceBrokenImageIcons.GetUnit()) { michael@0: ui->mForceBrokenImageIcons = 0; michael@0: } michael@0: michael@0: if (inherited) michael@0: // We inherited, and therefore can't be cached in the rule node. We have to be put right on the michael@0: // style context. michael@0: aContext->SetStyle(eStyleStruct_UIReset, *ui); michael@0: else { michael@0: // We were fully specified and can therefore be cached right on the rule node. michael@0: if (!aHighestNode->mStyleData.mResetData) michael@0: aHighestNode->mStyleData.mResetData = new (mPresContext) nsResetStyleData; michael@0: aHighestNode->mStyleData.mResetData->mUIData = ui; michael@0: // Propagate the bit down. michael@0: PropagateDependentBit(NS_STYLE_INHERIT_UI_RESET, aHighestNode); michael@0: } michael@0: ... michael@0:michael@0:
nsIDOMCSSStyleDeclaration
and CSS2Properties
.
michael@0: By the magic of C++ pre-processing, the
michael@0: CSS2Properties bits will be implemented automatically when you
michael@0: add your property to
michael@0: nsCSSPropList.h.
michael@0: PRBool forceIcon = PR_FALSE; michael@0: michael@0: if (StyleUIReset()->mForceBrokenImageIcon) { michael@0: forceIcon = PR_TRUE; michael@0: } michael@0: michael@0:michael@0: Create some testcases with style rules that use the new property, make sure michael@0: it is being parsed correctly. Test it in an external stylesheet and in inline michael@0: style. Test that it is inherited correctly, or not inherited as appropriate michael@0: to your property. Update this document with any further details, or correcting michael@0: any errors.