Fix for bugs 20485 and 24600. We no longer flush immediately in the content sink when we hit a script element. Instead the sink is a document observer and listens for BeginUpdate/EndUpdate notifications when evaluating a script and flushes only if necessary. Added BeginUpdate/EndUpdate notifications to nsIDocument and layout content (note that it's still necessary for XUL content). r=nisheeth,pollmann

This commit is contained in:
vidur%netscape.com 2000-01-28 23:43:12 +00:00
Родитель 92dc6a32b9
Коммит fa580e6551
22 изменённых файлов: 806 добавлений и 234 удалений

Просмотреть файл

@ -240,6 +240,8 @@ public:
// Observation hooks used by content nodes to propagate
// notifications to document observers.
NS_IMETHOD BeginUpdate() = 0;
NS_IMETHOD EndUpdate() = 0;
NS_IMETHOD BeginLoad() = 0;
NS_IMETHOD EndLoad() = 0;
NS_IMETHOD ContentChanged(nsIContent* aContent,

Просмотреть файл

@ -1463,6 +1463,42 @@ PRBool nsDocument::RemoveObserver(nsIDocumentObserver* aObserver)
return (mObservers.IndexOf(aObserver) != -1);
}
NS_IMETHODIMP
nsDocument::BeginUpdate()
{
PRInt32 i;
// Get new value of count for every iteration in case
// observers remove themselves during the loop.
for (i = 0; i < mObservers.Count(); i++) {
nsIDocumentObserver* observer = (nsIDocumentObserver*) mObservers[i];
observer->BeginUpdate(this);
// Make sure that the observer didn't remove itself during the
// notification. If it did, update our index and count.
if (observer != (nsIDocumentObserver*)mObservers[i]) {
i--;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsDocument::EndUpdate()
{
PRInt32 i;
// Get new value of count for every iteration in case
// observers remove themselves during the loop.
for (i = 0; i < mObservers.Count(); i++) {
nsIDocumentObserver* observer = (nsIDocumentObserver*) mObservers[i];
observer->EndUpdate(this);
// Make sure that the observer didn't remove itself during the
// notification. If it did, update our index and count.
if (observer != (nsIDocumentObserver*)mObservers[i]) {
i--;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsDocument::BeginLoad()
{
@ -1651,12 +1687,16 @@ nsDocument::StyleRuleChanged(nsIStyleSheet* aStyleSheet, nsIStyleRule* aStyleRul
// observers remove themselves during the loop.
for (i = 0; i < mObservers.Count(); i++) {
nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i];
observer->BeginUpdate(this);
observer->StyleRuleChanged(this, aStyleSheet, aStyleRule, aHint);
// Make sure that the observer didn't remove itself during the
// notification. If it did, update our index and count.
if (observer != (nsIDocumentObserver*)mObservers[i]) {
i--;
}
else {
observer->EndUpdate(this);
}
}
return NS_OK;
}
@ -1669,12 +1709,16 @@ nsDocument::StyleRuleAdded(nsIStyleSheet* aStyleSheet, nsIStyleRule* aStyleRule)
// observers remove themselves during the loop.
for (i = 0; i < mObservers.Count(); i++) {
nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i];
observer->BeginUpdate(this);
observer->StyleRuleAdded(this, aStyleSheet, aStyleRule);
// Make sure that the observer didn't remove itself during the
// notification. If it did, update our index and count.
if (observer != (nsIDocumentObserver*)mObservers[i]) {
i--;
}
else {
observer->EndUpdate(this);
}
}
return NS_OK;
}
@ -1687,12 +1731,16 @@ nsDocument::StyleRuleRemoved(nsIStyleSheet* aStyleSheet, nsIStyleRule* aStyleRul
// observers remove themselves during the loop.
for (i = 0; i < mObservers.Count(); i++) {
nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i];
observer->BeginUpdate(this);
observer->StyleRuleRemoved(this, aStyleSheet, aStyleRule);
// Make sure that the observer didn't remove itself during the
// notification. If it did, update our index and count.
if (observer != (nsIDocumentObserver*)mObservers[i]) {
i--;
}
else {
observer->EndUpdate(this);
}
}
return NS_OK;
}

Просмотреть файл

@ -1004,11 +1004,15 @@ nsGenericDOMDataNode::SetText(const PRUnichar* aBuffer, PRInt32 aLength,
if (nsnull == aBuffer) {
return NS_ERROR_NULL_POINTER;
}
if (aNotify && (nsnull != mDocument)) {
mDocument->BeginUpdate();
}
mText.SetTo(aBuffer, aLength);
// Trigger a reflow
if (aNotify && (nsnull != mDocument)) {
mDocument->ContentChanged(mContent, nsnull);
mDocument->EndUpdate();
}
return NS_OK;
}
@ -1025,11 +1029,15 @@ nsGenericDOMDataNode::SetText(const char* aBuffer,
if (nsnull == aBuffer) {
return NS_ERROR_NULL_POINTER;
}
if (aNotify && (nsnull != mDocument)) {
mDocument->BeginUpdate();
}
mText.SetTo(aBuffer, aLength);
// Trigger a reflow
if (aNotify && (nsnull != mDocument)) {
mDocument->ContentChanged(mContent, nsnull);
mDocument->EndUpdate();
}
return NS_OK;
}

Просмотреть файл

@ -1868,6 +1868,11 @@ nsGenericContainerElement::SetAttribute(PRInt32 aNameSpaceID, nsIAtom* aName,
if (nsnull == mAttributes) {
mAttributes = new nsVoidArray();
}
if (aNotify && (nsnull != mDocument)) {
mDocument->BeginUpdate();
}
if (nsnull != mAttributes) {
nsGenericAttribute* attr;
PRInt32 index;
@ -1890,8 +1895,11 @@ nsGenericContainerElement::SetAttribute(PRInt32 aNameSpaceID, nsIAtom* aName,
}
}
if (NS_SUCCEEDED(rv) && aNotify && (nsnull != mDocument)) {
mDocument->AttributeChanged(mContent, aNameSpaceID, aName, NS_STYLE_HINT_UNKNOWN);
if (aNotify && (nsnull != mDocument)) {
if (NS_SUCCEEDED(rv)) {
mDocument->AttributeChanged(mContent, aNameSpaceID, aName, NS_STYLE_HINT_UNKNOWN);
}
mDocument->EndUpdate();
}
return rv;
@ -1957,6 +1965,9 @@ nsGenericContainerElement::UnsetAttribute(PRInt32 aNameSpaceID, nsIAtom* aName,
nsGenericAttribute* attr = (nsGenericAttribute*)mAttributes->ElementAt(index);
if (((kNameSpaceID_Unknown == aNameSpaceID) || (attr->mNameSpaceID == aNameSpaceID)) &&
(attr->mName == aName)) {
if (aNotify && (nsnull != mDocument)) {
mDocument->BeginUpdate();
}
mAttributes->RemoveElementAt(index);
delete attr;
found = PR_TRUE;
@ -1966,6 +1977,7 @@ nsGenericContainerElement::UnsetAttribute(PRInt32 aNameSpaceID, nsIAtom* aName,
if (NS_SUCCEEDED(rv) && found && aNotify && (nsnull != mDocument)) {
mDocument->AttributeChanged(mContent, aNameSpaceID, aName, NS_STYLE_HINT_UNKNOWN);
mDocument->EndUpdate();
}
}
@ -2117,12 +2129,15 @@ nsGenericContainerElement::InsertChildAt(nsIContent* aKid,
PRBool aNotify)
{
NS_PRECONDITION(nsnull != aKid, "null ptr");
nsIDocument* doc = mDocument;
if (aNotify && (nsnull != doc)) {
doc->BeginUpdate();
}
PRBool rv = mChildren.InsertElementAt(aKid, aIndex);/* XXX fix up void array api to use nsresult's*/
if (rv) {
NS_ADDREF(aKid);
aKid->SetParent(mContent);
nsRange::OwnerChildInserted(mContent, aIndex);
nsIDocument* doc = mDocument;
if (nsnull != doc) {
aKid->SetDocument(doc, PR_FALSE);
if (aNotify) {
@ -2130,6 +2145,9 @@ nsGenericContainerElement::InsertChildAt(nsIContent* aKid,
}
}
}
if (aNotify && (nsnull != doc)) {
doc->EndUpdate();
}
return NS_OK;
}
@ -2139,13 +2157,16 @@ nsGenericContainerElement::ReplaceChildAt(nsIContent* aKid,
PRBool aNotify)
{
NS_PRECONDITION(nsnull != aKid, "null ptr");
nsIDocument* doc = mDocument;
if (aNotify && (nsnull != mDocument)) {
doc->BeginUpdate();
}
nsIContent* oldKid = (nsIContent *)mChildren.ElementAt(aIndex);
nsRange::OwnerChildReplaced(mContent, aIndex, oldKid);
PRBool rv = mChildren.ReplaceElementAt(aKid, aIndex);
if (rv) {
NS_ADDREF(aKid);
aKid->SetParent(mContent);
nsIDocument* doc = mDocument;
if (nsnull != doc) {
aKid->SetDocument(doc, PR_FALSE);
if (aNotify) {
@ -2156,6 +2177,9 @@ nsGenericContainerElement::ReplaceChildAt(nsIContent* aKid,
oldKid->SetParent(nsnull);
NS_RELEASE(oldKid);
}
if (aNotify && (nsnull != mDocument)) {
doc->EndUpdate();
}
return NS_OK;
}
@ -2163,12 +2187,15 @@ nsresult
nsGenericContainerElement::AppendChildTo(nsIContent* aKid, PRBool aNotify)
{
NS_PRECONDITION((nsnull != aKid) && (aKid != mContent), "null ptr");
nsIDocument* doc = mDocument;
if (aNotify && (nsnull != doc)) {
doc->BeginUpdate();
}
PRBool rv = mChildren.AppendElement(aKid);
if (rv) {
NS_ADDREF(aKid);
aKid->SetParent(mContent);
// ranges don't need adjustment since new child is at end of list
nsIDocument* doc = mDocument;
if (nsnull != doc) {
aKid->SetDocument(doc, PR_FALSE);
if (aNotify) {
@ -2176,6 +2203,9 @@ nsGenericContainerElement::AppendChildTo(nsIContent* aKid, PRBool aNotify)
}
}
}
if (aNotify && (nsnull != doc)) {
doc->EndUpdate();
}
return NS_OK;
}
@ -2185,6 +2215,9 @@ nsGenericContainerElement::RemoveChildAt(PRInt32 aIndex, PRBool aNotify)
nsIContent* oldKid = (nsIContent *)mChildren.ElementAt(aIndex);
if (nsnull != oldKid ) {
nsIDocument* doc = mDocument;
if (aNotify && (nsnull != doc)) {
doc->BeginUpdate();
}
nsRange::OwnerChildRemoved(mContent, aIndex, oldKid);
mChildren.RemoveElementAt(aIndex);
if (aNotify) {
@ -2195,6 +2228,9 @@ nsGenericContainerElement::RemoveChildAt(PRInt32 aIndex, PRBool aNotify)
oldKid->SetDocument(nsnull, PR_TRUE);
oldKid->SetParent(nsnull);
NS_RELEASE(oldKid);
if (aNotify && (nsnull != doc)) {
doc->EndUpdate();
}
}
return NS_OK;

Просмотреть файл

@ -2085,6 +2085,7 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState)
nsIDocument *document; // this presumes content can't get/lose state if not connected to doc
notifyContent[0]->GetDocument(document);
if (document) {
document->BeginUpdate();
document->ContentStatesChanged(notifyContent[0], notifyContent[1]);
if (notifyContent[2]) { // more that two notifications are needed (should be rare)
// XXX a further optimization here would be to group the notification pairs
@ -2095,6 +2096,7 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState)
document->ContentStatesChanged(notifyContent[4], nsnull);
}
}
document->EndUpdate();
NS_RELEASE(document);
}

Просмотреть файл

@ -217,11 +217,15 @@ nsDOMCSSAttributeDeclaration::ParseDeclaration(const nsString& aDecl)
if (NS_SUCCEEDED(result)) {
PRInt32 hint;
if (doc) {
doc->BeginUpdate();
}
result = cssParser->ParseAndAppendDeclaration(aDecl, baseURI, decl, &hint);
if (NS_SUCCEEDED(result)) {
if (doc) {
if (doc) {
if (NS_SUCCEEDED(result)) {
doc->AttributeChanged(mContent, kNameSpaceID_None, nsHTMLAtoms::style, hint);
}
doc->EndUpdate();
}
if (cssLoader) {
cssLoader->RecycleParser(cssParser);
@ -700,6 +704,10 @@ nsGenericHTMLElement::SetAttribute(PRInt32 aNameSpaceID,
NS_RELEASE(htmlContent);
return result;
}
if (aNotify && (nsnull != mDocument)) {
mDocument->BeginUpdate();
}
// set as string value to avoid another string copy
PRBool impact = NS_STYLE_HINT_NONE;
htmlContent->GetMappedAttributeImpact(aAttribute, impact);
@ -729,6 +737,7 @@ nsGenericHTMLElement::SetAttribute(PRInt32 aNameSpaceID,
if (aNotify && (nsnull != mDocument)) {
mDocument->AttributeChanged(mContent, aNameSpaceID, aAttribute, NS_STYLE_HINT_UNKNOWN);
mDocument->EndUpdate();
}
return result;
@ -771,15 +780,18 @@ nsGenericHTMLElement::SetHTMLAttribute(nsIAtom* aAttribute,
PRBool impact = NS_STYLE_HINT_NONE;
htmlContent->GetMappedAttributeImpact(aAttribute, impact);
if (nsnull != mDocument) { // set attr via style sheet
if (aNotify && (nsHTMLAtoms::style == aAttribute)) {
nsHTMLValue oldValue;
PRInt32 oldImpact = NS_STYLE_HINT_NONE;
if (NS_CONTENT_ATTR_NOT_THERE != GetHTMLAttribute(aAttribute, oldValue)) {
oldImpact = GetStyleImpactFrom(oldValue);
}
impact = GetStyleImpactFrom(aValue);
if (impact < oldImpact) {
impact = oldImpact;
if (aNotify) {
mDocument->BeginUpdate();
if (nsHTMLAtoms::style == aAttribute) {
nsHTMLValue oldValue;
PRInt32 oldImpact = NS_STYLE_HINT_NONE;
if (NS_CONTENT_ATTR_NOT_THERE != GetHTMLAttribute(aAttribute, oldValue)) {
oldImpact = GetStyleImpactFrom(oldValue);
}
impact = GetStyleImpactFrom(aValue);
if (impact < oldImpact) {
impact = oldImpact;
}
}
}
nsIHTMLStyleSheet* sheet = GetAttrStyleSheet(mDocument);
@ -791,6 +803,7 @@ nsGenericHTMLElement::SetHTMLAttribute(nsIAtom* aAttribute,
}
if (aNotify) {
mDocument->AttributeChanged(mContent, kNameSpaceID_None, aAttribute, impact);
mDocument->EndUpdate();
}
}
else { // manage this ourselves and re-sync when we connect to doc
@ -833,13 +846,16 @@ nsGenericHTMLElement::UnsetAttribute(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
}
if (nsnull != mDocument) { // set attr via style sheet
PRInt32 impact = NS_STYLE_HINT_UNKNOWN;
if (aNotify && (nsHTMLAtoms::style == aAttribute)) {
nsHTMLValue oldValue;
if (NS_CONTENT_ATTR_NOT_THERE != GetHTMLAttribute(aAttribute, oldValue)) {
impact = GetStyleImpactFrom(oldValue);
}
else {
impact = NS_STYLE_HINT_NONE;
if (aNotify) {
mDocument->BeginUpdate();
if (nsHTMLAtoms::style == aAttribute) {
nsHTMLValue oldValue;
if (NS_CONTENT_ATTR_NOT_THERE != GetHTMLAttribute(aAttribute, oldValue)) {
impact = GetStyleImpactFrom(oldValue);
}
else {
impact = NS_STYLE_HINT_NONE;
}
}
}
nsIHTMLStyleSheet* sheet = GetAttrStyleSheet(mDocument);
@ -849,6 +865,7 @@ nsGenericHTMLElement::UnsetAttribute(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
}
if (aNotify) {
mDocument->AttributeChanged(mContent, aNameSpaceID, aAttribute, impact);
mDocument->EndUpdate();
}
}
else { // manage this ourselves and re-sync when we connect to doc
@ -1585,16 +1602,19 @@ nsGenericHTMLElement::ColorToString(const nsHTMLValue& aValue,
// XXX This creates a dependency between content and frames
nsresult
nsGenericHTMLElement::GetPrimaryFrame(nsIHTMLContent* aContent,
nsIFormControlFrame *&aFormControlFrame)
nsIFormControlFrame *&aFormControlFrame,
PRBool aFlushNotifications)
{
nsIDocument* doc = nsnull;
nsresult res = NS_NOINTERFACE;
// Get the document
if (NS_OK == aContent->GetDocument(doc)) {
if (nsnull != doc) {
// Cause a flushing of notifications, so we get
// up-to-date presentation information
doc->FlushPendingNotifications();
if (aFlushNotifications) {
// Cause a flushing of notifications, so we get
// up-to-date presentation information
doc->FlushPendingNotifications();
}
// Get presentation shell 0
nsIPresShell* presShell = doc->GetShellAt(0);
@ -1618,24 +1638,32 @@ nsGenericHTMLElement::GetPrimaryPresState(nsIHTMLContent* aContent,
nsIStatefulFrame::StateType aStateType,
nsIPresState** aPresState)
{
nsresult result = NS_OK;
// Get the document
nsCOMPtr<nsIDocument> doc;
aContent->GetDocument(*getter_AddRefs(doc));
result = aContent->GetDocument(*getter_AddRefs(doc));
if (doc) {
// Get presentation shell 0
nsCOMPtr<nsIPresShell> presShell = getter_AddRefs(doc->GetShellAt(0));
if (presShell) {
nsCOMPtr<nsILayoutHistoryState> history;
presShell->GetHistoryState(getter_AddRefs(history));
result = presShell->GetHistoryState(getter_AddRefs(history));
if (history) {
PRUint32 ID;
aContent->GetContentID(&ID);
history->GetState(ID, aPresState, aStateType);
result = history->GetState(ID, aPresState, aStateType);
if (!*aPresState) {
result = NS_NewPresState(aPresState);
if (NS_SUCCEEDED(result)) {
result = history->AddState(ID, *aPresState, aStateType);
}
}
}
}
}
return NS_OK;
return result;
}
// XXX This creates a dependency between content and frames
@ -2941,12 +2969,15 @@ nsGenericHTMLContainerElement::InsertChildAt(nsIContent* aKid,
PRBool aNotify)
{
NS_PRECONDITION(nsnull != aKid, "null ptr");
nsIDocument* doc = mDocument;
if (aNotify && (nsnull != doc)) {
doc->BeginUpdate();
}
PRBool rv = mChildren.InsertElementAt(aKid, aIndex);/* XXX fix up void array api to use nsresult's*/
if (rv) {
NS_ADDREF(aKid);
aKid->SetParent(mContent);
nsRange::OwnerChildInserted(mContent, aIndex);
nsIDocument* doc = mDocument;
if (nsnull != doc) {
aKid->SetDocument(doc, PR_FALSE);
if (aNotify) {
@ -2954,6 +2985,9 @@ nsGenericHTMLContainerElement::InsertChildAt(nsIContent* aKid,
}
}
}
if (aNotify && (nsnull != doc)) {
doc->EndUpdate();
}
return NS_OK;
}
@ -2964,12 +2998,15 @@ nsGenericHTMLContainerElement::ReplaceChildAt(nsIContent* aKid,
{
NS_PRECONDITION(nsnull != aKid, "null ptr");
nsIContent* oldKid = (nsIContent *)mChildren.ElementAt(aIndex);
nsIDocument* doc = mDocument;
if (aNotify && (nsnull != doc)) {
doc->BeginUpdate();
}
nsRange::OwnerChildReplaced(mContent, aIndex, oldKid);
PRBool rv = mChildren.ReplaceElementAt(aKid, aIndex);
if (rv) {
NS_ADDREF(aKid);
aKid->SetParent(mContent);
nsIDocument* doc = mDocument;
if (nsnull != doc) {
aKid->SetDocument(doc, PR_FALSE);
if (aNotify) {
@ -2980,6 +3017,9 @@ nsGenericHTMLContainerElement::ReplaceChildAt(nsIContent* aKid,
oldKid->SetParent(nsnull);
NS_RELEASE(oldKid);
}
if (aNotify && (nsnull != doc)) {
doc->EndUpdate();
}
return NS_OK;
}
@ -2987,12 +3027,15 @@ nsresult
nsGenericHTMLContainerElement::AppendChildTo(nsIContent* aKid, PRBool aNotify)
{
NS_PRECONDITION((nsnull != aKid) && (aKid != mContent), "null ptr");
nsIDocument* doc = mDocument;
if (aNotify && (nsnull != doc)) {
doc->BeginUpdate();
}
PRBool rv = mChildren.AppendElement(aKid);
if (rv) {
NS_ADDREF(aKid);
aKid->SetParent(mContent);
// ranges don't need adjustment since new child is at end of list
nsIDocument* doc = mDocument;
if (nsnull != doc) {
aKid->SetDocument(doc, PR_FALSE);
if (aNotify) {
@ -3000,15 +3043,21 @@ nsGenericHTMLContainerElement::AppendChildTo(nsIContent* aKid, PRBool aNotify)
}
}
}
if (aNotify && (nsnull != doc)) {
doc->EndUpdate();
}
return NS_OK;
}
nsresult
nsGenericHTMLContainerElement::RemoveChildAt(PRInt32 aIndex, PRBool aNotify)
{
nsIDocument* doc = mDocument;
if (aNotify && (nsnull != doc)) {
doc->BeginUpdate();
}
nsIContent* oldKid = (nsIContent *)mChildren.ElementAt(aIndex);
if (nsnull != oldKid ) {
nsIDocument* doc = mDocument;
nsRange::OwnerChildRemoved(mContent, aIndex, oldKid);
mChildren.RemoveElementAt(aIndex);
if (aNotify) {
@ -3020,6 +3069,9 @@ nsGenericHTMLContainerElement::RemoveChildAt(PRInt32 aIndex, PRBool aNotify)
oldKid->SetParent(nsnull);
NS_RELEASE(oldKid);
}
if (aNotify && (nsnull != doc)) {
doc->EndUpdate();
}
return NS_OK;
}

Просмотреть файл

@ -286,7 +286,8 @@ public:
//XXX These three create a dependency between content and frames
static nsresult GetPrimaryFrame(nsIHTMLContent* aContent,
nsIFormControlFrame *&aFormControlFrame);
nsIFormControlFrame *&aFormControlFrame,
PRBool aFlushNotifications=PR_TRUE);
static nsresult GetPrimaryPresState(nsIHTMLContent* aContent,
nsIStatefulFrame::StateType aStateType,
nsIPresState** aPresState);

Просмотреть файл

@ -720,7 +720,7 @@ nsHTMLSelectElement::DoneAddingContent(PRBool aIsDone)
{
mIsDoneAddingContent = aIsDone;
nsIFormControlFrame* fcFrame = nsnull;
nsresult result = nsGenericHTMLElement::GetPrimaryFrame(this, fcFrame);
nsresult result = nsGenericHTMLElement::GetPrimaryFrame(this, fcFrame,PR_FALSE);
if (NS_SUCCEEDED(result) && (nsnull != fcFrame)) {
nsISelectControlFrame* selectFrame = nsnull;
result = fcFrame->QueryInterface(nsISelectControlFrame::GetIID(),(void **) &selectFrame);

Просмотреть файл

@ -63,6 +63,7 @@
#include "nsIWebShell.h"
#include "nsIDocument.h"
#include "nsIDocumentObserver.h"
#include "nsIHTMLDocument.h"
#include "nsStyleConsts.h"
#include "nsINameSpaceManager.h"
@ -144,7 +145,8 @@ class SinkContext;
class HTMLContentSink : public nsIHTMLContentSink,
public nsIUnicharStreamLoaderObserver,
public nsITimerCallback,
public nsICSSLoaderObserver
public nsICSSLoaderObserver,
public nsIDocumentObserver
{
public:
HTMLContentSink();
@ -200,6 +202,62 @@ public:
// nsICSSLoaderObserver
NS_IMETHOD StyleSheetLoaded(nsICSSStyleSheet*aSheet, PRBool aNotify);
// nsIDocumentObserver
NS_IMETHOD BeginUpdate(nsIDocument *aDocument);
NS_IMETHOD EndUpdate(nsIDocument *aDocument);
NS_IMETHOD BeginLoad(nsIDocument *aDocument) { return NS_OK; }
NS_IMETHOD EndLoad(nsIDocument *aDocument) { return NS_OK; }
NS_IMETHOD BeginReflow(nsIDocument *aDocument,
nsIPresShell* aShell) { return NS_OK; }
NS_IMETHOD EndReflow(nsIDocument *aDocument,
nsIPresShell* aShell) { return NS_OK; }
NS_IMETHOD ContentChanged(nsIDocument *aDocument,
nsIContent* aContent,
nsISupports* aSubContent) { return NS_OK; }
NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2) { return NS_OK; }
NS_IMETHOD AttributeChanged(nsIDocument *aDocument,
nsIContent* aContent,
PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
PRInt32 aHint) { return NS_OK; }
NS_IMETHOD ContentAppended(nsIDocument *aDocument,
nsIContent* aContainer,
PRInt32 aNewIndexInContainer)
{ return NS_OK; }
NS_IMETHOD ContentInserted(nsIDocument *aDocument,
nsIContent* aContainer,
nsIContent* aChild,
PRInt32 aIndexInContainer) { return NS_OK; }
NS_IMETHOD ContentReplaced(nsIDocument *aDocument,
nsIContent* aContainer,
nsIContent* aOldChild,
nsIContent* aNewChild,
PRInt32 aIndexInContainer) { return NS_OK; }
NS_IMETHOD ContentRemoved(nsIDocument *aDocument,
nsIContent* aContainer,
nsIContent* aChild,
PRInt32 aIndexInContainer) { return NS_OK; }
NS_IMETHOD StyleSheetAdded(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet) { return NS_OK; }
NS_IMETHOD StyleSheetRemoved(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet) { return NS_OK; }
NS_IMETHOD StyleSheetDisabledStateChanged(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet,
PRBool aDisabled) { return NS_OK; }
NS_IMETHOD StyleRuleChanged(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet,
nsIStyleRule* aStyleRule,
PRInt32 aHint) { return NS_OK; }
NS_IMETHOD StyleRuleAdded(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet,
nsIStyleRule* aStyleRule) { return NS_OK; }
NS_IMETHOD StyleRuleRemoved(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet,
nsIStyleRule* aStyleRule) { return NS_OK; }
NS_IMETHOD DocumentWillBeDestroyed(nsIDocument *aDocument) { return NS_OK; }
PRBool IsTimeToNotify();
PRBool IsInScript();
void ReduceEntities(nsString& aString);
@ -243,6 +301,7 @@ public:
PRBool mLayoutStarted;
PRInt32 mInScript;
PRInt32 mInNotification;
nsIDOMHTMLFormElement* mCurrentForm;
nsIHTMLContent* mCurrentMap;
@ -344,7 +403,7 @@ public:
{
return FlushText(aDidFlush, PR_TRUE);
}
nsresult FlushTags();
nsresult FlushTags(PRBool aNotify = PR_TRUE);
PRBool IsCurrentContainer(nsHTMLTag mType);
PRBool IsAncestorContainer(nsHTMLTag mType);
@ -1152,7 +1211,7 @@ SinkContext::DidAddContent(nsIContent* aContent, PRBool aDidNotify)
else if (!aDidNotify && mSink->IsTimeToNotify()) {
SINK_TRACE(SINK_TRACE_REFLOW,
("SinkContext::DidAddContent: Notification as a result of the interval expiring; backoff count: %d", mSink->mBackoffCount));
FlushTags();
FlushTags(PR_TRUE);
}
}
@ -1210,10 +1269,10 @@ SinkContext::OpenContainer(const nsIParserNode& aNode)
if (mStack[mStackPos-1].mInsertionPoint != -1) {
parent->InsertChildAt(content,
mStack[mStackPos-1].mInsertionPoint++,
mSink->IsInScript());
PR_FALSE);
}
else {
parent->AppendChildTo(content, mSink->IsInScript());
parent->AppendChildTo(content, PR_FALSE);
}
mStack[mStackPos].mFlags |= APPENDED;
}
@ -1287,10 +1346,10 @@ SinkContext::CloseContainer(const nsIParserNode& aNode)
if (mStack[mStackPos-1].mInsertionPoint != -1) {
result = parent->InsertChildAt(content,
mStack[mStackPos-1].mInsertionPoint++,
mSink->IsInScript());
PR_FALSE);
}
else {
result = parent->AppendChildTo(content, mSink->IsInScript());
result = parent->AppendChildTo(content, PR_FALSE);
}
}
@ -1324,7 +1383,7 @@ SinkContext::CloseContainer(const nsIParserNode& aNode)
mNotifyLevel = mStackPos-1;
}
DidAddContent(content, mSink->IsInScript());
DidAddContent(content, PR_FALSE);
// Special handling for certain tags
@ -1434,7 +1493,7 @@ SinkContext::DemoteContainer(const nsIParserNode& aNode)
// with later.
parent->ChildCount(parentCount);
if (mStack[stackPos-1].mNumFlushed == parentCount) {
FlushTags();
FlushTags(PR_TRUE);
sync = PR_TRUE;
}
// Otherwise just append the container to the parent without
@ -1601,13 +1660,13 @@ SinkContext::AddLeaf(nsIHTMLContent* aContent)
if (mStack[mStackPos-1].mInsertionPoint != -1) {
parent->InsertChildAt(aContent,
mStack[mStackPos-1].mInsertionPoint++,
mSink->IsInScript());
PR_FALSE);
}
else {
parent->AppendChildTo(aContent, mSink->IsInScript());
parent->AppendChildTo(aContent, PR_FALSE);
}
DidAddContent(aContent, mSink->IsInScript());
DidAddContent(aContent, PR_FALSE);
#ifdef DEBUG
if (mPreAppend &&
@ -1653,13 +1712,13 @@ SinkContext::AddComment(const nsIParserNode& aNode)
if (mStack[mStackPos-1].mInsertionPoint != -1) {
parent->InsertChildAt(comment,
mStack[mStackPos-1].mInsertionPoint++,
mSink->IsInScript());
PR_FALSE);
}
else {
parent->AppendChildTo(comment, mSink->IsInScript());
parent->AppendChildTo(comment, PR_FALSE);
}
DidAddContent(comment, mSink->IsInScript());
DidAddContent(comment, PR_FALSE);
#ifdef DEBUG
if (mPreAppend &&
@ -1764,7 +1823,7 @@ SinkContext::AddText(const nsString& aText)
* has been newly added so that the frame tree is complete.
*/
nsresult
SinkContext::FlushTags()
SinkContext::FlushTags(PRBool aNotify)
{
nsresult result = NS_OK;
@ -1796,47 +1855,49 @@ SinkContext::FlushTags()
stackPos--;
}
// Start from the base of the stack (growing upward) and do
// a notification from the node that is closest to the root of
// tree for any content that has been added.
stackPos = 1;
PRBool flushed = PR_FALSE;
while (stackPos < mStackPos) {
content = mStack[stackPos].mContent;
content->ChildCount(childCount);
if (aNotify) {
// Start from the base of the stack (growing upward) and do
// a notification from the node that is closest to the root of
// tree for any content that has been added.
stackPos = 1;
PRBool flushed = PR_FALSE;
while (stackPos < mStackPos) {
content = mStack[stackPos].mContent;
content->ChildCount(childCount);
if (!flushed && (mStack[stackPos].mNumFlushed < childCount)) {
if (!flushed && (mStack[stackPos].mNumFlushed < childCount)) {
#ifdef NS_DEBUG
// Tracing code
char cbuf[40];
const char* cp;
nsAutoString str;
nsCOMPtr<nsIDTD> dtd;
mSink->mParser->GetDTD(getter_AddRefs(dtd));
dtd->IntTagToStringTag(nsHTMLTag(mStack[stackPos].mType), str);
cp = str.ToCString(cbuf, sizeof(cbuf));
// Tracing code
char cbuf[40];
const char* cp;
nsAutoString str;
nsCOMPtr<nsIDTD> dtd;
mSink->mParser->GetDTD(getter_AddRefs(dtd));
dtd->IntTagToStringTag(nsHTMLTag(mStack[stackPos].mType), str);
cp = str.ToCString(cbuf, sizeof(cbuf));
SINK_TRACE(SINK_TRACE_REFLOW,
("SinkContext::FlushTags: tag=%s from newindex=%d at stackPos=%d",
cp, mStack[stackPos].mNumFlushed, stackPos));
SINK_TRACE(SINK_TRACE_REFLOW,
("SinkContext::FlushTags: tag=%s from newindex=%d at stackPos=%d",
cp, mStack[stackPos].mNumFlushed, stackPos));
#endif
if ((mStack[stackPos].mInsertionPoint != -1) &&
(mStackPos > (stackPos+1))) {
nsIContent* child = mStack[stackPos+1].mContent;
mSink->NotifyInsert(content,
child,
mStack[stackPos].mInsertionPoint);
if ((mStack[stackPos].mInsertionPoint != -1) &&
(mStackPos > (stackPos+1))) {
nsIContent* child = mStack[stackPos+1].mContent;
mSink->NotifyInsert(content,
child,
mStack[stackPos].mInsertionPoint);
}
else {
mSink->NotifyAppend(content, mStack[stackPos].mNumFlushed);
}
flushed = PR_TRUE;
}
else {
mSink->NotifyAppend(content, mStack[stackPos].mNumFlushed);
}
flushed = PR_TRUE;
}
mStack[stackPos].mNumFlushed = childCount;
stackPos++;
mStack[stackPos].mNumFlushed = childCount;
stackPos++;
}
mNotifyLevel = mStackPos-1;
}
mNotifyLevel = mStackPos-1;
return result;
}
@ -1907,10 +1968,10 @@ SinkContext::FlushText(PRBool* aDidFlush, PRBool aReleaseLast)
if (mStack[mStackPos-1].mInsertionPoint != -1) {
parent->InsertChildAt(content,
mStack[mStackPos-1].mInsertionPoint++,
mSink->IsInScript());
PR_FALSE);
}
else {
parent->AppendChildTo(content, mSink->IsInScript());
parent->AppendChildTo(content, PR_FALSE);
}
mLastTextNode = content;
@ -1918,7 +1979,7 @@ SinkContext::FlushText(PRBool* aDidFlush, PRBool aReleaseLast)
mTextLength = 0;
didFlush = PR_TRUE;
DidAddContent(content, mSink->IsInScript());
DidAddContent(content, PR_FALSE);
}
}
}
@ -1972,6 +2033,7 @@ HTMLContentSink::HTMLContentSink() {
mNotAtRef = PR_TRUE;
mContentIDCounter = NS_CONTENT_ID_COUNTER_BASE;
mInScript = 0;
mInNotification = 0;
mInsideNoXXXTag = 0;
}
@ -1982,7 +2044,10 @@ HTMLContentSink::~HTMLContentSink()
NS_IF_RELEASE(mFrameset);
NS_IF_RELEASE(mRoot);
NS_IF_RELEASE(mDocument);
if (mDocument) {
mDocument->RemoveObserver(this);
NS_RELEASE(mDocument);
}
NS_IF_RELEASE(mHTMLDocument);
NS_IF_RELEASE(mDocumentURI);
NS_IF_RELEASE(mDocumentBaseURL);
@ -2033,12 +2098,13 @@ HTMLContentSink::~HTMLContentSink()
}
}
NS_IMPL_ISUPPORTS5(HTMLContentSink,
NS_IMPL_ISUPPORTS6(HTMLContentSink,
nsIHTMLContentSink,
nsIContentSink,
nsIUnicharStreamLoaderObserver,
nsITimerCallback,
nsICSSLoaderObserver)
nsICSSLoaderObserver,
nsIDocumentObserver)
nsresult
HTMLContentSink::Init(nsIDocument* aDoc,
@ -2060,6 +2126,7 @@ HTMLContentSink::Init(nsIDocument* aDoc,
mDocument = aDoc;
NS_ADDREF(aDoc);
aDoc->AddObserver(this);
aDoc->QueryInterface(kIHTMLDocumentIID, (void**)&mHTMLDocument);
mDocumentURI = aURL;
NS_ADDREF(aURL);
@ -2187,7 +2254,7 @@ HTMLContentSink::DidBuildModel(PRInt32 aQualityLevel)
if (nsnull != mBody) {
SINK_TRACE(SINK_TRACE_REFLOW,
("HTMLContentSink::DidBuildModel: layout final content"));
mCurrentContext->FlushTags();
mCurrentContext->FlushTags(PR_TRUE);
}
ScrollToRef();
@ -2220,7 +2287,7 @@ HTMLContentSink::Notify(nsITimer *timer)
("HTMLContentSink::Notify: reflow on a timer: %d milliseconds late, backoff count: %d", delay, mBackoffCount));
#endif
if (mCurrentContext) {
mCurrentContext->FlushTags();
mCurrentContext->FlushTags(PR_TRUE);
}
mNotificationTimer = 0;
MOZ_TIMER_DEBUGLOG(("Stop: nsHTMLContentSink::Notify()\n"));
@ -2251,7 +2318,7 @@ HTMLContentSink::WillInterrupt()
mBackoffCount--;
SINK_TRACE(SINK_TRACE_REFLOW,
("HTMLContentSink::WillInterrupt: flushing tags since we've run out time; backoff count: %d", mBackoffCount));
result = mCurrentContext->FlushTags();
result = mCurrentContext->FlushTags(PR_TRUE);
}
else {
// If the time since the last notification is less than
@ -2289,7 +2356,7 @@ HTMLContentSink::WillInterrupt()
else {
SINK_TRACE(SINK_TRACE_REFLOW,
("HTMLContentSink::WillInterrupt: flushing tags unconditionally"));
result = mCurrentContext->FlushTags();
result = mCurrentContext->FlushTags(PR_TRUE);
}
return result;
@ -2343,7 +2410,7 @@ HTMLContentSink::BeginContext(PRInt32 aPosition)
}
// Flush everything in the current context so that we don't have
// to worry about insertions resulting in inconsistent frame creation.
mCurrentContext->FlushTags();
mCurrentContext->FlushTags(PR_TRUE);
PRInt32 insertionPoint = -1;
nsHTMLTag nodeType = mCurrentContext->mStack[aPosition].mType;
@ -2477,8 +2544,8 @@ HTMLContentSink::CloseHTML(const nsIParserNode& aNode)
if(mCurrentContext==mHeadContext) {
PRInt32 numContexts = mContextStack.Count();
// Pop off the second html context if it's not done earlier
mContextStack.RemoveElementAt(--numContexts);
mCurrentContext = nsnull;
mCurrentContext = (SinkContext*)mContextStack.ElementAt(--numContexts);
mContextStack.RemoveElementAt(numContexts);
}
mHeadContext->End();
delete mHeadContext;
@ -2596,7 +2663,7 @@ HTMLContentSink::CloseBody(const nsIParserNode& aNode)
// Flush out anything that's left
SINK_TRACE(SINK_TRACE_REFLOW,
("HTMLContentSink::CloseBody: layout final body content"));
mCurrentContext->FlushTags();
mCurrentContext->FlushTags(PR_TRUE);
mCurrentContext->CloseContainer(aNode);
MOZ_TIMER_DEBUGLOG(("Stop: nsHTMLContentSink::CloseBody()\n"));
@ -3770,7 +3837,7 @@ IsJavaScriptLanguage(const nsString& aName, const char* *aVersion)
void
HTMLContentSink::ForceReflow()
{
mCurrentContext->FlushTags();
mCurrentContext->FlushTags(PR_TRUE);
}
#endif
@ -3778,6 +3845,7 @@ HTMLContentSink::ForceReflow()
void
HTMLContentSink::NotifyAppend(nsIContent* aContainer, PRInt32 aStartIndex)
{
mInNotification++;
MOZ_TIMER_DEBUGLOG(("Save and stop: nsHTMLContentSink::NotifyAppend()\n"));
MOZ_TIMER_SAVE(mWatch)
MOZ_TIMER_STOP(mWatch);
@ -3785,6 +3853,7 @@ HTMLContentSink::NotifyAppend(nsIContent* aContainer, PRInt32 aStartIndex)
mLastNotificationTime = PR_Now();
MOZ_TIMER_DEBUGLOG(("Restore: nsHTMLContentSink::NotifyAppend()\n"));
MOZ_TIMER_RESTORE(mWatch);
mInNotification--;
}
void
@ -3792,6 +3861,7 @@ HTMLContentSink::NotifyInsert(nsIContent* aContent,
nsIContent* aChildContent,
PRInt32 aIndexInContainer)
{
mInNotification++;
MOZ_TIMER_DEBUGLOG(("Save and stop: nsHTMLContentSink::NotifyInsert()\n"));
MOZ_TIMER_SAVE(mWatch)
MOZ_TIMER_STOP(mWatch);
@ -3799,6 +3869,7 @@ HTMLContentSink::NotifyInsert(nsIContent* aContent,
mLastNotificationTime = PR_Now();
MOZ_TIMER_DEBUGLOG(("Restore: nsHTMLContentSink::NotifyInsert()\n"));
MOZ_TIMER_RESTORE(mWatch);
mInNotification--;
}
PRBool
@ -3835,6 +3906,37 @@ HTMLContentSink::UpdateAllContexts()
mCurrentContext->UpdateChildCounts();
}
NS_IMETHODIMP
HTMLContentSink::BeginUpdate(nsIDocument *aDocument)
{
nsresult result = NS_OK;
// If we're in a script and we didn't do the notification,
// something else in the script processing caused the
// notification to occur. Since this could result in frame
// creation, make sure we've flushed everything before we
// continue
if (mInScript && !mInNotification && mCurrentContext) {
result = mCurrentContext->FlushTags(PR_TRUE);
}
return result;
}
NS_IMETHODIMP
HTMLContentSink::EndUpdate(nsIDocument *aDocument)
{
// If we're in a script and we didn't do the notification,
// something else in the script processing caused the
// notification to occur. Update our notion of how much
// has been flushed to include any new content.
if (mInScript && !mInNotification) {
UpdateAllContexts();
}
return NS_OK;
}
nsresult
HTMLContentSink::ResumeParsing()
{
@ -3853,10 +3955,12 @@ HTMLContentSink::PreEvaluateScript()
// to the body (so that they can be seen by scripts) and force reflow.
SINK_TRACE(SINK_TRACE_CALLS,
("HTMLContentSink::PreEvaluateScript: flushing tags before evaluating script"));
mCurrentContext->FlushTags();
mCurrentContext->FlushTags(PR_FALSE);
mCurrentContext->SetPreAppend(PR_TRUE);
mInScript++;
return PR_TRUE;
}
@ -3864,8 +3968,7 @@ void
HTMLContentSink::PostEvaluateScript(PRBool aBodyPresent)
{
mInScript--;
mCurrentContext->UpdateChildCounts();
mCurrentContext->SetPreAppend(PR_FALSE);
}
PRBool
@ -4019,10 +4122,10 @@ HTMLContentSink::ProcessSCRIPTTag(const nsIParserNode& aNode)
if (mCurrentContext->mStack[mCurrentContext->mStackPos-1].mInsertionPoint != -1) {
parent->InsertChildAt(element,
mCurrentContext->mStack[mCurrentContext->mStackPos-1].mInsertionPoint++,
IsInScript());
PR_FALSE);
}
else {
parent->AppendChildTo(element, IsInScript());
parent->AppendChildTo(element, PR_FALSE);
}
}
else {
@ -4044,7 +4147,7 @@ HTMLContentSink::ProcessSCRIPTTag(const nsIParserNode& aNode)
tc->SetData(script);
NS_RELEASE(tc);
}
element->AppendChildTo(text, IsInScript());
element->AppendChildTo(text, PR_FALSE);
text->SetDocument(mDocument, PR_FALSE);
NS_RELEASE(text);
}
@ -4201,7 +4304,7 @@ HTMLContentSink::ProcessSTYLETag(const nsIParserNode& aNode)
tc->SetData(content);
NS_RELEASE(tc);
}
element->AppendChildTo(text, IsInScript());
element->AppendChildTo(text, PR_FALSE);
text->SetDocument(mDocument, PR_FALSE);
NS_RELEASE(text);
}
@ -4262,13 +4365,15 @@ HTMLContentSink::NotifyError(const nsParserError* aError)
NS_IMETHODIMP
HTMLContentSink::FlushPendingNotifications()
{
/* XXX This is temporarily commented out so that this change can be tested locally.
nsresult result = NS_OK;
if (mCurrentContext) {
// Only flush tags if we're not doing the notification ourselves
// (since we aren't reentrant) and if we're in a script (since
// we only care to flush if this is done via script).
if (mCurrentContext && !mInNotification && mInScript) {
result = mCurrentContext->FlushTags();
}
*/
return NS_OK;
return result;
}
NS_IMETHODIMP

Просмотреть файл

@ -1294,6 +1294,34 @@ nsXULDocument::RemoveObserver(nsIDocumentObserver* aObserver)
return mObservers.RemoveElement(aObserver);
}
NS_IMETHODIMP
nsXULDocument::BeginUpdate()
{
// XXX Never called. Does this matter?
for (PRInt32 i = 0; i < mObservers.Count(); i++) {
nsIDocumentObserver* observer = (nsIDocumentObserver*) mObservers[i];
observer->BeginUpdate(this);
if (observer != (nsIDocumentObserver*)mObservers.ElementAt(i)) {
i--;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsXULDocument::EndUpdate()
{
// XXX Never called. Does this matter?
for (PRInt32 i = 0; i < mObservers.Count(); i++) {
nsIDocumentObserver* observer = (nsIDocumentObserver*) mObservers[i];
observer->EndUpdate(this);
if (observer != (nsIDocumentObserver*)mObservers.ElementAt(i)) {
i--;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsXULDocument::BeginLoad()
{

Просмотреть файл

@ -191,6 +191,10 @@ public:
virtual PRBool RemoveObserver(nsIDocumentObserver* aObserver);
NS_IMETHOD BeginUpdate();
NS_IMETHOD EndUpdate();
NS_IMETHOD BeginLoad();
NS_IMETHOD EndLoad();

Просмотреть файл

@ -240,6 +240,8 @@ public:
// Observation hooks used by content nodes to propagate
// notifications to document observers.
NS_IMETHOD BeginUpdate() = 0;
NS_IMETHOD EndUpdate() = 0;
NS_IMETHOD BeginLoad() = 0;
NS_IMETHOD EndLoad() = 0;
NS_IMETHOD ContentChanged(nsIContent* aContent,

Просмотреть файл

@ -1463,6 +1463,42 @@ PRBool nsDocument::RemoveObserver(nsIDocumentObserver* aObserver)
return (mObservers.IndexOf(aObserver) != -1);
}
NS_IMETHODIMP
nsDocument::BeginUpdate()
{
PRInt32 i;
// Get new value of count for every iteration in case
// observers remove themselves during the loop.
for (i = 0; i < mObservers.Count(); i++) {
nsIDocumentObserver* observer = (nsIDocumentObserver*) mObservers[i];
observer->BeginUpdate(this);
// Make sure that the observer didn't remove itself during the
// notification. If it did, update our index and count.
if (observer != (nsIDocumentObserver*)mObservers[i]) {
i--;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsDocument::EndUpdate()
{
PRInt32 i;
// Get new value of count for every iteration in case
// observers remove themselves during the loop.
for (i = 0; i < mObservers.Count(); i++) {
nsIDocumentObserver* observer = (nsIDocumentObserver*) mObservers[i];
observer->EndUpdate(this);
// Make sure that the observer didn't remove itself during the
// notification. If it did, update our index and count.
if (observer != (nsIDocumentObserver*)mObservers[i]) {
i--;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsDocument::BeginLoad()
{
@ -1651,12 +1687,16 @@ nsDocument::StyleRuleChanged(nsIStyleSheet* aStyleSheet, nsIStyleRule* aStyleRul
// observers remove themselves during the loop.
for (i = 0; i < mObservers.Count(); i++) {
nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i];
observer->BeginUpdate(this);
observer->StyleRuleChanged(this, aStyleSheet, aStyleRule, aHint);
// Make sure that the observer didn't remove itself during the
// notification. If it did, update our index and count.
if (observer != (nsIDocumentObserver*)mObservers[i]) {
i--;
}
else {
observer->EndUpdate(this);
}
}
return NS_OK;
}
@ -1669,12 +1709,16 @@ nsDocument::StyleRuleAdded(nsIStyleSheet* aStyleSheet, nsIStyleRule* aStyleRule)
// observers remove themselves during the loop.
for (i = 0; i < mObservers.Count(); i++) {
nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i];
observer->BeginUpdate(this);
observer->StyleRuleAdded(this, aStyleSheet, aStyleRule);
// Make sure that the observer didn't remove itself during the
// notification. If it did, update our index and count.
if (observer != (nsIDocumentObserver*)mObservers[i]) {
i--;
}
else {
observer->EndUpdate(this);
}
}
return NS_OK;
}
@ -1687,12 +1731,16 @@ nsDocument::StyleRuleRemoved(nsIStyleSheet* aStyleSheet, nsIStyleRule* aStyleRul
// observers remove themselves during the loop.
for (i = 0; i < mObservers.Count(); i++) {
nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i];
observer->BeginUpdate(this);
observer->StyleRuleRemoved(this, aStyleSheet, aStyleRule);
// Make sure that the observer didn't remove itself during the
// notification. If it did, update our index and count.
if (observer != (nsIDocumentObserver*)mObservers[i]) {
i--;
}
else {
observer->EndUpdate(this);
}
}
return NS_OK;
}

Просмотреть файл

@ -1004,11 +1004,15 @@ nsGenericDOMDataNode::SetText(const PRUnichar* aBuffer, PRInt32 aLength,
if (nsnull == aBuffer) {
return NS_ERROR_NULL_POINTER;
}
if (aNotify && (nsnull != mDocument)) {
mDocument->BeginUpdate();
}
mText.SetTo(aBuffer, aLength);
// Trigger a reflow
if (aNotify && (nsnull != mDocument)) {
mDocument->ContentChanged(mContent, nsnull);
mDocument->EndUpdate();
}
return NS_OK;
}
@ -1025,11 +1029,15 @@ nsGenericDOMDataNode::SetText(const char* aBuffer,
if (nsnull == aBuffer) {
return NS_ERROR_NULL_POINTER;
}
if (aNotify && (nsnull != mDocument)) {
mDocument->BeginUpdate();
}
mText.SetTo(aBuffer, aLength);
// Trigger a reflow
if (aNotify && (nsnull != mDocument)) {
mDocument->ContentChanged(mContent, nsnull);
mDocument->EndUpdate();
}
return NS_OK;
}

Просмотреть файл

@ -1868,6 +1868,11 @@ nsGenericContainerElement::SetAttribute(PRInt32 aNameSpaceID, nsIAtom* aName,
if (nsnull == mAttributes) {
mAttributes = new nsVoidArray();
}
if (aNotify && (nsnull != mDocument)) {
mDocument->BeginUpdate();
}
if (nsnull != mAttributes) {
nsGenericAttribute* attr;
PRInt32 index;
@ -1890,8 +1895,11 @@ nsGenericContainerElement::SetAttribute(PRInt32 aNameSpaceID, nsIAtom* aName,
}
}
if (NS_SUCCEEDED(rv) && aNotify && (nsnull != mDocument)) {
mDocument->AttributeChanged(mContent, aNameSpaceID, aName, NS_STYLE_HINT_UNKNOWN);
if (aNotify && (nsnull != mDocument)) {
if (NS_SUCCEEDED(rv)) {
mDocument->AttributeChanged(mContent, aNameSpaceID, aName, NS_STYLE_HINT_UNKNOWN);
}
mDocument->EndUpdate();
}
return rv;
@ -1957,6 +1965,9 @@ nsGenericContainerElement::UnsetAttribute(PRInt32 aNameSpaceID, nsIAtom* aName,
nsGenericAttribute* attr = (nsGenericAttribute*)mAttributes->ElementAt(index);
if (((kNameSpaceID_Unknown == aNameSpaceID) || (attr->mNameSpaceID == aNameSpaceID)) &&
(attr->mName == aName)) {
if (aNotify && (nsnull != mDocument)) {
mDocument->BeginUpdate();
}
mAttributes->RemoveElementAt(index);
delete attr;
found = PR_TRUE;
@ -1966,6 +1977,7 @@ nsGenericContainerElement::UnsetAttribute(PRInt32 aNameSpaceID, nsIAtom* aName,
if (NS_SUCCEEDED(rv) && found && aNotify && (nsnull != mDocument)) {
mDocument->AttributeChanged(mContent, aNameSpaceID, aName, NS_STYLE_HINT_UNKNOWN);
mDocument->EndUpdate();
}
}
@ -2117,12 +2129,15 @@ nsGenericContainerElement::InsertChildAt(nsIContent* aKid,
PRBool aNotify)
{
NS_PRECONDITION(nsnull != aKid, "null ptr");
nsIDocument* doc = mDocument;
if (aNotify && (nsnull != doc)) {
doc->BeginUpdate();
}
PRBool rv = mChildren.InsertElementAt(aKid, aIndex);/* XXX fix up void array api to use nsresult's*/
if (rv) {
NS_ADDREF(aKid);
aKid->SetParent(mContent);
nsRange::OwnerChildInserted(mContent, aIndex);
nsIDocument* doc = mDocument;
if (nsnull != doc) {
aKid->SetDocument(doc, PR_FALSE);
if (aNotify) {
@ -2130,6 +2145,9 @@ nsGenericContainerElement::InsertChildAt(nsIContent* aKid,
}
}
}
if (aNotify && (nsnull != doc)) {
doc->EndUpdate();
}
return NS_OK;
}
@ -2139,13 +2157,16 @@ nsGenericContainerElement::ReplaceChildAt(nsIContent* aKid,
PRBool aNotify)
{
NS_PRECONDITION(nsnull != aKid, "null ptr");
nsIDocument* doc = mDocument;
if (aNotify && (nsnull != mDocument)) {
doc->BeginUpdate();
}
nsIContent* oldKid = (nsIContent *)mChildren.ElementAt(aIndex);
nsRange::OwnerChildReplaced(mContent, aIndex, oldKid);
PRBool rv = mChildren.ReplaceElementAt(aKid, aIndex);
if (rv) {
NS_ADDREF(aKid);
aKid->SetParent(mContent);
nsIDocument* doc = mDocument;
if (nsnull != doc) {
aKid->SetDocument(doc, PR_FALSE);
if (aNotify) {
@ -2156,6 +2177,9 @@ nsGenericContainerElement::ReplaceChildAt(nsIContent* aKid,
oldKid->SetParent(nsnull);
NS_RELEASE(oldKid);
}
if (aNotify && (nsnull != mDocument)) {
doc->EndUpdate();
}
return NS_OK;
}
@ -2163,12 +2187,15 @@ nsresult
nsGenericContainerElement::AppendChildTo(nsIContent* aKid, PRBool aNotify)
{
NS_PRECONDITION((nsnull != aKid) && (aKid != mContent), "null ptr");
nsIDocument* doc = mDocument;
if (aNotify && (nsnull != doc)) {
doc->BeginUpdate();
}
PRBool rv = mChildren.AppendElement(aKid);
if (rv) {
NS_ADDREF(aKid);
aKid->SetParent(mContent);
// ranges don't need adjustment since new child is at end of list
nsIDocument* doc = mDocument;
if (nsnull != doc) {
aKid->SetDocument(doc, PR_FALSE);
if (aNotify) {
@ -2176,6 +2203,9 @@ nsGenericContainerElement::AppendChildTo(nsIContent* aKid, PRBool aNotify)
}
}
}
if (aNotify && (nsnull != doc)) {
doc->EndUpdate();
}
return NS_OK;
}
@ -2185,6 +2215,9 @@ nsGenericContainerElement::RemoveChildAt(PRInt32 aIndex, PRBool aNotify)
nsIContent* oldKid = (nsIContent *)mChildren.ElementAt(aIndex);
if (nsnull != oldKid ) {
nsIDocument* doc = mDocument;
if (aNotify && (nsnull != doc)) {
doc->BeginUpdate();
}
nsRange::OwnerChildRemoved(mContent, aIndex, oldKid);
mChildren.RemoveElementAt(aIndex);
if (aNotify) {
@ -2195,6 +2228,9 @@ nsGenericContainerElement::RemoveChildAt(PRInt32 aIndex, PRBool aNotify)
oldKid->SetDocument(nsnull, PR_TRUE);
oldKid->SetParent(nsnull);
NS_RELEASE(oldKid);
if (aNotify && (nsnull != doc)) {
doc->EndUpdate();
}
}
return NS_OK;

Просмотреть файл

@ -2085,6 +2085,7 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState)
nsIDocument *document; // this presumes content can't get/lose state if not connected to doc
notifyContent[0]->GetDocument(document);
if (document) {
document->BeginUpdate();
document->ContentStatesChanged(notifyContent[0], notifyContent[1]);
if (notifyContent[2]) { // more that two notifications are needed (should be rare)
// XXX a further optimization here would be to group the notification pairs
@ -2095,6 +2096,7 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState)
document->ContentStatesChanged(notifyContent[4], nsnull);
}
}
document->EndUpdate();
NS_RELEASE(document);
}

Просмотреть файл

@ -217,11 +217,15 @@ nsDOMCSSAttributeDeclaration::ParseDeclaration(const nsString& aDecl)
if (NS_SUCCEEDED(result)) {
PRInt32 hint;
if (doc) {
doc->BeginUpdate();
}
result = cssParser->ParseAndAppendDeclaration(aDecl, baseURI, decl, &hint);
if (NS_SUCCEEDED(result)) {
if (doc) {
if (doc) {
if (NS_SUCCEEDED(result)) {
doc->AttributeChanged(mContent, kNameSpaceID_None, nsHTMLAtoms::style, hint);
}
doc->EndUpdate();
}
if (cssLoader) {
cssLoader->RecycleParser(cssParser);
@ -700,6 +704,10 @@ nsGenericHTMLElement::SetAttribute(PRInt32 aNameSpaceID,
NS_RELEASE(htmlContent);
return result;
}
if (aNotify && (nsnull != mDocument)) {
mDocument->BeginUpdate();
}
// set as string value to avoid another string copy
PRBool impact = NS_STYLE_HINT_NONE;
htmlContent->GetMappedAttributeImpact(aAttribute, impact);
@ -729,6 +737,7 @@ nsGenericHTMLElement::SetAttribute(PRInt32 aNameSpaceID,
if (aNotify && (nsnull != mDocument)) {
mDocument->AttributeChanged(mContent, aNameSpaceID, aAttribute, NS_STYLE_HINT_UNKNOWN);
mDocument->EndUpdate();
}
return result;
@ -771,15 +780,18 @@ nsGenericHTMLElement::SetHTMLAttribute(nsIAtom* aAttribute,
PRBool impact = NS_STYLE_HINT_NONE;
htmlContent->GetMappedAttributeImpact(aAttribute, impact);
if (nsnull != mDocument) { // set attr via style sheet
if (aNotify && (nsHTMLAtoms::style == aAttribute)) {
nsHTMLValue oldValue;
PRInt32 oldImpact = NS_STYLE_HINT_NONE;
if (NS_CONTENT_ATTR_NOT_THERE != GetHTMLAttribute(aAttribute, oldValue)) {
oldImpact = GetStyleImpactFrom(oldValue);
}
impact = GetStyleImpactFrom(aValue);
if (impact < oldImpact) {
impact = oldImpact;
if (aNotify) {
mDocument->BeginUpdate();
if (nsHTMLAtoms::style == aAttribute) {
nsHTMLValue oldValue;
PRInt32 oldImpact = NS_STYLE_HINT_NONE;
if (NS_CONTENT_ATTR_NOT_THERE != GetHTMLAttribute(aAttribute, oldValue)) {
oldImpact = GetStyleImpactFrom(oldValue);
}
impact = GetStyleImpactFrom(aValue);
if (impact < oldImpact) {
impact = oldImpact;
}
}
}
nsIHTMLStyleSheet* sheet = GetAttrStyleSheet(mDocument);
@ -791,6 +803,7 @@ nsGenericHTMLElement::SetHTMLAttribute(nsIAtom* aAttribute,
}
if (aNotify) {
mDocument->AttributeChanged(mContent, kNameSpaceID_None, aAttribute, impact);
mDocument->EndUpdate();
}
}
else { // manage this ourselves and re-sync when we connect to doc
@ -833,13 +846,16 @@ nsGenericHTMLElement::UnsetAttribute(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
}
if (nsnull != mDocument) { // set attr via style sheet
PRInt32 impact = NS_STYLE_HINT_UNKNOWN;
if (aNotify && (nsHTMLAtoms::style == aAttribute)) {
nsHTMLValue oldValue;
if (NS_CONTENT_ATTR_NOT_THERE != GetHTMLAttribute(aAttribute, oldValue)) {
impact = GetStyleImpactFrom(oldValue);
}
else {
impact = NS_STYLE_HINT_NONE;
if (aNotify) {
mDocument->BeginUpdate();
if (nsHTMLAtoms::style == aAttribute) {
nsHTMLValue oldValue;
if (NS_CONTENT_ATTR_NOT_THERE != GetHTMLAttribute(aAttribute, oldValue)) {
impact = GetStyleImpactFrom(oldValue);
}
else {
impact = NS_STYLE_HINT_NONE;
}
}
}
nsIHTMLStyleSheet* sheet = GetAttrStyleSheet(mDocument);
@ -849,6 +865,7 @@ nsGenericHTMLElement::UnsetAttribute(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
}
if (aNotify) {
mDocument->AttributeChanged(mContent, aNameSpaceID, aAttribute, impact);
mDocument->EndUpdate();
}
}
else { // manage this ourselves and re-sync when we connect to doc
@ -1585,16 +1602,19 @@ nsGenericHTMLElement::ColorToString(const nsHTMLValue& aValue,
// XXX This creates a dependency between content and frames
nsresult
nsGenericHTMLElement::GetPrimaryFrame(nsIHTMLContent* aContent,
nsIFormControlFrame *&aFormControlFrame)
nsIFormControlFrame *&aFormControlFrame,
PRBool aFlushNotifications)
{
nsIDocument* doc = nsnull;
nsresult res = NS_NOINTERFACE;
// Get the document
if (NS_OK == aContent->GetDocument(doc)) {
if (nsnull != doc) {
// Cause a flushing of notifications, so we get
// up-to-date presentation information
doc->FlushPendingNotifications();
if (aFlushNotifications) {
// Cause a flushing of notifications, so we get
// up-to-date presentation information
doc->FlushPendingNotifications();
}
// Get presentation shell 0
nsIPresShell* presShell = doc->GetShellAt(0);
@ -1618,24 +1638,32 @@ nsGenericHTMLElement::GetPrimaryPresState(nsIHTMLContent* aContent,
nsIStatefulFrame::StateType aStateType,
nsIPresState** aPresState)
{
nsresult result = NS_OK;
// Get the document
nsCOMPtr<nsIDocument> doc;
aContent->GetDocument(*getter_AddRefs(doc));
result = aContent->GetDocument(*getter_AddRefs(doc));
if (doc) {
// Get presentation shell 0
nsCOMPtr<nsIPresShell> presShell = getter_AddRefs(doc->GetShellAt(0));
if (presShell) {
nsCOMPtr<nsILayoutHistoryState> history;
presShell->GetHistoryState(getter_AddRefs(history));
result = presShell->GetHistoryState(getter_AddRefs(history));
if (history) {
PRUint32 ID;
aContent->GetContentID(&ID);
history->GetState(ID, aPresState, aStateType);
result = history->GetState(ID, aPresState, aStateType);
if (!*aPresState) {
result = NS_NewPresState(aPresState);
if (NS_SUCCEEDED(result)) {
result = history->AddState(ID, *aPresState, aStateType);
}
}
}
}
}
return NS_OK;
return result;
}
// XXX This creates a dependency between content and frames
@ -2941,12 +2969,15 @@ nsGenericHTMLContainerElement::InsertChildAt(nsIContent* aKid,
PRBool aNotify)
{
NS_PRECONDITION(nsnull != aKid, "null ptr");
nsIDocument* doc = mDocument;
if (aNotify && (nsnull != doc)) {
doc->BeginUpdate();
}
PRBool rv = mChildren.InsertElementAt(aKid, aIndex);/* XXX fix up void array api to use nsresult's*/
if (rv) {
NS_ADDREF(aKid);
aKid->SetParent(mContent);
nsRange::OwnerChildInserted(mContent, aIndex);
nsIDocument* doc = mDocument;
if (nsnull != doc) {
aKid->SetDocument(doc, PR_FALSE);
if (aNotify) {
@ -2954,6 +2985,9 @@ nsGenericHTMLContainerElement::InsertChildAt(nsIContent* aKid,
}
}
}
if (aNotify && (nsnull != doc)) {
doc->EndUpdate();
}
return NS_OK;
}
@ -2964,12 +2998,15 @@ nsGenericHTMLContainerElement::ReplaceChildAt(nsIContent* aKid,
{
NS_PRECONDITION(nsnull != aKid, "null ptr");
nsIContent* oldKid = (nsIContent *)mChildren.ElementAt(aIndex);
nsIDocument* doc = mDocument;
if (aNotify && (nsnull != doc)) {
doc->BeginUpdate();
}
nsRange::OwnerChildReplaced(mContent, aIndex, oldKid);
PRBool rv = mChildren.ReplaceElementAt(aKid, aIndex);
if (rv) {
NS_ADDREF(aKid);
aKid->SetParent(mContent);
nsIDocument* doc = mDocument;
if (nsnull != doc) {
aKid->SetDocument(doc, PR_FALSE);
if (aNotify) {
@ -2980,6 +3017,9 @@ nsGenericHTMLContainerElement::ReplaceChildAt(nsIContent* aKid,
oldKid->SetParent(nsnull);
NS_RELEASE(oldKid);
}
if (aNotify && (nsnull != doc)) {
doc->EndUpdate();
}
return NS_OK;
}
@ -2987,12 +3027,15 @@ nsresult
nsGenericHTMLContainerElement::AppendChildTo(nsIContent* aKid, PRBool aNotify)
{
NS_PRECONDITION((nsnull != aKid) && (aKid != mContent), "null ptr");
nsIDocument* doc = mDocument;
if (aNotify && (nsnull != doc)) {
doc->BeginUpdate();
}
PRBool rv = mChildren.AppendElement(aKid);
if (rv) {
NS_ADDREF(aKid);
aKid->SetParent(mContent);
// ranges don't need adjustment since new child is at end of list
nsIDocument* doc = mDocument;
if (nsnull != doc) {
aKid->SetDocument(doc, PR_FALSE);
if (aNotify) {
@ -3000,15 +3043,21 @@ nsGenericHTMLContainerElement::AppendChildTo(nsIContent* aKid, PRBool aNotify)
}
}
}
if (aNotify && (nsnull != doc)) {
doc->EndUpdate();
}
return NS_OK;
}
nsresult
nsGenericHTMLContainerElement::RemoveChildAt(PRInt32 aIndex, PRBool aNotify)
{
nsIDocument* doc = mDocument;
if (aNotify && (nsnull != doc)) {
doc->BeginUpdate();
}
nsIContent* oldKid = (nsIContent *)mChildren.ElementAt(aIndex);
if (nsnull != oldKid ) {
nsIDocument* doc = mDocument;
nsRange::OwnerChildRemoved(mContent, aIndex, oldKid);
mChildren.RemoveElementAt(aIndex);
if (aNotify) {
@ -3020,6 +3069,9 @@ nsGenericHTMLContainerElement::RemoveChildAt(PRInt32 aIndex, PRBool aNotify)
oldKid->SetParent(nsnull);
NS_RELEASE(oldKid);
}
if (aNotify && (nsnull != doc)) {
doc->EndUpdate();
}
return NS_OK;
}

Просмотреть файл

@ -286,7 +286,8 @@ public:
//XXX These three create a dependency between content and frames
static nsresult GetPrimaryFrame(nsIHTMLContent* aContent,
nsIFormControlFrame *&aFormControlFrame);
nsIFormControlFrame *&aFormControlFrame,
PRBool aFlushNotifications=PR_TRUE);
static nsresult GetPrimaryPresState(nsIHTMLContent* aContent,
nsIStatefulFrame::StateType aStateType,
nsIPresState** aPresState);

Просмотреть файл

@ -720,7 +720,7 @@ nsHTMLSelectElement::DoneAddingContent(PRBool aIsDone)
{
mIsDoneAddingContent = aIsDone;
nsIFormControlFrame* fcFrame = nsnull;
nsresult result = nsGenericHTMLElement::GetPrimaryFrame(this, fcFrame);
nsresult result = nsGenericHTMLElement::GetPrimaryFrame(this, fcFrame,PR_FALSE);
if (NS_SUCCEEDED(result) && (nsnull != fcFrame)) {
nsISelectControlFrame* selectFrame = nsnull;
result = fcFrame->QueryInterface(nsISelectControlFrame::GetIID(),(void **) &selectFrame);

Просмотреть файл

@ -63,6 +63,7 @@
#include "nsIWebShell.h"
#include "nsIDocument.h"
#include "nsIDocumentObserver.h"
#include "nsIHTMLDocument.h"
#include "nsStyleConsts.h"
#include "nsINameSpaceManager.h"
@ -144,7 +145,8 @@ class SinkContext;
class HTMLContentSink : public nsIHTMLContentSink,
public nsIUnicharStreamLoaderObserver,
public nsITimerCallback,
public nsICSSLoaderObserver
public nsICSSLoaderObserver,
public nsIDocumentObserver
{
public:
HTMLContentSink();
@ -200,6 +202,62 @@ public:
// nsICSSLoaderObserver
NS_IMETHOD StyleSheetLoaded(nsICSSStyleSheet*aSheet, PRBool aNotify);
// nsIDocumentObserver
NS_IMETHOD BeginUpdate(nsIDocument *aDocument);
NS_IMETHOD EndUpdate(nsIDocument *aDocument);
NS_IMETHOD BeginLoad(nsIDocument *aDocument) { return NS_OK; }
NS_IMETHOD EndLoad(nsIDocument *aDocument) { return NS_OK; }
NS_IMETHOD BeginReflow(nsIDocument *aDocument,
nsIPresShell* aShell) { return NS_OK; }
NS_IMETHOD EndReflow(nsIDocument *aDocument,
nsIPresShell* aShell) { return NS_OK; }
NS_IMETHOD ContentChanged(nsIDocument *aDocument,
nsIContent* aContent,
nsISupports* aSubContent) { return NS_OK; }
NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2) { return NS_OK; }
NS_IMETHOD AttributeChanged(nsIDocument *aDocument,
nsIContent* aContent,
PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
PRInt32 aHint) { return NS_OK; }
NS_IMETHOD ContentAppended(nsIDocument *aDocument,
nsIContent* aContainer,
PRInt32 aNewIndexInContainer)
{ return NS_OK; }
NS_IMETHOD ContentInserted(nsIDocument *aDocument,
nsIContent* aContainer,
nsIContent* aChild,
PRInt32 aIndexInContainer) { return NS_OK; }
NS_IMETHOD ContentReplaced(nsIDocument *aDocument,
nsIContent* aContainer,
nsIContent* aOldChild,
nsIContent* aNewChild,
PRInt32 aIndexInContainer) { return NS_OK; }
NS_IMETHOD ContentRemoved(nsIDocument *aDocument,
nsIContent* aContainer,
nsIContent* aChild,
PRInt32 aIndexInContainer) { return NS_OK; }
NS_IMETHOD StyleSheetAdded(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet) { return NS_OK; }
NS_IMETHOD StyleSheetRemoved(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet) { return NS_OK; }
NS_IMETHOD StyleSheetDisabledStateChanged(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet,
PRBool aDisabled) { return NS_OK; }
NS_IMETHOD StyleRuleChanged(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet,
nsIStyleRule* aStyleRule,
PRInt32 aHint) { return NS_OK; }
NS_IMETHOD StyleRuleAdded(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet,
nsIStyleRule* aStyleRule) { return NS_OK; }
NS_IMETHOD StyleRuleRemoved(nsIDocument *aDocument,
nsIStyleSheet* aStyleSheet,
nsIStyleRule* aStyleRule) { return NS_OK; }
NS_IMETHOD DocumentWillBeDestroyed(nsIDocument *aDocument) { return NS_OK; }
PRBool IsTimeToNotify();
PRBool IsInScript();
void ReduceEntities(nsString& aString);
@ -243,6 +301,7 @@ public:
PRBool mLayoutStarted;
PRInt32 mInScript;
PRInt32 mInNotification;
nsIDOMHTMLFormElement* mCurrentForm;
nsIHTMLContent* mCurrentMap;
@ -344,7 +403,7 @@ public:
{
return FlushText(aDidFlush, PR_TRUE);
}
nsresult FlushTags();
nsresult FlushTags(PRBool aNotify = PR_TRUE);
PRBool IsCurrentContainer(nsHTMLTag mType);
PRBool IsAncestorContainer(nsHTMLTag mType);
@ -1152,7 +1211,7 @@ SinkContext::DidAddContent(nsIContent* aContent, PRBool aDidNotify)
else if (!aDidNotify && mSink->IsTimeToNotify()) {
SINK_TRACE(SINK_TRACE_REFLOW,
("SinkContext::DidAddContent: Notification as a result of the interval expiring; backoff count: %d", mSink->mBackoffCount));
FlushTags();
FlushTags(PR_TRUE);
}
}
@ -1210,10 +1269,10 @@ SinkContext::OpenContainer(const nsIParserNode& aNode)
if (mStack[mStackPos-1].mInsertionPoint != -1) {
parent->InsertChildAt(content,
mStack[mStackPos-1].mInsertionPoint++,
mSink->IsInScript());
PR_FALSE);
}
else {
parent->AppendChildTo(content, mSink->IsInScript());
parent->AppendChildTo(content, PR_FALSE);
}
mStack[mStackPos].mFlags |= APPENDED;
}
@ -1287,10 +1346,10 @@ SinkContext::CloseContainer(const nsIParserNode& aNode)
if (mStack[mStackPos-1].mInsertionPoint != -1) {
result = parent->InsertChildAt(content,
mStack[mStackPos-1].mInsertionPoint++,
mSink->IsInScript());
PR_FALSE);
}
else {
result = parent->AppendChildTo(content, mSink->IsInScript());
result = parent->AppendChildTo(content, PR_FALSE);
}
}
@ -1324,7 +1383,7 @@ SinkContext::CloseContainer(const nsIParserNode& aNode)
mNotifyLevel = mStackPos-1;
}
DidAddContent(content, mSink->IsInScript());
DidAddContent(content, PR_FALSE);
// Special handling for certain tags
@ -1434,7 +1493,7 @@ SinkContext::DemoteContainer(const nsIParserNode& aNode)
// with later.
parent->ChildCount(parentCount);
if (mStack[stackPos-1].mNumFlushed == parentCount) {
FlushTags();
FlushTags(PR_TRUE);
sync = PR_TRUE;
}
// Otherwise just append the container to the parent without
@ -1601,13 +1660,13 @@ SinkContext::AddLeaf(nsIHTMLContent* aContent)
if (mStack[mStackPos-1].mInsertionPoint != -1) {
parent->InsertChildAt(aContent,
mStack[mStackPos-1].mInsertionPoint++,
mSink->IsInScript());
PR_FALSE);
}
else {
parent->AppendChildTo(aContent, mSink->IsInScript());
parent->AppendChildTo(aContent, PR_FALSE);
}
DidAddContent(aContent, mSink->IsInScript());
DidAddContent(aContent, PR_FALSE);
#ifdef DEBUG
if (mPreAppend &&
@ -1653,13 +1712,13 @@ SinkContext::AddComment(const nsIParserNode& aNode)
if (mStack[mStackPos-1].mInsertionPoint != -1) {
parent->InsertChildAt(comment,
mStack[mStackPos-1].mInsertionPoint++,
mSink->IsInScript());
PR_FALSE);
}
else {
parent->AppendChildTo(comment, mSink->IsInScript());
parent->AppendChildTo(comment, PR_FALSE);
}
DidAddContent(comment, mSink->IsInScript());
DidAddContent(comment, PR_FALSE);
#ifdef DEBUG
if (mPreAppend &&
@ -1764,7 +1823,7 @@ SinkContext::AddText(const nsString& aText)
* has been newly added so that the frame tree is complete.
*/
nsresult
SinkContext::FlushTags()
SinkContext::FlushTags(PRBool aNotify)
{
nsresult result = NS_OK;
@ -1796,47 +1855,49 @@ SinkContext::FlushTags()
stackPos--;
}
// Start from the base of the stack (growing upward) and do
// a notification from the node that is closest to the root of
// tree for any content that has been added.
stackPos = 1;
PRBool flushed = PR_FALSE;
while (stackPos < mStackPos) {
content = mStack[stackPos].mContent;
content->ChildCount(childCount);
if (aNotify) {
// Start from the base of the stack (growing upward) and do
// a notification from the node that is closest to the root of
// tree for any content that has been added.
stackPos = 1;
PRBool flushed = PR_FALSE;
while (stackPos < mStackPos) {
content = mStack[stackPos].mContent;
content->ChildCount(childCount);
if (!flushed && (mStack[stackPos].mNumFlushed < childCount)) {
if (!flushed && (mStack[stackPos].mNumFlushed < childCount)) {
#ifdef NS_DEBUG
// Tracing code
char cbuf[40];
const char* cp;
nsAutoString str;
nsCOMPtr<nsIDTD> dtd;
mSink->mParser->GetDTD(getter_AddRefs(dtd));
dtd->IntTagToStringTag(nsHTMLTag(mStack[stackPos].mType), str);
cp = str.ToCString(cbuf, sizeof(cbuf));
// Tracing code
char cbuf[40];
const char* cp;
nsAutoString str;
nsCOMPtr<nsIDTD> dtd;
mSink->mParser->GetDTD(getter_AddRefs(dtd));
dtd->IntTagToStringTag(nsHTMLTag(mStack[stackPos].mType), str);
cp = str.ToCString(cbuf, sizeof(cbuf));
SINK_TRACE(SINK_TRACE_REFLOW,
("SinkContext::FlushTags: tag=%s from newindex=%d at stackPos=%d",
cp, mStack[stackPos].mNumFlushed, stackPos));
SINK_TRACE(SINK_TRACE_REFLOW,
("SinkContext::FlushTags: tag=%s from newindex=%d at stackPos=%d",
cp, mStack[stackPos].mNumFlushed, stackPos));
#endif
if ((mStack[stackPos].mInsertionPoint != -1) &&
(mStackPos > (stackPos+1))) {
nsIContent* child = mStack[stackPos+1].mContent;
mSink->NotifyInsert(content,
child,
mStack[stackPos].mInsertionPoint);
if ((mStack[stackPos].mInsertionPoint != -1) &&
(mStackPos > (stackPos+1))) {
nsIContent* child = mStack[stackPos+1].mContent;
mSink->NotifyInsert(content,
child,
mStack[stackPos].mInsertionPoint);
}
else {
mSink->NotifyAppend(content, mStack[stackPos].mNumFlushed);
}
flushed = PR_TRUE;
}
else {
mSink->NotifyAppend(content, mStack[stackPos].mNumFlushed);
}
flushed = PR_TRUE;
}
mStack[stackPos].mNumFlushed = childCount;
stackPos++;
mStack[stackPos].mNumFlushed = childCount;
stackPos++;
}
mNotifyLevel = mStackPos-1;
}
mNotifyLevel = mStackPos-1;
return result;
}
@ -1907,10 +1968,10 @@ SinkContext::FlushText(PRBool* aDidFlush, PRBool aReleaseLast)
if (mStack[mStackPos-1].mInsertionPoint != -1) {
parent->InsertChildAt(content,
mStack[mStackPos-1].mInsertionPoint++,
mSink->IsInScript());
PR_FALSE);
}
else {
parent->AppendChildTo(content, mSink->IsInScript());
parent->AppendChildTo(content, PR_FALSE);
}
mLastTextNode = content;
@ -1918,7 +1979,7 @@ SinkContext::FlushText(PRBool* aDidFlush, PRBool aReleaseLast)
mTextLength = 0;
didFlush = PR_TRUE;
DidAddContent(content, mSink->IsInScript());
DidAddContent(content, PR_FALSE);
}
}
}
@ -1972,6 +2033,7 @@ HTMLContentSink::HTMLContentSink() {
mNotAtRef = PR_TRUE;
mContentIDCounter = NS_CONTENT_ID_COUNTER_BASE;
mInScript = 0;
mInNotification = 0;
mInsideNoXXXTag = 0;
}
@ -1982,7 +2044,10 @@ HTMLContentSink::~HTMLContentSink()
NS_IF_RELEASE(mFrameset);
NS_IF_RELEASE(mRoot);
NS_IF_RELEASE(mDocument);
if (mDocument) {
mDocument->RemoveObserver(this);
NS_RELEASE(mDocument);
}
NS_IF_RELEASE(mHTMLDocument);
NS_IF_RELEASE(mDocumentURI);
NS_IF_RELEASE(mDocumentBaseURL);
@ -2033,12 +2098,13 @@ HTMLContentSink::~HTMLContentSink()
}
}
NS_IMPL_ISUPPORTS5(HTMLContentSink,
NS_IMPL_ISUPPORTS6(HTMLContentSink,
nsIHTMLContentSink,
nsIContentSink,
nsIUnicharStreamLoaderObserver,
nsITimerCallback,
nsICSSLoaderObserver)
nsICSSLoaderObserver,
nsIDocumentObserver)
nsresult
HTMLContentSink::Init(nsIDocument* aDoc,
@ -2060,6 +2126,7 @@ HTMLContentSink::Init(nsIDocument* aDoc,
mDocument = aDoc;
NS_ADDREF(aDoc);
aDoc->AddObserver(this);
aDoc->QueryInterface(kIHTMLDocumentIID, (void**)&mHTMLDocument);
mDocumentURI = aURL;
NS_ADDREF(aURL);
@ -2187,7 +2254,7 @@ HTMLContentSink::DidBuildModel(PRInt32 aQualityLevel)
if (nsnull != mBody) {
SINK_TRACE(SINK_TRACE_REFLOW,
("HTMLContentSink::DidBuildModel: layout final content"));
mCurrentContext->FlushTags();
mCurrentContext->FlushTags(PR_TRUE);
}
ScrollToRef();
@ -2220,7 +2287,7 @@ HTMLContentSink::Notify(nsITimer *timer)
("HTMLContentSink::Notify: reflow on a timer: %d milliseconds late, backoff count: %d", delay, mBackoffCount));
#endif
if (mCurrentContext) {
mCurrentContext->FlushTags();
mCurrentContext->FlushTags(PR_TRUE);
}
mNotificationTimer = 0;
MOZ_TIMER_DEBUGLOG(("Stop: nsHTMLContentSink::Notify()\n"));
@ -2251,7 +2318,7 @@ HTMLContentSink::WillInterrupt()
mBackoffCount--;
SINK_TRACE(SINK_TRACE_REFLOW,
("HTMLContentSink::WillInterrupt: flushing tags since we've run out time; backoff count: %d", mBackoffCount));
result = mCurrentContext->FlushTags();
result = mCurrentContext->FlushTags(PR_TRUE);
}
else {
// If the time since the last notification is less than
@ -2289,7 +2356,7 @@ HTMLContentSink::WillInterrupt()
else {
SINK_TRACE(SINK_TRACE_REFLOW,
("HTMLContentSink::WillInterrupt: flushing tags unconditionally"));
result = mCurrentContext->FlushTags();
result = mCurrentContext->FlushTags(PR_TRUE);
}
return result;
@ -2343,7 +2410,7 @@ HTMLContentSink::BeginContext(PRInt32 aPosition)
}
// Flush everything in the current context so that we don't have
// to worry about insertions resulting in inconsistent frame creation.
mCurrentContext->FlushTags();
mCurrentContext->FlushTags(PR_TRUE);
PRInt32 insertionPoint = -1;
nsHTMLTag nodeType = mCurrentContext->mStack[aPosition].mType;
@ -2477,8 +2544,8 @@ HTMLContentSink::CloseHTML(const nsIParserNode& aNode)
if(mCurrentContext==mHeadContext) {
PRInt32 numContexts = mContextStack.Count();
// Pop off the second html context if it's not done earlier
mContextStack.RemoveElementAt(--numContexts);
mCurrentContext = nsnull;
mCurrentContext = (SinkContext*)mContextStack.ElementAt(--numContexts);
mContextStack.RemoveElementAt(numContexts);
}
mHeadContext->End();
delete mHeadContext;
@ -2596,7 +2663,7 @@ HTMLContentSink::CloseBody(const nsIParserNode& aNode)
// Flush out anything that's left
SINK_TRACE(SINK_TRACE_REFLOW,
("HTMLContentSink::CloseBody: layout final body content"));
mCurrentContext->FlushTags();
mCurrentContext->FlushTags(PR_TRUE);
mCurrentContext->CloseContainer(aNode);
MOZ_TIMER_DEBUGLOG(("Stop: nsHTMLContentSink::CloseBody()\n"));
@ -3770,7 +3837,7 @@ IsJavaScriptLanguage(const nsString& aName, const char* *aVersion)
void
HTMLContentSink::ForceReflow()
{
mCurrentContext->FlushTags();
mCurrentContext->FlushTags(PR_TRUE);
}
#endif
@ -3778,6 +3845,7 @@ HTMLContentSink::ForceReflow()
void
HTMLContentSink::NotifyAppend(nsIContent* aContainer, PRInt32 aStartIndex)
{
mInNotification++;
MOZ_TIMER_DEBUGLOG(("Save and stop: nsHTMLContentSink::NotifyAppend()\n"));
MOZ_TIMER_SAVE(mWatch)
MOZ_TIMER_STOP(mWatch);
@ -3785,6 +3853,7 @@ HTMLContentSink::NotifyAppend(nsIContent* aContainer, PRInt32 aStartIndex)
mLastNotificationTime = PR_Now();
MOZ_TIMER_DEBUGLOG(("Restore: nsHTMLContentSink::NotifyAppend()\n"));
MOZ_TIMER_RESTORE(mWatch);
mInNotification--;
}
void
@ -3792,6 +3861,7 @@ HTMLContentSink::NotifyInsert(nsIContent* aContent,
nsIContent* aChildContent,
PRInt32 aIndexInContainer)
{
mInNotification++;
MOZ_TIMER_DEBUGLOG(("Save and stop: nsHTMLContentSink::NotifyInsert()\n"));
MOZ_TIMER_SAVE(mWatch)
MOZ_TIMER_STOP(mWatch);
@ -3799,6 +3869,7 @@ HTMLContentSink::NotifyInsert(nsIContent* aContent,
mLastNotificationTime = PR_Now();
MOZ_TIMER_DEBUGLOG(("Restore: nsHTMLContentSink::NotifyInsert()\n"));
MOZ_TIMER_RESTORE(mWatch);
mInNotification--;
}
PRBool
@ -3835,6 +3906,37 @@ HTMLContentSink::UpdateAllContexts()
mCurrentContext->UpdateChildCounts();
}
NS_IMETHODIMP
HTMLContentSink::BeginUpdate(nsIDocument *aDocument)
{
nsresult result = NS_OK;
// If we're in a script and we didn't do the notification,
// something else in the script processing caused the
// notification to occur. Since this could result in frame
// creation, make sure we've flushed everything before we
// continue
if (mInScript && !mInNotification && mCurrentContext) {
result = mCurrentContext->FlushTags(PR_TRUE);
}
return result;
}
NS_IMETHODIMP
HTMLContentSink::EndUpdate(nsIDocument *aDocument)
{
// If we're in a script and we didn't do the notification,
// something else in the script processing caused the
// notification to occur. Update our notion of how much
// has been flushed to include any new content.
if (mInScript && !mInNotification) {
UpdateAllContexts();
}
return NS_OK;
}
nsresult
HTMLContentSink::ResumeParsing()
{
@ -3853,10 +3955,12 @@ HTMLContentSink::PreEvaluateScript()
// to the body (so that they can be seen by scripts) and force reflow.
SINK_TRACE(SINK_TRACE_CALLS,
("HTMLContentSink::PreEvaluateScript: flushing tags before evaluating script"));
mCurrentContext->FlushTags();
mCurrentContext->FlushTags(PR_FALSE);
mCurrentContext->SetPreAppend(PR_TRUE);
mInScript++;
return PR_TRUE;
}
@ -3864,8 +3968,7 @@ void
HTMLContentSink::PostEvaluateScript(PRBool aBodyPresent)
{
mInScript--;
mCurrentContext->UpdateChildCounts();
mCurrentContext->SetPreAppend(PR_FALSE);
}
PRBool
@ -4019,10 +4122,10 @@ HTMLContentSink::ProcessSCRIPTTag(const nsIParserNode& aNode)
if (mCurrentContext->mStack[mCurrentContext->mStackPos-1].mInsertionPoint != -1) {
parent->InsertChildAt(element,
mCurrentContext->mStack[mCurrentContext->mStackPos-1].mInsertionPoint++,
IsInScript());
PR_FALSE);
}
else {
parent->AppendChildTo(element, IsInScript());
parent->AppendChildTo(element, PR_FALSE);
}
}
else {
@ -4044,7 +4147,7 @@ HTMLContentSink::ProcessSCRIPTTag(const nsIParserNode& aNode)
tc->SetData(script);
NS_RELEASE(tc);
}
element->AppendChildTo(text, IsInScript());
element->AppendChildTo(text, PR_FALSE);
text->SetDocument(mDocument, PR_FALSE);
NS_RELEASE(text);
}
@ -4201,7 +4304,7 @@ HTMLContentSink::ProcessSTYLETag(const nsIParserNode& aNode)
tc->SetData(content);
NS_RELEASE(tc);
}
element->AppendChildTo(text, IsInScript());
element->AppendChildTo(text, PR_FALSE);
text->SetDocument(mDocument, PR_FALSE);
NS_RELEASE(text);
}
@ -4262,13 +4365,15 @@ HTMLContentSink::NotifyError(const nsParserError* aError)
NS_IMETHODIMP
HTMLContentSink::FlushPendingNotifications()
{
/* XXX This is temporarily commented out so that this change can be tested locally.
nsresult result = NS_OK;
if (mCurrentContext) {
// Only flush tags if we're not doing the notification ourselves
// (since we aren't reentrant) and if we're in a script (since
// we only care to flush if this is done via script).
if (mCurrentContext && !mInNotification && mInScript) {
result = mCurrentContext->FlushTags();
}
*/
return NS_OK;
return result;
}
NS_IMETHODIMP

Просмотреть файл

@ -1294,6 +1294,34 @@ nsXULDocument::RemoveObserver(nsIDocumentObserver* aObserver)
return mObservers.RemoveElement(aObserver);
}
NS_IMETHODIMP
nsXULDocument::BeginUpdate()
{
// XXX Never called. Does this matter?
for (PRInt32 i = 0; i < mObservers.Count(); i++) {
nsIDocumentObserver* observer = (nsIDocumentObserver*) mObservers[i];
observer->BeginUpdate(this);
if (observer != (nsIDocumentObserver*)mObservers.ElementAt(i)) {
i--;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsXULDocument::EndUpdate()
{
// XXX Never called. Does this matter?
for (PRInt32 i = 0; i < mObservers.Count(); i++) {
nsIDocumentObserver* observer = (nsIDocumentObserver*) mObservers[i];
observer->EndUpdate(this);
if (observer != (nsIDocumentObserver*)mObservers.ElementAt(i)) {
i--;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsXULDocument::BeginLoad()
{

Просмотреть файл

@ -191,6 +191,10 @@ public:
virtual PRBool RemoveObserver(nsIDocumentObserver* aObserver);
NS_IMETHOD BeginUpdate();
NS_IMETHOD EndUpdate();
NS_IMETHOD BeginLoad();
NS_IMETHOD EndLoad();