Closed Bug 311827 Opened 19 years ago Closed 19 years ago

Make GetAttr return a bool

Categories

(Core :: DOM: Core & HTML, defect)

defect
Not set
normal

Tracking

()

RESOLVED FIXED

People

(Reporter: sicking, Assigned: sicking)

References

Details

Attachments

(2 files, 2 obsolete files)

The current situation where GetAttr returns an nsresult containing one of three
possible values, all success values, is less then optimal.

First we for every getattr have to check if the returned string is empty or not,
which in most cases is then just ignored. Second, nsGenericHTMLElement behaves
differently from all other elements and never returns NO_VALUE, only NOT_THERE
or HAS_VALUE, so for a random element you can't rely on the returned value anyway.

And in most places in the code it is very unclear if the author really want to
differentiate between an attribute being set to "" or the attribute being
missing, or if that was just a misstake not realizing that there are three
possible returns.

So I propose that we make GetAttr return a bool indicating whether the attribute
was set or not. This makes it easy to differentiate between missing and
emptystring, and noone should waste time on NS_ENSURE_SUCCESS checks.

I'm currently going through the tree removing by searching for NS_CONTENT_ATTR_.
So I might miss a few places where we do 
rv = GetAttr(...
NS_ENSURE_SUCCESS(rv, rv)

However code like that should behave correctly since both PR_TRUE and PR_FALSE
will be treated as success values. My plan is to make a followup patch once the
first patch is in and I can use lxr to search for the remaining.
> Second, nsGenericHTMLElement behaves differently from all other elements

That's fixed in bug 309054 fwiw -- it's just been waiting on review for a few
weeks now...

> And in most places in the code it is very unclear if the author really want

Agreed, and this is the hardest part of making this change.

Generally I would OK with this, I think...  I agree that it would make things
clearer for callers.
(In reply to comment #1)
> > And in most places in the code it is very unclear if the author really want
> Agreed, and this is the hardest part of making this change.

Yes, this is a pain. I'm trying to not make any changes except in the places
where I think the code is doing the wrong thing. Once this patch has landed it
should be clearer what the code does and people can fix the areas that are wrong.
Again, bug 309054 has a bunch of places that we've already looked at, I think...
 So you probably want to use that as a basis, not the current tree.
Attached patch Patch to fix (obsolete) — Splinter Review
This should do it. I've merged in the patch from bug 309054, but this one
touches a whole lot more places.

The only thing I did differently was the comments about the basetag handling in
the sinks. Why would we want to ignore the attributes if they contain the empty
string? Seems like "" is a valid value both for base-target and base-href?
Attachment #199195 - Flags: superreview?(peterv)
Attachment #199195 - Flags: review?(bzbarsky)
Comment on attachment 199195 [details] [diff] [review]
Patch to fix

Aaron: It would be great if you could look at the accessibility changes to this
patch too. It's basically the same idea as bug 309054, but it touches more
places.
Attachment #199195 - Flags: review?(aaronleventhal)
Attached patch With -w (obsolete) — Splinter Review
Same as previous but with -w. Should be a lot eaiser to see what's going on
since i've merged if-statements in a few places.
The SVG specification says that for requiredFeatures, requiredExtensions, and
systemLanguage that "" is equivalent to false.

    http://www.w3.org/TR/SVG11/struct.html#RequiredFeaturesAttribute
    http://www.w3.org/TR/SVG11/struct.html#RequiredExtensionsAttribute
    http://www.w3.org/TR/SVG11/struct.html#SystemLanguageAttribute
> Seems like "" is a valid value both for base-target and base-href?

Might be OK for base target.  Base href is an absolute URI, so "" will just
throw when we NS_NewURI in ProcessBaseHref.  Bailing up front might be faster,
but maybe not...

I'll try to get to this this weekend.
Comment on attachment 199195 [details] [diff] [review]
Patch to fix

Actually, i think an r/sr is good enough here. It's a lot of changes, but they
are all really simple.
Attachment #199195 - Flags: superreview?(peterv) → superreview?(bzbarsky)
Comment on attachment 199195 [details] [diff] [review]
Patch to fix

> * @returns PR_TRUE if the attribute was set (even when set to empty string)
Nit: s/was/is -- if someone does a removeAttribute call after that attribute was set I hope it will return false

r=aaronlev on the accessible parts.
Attachment #199195 - Flags: review?(aaronleventhal) → review+
Comment on attachment 199195 [details] [diff] [review]
Patch to fix

There are some things I request that you fix below that might be ok not being fixed on initial checkin, since both PR_FALSE and PR_TRUE do test NS_SUCCEEDED...  Feel free to fix them either in this patch or in a followup.

>Index: accessible/src/base/nsAccessibilityService.cpp
> PRBool nsAccessibilityService::GetRole(nsIContent *aContent,
>-  return NS_CONTENT_ATTR_HAS_VALUE ==
>-         aContent->GetAttr(kNameSpaceID_XHTML2_Unofficial,
>+  return aContent->GetAttr(kNameSpaceID_XHTML2_Unofficial,

This changes the behavior, does it not?  I guess aaronl OK'ed it, so I'll just not worry about it, or the other accessibility changes.  At least too much.  ;)

aaron, please note that a lot of these changes change behavior if an attribute ise set, but set to the empty string.  I'm assuming you're ok with these behavior changes...

>Index: accessible/src/base/nsAccessible.cpp
>@@ -1289,20 +1286,18 @@ nsresult nsAccessible::AppendFlatStringF
>-      else if (NS_CONTENT_ATTR_HAS_VALUE !=
>-               aContent->GetAttr(kNameSpaceID_None,
>-                                 nsAccessibilityAtoms::tooltiptext,
>-                                 textEquivalent)) {
>+      else if (aContent->GetAttr(kNameSpaceID_None,
>+                                 nsAccessibilityAtoms::tooltiptext, textEquivalent)) {

I believe you want a ! there.  And possibly a IsEmpty() check on textEquivalent?  So

  else if (!aContent->GetAttr( ... ) || textEquivalent.IsEmpty()) {
  }

> nsresult nsAccessible::GetTextFromRelationID(nsIAtom *aIDAttrib, nsString &aName)
>   nsAutoString id;
>-  if (NS_CONTENT_ATTR_HAS_VALUE !=
>-      content->GetAttr(kNameSpaceID_WAIProperties, aIDAttrib, id)) {
>+  if (!content->GetAttr(kNameSpaceID_WAIProperties, aIDAttrib, id)) {

Definitely add "|| id.IsEmpty()" here.  We don't want to be using empty ids for anything.

>Index: accessible/src/msaa/nsAccessNodeWrap.cpp

The caller at line 206 of this file should either check whether true was returned or just unconditionally assign.  The latter is what we do now, so just do that?

>Index: accessible/src/xul/nsXULTextAccessible.cpp

In this file, nsXULLinkAccessible::GetValue returns the retval of GetAttr, and it's a NS_IMETHODIMP.  Please fix it to just return NS_OK?

>Index: content/base/public/nsIContent.h
>+// e5417db2-fc59-4b43-8c9a-edc3173a8540

Don't add that, please.  It's just one more thing to maintain every time we change the IID... ;)

>Index: content/base/src/nsObjectLoadingContent.cpp
>@@ -739,21 +738,23 @@ nsObjectLoadingContent::ObjectURIChanged
>+    hasID = thisContent->GetAttr(kNameSpaceID_None, nsHTMLAtoms::classid,
>+                                 classid);

I think we want hasID == !classid.IsEmpty() here.  That is, I think we should ignore |classid=""| on objects and render them normally in that case.  That's what IE does, at least.

Please fix nsScriptLoader::IsScriptEventHandler.  I think we want something like:

  if (!contElement->GetAttr(kNameSpaceID_None, nsHTMLAtoms::_for, str)) {
     return PR_FALSE;
  }

there.  Similar for the _event attr.

>Index: content/events/src/nsXMLEventsManager.cpp
>@@ -102,33 +102,29 @@ PRBool nsXMLEventsListener::InitXMLEvent
>+    aContent->AttrValueIs(nameSpaceID, nsHTMLAtoms::phase,
>+                          NS_LITERAL_STRING("capture"), eCaseMatters);

I almost wonder whether we should have atoms for those string... (and in fact store the attr values as atoms, if we start atomizing short attr values in general, not just for XUL).  Later bug, I guess... ;)

>Index: content/html/content/src/nsGenericHTMLElement.cpp
>@@ -1689,18 +1689,17 @@ nsGenericHTMLElement::SetAttr(PRInt32 aN
>-      rv = GetAttr(aNamespaceID, aAttribute, oldValue);
>-      modification = rv != NS_CONTENT_ATTR_NOT_THERE;
>+      modification = GetAttr(aNamespaceID, aAttribute, oldValue);

Argh....  This will conflict with my SetAttr patch....  :(  Fun merge times...

You need to fix the (new) GetAttr caller in nsHTMLAppletElement::StartAppletLoad.

>Index: content/html/content/src/nsHTMLButtonElement.cpp

Please fix nsHTMLButtonElement::GetDefaultValue.

Also, please file a followup bug to investigate whether a button with an empty name should really be trying to submit?  Same for other form controls (eg textarea, etc).

>Index: content/html/content/src/nsHTMLFormElement.cpp

Please fix nsHTMLFormElement::GetAction also.

Please fix nsHTMLDocument::MatchNameAttribute?  It's using NS_SUCCEEDED on the retval of GetAttr.

Please fix nsEventListenerManager::CompileEventHandlerInternal.

Please fix nsSVGElement::GetId.

Please fix nsSVGScriptElement::GetType.

>Index: content/xml/content/src/nsXMLElement.cpp
>+      if (AttrValueIs(kNameSpaceID_XLink, nsLayoutAtoms::actuate,
>+                      onloadString, eCaseMatters)) {

We might also want to move to an atom here, if we start storing short attr values as atoms for XML.

>@@ -247,19 +242,18 @@ nsXMLElement::MaybeTriggerAutoLink(nsIDo
>-        rv = nsGenericElement::GetAttr(kNameSpaceID_XLink, nsHTMLAtoms::href,
>-                                       value);
>-        if (rv == NS_CONTENT_ATTR_HAS_VALUE && !value.IsEmpty()) {
>+        GetAttr(kNameSpaceID_XLink, nsHTMLAtoms::href, value);
>+        if (!value.IsEmpty()) {

I think this code was wrong -- an empty href, if set, is perfectly valid, really...  I think this should just check |if (GetAttr(...))|

>Index: content/xul/content/src/nsXULElement.cpp
>@@ -2143,31 +2142,28 @@ nsXULElement::GetRangeList() const
> nsXULElement::GetResource(nsIRDFResource** aResource)
> {
>+    nsresult rv;

I believe that's unused with your changes.  Just remove it.

>Index: content/xul/document/src/nsXULDocument.cpp

Please fix nsXULDocument::MatchAttribute.

Please fix nsXULDocument::OverlayForwardReference::Resolve.

Please fix the first and third GetAttr calls in nsXULDocument::OverlayForwardReference::Merge.

Please fix nsXULDocument::BroadcasterHookup::~BroadcasterHookup.

Please fix the remaining GetAttr calls in nsXULDocument::FindBroadcaster.

>@@ -4245,20 +4217,18 @@ nsXULDocument::InsertElement(nsIContent*
>-        rv = aChild->GetAttr(kNameSpaceID_None, nsXULAtoms::position, posStr);
>-        if (NS_FAILED(rv)) return rv;
>-
>-        if (rv == NS_CONTENT_ATTR_HAS_VALUE) {
>+        if (aChild->GetAttr(kNameSpaceID_None, nsXULAtoms::position,
>+                            posStr)) {

This changes behavior; please check for posStr.IsEmpty()?

>Index: content/xul/templates/src/nsXULContentBuilder.cpp

Please remove the setting of rv in nsXULContentBuilder::SynchronizeUsingTemplate.

Please fix nsXULContentBuilder::IsOpen (probably use AttrValueIs with an "open" atom).

>Index: content/xul/templates/src/nsXULSortService.cpp
>@@ -383,97 +381,69 @@ XULSortServiceImpl::SetSortColumnHints(n

That method should really become void, but that can happen in a separate patch.

Please fix the GetAttr() calls in the "if (sortInfo.db && sortInfo.naturalOrderSort) {" block in XULSortServiceImpl::InsertContainerNode.

>@@ -1578,34 +1538,27 @@ XULSortServiceImpl::Sort(nsIDOMNode* nod
>+      (sortDirection.Equals(*kAscendingStr) &&
>+       dbNode->AttrValueIs(kNameSpaceID_None, nsXULAtoms::sortDirection,
>+                           *kDescendingStr, eCaseMatters) ||
>+       sortDirection.Equals(*kDescendingStr) &&
>+       dbNode->AttrValueIs(kNameSpaceID_None, nsXULAtoms::sortDirection,
>+                    *kAscendingStr, eCaseMatters))) {

I think I prefer |((foo && bar) || (baz && whatever))| with the extra parens.  Remembering that && binds tighter than || is a pain, really.  ;)

>Index: content/xul/templates/src/nsXULTemplateBuilder.cpp

Please fix nsXULTemplateBuilder::ComputeContainmentProperties.

Please fix the first GetAttr call in nsXULTemplateBuilder::CompileSimpleRule.

>Index: extensions/xforms/nsXFormsUtils.cpp
>+      if(content->AttrValueIs(kNameSpaceID_None, content->GetIDAttributeName(),

Space before '(', please.

>Index: layout/base/nsCSSFrameConstructor.cpp
>@@ -7226,47 +7224,42 @@ nsCSSFrameConstructor::TestSVGConditions
>   aHasSystemLanguage = PR_TRUE;
>-  rv = aContent->GetAttr(kNameSpaceID_None, nsSVGAtoms::systemLanguage, value);
>-  if (NS_CONTENT_ATTR_HAS_VALUE == rv) {
>+  if (aContent->GetAttr(kNameSpaceID_None, nsSVGAtoms::systemLanguage,
>+                        value)) {

This is actually wrong.  We should set aHasSystemLanguage to !aContent->GetAttr() to start with, or something, then do this stuff.  That is, the right behavior is:

1)  No attr set means aHasSystemLanguage == PR_TRUE
2)  Attr set to empty string means aHasSystemLanguage == PR_FALSE
3)  Attr set to nonempty string means compare to our pref.

>Index: layout/generic/nsObjectFrame.cpp
> nsObjectFrame::GetMIMEType(nsACString& aType)

This method is gone on trunk.  ;)

>@@ -1856,17 +1854,17 @@ nsObjectFrame::Instantiate(const char* a
>   if (mContent->Tag() == nsHTMLAtoms::object &&
>-      NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttr(kNameSpaceID_None, nsHTMLAtoms::classid, classid)) {
>+      mContent->GetAttr(kNameSpaceID_None, nsHTMLAtoms::classid, classid)) {

Just make sure this check ends up matching the check in nsObjectLoadingContent::ObjectURIChanged, ok?

>Index: layout/xul/base/src/nsBoxFrame.cpp

>@@ -628,22 +625,21 @@ nsBoxFrame::GetInitialEqualSize(PRBool& 
>+  if (content->AttrValueIs(kNameSpaceID_None, nsXULAtoms::equalsize,
>+                           NS_LITERAL_STRING("always"), eCaseMatters)) {

We should have an nsXULAtom for that and use it here.

>Index: layout/xul/base/src/nsGrippyFrame.cpp
>@@ -129,23 +128,19 @@ nsGrippyFrame::MouseClicked(nsPresContex
>+    PRBool before =
>+      !content->AttrValueIs(kNameSpaceID_None, nsXULAtoms::collapse,
>+                            NS_LITERAL_STRING("after"), eCaseMatters);

Again, there should be an atom for that.

Please fix nsComposeTxtSrvFilter::Skip (in editor).

>Index: widget/src/xpwidgets/nsNativeTheme.cpp
>@@ -130,24 +130,21 @@ nsNativeTheme::CheckBooleanAttr(nsIFrame
>+  return content->AttrValueIs(kNameSpaceID_None, aAtom,
>+                              NS_LITERAL_STRING("true"), eCaseMatters);

This might be worth making an atom.

r+sr=bzbarsky with those fixed or followups filed appropriately.
Attachment #199195 - Flags: superreview?(bzbarsky)
Attachment #199195 - Flags: superreview+
Attachment #199195 - Flags: review?(bzbarsky)
Attachment #199195 - Flags: review+
Boris, I looked at what's being changed in the accessibility module and have no problem with it. In some cases it really makes no difference and in others it's arguably better now.
(In reply to comment #11)
> There are some things I request that you fix below that might be ok not being
> fixed on initial checkin, since both PR_FALSE and PR_TRUE do test
> NS_SUCCEEDED...  Feel free to fix them either in this patch or in a followup.
> 

> I believe you want a ! there.  And possibly a IsEmpty() check on
> textEquivalent?  So
> 
>   else if (!aContent->GetAttr( ... ) || textEquivalent.IsEmpty()) {
>   }

Good catch! I'm not sure if the IsEmpty check should be there or not, but i'll put it back. Aaron, let me know if you don't want the IsEmpty check there.

> Definitely add "|| id.IsEmpty()" here.  We don't want to be using empty ids for
> anything.

Actually, if this attribute is empty the code returns NS_OK, and i'd rather not change that. Note that this isn't the the id attribute that is being retrived, but an attribute that contains an id.

> >+// e5417db2-fc59-4b43-8c9a-edc3173a8540
> Don't add that, please.  It's just one more thing to maintain every time we
> change the IID... ;)

Actually, i sort of like this since it allows you to search the tree for an IID. I'll give in this time though :)

> I almost wonder whether we should have atoms for those string... (and in fact
> store the attr values as atoms, if we start atomizing short attr values in
> general, not just for XUL).  Later bug, I guess... ;)

I changed to using an attribute rather then a string. But making us store atoms for short values is a different bug, though something we should do.

> Also, please file a followup bug to investigate whether a button with an empty
> name should really be trying to submit?  Same for other form controls (eg
> textarea, etc).

Filed bug 314117.

> >@@ -4245,20 +4217,18 @@ nsXULDocument::InsertElement(nsIContent*
> This changes behavior; please check for posStr.IsEmpty()?

Actually, the other way amounts to the same thing, but an IsEmpty check is slightly faster.

> Please fix nsXULContentBuilder::IsOpen (probably use AttrValueIs with an
> "open" atom).

I already had :)

> I think I prefer |((foo && bar) || (baz && whatever))| with the extra parens. 
> Remembering that && binds tighter than || is a pain, really.  ;)

bah! Boolean algerbra is only logical that way ;)

> >Index: layout/xul/base/src/nsGrippyFrame.cpp
> >@@ -129,23 +128,19 @@ nsGrippyFrame::MouseClicked(nsPresContex
> >+    PRBool before =
> >+      !content->AttrValueIs(kNameSpaceID_None, nsXULAtoms::collapse,
> >+                            NS_LITERAL_STRING("after"), eCaseMatters);
> 
> Again, there should be an atom for that.

I didn't do this one since this code is commented out.

> >Index: widget/src/xpwidgets/nsNativeTheme.cpp
> >@@ -130,24 +130,21 @@ nsNativeTheme::CheckBooleanAttr(nsIFrame
> >+  return content->AttrValueIs(kNameSpaceID_None, aAtom,
> >+                              NS_LITERAL_STRING("true"), eCaseMatters);
> 
> This might be worth making an atom.

There is no nsFooAtoms class around here so i'll let this be as is.
Just to clarify, some of those "this should be an atom" are fodder for followup bugs, imo.
Too late :)

It's something we should do eventually anyway so i just went with it.
Checked in. I'll attach the patch that was checked in when I get home.

Once lxr is updated i'll look through the tree to make sure all callers of GetAttr have been fixed and file a new bug if needed.
Status: NEW → RESOLVED
Closed: 19 years ago
Resolution: --- → FIXED
Patch that was checked in.

I also looked over all GetAttr callers and it looks like they all should be fine.
Attachment #199195 - Attachment is obsolete: true
Attachment #199197 - Attachment is obsolete: true
Attached patch Minor fixSplinter Review
I found one remaining place where the returnvalue was treated as an nsresult (though never used).
Attachment #202104 - Flags: superreview?(bzbarsky)
Attachment #202104 - Flags: review?(bzbarsky)
Attachment #202104 - Flags: superreview?(bzbarsky)
Attachment #202104 - Flags: superreview+
Attachment #202104 - Flags: review?(bzbarsky)
Attachment #202104 - Flags: review+
checked in followup patch.
Depends on: 330469
Component: DOM: Core → DOM: Core & HTML
QA Contact: ian → general
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: