Closed
Bug 131775
Opened 23 years ago
Closed 21 years ago
[FIX]BeginUpdate is not always matched by EndUpdate in DOM code
Categories
(Core :: DOM: Core & HTML, defect, P1)
Core
DOM: Core & HTML
Tracking
()
RESOLVED
FIXED
mozilla1.6alpha
People
(Reporter: bzbarsky, Assigned: bzbarsky)
References
Details
Attachments
(2 files, 2 obsolete files)
70.68 KB,
patch
|
Details | Diff | Splinter Review | |
67.20 KB,
patch
|
caillon
:
review+
jst
:
superreview+
|
Details | Diff | Splinter Review |
We have a few places in our code where we BeginUpdate() but may not EndUpdate():
nsSVGAttributes::SetAttr
nsSVGAttributes::UnsetAttr
DOMMediaListImpl::BeginMediaChange/DOMMediaListImpl::EndMediaChange (the latter
is not always called by the medialist manipulation methods)
DOMCSSDeclarationImpl::ParsePropertyValue
CSSStyleSheetImpl::InsertRule
CSSStyleSheetImpl::DeleteRule
CSSStyleSheetImpl::DeleteRuleFromGroup
CSSStyleSheetImpl::InsertRuleIntoGroup
nsGenericContainerElement::UnsetAttr
nsGenericContainerElement::SetAttr
Not assigning this to myself because I don't have time to do this till sometime
in mid-May and some of that code is hairy, but feel free to punt to me if this
is not a priority and if you're not going to get to it till then anyway, jst.
Comment 3•22 years ago
|
||
Should we write a little nsAutoUpdate (or whatever) class to help here?
![]() |
Assignee | |
Comment 4•22 years ago
|
||
Yeah, that was what I was thinking... I was gonna call it
nsContentUpdateBatch, maybe... (or just nsUpdateBatch).
![]() |
Assignee | |
Updated•22 years ago
|
Priority: -- → P1
Target Milestone: --- → mozilla1.5alpha
![]() |
Assignee | |
Comment 5•21 years ago
|
||
This introduces the mozAutoDocUpdate class and uses it in various places.
![]() |
Assignee | |
Comment 6•21 years ago
|
||
![]() |
Assignee | |
Comment 7•21 years ago
|
||
Comment on attachment 132561 [details] [diff] [review]
Same as diff -w FOR REVIEW ONLY
reviews?
Attachment #132561 -
Flags: superreview?(jst)
Attachment #132561 -
Flags: review?(caillon)
![]() |
Assignee | |
Comment 8•21 years ago
|
||
Incidentally, this fixes bug 211022
Blocks: 211022
Summary: BeginUpdate is not always matched by EndUpdate in DOM code → [FIX]BeginUpdate is not always matched by EndUpdate in DOM code
![]() |
Assignee | |
Updated•21 years ago
|
Target Milestone: mozilla1.5alpha → mozilla1.6alpha
![]() |
Assignee | |
Comment 9•21 years ago
|
||
Comment on attachment 132561 [details] [diff] [review]
Same as diff -w FOR REVIEW ONLY
This patch is bogus...
Attachment #132561 -
Flags: superreview?(jst)
Attachment #132561 -
Flags: review?(caillon)
![]() |
Assignee | |
Comment 10•21 years ago
|
||
Attachment #132560 -
Attachment is obsolete: true
![]() |
Assignee | |
Updated•21 years ago
|
Attachment #132561 -
Attachment is obsolete: true
![]() |
Assignee | |
Comment 11•21 years ago
|
||
![]() |
Assignee | |
Updated•21 years ago
|
Attachment #132623 -
Flags: superreview?(jst)
Attachment #132623 -
Flags: review?(caillon)
![]() |
Assignee | |
Updated•21 years ago
|
Attachment #132561 -
Flags: superreview?(jst)
Attachment #132561 -
Flags: review?(caillon)
![]() |
Assignee | |
Updated•21 years ago
|
Attachment #132561 -
Flags: superreview?(jst)
Attachment #132561 -
Flags: review?(caillon)
Comment 12•21 years ago
|
||
Comment on attachment 132623 [details] [diff] [review]
Same as diff -w FOR REVIEW ONLY
General comment:
It seems there are quite a few callsites, (though most prominent in
nsSVGElement) where things are similar to:
A::DoFoo()
{
mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, aNotify);
if (foo) {
// Do things which will send notifications
}
}
I think that in these cases, you can either use early returns if (!foo) since
nothing will happen to get rid of the extra scope, or move the mozAutoDocUpdate
inside the if so that we don't tell the document there will be udpates when
there really won't be.
There are cases in other places where you can't do an early return, so I would
just recommend changing the scope. Let's send as few notifications to
observers as possible. :-)
>Index: content/base/public/nsIDocument.h
> // Observation hooks used to propagate notifications to document observers.
> // BeginUpdate must be called before any batch of modifications of the
>+ // content model or of style data, EndUpdate must be called afterward. To
>+ // make this easy and painless, use the mozAutoDocUpdate helper class.
Hm, I never thought I would make a nit this anal, but...
Could you move the "To" in the above comment down to the next line? It seems
to dangle out there. Sorry, I used to work at a newspaper a few years back and
that was one of the guidelines of making things more readable we tried to
follow (not ending a line with the first word of a multi-word statement when
said word is a short one), and I tend to agree that it makes it easier to read.
> NS_IMETHOD BeginUpdate(nsUpdateType aUpdateType) = 0;
> NS_IMETHOD EndUpdate(nsUpdateType aUpdateType) = 0;
> NS_IMETHOD BeginLoad() = 0;
> NS_IMETHOD EndLoad() = 0;
> NS_IMETHOD ContentChanged(nsIContent* aContent,
> nsISupports* aSubContent) = 0;
> // notify that one or two content nodes changed state
> // either may be nsnull, but not both
> NS_IMETHOD ContentStatesChanged(nsIContent* aContent1,
> nsIContent* aContent2,
>@@ -467,20 +469,43 @@ public:
> const nsAString& Standalone) = 0;
> NS_IMETHOD GetXMLDeclaration(nsAString& aVersion,
> nsAString& aEncoding,
> nsAString& Standalone) = 0;
>
> NS_IMETHOD_(PRBool) IsCaseSensitive() = 0;
>
> NS_IMETHOD_(PRBool) IsScriptEnabled() = 0;
> };
>
>+class mozAutoDocUpdate {
Brace on its own line? Also, could you please document we allow mDocument to
be null so that we don't have to null-check (and therefore add another scope)
in all the callers?
>+public:
>+ mozAutoDocUpdate(nsIDocument* aDocument, nsUpdateType aUpdateType,
>+ PRBool aNotify) :
>+ mDocument(aNotify ? aDocument : nsnull),
>+ mUpdateType(aUpdateType)
>+ {
>+ if (mDocument) {
>+ mDocument->BeginUpdate(mUpdateType);
>+ }
>+ }
>+
>+ ~mozAutoDocUpdate()
>+ {
>+ if (mDocument) {
>+ mDocument->EndUpdate(mUpdateType);
>+ }
>+ }
>+
>+private:
>+ nsCOMPtr<nsIDocument> mDocument;
>+ nsUpdateType mUpdateType;
>+};
>
> // XXX These belong somewhere else
> nsresult
> NS_NewHTMLDocument(nsIDocument** aInstancePtrResult);
>
> nsresult
> NS_NewXMLDocument(nsIDocument** aInstancePtrResult);
>
> #ifdef MOZ_SVG
> nsresult
>Index: content/base/src/nsGenericElement.cpp
>===================================================================
>RCS file: /cvsroot/mozilla/content/base/src/nsGenericElement.cpp,v
>retrieving revision 3.291
>diff -p -u -1 -0 -w -r3.291 nsGenericElement.cpp
>--- content/base/src/nsGenericElement.cpp 2 Oct 2003 21:29:31 -0000 3.291
>+++ content/base/src/nsGenericElement.cpp 4 Oct 2003 08:23:41 -0000
>@@ -2606,23 +2606,24 @@ nsGenericElement::doInsertBefore(nsIDOMN
> NS_ENSURE_TRUE(doc_fragment, NS_ERROR_UNEXPECTED);
>
> doc_fragment->DisconnectChildren();
>
> PRUint32 count = newContent->GetChildCount();
>
> PRUint32 old_count = GetChildCount();
>
> PRBool do_notify = !!aRefChild;
>
>- if (count && !do_notify && mDocument) {
>- mDocument->BeginUpdate(UPDATE_CONTENT_MODEL);
>- }
>+ // If do_notify is true, then we don't have to handle the
>+ // notifications ourselves... So pass !do_notify as aNotify.
I guess technically, you're only passing !do_notify if there are children.
Also is the reader of the comment supposed to know where |aNotify| comes from?
>+ mozAutoDocUpdate updateBatch(mDocument, UPDATE_CONTENT_MODEL,
>+ count && !do_notify);
>Index: content/html/style/src/nsCSSStyleSheet.cpp
>+#define BEGIN_MEDIA_CHANGE() \
>+ if (mStyleSheet) { \
>+ rv = mStyleSheet->GetOwningDocument(*getter_AddRefs(doc)); \
>+ NS_ENSURE_SUCCESS(rv, rv); \
>+ } \
>+ mozAutoDocUpdate updateBatch(doc, UPDATE_STYLE, PR_TRUE); \
>+ if (mStyleSheet) { \
>+ rv = mStyleSheet->WillDirty(); \
>+ NS_ENSURE_SUCCESS(rv, rv); \
>+ }
>+
>+#define END_MEDIA_CHANGE() \
>+ if (mStyleSheet) { \
>+ mStyleSheet->DidDirty(); \
>+ } \
>+ /* XXXldb Pass something meaningful? */ \
>+ if (doc) { \
>+ rv = doc->StyleRuleChanged(mStyleSheet, nsnull, nsnull); \
>+ NS_ENSURE_SUCCESS(rv, rv); \
>+ }
>+
How about making mStyleSheet and doc be parameters to the macros? This way it
makes the call-sites more explicit as to what is going on, and doesn't rely on
a local being defined |doc| at each call site, though it doesn't really matter
much since you name the variable the same thing everywhere.... Does this also
need PR_BEGIN_MACRO and PR_END_MACRO?
Comment 13•21 years ago
|
||
Oh duh, can't use PR_BEGIN/END_MACRO because of scoping.
![]() |
Assignee | |
Comment 14•21 years ago
|
||
> though most prominent in nsSVGElement
There is only one callsite in nsSVGElement where I could change the scope (in
nsSVGElement::RemoveChildAt). The rest are correct, in fact.
Added comments about mozAutoDocUpdate.
> Also is the reader of the comment supposed to know where |aNotify| comes from?
Made comment clearer.
> How about making mStyleSheet and doc be parameters to the macros?
Good idea. Done.
Comment 15•21 years ago
|
||
Comment on attachment 132623 [details] [diff] [review]
Same as diff -w FOR REVIEW ONLY
(btw, that was r= with comments fixed)
Attachment #132623 -
Flags: review?(caillon) → review+
Comment 16•21 years ago
|
||
Comment on attachment 132623 [details] [diff] [review]
Same as diff -w FOR REVIEW ONLY
sr=jst
Attachment #132623 -
Flags: superreview?(jst) → superreview+
![]() |
Assignee | |
Comment 17•21 years ago
|
||
Checked in, with caillon's review comments addressed.
Status: NEW → RESOLVED
Closed: 21 years ago
Resolution: --- → FIXED
Updated•6 years ago
|
Component: DOM → DOM: Core & HTML
You need to log in
before you can comment on or make changes to this bug.
Description
•