From 6f25a6cffd5d3fb167ff61ce889b38d50980eb25 Mon Sep 17 00:00:00 2001 From: "Olli.Pettay%helsinki.fi" Date: Tue, 22 May 2007 21:45:07 +0000 Subject: [PATCH] Bug 378776, Need safe way to iterate a document's presshells, r+sr=bz --- camino/src/embedding/CHClickListener.mm | 265 ------------------ chrome/src/nsChromeRegistry.cpp | 8 +- content/base/public/Makefile.in | 1 + content/base/public/nsIDocument.h | 15 +- content/base/public/nsPresShellIterator.h | 68 +++++ content/base/src/nsContentSink.cpp | 115 ++++---- content/base/src/nsDocument.cpp | 109 +++---- content/base/src/nsDocument.h | 8 +- content/base/src/nsObjectLoadingContent.cpp | 13 +- content/events/src/nsEventStateManager.cpp | 7 +- content/html/document/src/nsHTMLDocument.cpp | 2 +- content/html/document/src/nsMediaDocument.cpp | 9 +- .../xml/document/src/nsXMLPrettyPrinter.cpp | 2 +- content/xul/content/src/nsXULElement.cpp | 33 +-- .../document/src/nsXULCommandDispatcher.cpp | 7 +- content/xul/document/src/nsXULDocument.cpp | 13 +- dom/src/base/nsFocusController.cpp | 6 +- .../typeaheadfind/src/nsTypeAheadFind.cpp | 7 +- layout/svg/base/src/nsSVGOuterSVGFrame.cpp | 8 +- rdf/chrome/src/nsChromeRegistry.cpp | 8 +- 20 files changed, 237 insertions(+), 467 deletions(-) create mode 100644 content/base/public/nsPresShellIterator.h diff --git a/camino/src/embedding/CHClickListener.mm b/camino/src/embedding/CHClickListener.mm index 349f6174202..e69de29bb2d 100644 --- a/camino/src/embedding/CHClickListener.mm +++ b/camino/src/embedding/CHClickListener.mm @@ -1,265 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 2002 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * David Hyatt (Original Author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#import "NSString+Utils.h" -#import "NSArray+Utils.h" -#import "CHBrowserView.h" - -#include "nsCOMPtr.h" -#include "nsString.h" -#include "CHClickListener.h" -#include "nsIDOMEventTarget.h" -#include "nsIContent.h" -#include "nsIDOMElement.h" -#include "nsIDOMMouseEvent.h" -#include "nsEmbedAPI.h" -#include "nsIDOMDocument.h" -#include "nsIDOMDocumentEvent.h" -#include "nsIDOMEventTarget.h" -#include "nsIDOMHTMLSelectElement.h" -#include "nsIDOMHTMLOptionElement.h" -#include "nsIDOMHTMLOptionsCollection.h" -#include "nsIDOMHTMLOptGroupElement.h" -#include "nsIDOMWindow.h" -#include "nsIDocument.h" -#include "nsIPresShell.h" -#include "nsIFrame.h" - - -@interface CHOptionSelector : NSObject -{ - nsIDOMHTMLSelectElement* mSelectElt; -} - --(id)initWithSelect:(nsIDOMHTMLSelectElement*)aSel; --(IBAction)selectOption:(id)aSender; - -@end - -@implementation CHOptionSelector - --(id)initWithSelect:(nsIDOMHTMLSelectElement*)aSel -{ - if ( (self = [super init]) ) { - mSelectElt = aSel; - } - return self; -} - --(IBAction)selectOption:(id)aSender -{ - nsIDOMHTMLOptionElement* optionElt = (nsIDOMHTMLOptionElement*)[[aSender representedObject] pointerValue]; - NS_ASSERTION(optionElt, "Missing option element"); - if (!optionElt) return; - - optionElt->SetSelected(PR_TRUE); - - // Fire a DOM event for the title change. - nsCOMPtr event; - nsCOMPtr domDocument; - mSelectElt->GetOwnerDocument(getter_AddRefs(domDocument)); - nsCOMPtr docEvent(do_QueryInterface(domDocument)); - - docEvent->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event)); - if (event) { - event->InitEvent(NS_LITERAL_STRING("change"), PR_TRUE, PR_TRUE); - PRBool noDefault; - nsCOMPtr target(do_QueryInterface(mSelectElt)); - target->DispatchEvent(event, &noDefault); - } -} - -@end - -NS_IMPL_ISUPPORTS2(CHClickListener, nsIDOMMouseListener, nsIDOMEventListener) - -CHClickListener::CHClickListener() -{ -} - -CHClickListener::~CHClickListener() -{ -} - -NS_IMETHODIMP -CHClickListener::MouseDown(nsIDOMEvent* aEvent) -{ - nsCOMPtr mouseEvent(do_QueryInterface(aEvent)); - if (!mouseEvent) return NS_ERROR_FAILURE; - - PRUint16 button; - mouseEvent->GetButton(&button); - // only show popup on left button - if (button != 0) - return NS_OK; - - nsCOMPtr target; - mouseEvent->GetTarget(getter_AddRefs(target)); - if (!target) - return NS_OK; - - nsCOMPtr sel(do_QueryInterface(target)); - if (!sel) - return NS_OK; - - PRInt32 size = 0; - sel->GetSize(&size); - PRBool multiple = PR_FALSE; - sel->GetMultiple(&multiple); - if(size > 1 || multiple) - return NS_OK; - - // the call to popUpContextMenu: is synchronous so we don't need to - // worry about retaining the menu for later. - NSMenu* menu = [[[NSMenu alloc] init] autorelease]; - - // We'll set the disabled state as the options are created, so disable - // auto-enabling via NSMenuValidation. - [menu setAutoenablesItems: NO]; - - nsCOMPtr options; - sel->GetOptions(getter_AddRefs(options)); - PRUint32 count; - options->GetLength(&count); - PRInt32 selIndex = 0; // currently unused - - nsCOMPtr curOptGroup; - - for (PRUint32 i = 0; i < count; i++) { - nsAutoString itemLabel; - - nsCOMPtr node; - options->Item(i, getter_AddRefs(node)); - - nsCOMPtr option(do_QueryInterface(node)); - - nsCOMPtr parentNode; - option->GetParentNode(getter_AddRefs(parentNode)); - nsCOMPtr parentOptGroup = do_QueryInterface(parentNode); - if (parentOptGroup && (parentOptGroup != curOptGroup)) - { - // insert optgroup item - parentOptGroup->GetLabel(itemLabel); - NSString* title = [[NSString stringWith_nsAString: itemLabel] stringByTruncatingTo:75 at:kTruncateAtMiddle]; - NSMenuItem* menuItem = [[[NSMenuItem alloc] initWithTitle: title action: NULL keyEquivalent: @""] autorelease]; - [menu addItem: menuItem]; - [menuItem setEnabled: NO]; - - curOptGroup = parentOptGroup; - } - - option->GetLabel(itemLabel); - if (itemLabel.IsEmpty()) - option->GetText(itemLabel); - - NSString* title = [[NSString stringWith_nsAString: itemLabel] stringByTruncatingTo:75 at:kTruncateAtMiddle]; - - // indent items in optgroup - if (parentOptGroup) - title = [@" " stringByAppendingString:title]; - - NSMenuItem* menuItem = [[[NSMenuItem alloc] initWithTitle: title action: NULL keyEquivalent: @""] autorelease]; - [menu addItem: menuItem]; - [menuItem setRepresentedObject:[NSValue valueWithPointer:option.get()]]; - - PRBool selected; - option->GetSelected(&selected); - if (selected) { - [menuItem setState: NSOnState]; - selIndex = i; - } - PRBool disabled; - option->GetDisabled(&disabled); - if (disabled) - [menuItem setEnabled: NO]; - CHOptionSelector* optSelector = [[[CHOptionSelector alloc] initWithSelect: sel] autorelease]; - [menuItem setTarget: optSelector]; // retains - if (!selected) - [menuItem setAction:@selector(selectOption:)]; - } - - nsCOMPtr selContent = do_QueryInterface(sel); - nsCOMPtr doc = selContent->GetDocument(); - - NSEvent* event = [NSApp currentEvent]; - NSWindow* hostWindow = [event window]; - - // get the frame location - nsIPresShell* presShell = doc->GetShellAt(0); - if (!presShell) - return NS_ERROR_FAILURE; - - nsIFrame* selectFrame = presShell->GetPrimaryFrameFor(selContent); - if (!selectFrame) - return NS_ERROR_FAILURE; - - nsIntRect selectRect = selectFrame->GetScreenRectExternal(); - NSRect selectScreenRect = NSMakeRect(selectRect.x, selectRect.y, selectRect.width, selectRect.height); - - NSScreen* mainScreen = [[NSScreen screens] firstObject]; // NSArray category method - if (!mainScreen) - return NS_ERROR_FAILURE; - - // y-flip and subtract the control height to convert to cocoa coords - NSRect mainScreenFrame = [mainScreen frame]; - selectScreenRect.origin.y = NSMaxY(mainScreenFrame) - selectScreenRect.origin.y - selectScreenRect.size.height; - - // convert to window coords - NSRect selectFrameRect = selectScreenRect; - selectFrameRect.origin = [hostWindow convertScreenToBase:selectFrameRect.origin]; - - // we're gonna make a little view to display things with, so that the popup isn't - // shown at the top of the window when it's near the bottom of the screen. - NSView* hostView = [[NSView alloc] initWithFrame:selectFrameRect]; - [[hostWindow contentView] addSubview:hostView]; // takes ownership - [hostView release]; - - const float kMenuWidth = 20.0; // specify something small so it sizes to fit - const float kMenuPopupHeight = 20.0; // height of a popup in aqua - - NSRect bounds = NSMakeRect(0, 0, kMenuWidth, kMenuPopupHeight); - - NSPopUpButtonCell* popupCell = [[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]; - [popupCell setMenu: menu]; - [popupCell setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]]; - [popupCell trackMouse:event inRect:bounds ofView:hostView untilMouseUp:YES]; - [popupCell release]; - - [hostView removeFromSuperview]; // this releases it - return NS_OK; -} diff --git a/chrome/src/nsChromeRegistry.cpp b/chrome/src/nsChromeRegistry.cpp index 577d59de7e6..b75d488d7c3 100644 --- a/chrome/src/nsChromeRegistry.cpp +++ b/chrome/src/nsChromeRegistry.cpp @@ -100,6 +100,7 @@ #include "nsIXPConnect.h" #include "nsIXULAppInfo.h" #include "nsIXULRuntime.h" +#include "nsPresShellIterator.h" #ifdef MOZ_XUL // keep all the RDF stuff together, in case we can remove it in the far future @@ -923,10 +924,9 @@ nsresult nsChromeRegistry::RefreshWindow(nsIDOMWindowInternal* aWindow, return NS_OK; // Deal with the agent sheets first. Have to do all the style sets by hand. - PRUint32 shellCount = document->GetNumberOfShells(); - for (PRUint32 k = 0; k < shellCount; k++) { - nsIPresShell *shell = document->GetShellAt(k); - + nsPresShellIterator iter(document); + nsCOMPtr shell; + while ((shell = iter.GetNextShell())) { // Reload only the chrome URL agent style sheets. nsCOMArray agentSheets; rv = shell->GetAgentStyleSheets(agentSheets); diff --git a/content/base/public/Makefile.in b/content/base/public/Makefile.in index 6c1b98ae21a..5a69029dd5c 100644 --- a/content/base/public/Makefile.in +++ b/content/base/public/Makefile.in @@ -74,6 +74,7 @@ nsCopySupport.h \ nsContentCreatorFunctions.h \ nsLineBreaker.h \ nsXMLNameSpaceMap.h \ +nsPresShellIterator.h \ $(NULL) ifndef DISABLE_XFORMS_HOOKS diff --git a/content/base/public/nsIDocument.h b/content/base/public/nsIDocument.h index 2edbf495dd2..c1337b0c4a7 100644 --- a/content/base/public/nsIDocument.h +++ b/content/base/public/nsIDocument.h @@ -49,6 +49,7 @@ #include "mozFlushType.h" #include "nsIAtom.h" #include "nsCompatibility.h" +#include "nsTObserverArray.h" class nsIContent; class nsPresContext; @@ -94,8 +95,8 @@ class mozAutoSubtreeModified; // IID for the nsIDocument interface #define NS_IDOCUMENT_IID \ -{ 0xb7f930df, 0x1c61, 0x410f, \ - { 0xab, 0x3c, 0xe2, 0x53, 0xca, 0x8d, 0x85, 0x49 } } +{ 0x7dd5790f, 0x110d, 0x4bf6, \ + { 0x83, 0x50, 0x4b, 0xe3, 0x5d, 0xdc, 0xe1, 0x1e } } // Flag for AddStyleSheet(). #define NS_STYLESHEET_FROM_CATALOG (1 << 0) @@ -349,10 +350,9 @@ public: nsStyleSet* aStyleSet, nsIPresShell** aInstancePtrResult) = 0; virtual PRBool DeleteShell(nsIPresShell* aShell) = 0; - virtual PRUint32 GetNumberOfShells() const = 0; - virtual nsIPresShell *GetShellAt(PRUint32 aIndex) const = 0; virtual nsIPresShell *GetPrimaryShell() const = 0; - virtual void SetShellsHidden(PRBool aHide) = 0; + void SetShellsHidden(PRBool aHide) { mShellsAreHidden = aHide; } + PRBool ShellsAreHidden() const { return mShellsAreHidden; } /** * Return the parent document of this document. Will return null @@ -891,6 +891,7 @@ protected: virtual void WillDispatchMutationEvent(nsINode* aTarget) = 0; virtual void MutationEventDispatched(nsINode* aTarget) = 0; friend class mozAutoSubtreeModified; + friend class nsPresShellIterator; nsString mDocumentTitle; nsCOMPtr mDocumentURI; @@ -932,6 +933,8 @@ protected: // document in it. PRPackedBool mIsInitialDocumentInWindow; + PRPackedBool mShellsAreHidden; + // The bidi options for this document. What this bitfield means is // defined in nsBidiUtils.h PRUint32 mBidiOptions; @@ -949,6 +952,8 @@ protected: // Cycle collector generation in which we're certain that this document // won't be collected PRUint32 mMarkedCCGeneration; + + nsTObserverArray mPresShells; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID) diff --git a/content/base/public/nsPresShellIterator.h b/content/base/public/nsPresShellIterator.h new file mode 100644 index 00000000000..00822b9ca4e --- /dev/null +++ b/content/base/public/nsPresShellIterator.h @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Olli Pettay (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsPresShellIterato_h___ +#define nsPresShellIterato_h___ + +#include "nsIPresShell.h" +#include "nsIDocument.h" + +class nsPresShellIterator : + private nsTObserverArray::ForwardIterator +{ +public: + nsPresShellIterator(nsIDocument* aDoc) + : nsTObserverArray::ForwardIterator(aDoc->mPresShells), + mDoc(aDoc) {} + + already_AddRefed GetNextShell() + { + nsIPresShell* shell = nsnull; + if (!mDoc->ShellsAreHidden()) { + shell = GetNext(); + NS_IF_ADDREF(shell); + } + return shell; + } +private: + static void* operator new(size_t) CPP_THROW_NEW { return 0; } + static void operator delete(void*, size_t) {} + + nsCOMPtr mDoc; +}; + +#endif diff --git a/content/base/src/nsContentSink.cpp b/content/base/src/nsContentSink.cpp index 025d9b33877..d55d803ff47 100644 --- a/content/base/src/nsContentSink.cpp +++ b/content/base/src/nsContentSink.cpp @@ -91,6 +91,7 @@ #include "nsNodeUtils.h" #include "nsIDOMNode.h" #include "nsThreadUtils.h" +#include "nsPresShellIterator.h" PRLogModuleInfo* gContentSinkLogModuleInfo; @@ -949,32 +950,30 @@ nsContentSink::ScrollToRef() // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1 NS_ConvertUTF8toUTF16 ref(unescapedRef); - PRInt32 i, ns = mDocument->GetNumberOfShells(); - for (i = 0; i < ns; i++) { - nsIPresShell* shell = mDocument->GetShellAt(i); - if (shell) { - // Check an empty string which might be caused by the UTF-8 conversion - if (!ref.IsEmpty()) { - // Note that GoToAnchor will handle flushing layout as needed. + nsPresShellIterator iter(mDocument); + nsCOMPtr shell; + while ((shell = iter.GetNextShell())) { + // Check an empty string which might be caused by the UTF-8 conversion + if (!ref.IsEmpty()) { + // Note that GoToAnchor will handle flushing layout as needed. + rv = shell->GoToAnchor(ref, mChangeScrollPosWhenScrollingToRef); + } else { + rv = NS_ERROR_FAILURE; + } + + // If UTF-8 URI failed then try to assume the string as a + // document's charset. + + if (NS_FAILED(rv)) { + const nsACString &docCharset = mDocument->GetDocumentCharacterSet(); + + rv = nsContentUtils::ConvertStringFromCharset(docCharset, unescapedRef, ref); + + if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) rv = shell->GoToAnchor(ref, mChangeScrollPosWhenScrollingToRef); - } else { - rv = NS_ERROR_FAILURE; - } - - // If UTF-8 URI failed then try to assume the string as a - // document's charset. - - if (NS_FAILED(rv)) { - const nsACString &docCharset = mDocument->GetDocumentCharacterSet(); - - rv = nsContentUtils::ConvertStringFromCharset(docCharset, unescapedRef, ref); - - if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) - rv = shell->GoToAnchor(ref, mChangeScrollPosWhenScrollingToRef); - } - if (NS_SUCCEEDED(rv)) { - mScrolledToRefAlready = PR_TRUE; - } + } + if (NS_SUCCEEDED(rv)) { + mScrolledToRefAlready = PR_TRUE; } } } @@ -1029,46 +1028,40 @@ nsContentSink::StartLayout(PRBool aIgnorePendingSheets) mLayoutStarted = PR_TRUE; mLastNotificationTime = PR_Now(); - - PRUint32 i; - // XXXbz Shells can get removed (or added!) as we iterate through this loop. - // We should try to use an nsTObserverArray for this. - for (i = 0; i < mDocument->GetNumberOfShells(); i++) { - nsIPresShell *shell = mDocument->GetShellAt(i); + nsPresShellIterator iter(mDocument); + nsCOMPtr shell; + while ((shell = iter.GetNextShell())) { + // Make sure we don't call InitialReflow() for a shell that has + // already called it. This can happen when the layout frame for + // an iframe is constructed *between* the Embed() call for the + // docshell in the iframe, and the content sink's call to OpenBody(). + // (Bug 153815) - if (shell) { - // Make sure we don't call InitialReflow() for a shell that has - // already called it. This can happen when the layout frame for - // an iframe is constructed *between* the Embed() call for the - // docshell in the iframe, and the content sink's call to OpenBody(). - // (Bug 153815) + PRBool didInitialReflow = PR_FALSE; + shell->GetDidInitialReflow(&didInitialReflow); + if (didInitialReflow) { + // XXX: The assumption here is that if something already + // called InitialReflow() on this shell, it also did some of + // the setup below, so we do nothing and just move on to the + // next shell in the list. - PRBool didInitialReflow = PR_FALSE; - shell->GetDidInitialReflow(&didInitialReflow); - if (didInitialReflow) { - // XXX: The assumption here is that if something already - // called InitialReflow() on this shell, it also did some of - // the setup below, so we do nothing and just move on to the - // next shell in the list. - - continue; - } - - // Make shell an observer for next time - shell->BeginObservingDocument(); - - // Resize-reflow this time - nsRect r = shell->GetPresContext()->GetVisibleArea(); - nsCOMPtr shellGrip = shell; - nsresult rv = shell->InitialReflow(r.width, r.height); - if (NS_FAILED(rv)) { - return; - } - - // Now trigger a refresh - RefreshIfEnabled(shell->GetViewManager()); + continue; } + + // Make shell an observer for next time + shell->BeginObservingDocument(); + + // Resize-reflow this time + nsRect r = shell->GetPresContext()->GetVisibleArea(); + nsCOMPtr shellGrip = shell; + nsresult rv = shell->InitialReflow(r.width, r.height); + if (NS_FAILED(rv)) { + return; + } + + // Now trigger a refresh + RefreshIfEnabled(shell->GetViewManager()); } // If the document we are loading has a reference or it is a diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 7559bd8cd5c..af15c288266 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -1294,9 +1294,10 @@ nsDocument::ResetStylesheetsToURI(nsIURI* aURI) PRBool applicable; sheet->GetApplicable(applicable); if (applicable) { - for (PRInt32 i = 0, i_end = GetNumberOfShells(); i < i_end; ++i) { - GetShellAt(i)->StyleSet()-> - RemoveStyleSheet(nsStyleSet::eAgentSheet, sheet); + nsPresShellIterator iter(this); + nsCOMPtr shell; + while ((shell = iter.GetNextShell())) { + shell->StyleSet()->RemoveStyleSheet(nsStyleSet::eAgentSheet, sheet); } } @@ -1315,10 +1316,10 @@ nsDocument::ResetStylesheetsToURI(nsIURI* aURI) nsStyleSet::sheetType attrSheetType = GetAttrSheetType(); if (mAttrStyleSheet) { // Remove this sheet from all style sets - PRInt32 count = GetNumberOfShells(); - for (indx = 0; indx < count; ++indx) { - GetShellAt(indx)->StyleSet()-> - RemoveStyleSheet(attrSheetType, mAttrStyleSheet); + nsPresShellIterator iter(this); + nsCOMPtr shell; + while ((shell = iter.GetNextShell())) { + shell->StyleSet()->RemoveStyleSheet(attrSheetType, mAttrStyleSheet); } rv = mAttrStyleSheet->Reset(aURI); } else { @@ -1332,9 +1333,10 @@ nsDocument::ResetStylesheetsToURI(nsIURI* aURI) if (mStyleAttrStyleSheet) { // Remove this sheet from all style sets - PRInt32 count = GetNumberOfShells(); - for (indx = 0; indx < count; ++indx) { - GetShellAt(indx)->StyleSet()-> + nsPresShellIterator iter(this); + nsCOMPtr shell; + while ((shell = iter.GetNextShell())) { + shell->StyleSet()-> RemoveStyleSheet(nsStyleSet::eStyleAttrSheet, mStyleAttrStyleSheet); } rv = mStyleAttrStyleSheet->Reset(aURI); @@ -1349,9 +1351,10 @@ nsDocument::ResetStylesheetsToURI(nsIURI* aURI) mStyleAttrStyleSheet->SetOwningDocument(this); // Now set up our style sets - PRInt32 count = GetNumberOfShells(); - for (indx = 0; indx < count; ++indx) { - FillStyleSet(GetShellAt(indx)->StyleSet()); + nsPresShellIterator iter(this); + nsCOMPtr shell; + while ((shell = iter.GetNextShell())) { + FillStyleSet(shell->StyleSet()); } return rv; @@ -1950,7 +1953,7 @@ nsDocument::doCreateShell(nsPresContext* aContext, NS_ENSURE_SUCCESS(rv, rv); // Note: we don't hold a ref to the shell (it holds a ref to us) - mPresShells.AppendElement(shell); + NS_ENSURE_TRUE(mPresShells.AppendObserver(shell), NS_ERROR_OUT_OF_MEMORY); shell.swap(*aInstancePtrResult); return NS_OK; @@ -1959,33 +1962,14 @@ nsDocument::doCreateShell(nsPresContext* aContext, PRBool nsDocument::DeleteShell(nsIPresShell* aShell) { - return mPresShells.RemoveElement(aShell); + return mPresShells.RemoveObserver(aShell); } -PRUint32 -nsDocument::GetNumberOfShells() const -{ - return mShellsAreHidden ? 0 : mPresShells.Count(); -} - -nsIPresShell * -nsDocument::GetShellAt(PRUint32 aIndex) const -{ - return mShellsAreHidden ? nsnull : - NS_STATIC_CAST(nsIPresShell*, mPresShells.SafeElementAt(aIndex)); -} nsIPresShell * nsDocument::GetPrimaryShell() const { - return mShellsAreHidden ? nsnull : - NS_STATIC_CAST(nsIPresShell*, mPresShells.SafeElementAt(0)); -} - -void -nsDocument::SetShellsHidden(PRBool aHide) -{ - mShellsAreHidden = aHide; + return mShellsAreHidden ? nsnull : mPresShells.SafeObserverAt(0); } PR_STATIC_CALLBACK(void) @@ -2279,10 +2263,10 @@ nsDocument::GetIndexOfStyleSheet(nsIStyleSheet* aSheet) const void nsDocument::AddStyleSheetToStyleSets(nsIStyleSheet* aSheet) { - PRInt32 count = GetNumberOfShells(); - PRInt32 indx; - for (indx = 0; indx < count; ++indx) { - GetShellAt(indx)->StyleSet()->AddDocStyleSheet(aSheet, this); + nsPresShellIterator iter(this); + nsCOMPtr shell; + while ((shell = iter.GetNextShell())) { + shell->StyleSet()->AddDocStyleSheet(aSheet, this); } } @@ -2306,9 +2290,11 @@ nsDocument::AddStyleSheet(nsIStyleSheet* aSheet) void nsDocument::RemoveStyleSheetFromStyleSets(nsIStyleSheet* aSheet) { - for (PRInt32 i = 0, i_end = GetNumberOfShells(); i < i_end; ++i) - GetShellAt(i)->StyleSet()-> - RemoveStyleSheet(nsStyleSet::eDocSheet, aSheet); + nsPresShellIterator iter(this); + nsCOMPtr shell; + while ((shell = iter.GetNextShell())) { + shell->StyleSet()->RemoveStyleSheet(nsStyleSet::eDocSheet, aSheet); + } } void @@ -2443,9 +2429,11 @@ nsDocument::AddCatalogStyleSheet(nsIStyleSheet* aSheet) if (applicable) { // This is like |AddStyleSheetToStyleSets|, but for an agent sheet. - for (PRInt32 i = 0, i_end = GetNumberOfShells(); i < i_end; ++i) - GetShellAt(i)->StyleSet()-> - AppendStyleSheet(nsStyleSet::eAgentSheet, aSheet); + nsPresShellIterator iter(this); + nsCOMPtr shell; + while ((shell = iter.GetNextShell())) { + shell->StyleSet()->AppendStyleSheet(nsStyleSet::eAgentSheet, aSheet); + } } NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded, (this, aSheet, PR_FALSE)); @@ -3633,9 +3621,9 @@ nsDocument::GetTitle(nsAString& aTitle) NS_IMETHODIMP nsDocument::SetTitle(const nsAString& aTitle) { - for (PRInt32 i = GetNumberOfShells() - 1; i >= 0; --i) { - nsCOMPtr shell = GetShellAt(i); - + nsPresShellIterator iter(this); + nsCOMPtr shell; + while ((shell = iter.GetNextShell())) { nsCOMPtr container = shell->GetPresContext()->GetContainer(); if (!container) continue; @@ -4805,14 +4793,10 @@ nsDocument::FlushPendingNotifications(mozFlushType aType) } } - PRInt32 i, count = GetNumberOfShells(); - - for (i = 0; i < count; i++) { - nsCOMPtr shell = GetShellAt(i); - - if (shell) { - shell->FlushPendingNotifications(aType); - } + nsPresShellIterator iter(this); + nsCOMPtr shell; + while ((shell = iter.GetNextShell())) { + shell->FlushPendingNotifications(aType); } } @@ -5261,14 +5245,11 @@ PRBool nsDocument::IsSafeToFlush() const { PRBool isSafeToFlush = PR_TRUE; - PRInt32 i = 0, n = GetNumberOfShells(); - while (i < n && isSafeToFlush) { - nsIPresShell* shell = GetShellAt(i); - - if (shell) { - shell->IsSafeToFlush(isSafeToFlush); - } - ++i; + nsPresShellIterator iter(NS_CONST_CAST(nsIDocument*, + NS_STATIC_CAST(const nsIDocument*, this))); + nsCOMPtr shell; + while ((shell = iter.GetNextShell()) && isSafeToFlush) { + shell->IsSafeToFlush(isSafeToFlush); } return isSafeToFlush; } diff --git a/content/base/src/nsDocument.h b/content/base/src/nsDocument.h index 5ef564c4e6c..170b0cf88e9 100644 --- a/content/base/src/nsDocument.h +++ b/content/base/src/nsDocument.h @@ -101,6 +101,7 @@ #include "pldhash.h" #include "nsAttrAndChildArray.h" #include "nsDOMAttributeMap.h" +#include "nsPresShellIterator.h" #define XML_DECLARATION_BITS_DECLARATION_EXISTS (1 << 0) #define XML_DECLARATION_BITS_ENCODING_EXISTS (1 << 1) @@ -374,10 +375,7 @@ public: nsStyleSet* aStyleSet, nsIPresShell** aInstancePtrResult); virtual PRBool DeleteShell(nsIPresShell* aShell); - virtual PRUint32 GetNumberOfShells() const; - virtual nsIPresShell *GetShellAt(PRUint32 aIndex) const; virtual nsIPresShell *GetPrimaryShell() const; - virtual void SetShellsHidden(PRBool aHide); virtual nsresult SetSubDocumentFor(nsIContent *aContent, nsIDocument* aSubDoc); @@ -765,8 +763,6 @@ protected: // True if the document "page" is not hidden PRPackedBool mVisible:1; - PRPackedBool mShellsAreHidden:1; - PRUint8 mXMLDeclarationBits; PRUint8 mDefaultElementType; @@ -807,8 +803,6 @@ private: nsDocument(const nsDocument& aOther); nsDocument& operator=(const nsDocument& aOther); - nsSmallVoidArray mPresShells; - nsCOMPtr mXPathEvaluatorTearoff; // The layout history state that should be used by nodes in this diff --git a/content/base/src/nsObjectLoadingContent.cpp b/content/base/src/nsObjectLoadingContent.cpp index 07ddb04773d..4ea6d901a20 100644 --- a/content/base/src/nsObjectLoadingContent.cpp +++ b/content/base/src/nsObjectLoadingContent.cpp @@ -74,6 +74,7 @@ #include "nsGkAtoms.h" #include "nsThreadUtils.h" #include "nsNetUtil.h" +#include "nsPresShellIterator.h" // Concrete classes #include "nsFrameLoader.h" @@ -543,9 +544,9 @@ nsObjectLoadingContent::EnsureInstantiation(nsIPluginInstance** aInstance) return NS_OK; } - PRUint32 numShells = doc->GetNumberOfShells(); - for (PRUint32 i = 0; i < numShells; ++i) { - nsIPresShell* shell = doc->GetShellAt(i); + nsPresShellIterator iter(doc); + nsCOMPtr shell; + while ((shell = iter.GetNextShell())) { shell->RecreateFramesFor(thisContent); } @@ -1175,9 +1176,9 @@ nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType, // If our state changed, then we already recreated frames // Otherwise, need to do that here - PRUint32 numShells = doc->GetNumberOfShells(); - for (PRUint32 i = 0; i < numShells; ++i) { - nsIPresShell* shell = doc->GetShellAt(i); + nsPresShellIterator iter(doc); + nsCOMPtr shell; + while ((shell = iter.GetNextShell())) { shell->RecreateFramesFor(thisContent); } } diff --git a/content/events/src/nsEventStateManager.cpp b/content/events/src/nsEventStateManager.cpp index f49ded77bce..87ad888f045 100644 --- a/content/events/src/nsEventStateManager.cpp +++ b/content/events/src/nsEventStateManager.cpp @@ -131,6 +131,7 @@ #include "nsIProperties.h" #include "nsISupportsPrimitives.h" #include "nsEventDispatcher.h" +#include "nsPresShellIterator.h" #ifdef XP_MACOSX #include @@ -1987,9 +1988,9 @@ nsEventStateManager::GetParentScrollingView(nsInputEvent *aEvent, } nsIPresShell *pPresShell = nsnull; - for (PRUint32 i = 0; i < parentDoc->GetNumberOfShells(); i++) { - nsIPresShell *tmpPresShell = parentDoc->GetShellAt(i); - NS_ENSURE_TRUE(tmpPresShell, NS_ERROR_FAILURE); + nsPresShellIterator iter(parentDoc); + nsCOMPtr tmpPresShell; + while ((tmpPresShell = iter.GetNextShell())) { NS_ENSURE_TRUE(tmpPresShell->GetPresContext(), NS_ERROR_FAILURE); if (tmpPresShell->GetPresContext()->Type() == aPresContext->Type()) { pPresShell = tmpPresShell; diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp index 44128204db8..346154eca20 100644 --- a/content/html/document/src/nsHTMLDocument.cpp +++ b/content/html/document/src/nsHTMLDocument.cpp @@ -2352,7 +2352,7 @@ nsHTMLDocument::Close() // it be for now, though. In any case, there's no reason to do // this if we have no presshell, since in that case none of the // above about reusing frames applies. - if (GetNumberOfShells() != 0) { + if (GetPrimaryShell()) { FlushPendingNotifications(Flush_Layout); } diff --git a/content/html/document/src/nsMediaDocument.cpp b/content/html/document/src/nsMediaDocument.cpp index b887a26e5ce..77b8a7914c7 100644 --- a/content/html/document/src/nsMediaDocument.cpp +++ b/content/html/document/src/nsMediaDocument.cpp @@ -266,12 +266,9 @@ nsMediaDocument::CreateSyntheticDocument() nsresult nsMediaDocument::StartLayout() { - PRUint32 numberOfShells = GetNumberOfShells(); - // XXXbz Shells can get removed (or added!) as we iterate through this loop. - // We should try to use an nsTObserverArray for this. - for (PRUint32 i = 0; i < numberOfShells; i++) { - nsIPresShell *shell = GetShellAt(i); - + nsPresShellIterator iter(this); + nsCOMPtr shell; + while ((shell = iter.GetNextShell())) { // Make shell an observer for next time. shell->BeginObservingDocument(); diff --git a/content/xml/document/src/nsXMLPrettyPrinter.cpp b/content/xml/document/src/nsXMLPrettyPrinter.cpp index 88e784dfbfb..dc18f60c69e 100644 --- a/content/xml/document/src/nsXMLPrettyPrinter.cpp +++ b/content/xml/document/src/nsXMLPrettyPrinter.cpp @@ -74,7 +74,7 @@ nsresult nsXMLPrettyPrinter::PrettyPrint(nsIDocument* aDocument) { // Check for iframe with display:none. Such iframes don't have presshells - if (!aDocument->GetNumberOfShells()) { + if (!aDocument->GetPrimaryShell()) { return NS_OK; } diff --git a/content/xul/content/src/nsXULElement.cpp b/content/xul/content/src/nsXULElement.cpp index faa1f493e90..1f6d476eb38 100644 --- a/content/xul/content/src/nsXULElement.cpp +++ b/content/xul/content/src/nsXULElement.cpp @@ -150,6 +150,7 @@ #include "nsNodeInfoManager.h" #include "nsXBLBinding.h" #include "nsEventDispatcher.h" +#include "nsPresShellIterator.h" /** * Three bits are used for XUL Element's lazy state. @@ -1889,10 +1890,10 @@ nsXULElement::Focus() return NS_OK; // Obtain a presentation context and then call SetFocus. - if (doc->GetNumberOfShells() == 0) - return NS_OK; nsIPresShell *shell = doc->GetPrimaryShell(); + if (!shell) + return NS_OK; // Set focus nsCOMPtr context = shell->GetPresContext(); @@ -1910,10 +1911,9 @@ nsXULElement::Blur() return NS_OK; // Obtain a presentation context and then call SetFocus. - if (doc->GetNumberOfShells() == 0) - return NS_OK; - nsIPresShell *shell = doc->GetPrimaryShell(); + if (!shell) + return NS_OK; // Set focus nsCOMPtr context = shell->GetPresContext(); @@ -1931,13 +1931,11 @@ nsXULElement::Click() nsCOMPtr doc = GetCurrentDoc(); // Strong just in case if (doc) { - PRUint32 numShells = doc->GetNumberOfShells(); - // strong ref to PresContext so events don't destroy it - nsCOMPtr context; - - for (PRUint32 i = 0; i < numShells; ++i) { - nsIPresShell *shell = doc->GetShellAt(i); - context = shell->GetPresContext(); + nsPresShellIterator iter(doc); + nsCOMPtr shell; + while ((shell = iter.GetNextShell())) { + // strong ref to PresContext so events don't destroy it + nsCOMPtr context = shell->GetPresContext(); PRBool isCallerChrome = nsContentUtils::IsCallerChrome(); @@ -1974,13 +1972,10 @@ nsXULElement::DoCommand() { nsCOMPtr doc = GetCurrentDoc(); // strong just in case if (doc) { - PRUint32 numShells = doc->GetNumberOfShells(); - nsCOMPtr context; - - for (PRUint32 i = 0; i < numShells; ++i) { - nsIPresShell *shell = doc->GetShellAt(i); - context = shell->GetPresContext(); - + nsPresShellIterator iter(doc); + nsCOMPtr shell; + while ((shell = iter.GetNextShell())) { + nsCOMPtr context = shell->GetPresContext(); nsEventStatus status = nsEventStatus_eIgnore; nsXULCommandEvent event(PR_TRUE, NS_XUL_COMMAND, nsnull); nsEventDispatcher::Dispatch(NS_STATIC_CAST(nsIContent*, this), diff --git a/content/xul/document/src/nsXULCommandDispatcher.cpp b/content/xul/document/src/nsXULCommandDispatcher.cpp index 6cde711254e..070e7a8fa18 100644 --- a/content/xul/document/src/nsXULCommandDispatcher.cpp +++ b/content/xul/document/src/nsXULCommandDispatcher.cpp @@ -69,6 +69,7 @@ #include "nsCRT.h" #include "nsDOMError.h" #include "nsEventDispatcher.h" +#include "nsPresShellIterator.h" #ifdef PR_LOGGING static PRLogModuleInfo* gLog; @@ -391,9 +392,9 @@ nsXULCommandDispatcher::UpdateCommands(const nsAString& aEventName) } #endif - PRUint32 count = document->GetNumberOfShells(); - for (PRUint32 i = 0; i < count; i++) { - nsIPresShell *shell = document->GetShellAt(i); + nsPresShellIterator iter(document); + nsCOMPtr shell; + while ((shell = iter.GetNextShell())) { // Retrieve the context in which our DOM event will fire. nsCOMPtr context = shell->GetPresContext(); diff --git a/content/xul/document/src/nsXULDocument.cpp b/content/xul/document/src/nsXULDocument.cpp index f9fb6460c75..57cf1ed7c89 100644 --- a/content/xul/document/src/nsXULDocument.cpp +++ b/content/xul/document/src/nsXULDocument.cpp @@ -901,9 +901,9 @@ nsXULDocument::ExecuteOnBroadcastHandlerFor(nsIContent* aBroadcaster, // |onbroadcast| event handler nsEvent event(PR_TRUE, NS_XUL_BROADCAST); - PRInt32 j = GetNumberOfShells(); - while (--j >= 0) { - nsCOMPtr shell = GetShellAt(j); + nsPresShellIterator iter(this); + nsCOMPtr shell; + while ((shell = iter.GetNextShell())) { nsCOMPtr aPresContext = shell->GetPresContext(); @@ -1973,10 +1973,9 @@ nsXULDocument::StartLayout(void) return NS_OK; } - // XXXbz Shells can get removed (or added!) as we iterate through this - // loop. We should try to use an nsTObserverArray for this. - for (PRUint32 i = 0; i < GetNumberOfShells(); ++i) { - nsIPresShell *shell = GetShellAt(i); + nsPresShellIterator iter(this); + nsCOMPtr shell; + while ((shell = iter.GetNextShell())) { // Resize-reflow this time nsPresContext *cx = shell->GetPresContext(); diff --git a/dom/src/base/nsFocusController.cpp b/dom/src/base/nsFocusController.cpp index 4764ddae151..03fff642bbd 100644 --- a/dom/src/base/nsFocusController.cpp +++ b/dom/src/base/nsFocusController.cpp @@ -211,7 +211,7 @@ nsFocusController::UpdateCommands() } // If there is no presshell, it's a zombie document which can't handle the command updates - if (window && doc && doc->GetNumberOfShells()) { + if (window && doc && doc->GetPrimaryShell()) { // Not a zombie document, so we can handle the command update window->UpdateCommands(NS_LITERAL_STRING("focus")); mNeedUpdateCommands = PR_FALSE; @@ -283,10 +283,6 @@ nsFocusController::MoveFocus(PRBool aForward, nsIDOMElement* aElt) // Obtain a presentation context - PRInt32 count = doc->GetNumberOfShells(); - if (count == 0) - return NS_OK; - nsIPresShell *shell = doc->GetPrimaryShell(); if (!shell) return NS_OK; diff --git a/extensions/typeaheadfind/src/nsTypeAheadFind.cpp b/extensions/typeaheadfind/src/nsTypeAheadFind.cpp index e1ca0b30f2e..8d422a7fcf0 100644 --- a/extensions/typeaheadfind/src/nsTypeAheadFind.cpp +++ b/extensions/typeaheadfind/src/nsTypeAheadFind.cpp @@ -101,6 +101,7 @@ #include "nsIDOMEventTarget.h" #include "nsIDOM3EventTarget.h" #include "nsIDOMEventGroup.h" +#include "nsPresShellIterator.h" // Header for this class #include "nsTypeAheadFind.h" @@ -554,11 +555,11 @@ nsTypeAheadFind::HandleEvent(nsIDOMEvent* aEvent) return NS_ERROR_FAILURE; } - PRUint32 numShells = doc->GetNumberOfShells(); PRBool cancelFind = PR_FALSE; - for (PRUint32 count = 0; count < numShells; count ++) { - nsIPresShell *shellToBeDestroyed = doc->GetShellAt(count); + nsPresShellIterator iter(doc); + nsCOMPtr shellToBeDestroyed; + while ((shellToBeDestroyed = iter.GetNextShell())) { if (shellToBeDestroyed == focusedShell) { cancelFind = PR_TRUE; break; diff --git a/layout/svg/base/src/nsSVGOuterSVGFrame.cpp b/layout/svg/base/src/nsSVGOuterSVGFrame.cpp index da8d73d801e..a8cd55906f5 100644 --- a/layout/svg/base/src/nsSVGOuterSVGFrame.cpp +++ b/layout/svg/base/src/nsSVGOuterSVGFrame.cpp @@ -44,6 +44,7 @@ #include "nsDisplayList.h" #include "nsStubMutationObserver.h" #include "gfxContext.h" +#include "nsPresShellIterator.h" #if defined(DEBUG) && defined(SVG_DEBUG_PRINTING) #include "nsIDeviceContext.h" @@ -88,9 +89,10 @@ nsSVGMutationObserver::AttributeChanged(nsIDocument *aDocument, return; } - PRUint32 count = aDocument->GetNumberOfShells(); - for (PRUint32 i = 0; i < count; ++i) { - nsIFrame *frame = aDocument->GetShellAt(i)->GetPrimaryFrameFor(aContent); + nsPresShellIterator iter(aDocument); + nsCOMPtr shell; + while ((shell = iter.GetNextShell())) { + nsIFrame *frame = shell->GetPrimaryFrameFor(aContent); if (!frame) { continue; } diff --git a/rdf/chrome/src/nsChromeRegistry.cpp b/rdf/chrome/src/nsChromeRegistry.cpp index 6981e08f341..df9dd6e9b97 100644 --- a/rdf/chrome/src/nsChromeRegistry.cpp +++ b/rdf/chrome/src/nsChromeRegistry.cpp @@ -94,6 +94,7 @@ #include "nsIJARURI.h" #include "nsIFileURL.h" #include "nsIXPConnect.h" +#include "nsPresShellIterator.h" static char kChromePrefix[] = "chrome://"; nsIAtom* nsChromeRegistry::sCPrefix; // atom for "c" @@ -1396,10 +1397,9 @@ nsresult nsChromeRegistry::RefreshWindow(nsIDOMWindowInternal* aWindow) return NS_OK; // Deal with the agent sheets first. Have to do all the style sets by hand. - PRUint32 shellCount = document->GetNumberOfShells(); - for (PRUint32 k = 0; k < shellCount; k++) { - nsIPresShell *shell = document->GetShellAt(k); - + nsPresShellIterator iter(document); + nsCOMPtr shell; + while ((shell = iter.GetNextShell())) { // Reload only the chrome URL agent style sheets. nsCOMArray agentSheets; rv = shell->GetAgentStyleSheets(agentSheets);