1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * The contents of this file are subject to the Netscape Public License
4 * Version 1.0 (the "NPL"); you may not use this file except in
5 * compliance with the NPL. You may obtain a copy of the NPL at
6 * http://www.mozilla.org/NPL/
8 * Software distributed under the NPL is distributed on an "AS IS" basis,
9 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
10 * for the specific language governing rights and limitations under the
13 * The Initial Developer of this code under the NPL is Netscape
14 * Communications Corporation. Portions created by Netscape are
15 * Copyright (C) 1998 Netscape Communications Corporation. All Rights
18 #include "nsIPresShell.h"
19 #include "nsIPresContext.h"
20 #include "nsIContent.h"
21 #include "nsIDocument.h"
22 #include "nsIDocumentObserver.h"
23 #include "nsIStyleSet.h"
24 #include "nsIStyleContext.h"
26 #include "nsIReflowCommand.h"
27 #include "nsIViewManager.h"
31 #include "nsVoidArray.h"
33 #include "nsIViewObserver.h"
34 #include "nsContainerFrame.h"
35 #include "nsHTMLIIDs.h"
36 #include "nsIDeviceContext.h"
37 #include "nsIEventStateManager.h"
38 #include "nsDOMEvent.h"
39 #include "nsHTMLParts.h"
41 static PRBool gsNoisyRefs = PR_FALSE;
46 HashKey(nsIFrame* key)
48 return (PLHashNumber) key;
52 CompareKeys(nsIFrame* key1, nsIFrame* key2)
57 class FrameHashTable {
62 void* Get(nsIFrame* aKey);
63 void* Put(nsIFrame* aKey, void* aValue);
64 void* Remove(nsIFrame* aKey);
70 FrameHashTable::FrameHashTable()
72 mTable = PL_NewHashTable(8, (PLHashFunction) HashKey,
73 (PLHashComparator) CompareKeys,
74 (PLHashComparator) nsnull,
78 FrameHashTable::~FrameHashTable()
80 // XXX if debugging then we should assert that the table is empty
81 PL_HashTableDestroy(mTable);
85 * Get the data associated with a frame.
88 FrameHashTable::Get(nsIFrame* aKey)
90 PRInt32 hashCode = (PRInt32) aKey;
91 PLHashEntry** hep = PL_HashTableRawLookup(mTable, hashCode, aKey);
92 PLHashEntry* he = *hep;
100 * Create an association between a frame and some data. This call
101 * returns an old association if there was one (or nsnull if there
105 FrameHashTable::Put(nsIFrame* aKey, void* aData)
107 PRInt32 hashCode = (PRInt32) aKey;
108 PLHashEntry** hep = PL_HashTableRawLookup(mTable, hashCode, aKey);
109 PLHashEntry* he = *hep;
111 void* oldValue = he->value;
115 PL_HashTableRawAdd(mTable, hep, hashCode, aKey, aData);
120 * Remove an association between a frame and it's data. This returns
121 * the old associated data.
124 FrameHashTable::Remove(nsIFrame* aKey)
126 PRInt32 hashCode = (PRInt32) aKey;
127 PLHashEntry** hep = PL_HashTableRawLookup(mTable, hashCode, aKey);
128 PLHashEntry* he = *hep;
129 void* oldValue = nsnull;
131 oldValue = he->value;
132 PL_HashTableRawRemove(mTable, hep, he);
138 //----------------------------------------------------------------------
140 static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
141 static NS_DEFINE_IID(kIPresShellIID, NS_IPRESSHELL_IID);
142 static NS_DEFINE_IID(kIDocumentObserverIID, NS_IDOCUMENT_OBSERVER_IID);
143 static NS_DEFINE_IID(kIViewObserverIID, NS_IVIEWOBSERVER_IID);
145 class PresShell : public nsIPresShell, public nsIViewObserver,
146 private nsIDocumentObserver
152 void* operator new(size_t sz) {
153 void* rv = new char[sz];
161 // nsIDocumentObserver
162 NS_IMETHOD BeginUpdate(nsIDocument *aDocument);
163 NS_IMETHOD EndUpdate(nsIDocument *aDocument);
164 NS_IMETHOD BeginLoad(nsIDocument *aDocument);
165 NS_IMETHOD EndLoad(nsIDocument *aDocument);
166 NS_IMETHOD BeginReflow(nsIDocument *aDocument, nsIPresShell* aShell);
167 NS_IMETHOD EndReflow(nsIDocument *aDocument, nsIPresShell* aShell);
168 NS_IMETHOD ContentChanged(nsIDocument *aDocument,
169 nsIContent* aContent,
170 nsISupports* aSubContent);
171 NS_IMETHOD AttributeChanged(nsIDocument *aDocument,
172 nsIContent* aContent,
175 NS_IMETHOD ContentAppended(nsIDocument *aDocument,
176 nsIContent* aContainer,
177 PRInt32 aNewIndexInContainer);
178 NS_IMETHOD ContentInserted(nsIDocument *aDocument,
179 nsIContent* aContainer,
181 PRInt32 aIndexInContainer);
182 NS_IMETHOD ContentReplaced(nsIDocument *aDocument,
183 nsIContent* aContainer,
184 nsIContent* aOldChild,
185 nsIContent* aNewChild,
186 PRInt32 aIndexInContainer);
187 NS_IMETHOD ContentRemoved(nsIDocument *aDocument,
188 nsIContent* aContainer,
190 PRInt32 aIndexInContainer);
191 NS_IMETHOD StyleSheetAdded(nsIDocument *aDocument,
192 nsIStyleSheet* aStyleSheet);
193 NS_IMETHOD StyleSheetDisabledStateChanged(nsIDocument *aDocument,
194 nsIStyleSheet* aStyleSheet,
196 NS_IMETHOD DocumentWillBeDestroyed(nsIDocument *aDocument);
199 NS_IMETHOD Init(nsIDocument* aDocument,
200 nsIPresContext* aPresContext,
201 nsIViewManager* aViewManager,
202 nsIStyleSet* aStyleSet);
203 virtual nsIDocument* GetDocument();
204 virtual nsIPresContext* GetPresContext();
205 virtual nsIViewManager* GetViewManager();
206 virtual nsIStyleSet* GetStyleSet();
207 NS_IMETHOD EnterReflowLock();
208 NS_IMETHOD ExitReflowLock();
209 virtual void BeginObservingDocument();
210 virtual void EndObservingDocument();
211 NS_IMETHOD InitialReflow(nscoord aWidth, nscoord aHeight);
212 NS_IMETHOD ResizeReflow(nscoord aWidth, nscoord aHeight);
213 NS_IMETHOD StyleChangeReflow();
214 virtual nsIFrame* GetRootFrame();
215 virtual nsIFrame* FindFrameWithContent(nsIContent* aContent);
216 virtual void AppendReflowCommand(nsIReflowCommand* aReflowCommand);
217 virtual void ProcessReflowCommands();
218 virtual void ClearFrameRefs(nsIFrame*);
219 NS_IMETHOD CreateRenderingContext(nsIFrame *aFrame, nsIRenderingContext *&aContext);
221 //nsIViewObserver interface
223 NS_IMETHOD Paint(nsIView *aView,
224 nsIRenderingContext& aRenderingContext,
225 const nsRect& aDirtyRect);
226 NS_IMETHOD HandleEvent(nsIView* aView,
228 nsEventStatus& aEventStatus);
229 NS_IMETHOD Scrolled(nsIView *aView);
230 NS_IMETHOD ResizeReflow(nsIView *aView, nscoord aWidth, nscoord aHeight);
236 void VerifyIncrementalReflow();
239 nsIDocument* mDocument;
240 nsIPresContext* mPresContext;
241 nsIStyleSet* mStyleSet;
242 nsIFrame* mRootFrame;
243 nsIViewManager* mViewManager;
244 PRUint32 mUpdateCount;
245 nsVoidArray mReflowCommands;
246 PRUint32 mReflowLockCount;
247 PRBool mIsDestroying;
248 nsIFrame* mCurrentEventFrame;
253 * Note: the log module is created during library initialization which
254 * means that you cannot perform logging before then.
256 static PRLogModuleInfo* gLogModule = PR_NewLogModule("verifyreflow");
259 static PRBool gVerifyReflow = PRBool(0x55);
262 nsIPresShell::GetVerifyReflowEnable()
265 if (gVerifyReflow == PRBool(0x55)) {
266 gVerifyReflow = 0 != gLogModule->level;
267 printf("Note: verifyreflow is %sabled\n",
268 gVerifyReflow ? "en" : "dis");
271 return gVerifyReflow;
275 nsIPresShell::SetVerifyReflowEnable(PRBool aEnabled)
277 gVerifyReflow = aEnabled;
280 //----------------------------------------------------------------------
283 NS_NewPresShell(nsIPresShell** aInstancePtrResult)
285 NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
286 if (nsnull == aInstancePtrResult) {
287 return NS_ERROR_NULL_POINTER;
289 PresShell* it = new PresShell();
291 return NS_ERROR_OUT_OF_MEMORY;
293 return it->QueryInterface(kIPresShellIID, (void **) aInstancePtrResult);
296 PresShell::PresShell()
298 //XXX joki 11/17 - temporary event hack.
299 mIsDestroying = PR_FALSE;
303 // for debugging only
304 nsrefcnt PresShell::AddRef(void)
306 if (gsNoisyRefs) printf("PresShell: AddRef: %x, cnt = %d \n",this, mRefCnt+1);
310 // for debugging only
311 nsrefcnt PresShell::Release(void)
313 if (gsNoisyRefs==PR_TRUE) printf("PresShell Release: %x, cnt = %d \n",this, mRefCnt-1);
314 if (--mRefCnt == 0) {
315 if (gsNoisyRefs==PR_TRUE) printf("PresShell Delete: %x, \n",this);
322 NS_IMPL_ADDREF(PresShell)
323 NS_IMPL_RELEASE(PresShell)
327 PresShell::QueryInterface(const nsIID& aIID, void** aInstancePtr)
329 if (aIID.Equals(kIPresShellIID)) {
330 nsIPresShell* tmp = this;
331 *aInstancePtr = (void*) tmp;
335 if (aIID.Equals(kIDocumentObserverIID)) {
336 nsIDocumentObserver* tmp = this;
337 *aInstancePtr = (void*) tmp;
341 if (aIID.Equals(kIViewObserverIID)) {
342 nsIViewObserver* tmp = this;
343 *aInstancePtr = (void*) tmp;
347 if (aIID.Equals(kISupportsIID)) {
348 nsIPresShell* tmp = this;
349 nsISupports* tmp2 = tmp;
350 *aInstancePtr = (void*) tmp2;
354 return NS_NOINTERFACE;
357 PresShell::~PresShell()
359 mRefCnt = 99;/* XXX hack! get around re-entrancy bugs */
360 mIsDestroying = PR_TRUE;
361 if (nsnull != mRootFrame) {
362 mRootFrame->DeleteFrame(*mPresContext);
364 NS_IF_RELEASE(mViewManager);
365 //Release mPresContext after mViewManager
366 NS_IF_RELEASE(mPresContext);
367 NS_IF_RELEASE(mStyleSet);
368 if (nsnull != mDocument) {
369 mDocument->DeleteShell(this);
370 NS_RELEASE(mDocument);
376 * Initialize the presentation shell. Create view manager and style
380 PresShell::Init(nsIDocument* aDocument,
381 nsIPresContext* aPresContext,
382 nsIViewManager* aViewManager,
383 nsIStyleSet* aStyleSet)
385 NS_PRECONDITION(nsnull != aDocument, "null ptr");
386 NS_PRECONDITION(nsnull != aPresContext, "null ptr");
387 NS_PRECONDITION(nsnull != aViewManager, "null ptr");
388 if ((nsnull == aDocument) || (nsnull == aPresContext) ||
389 (nsnull == aViewManager)) {
390 return NS_ERROR_NULL_POINTER;
392 if (nsnull != mDocument) {
393 return NS_ERROR_ALREADY_INITIALIZED;
396 mDocument = aDocument;
397 NS_ADDREF(aDocument);
398 mViewManager = aViewManager;
399 NS_ADDREF(mViewManager);
401 //doesn't add a ref since we own it... MMP
402 mViewManager->SetViewObserver((nsIViewObserver *)this);
404 // Bind the context to the presentation shell.
405 mPresContext = aPresContext;
406 NS_ADDREF(aPresContext);
407 aPresContext->SetShell(this);
409 mStyleSet = aStyleSet;
410 NS_ADDREF(aStyleSet);
416 PresShell::EnterReflowLock()
423 PresShell::ExitReflowLock()
425 PRUint32 newReflowLockCount = mReflowLockCount - 1;
426 if (newReflowLockCount == 0) {
427 ProcessReflowCommands();
429 mReflowLockCount = newReflowLockCount;
434 PresShell::GetDocument()
436 NS_IF_ADDREF(mDocument);
441 PresShell::GetPresContext()
443 NS_IF_ADDREF(mPresContext);
448 PresShell::GetViewManager()
450 NS_IF_ADDREF(mViewManager);
455 PresShell::GetStyleSet()
457 NS_IF_ADDREF(mStyleSet);
461 // Make shell be a document observer
463 PresShell::BeginObservingDocument()
465 if (nsnull != mDocument) {
466 mDocument->AddObserver(this);
470 // Make shell stop being a document observer
472 PresShell::EndObservingDocument()
474 if (nsnull != mDocument) {
475 mDocument->RemoveObserver(this);
480 PresShell::InitialReflow(nscoord aWidth, nscoord aHeight)
482 NS_PRECONDITION(nsnull == mRootFrame, "unexpected root frame");
486 if (nsnull != mPresContext) {
487 nsRect r(0, 0, aWidth, aHeight);
488 mPresContext->SetVisibleArea(r);
491 if (nsnull == mRootFrame) {
492 if (nsnull != mDocument) {
493 nsIContent* root = mDocument->GetRootContent();
494 if (nsnull != root) {
495 // Have style sheet processor construct a frame for the
496 // root content object
497 mStyleSet->ConstructFrame(mPresContext, root, nsnull, mRootFrame);
503 if (nsnull != mRootFrame) {
504 // Kick off a top-down reflow
505 NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
506 ("enter nsPresShell::InitialReflow: %d,%d", aWidth, aHeight));
508 if (nsIFrame::GetVerifyTreeEnable()) {
509 mRootFrame->VerifyTree();
513 mPresContext->GetVisibleArea(bounds);
514 nsSize maxSize(bounds.width, bounds.height);
515 nsHTMLReflowMetrics desiredSize(nsnull);
516 nsReflowStatus status;
517 nsIHTMLReflow* htmlReflow;
518 nsIRenderingContext* rcx = nsnull;
520 CreateRenderingContext(mRootFrame, rcx);
522 nsHTMLReflowState reflowState(*mPresContext, mRootFrame,
523 eReflowReason_Initial, maxSize, rcx);
525 if (NS_OK == mRootFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) {
526 htmlReflow->Reflow(*mPresContext, desiredSize, reflowState, status);
527 mRootFrame->SizeTo(desiredSize.width, desiredSize.height);
529 if (nsIFrame::GetVerifyTreeEnable()) {
530 mRootFrame->VerifyTree();
535 NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("exit nsPresShell::InitialReflow"));
540 return NS_OK; //XXX this needs to be real. MMP
544 PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight)
548 if (nsnull != mPresContext) {
549 nsRect r(0, 0, aWidth, aHeight);
550 mPresContext->SetVisibleArea(r);
553 // If we don't have a root frame yet, that means we haven't had our initial
555 if (nsnull != mRootFrame) {
556 // Kick off a top-down reflow
557 NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
558 ("enter nsPresShell::ResizeReflow: %d,%d", aWidth, aHeight));
560 if (nsIFrame::GetVerifyTreeEnable()) {
561 mRootFrame->VerifyTree();
565 mPresContext->GetVisibleArea(bounds);
566 nsSize maxSize(bounds.width, bounds.height);
567 nsHTMLReflowMetrics desiredSize(nsnull);
568 nsReflowStatus status;
569 nsIHTMLReflow* htmlReflow;
570 nsIRenderingContext* rcx = nsnull;
572 CreateRenderingContext(mRootFrame, rcx);
574 nsHTMLReflowState reflowState(*mPresContext, mRootFrame,
575 eReflowReason_Resize, maxSize, rcx);
577 if (NS_OK == mRootFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) {
578 htmlReflow->Reflow(*mPresContext, desiredSize, reflowState, status);
579 mRootFrame->SizeTo(desiredSize.width, desiredSize.height);
581 if (nsIFrame::GetVerifyTreeEnable()) {
582 mRootFrame->VerifyTree();
587 NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("exit nsPresShell::ResizeReflow"));
589 // XXX if debugging then we should assert that the cache is empty
592 printf("PresShell::ResizeReflow: null root frame\n");
598 return NS_OK; //XXX this needs to be real. MMP
602 PresShell::StyleChangeReflow()
606 if (nsnull != mRootFrame) {
607 // Kick off a top-down reflow
608 NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
609 ("enter nsPresShell::StyleChangeReflow"));
611 if (nsIFrame::GetVerifyTreeEnable()) {
612 mRootFrame->VerifyTree();
616 mPresContext->GetVisibleArea(bounds);
617 nsSize maxSize(bounds.width, bounds.height);
618 nsHTMLReflowMetrics desiredSize(nsnull);
619 nsReflowStatus status;
620 nsIHTMLReflow* htmlReflow;
621 nsIRenderingContext* rcx = nsnull;
623 CreateRenderingContext(mRootFrame, rcx);
625 // XXX We should be using eReflowReason_StyleChange
626 nsHTMLReflowState reflowState(*mPresContext, mRootFrame,
627 eReflowReason_Resize, maxSize, rcx);
629 if (NS_OK == mRootFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) {
630 htmlReflow->Reflow(*mPresContext, desiredSize, reflowState, status);
631 mRootFrame->SizeTo(desiredSize.width, desiredSize.height);
633 if (nsIFrame::GetVerifyTreeEnable()) {
634 mRootFrame->VerifyTree();
639 NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("exit nsPresShell::StyleChangeReflow"));
644 return NS_OK; //XXX this needs to be real. MMP
648 PresShell::GetRootFrame()
654 PresShell::BeginUpdate(nsIDocument *aDocument)
661 PresShell::EndUpdate(nsIDocument *aDocument)
663 NS_PRECONDITION(0 != mUpdateCount, "too many EndUpdate's");
664 if (--mUpdateCount == 0) {
665 // XXX do something here
671 PresShell::BeginLoad(nsIDocument *aDocument)
677 PresShell::EndLoad(nsIDocument *aDocument)
683 PresShell::BeginReflow(nsIDocument *aDocument, nsIPresShell* aShell)
689 PresShell::EndReflow(nsIDocument *aDocument, nsIPresShell* aShell)
695 PresShell::AppendReflowCommand(nsIReflowCommand* aReflowCommand)
697 mReflowCommands.AppendElement(aReflowCommand);
698 NS_ADDREF(aReflowCommand);
702 PresShell::ProcessReflowCommands()
704 if (0 != mReflowCommands.Count()) {
705 nsHTMLReflowMetrics desiredSize(nsnull);
706 nsIRenderingContext* rcx;
708 CreateRenderingContext(mRootFrame, rcx);
710 while (0 != mReflowCommands.Count()) {
711 nsIReflowCommand* rc = (nsIReflowCommand*) mReflowCommands.ElementAt(0);
712 mReflowCommands.RemoveElementAt(0);
714 // Dispatch the reflow command
716 mRootFrame->GetSize(maxSize);
718 nsIReflowCommand::ReflowType type;
720 NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
721 ("PresShell::ProcessReflowCommands: begin reflow command type=%d",
724 rc->Dispatch(*mPresContext, desiredSize, maxSize, *rcx);
726 NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
727 ("PresShell::ProcessReflowCommands: end reflow command"));
730 // Place and size the root frame
731 mRootFrame->SizeTo(desiredSize.width, desiredSize.height);
733 if (nsIFrame::GetVerifyTreeEnable()) {
734 mRootFrame->VerifyTree();
736 if (GetVerifyReflowEnable()) {
737 VerifyIncrementalReflow();
745 PresShell::ClearFrameRefs(nsIFrame* aFrame)
747 nsIEventStateManager *manager;
748 if (NS_OK == mPresContext->GetEventStateManager(&manager)) {
749 manager->ClearFrameRefs(aFrame);
752 if (aFrame == mCurrentEventFrame) {
753 mCurrentEventFrame = nsnull;
757 NS_IMETHODIMP PresShell :: CreateRenderingContext(nsIFrame *aFrame,
758 nsIRenderingContext *&aContext)
760 nsIWidget *widget = nsnull;
761 nsIView *view = nsnull;
765 aFrame->GetView(view);
768 aFrame->GetOffsetFromView(pt, view);
770 while (nsnull != view)
772 view->GetWidget(widget);
774 if (nsnull != widget)
780 view->GetParent(view);
783 nsIDeviceContext *dx;
785 dx = mPresContext->GetDeviceContext();
788 rv = dx->CreateRenderingContext(view, aContext);
790 rv = dx->CreateRenderingContext(aContext);
799 ContentTag(nsIContent* aContent, PRIntn aSlot)
801 static char buf0[100], buf1[100], buf2[100];
802 static char* bufs[] = { buf0, buf1, buf2 };
803 char* buf = bufs[aSlot];
805 aContent->GetTag(atom);
806 if (nsnull != atom) {
809 tmp.ToCString(buf, 100);
819 PresShell::ContentChanged(nsIDocument *aDocument,
820 nsIContent* aContent,
821 nsISupports* aSubContent)
823 NS_PRECONDITION(nsnull != mRootFrame, "null root frame");
826 nsresult rv = mStyleSet->ContentChanged(mPresContext, aContent, aSubContent);
832 PresShell::AttributeChanged(nsIDocument *aDocument,
833 nsIContent* aContent,
837 NS_PRECONDITION(nsnull != mRootFrame, "null root frame");
840 nsresult rv = mStyleSet->AttributeChanged(mPresContext, aContent, aAttribute, aHint);
846 PresShell::ContentAppended(nsIDocument *aDocument,
847 nsIContent* aContainer,
848 PRInt32 aNewIndexInContainer)
851 nsresult rv = mStyleSet->ContentAppended(mPresContext, aContainer, aNewIndexInContainer);
857 PresShell::ContentInserted(nsIDocument* aDocument,
858 nsIContent* aContainer,
860 PRInt32 aIndexInContainer)
863 nsresult rv = mStyleSet->ContentInserted(mPresContext, aContainer, aChild, aIndexInContainer);
869 PresShell::ContentReplaced(nsIDocument* aDocument,
870 nsIContent* aContainer,
871 nsIContent* aOldChild,
872 nsIContent* aNewChild,
873 PRInt32 aIndexInContainer)
876 nsresult rv = mStyleSet->ContentReplaced(mPresContext, aContainer, aOldChild,
877 aNewChild, aIndexInContainer);
883 PresShell::ContentRemoved(nsIDocument *aDocument,
884 nsIContent* aContainer,
886 PRInt32 aIndexInContainer)
889 nsresult rv = mStyleSet->ContentRemoved(mPresContext, aContainer,
890 aChild, aIndexInContainer);
896 PresShell::StyleSheetAdded(nsIDocument *aDocument,
897 nsIStyleSheet* aStyleSheet)
903 PresShell::StyleSheetDisabledStateChanged(nsIDocument *aDocument,
904 nsIStyleSheet* aStyleSheet,
908 if (nsnull != mRootFrame) {
909 nsIFrame* childFrame;
910 rv = mRootFrame->FirstChild(nsnull, childFrame);
912 if (nsnull != mDocument) {
913 nsIContent* root = mDocument->GetRootContent();
914 if (nsnull != root) {
917 rv = mStyleSet->ReconstructFrames(mPresContext, root,
918 mRootFrame, childFrame);
928 PresShell::DocumentWillBeDestroyed(nsIDocument *aDocument)
934 IsZeroSizedFrame(nsIFrame *aFrame)
937 aFrame->GetSize(size);
938 return ((0 == size.width) && (0 == size.height));
942 FindFrameWithContent(nsIFrame* aFrame, nsIContent* aContent)
944 nsIContent* frameContent;
946 aFrame->GetContent(frameContent);
947 if (frameContent == aContent) {
948 // XXX Sleazy hack to check whether this is a placeholder frame.
949 // If it is, we skip it and go on to (hopefully) find the
950 // absolutely positioned frame.
951 const nsStylePosition* position;
953 aFrame->GetStyleData(eStyleStruct_Position, (nsStyleStruct*&)position);
954 if ((NS_STYLE_POSITION_ABSOLUTE != position->mPosition) ||
955 !IsZeroSizedFrame(aFrame)) {
956 NS_RELEASE(frameContent);
960 NS_IF_RELEASE(frameContent);
962 // Search for the frame in each child list that aFrame supports
963 nsIAtom* listName = nsnull;
964 PRInt32 listIndex = 0;
967 aFrame->FirstChild(listName, kid);
968 while (nsnull != kid) {
969 nsIFrame* result = FindFrameWithContent(kid, aContent);
970 if (nsnull != result) {
971 NS_IF_RELEASE(listName);
974 kid->GetNextSibling(kid);
976 NS_IF_RELEASE(listName);
977 aFrame->GetAdditionalChildListName(listIndex++, listName);
978 } while(nsnull != listName);
984 PresShell::FindFrameWithContent(nsIContent* aContent)
986 // For the time being do a brute force depth-first search of
988 return ::FindFrameWithContent(mRootFrame, aContent);
993 NS_IMETHODIMP PresShell :: Paint(nsIView *aView,
994 nsIRenderingContext& aRenderingContext,
995 const nsRect& aDirtyRect)
1001 NS_ASSERTION(!(nsnull == aView), "null view");
1003 aView->GetClientData(clientData);
1004 frame = (nsIFrame *)clientData;
1006 if (nsnull != frame) {
1007 rv = frame->Paint(*mPresContext, aRenderingContext, aDirtyRect);
1009 // Draw a border around the frame
1010 if (nsIFrame::GetShowFrameBorders()) {
1013 aRenderingContext.SetColor(NS_RGB(0,0,255));
1014 aRenderingContext.DrawRect(0, 0, r.width, r.height);
1021 NS_IMETHODIMP PresShell :: HandleEvent(nsIView *aView,
1023 nsEventStatus& aEventStatus)
1027 nsresult rv = NS_OK;
1029 NS_ASSERTION(!(nsnull == aView), "null view");
1031 if (mIsDestroying || mReflowLockCount > 0) {
1035 aView->GetClientData(clientData);
1036 frame = (nsIFrame *)clientData;
1038 if (nsnull != frame) {
1039 frame->GetFrameForPoint(aEvent->point, &mCurrentEventFrame);
1040 if (nsnull != mCurrentEventFrame) {
1041 //Once we have the targetFrame, handle the event in this order
1042 nsIEventStateManager *manager;
1043 if (NS_OK == mPresContext->GetEventStateManager(&manager)) {
1044 //1. Give event to event manager for pre event state changes and generation of synthetic events.
1045 rv = manager->PreHandleEvent(*mPresContext, aEvent, mCurrentEventFrame, aEventStatus);
1047 //2. Give event to the DOM for third party and JS use.
1048 if (nsnull != mCurrentEventFrame && NS_OK == rv) {
1049 nsIContent* targetContent;
1050 if (NS_OK == mCurrentEventFrame->GetContent(targetContent) && nsnull != targetContent) {
1051 rv = targetContent->HandleDOMEvent(*mPresContext, (nsEvent*)aEvent, nsnull,
1052 DOM_EVENT_INIT, aEventStatus);
1053 NS_RELEASE(targetContent);
1056 //3. Give event to the Frames for browser default processing.
1057 // XXX The event isn't translated into the local coordinate space
1059 if (nsnull != mCurrentEventFrame && NS_OK == rv) {
1060 rv = mCurrentEventFrame->HandleEvent(*mPresContext, aEvent, aEventStatus);
1062 //4. Give event to event manager for post event state changes and generation of synthetic events.
1063 if (nsnull != mCurrentEventFrame && NS_OK == rv) {
1064 rv = manager->PostHandleEvent(*mPresContext, aEvent, mCurrentEventFrame, aEventStatus);
1068 NS_RELEASE(manager);
1079 NS_IMETHODIMP PresShell :: Scrolled(nsIView *aView)
1085 NS_ASSERTION(!(nsnull == aView), "null view");
1087 aView->GetClientData(clientData);
1088 frame = (nsIFrame *)clientData;
1090 if (nsnull != frame)
1091 rv = frame->Scrolled(aView);
1098 NS_IMETHODIMP PresShell :: ResizeReflow(nsIView *aView, nscoord aWidth, nscoord aHeight)
1100 return ResizeReflow(aWidth, aHeight);
1104 #include "nsViewsCID.h"
1105 #include "nsWidgetsCID.h"
1106 #include "nsIScrollableView.h"
1107 #include "nsIDeviceContext.h"
1109 #include "nsICSSParser.h"
1110 #include "nsIStyleSheet.h"
1112 static NS_DEFINE_IID(kViewManagerCID, NS_VIEW_MANAGER_CID);
1113 static NS_DEFINE_IID(kIViewManagerIID, NS_IVIEWMANAGER_IID);
1114 static NS_DEFINE_IID(kScrollingViewCID, NS_SCROLLING_VIEW_CID);
1115 static NS_DEFINE_IID(kIViewIID, NS_IVIEW_IID);
1116 static NS_DEFINE_IID(kScrollViewIID, NS_ISCROLLABLEVIEW_IID);
1117 static NS_DEFINE_IID(kWidgetCID, NS_CHILD_CID);
1120 ShowDiffs(nsIFrame* k1, nsIFrame* k2, const nsRect& r1, const nsRect& r2)
1122 printf("verifyreflow: ");
1124 k1->GetFrameName(name);
1125 fputs(name, stdout);
1129 k2->GetFrameName(name);
1130 fputs(name, stdout);
1137 CompareTrees(nsIFrame* aA, nsIFrame* aB)
1140 aA->FirstChild(nsnull, k1);
1141 aB->FirstChild(nsnull, k2);
1142 NS_ASSERTION(nsContainerFrame::LengthOf(k1) == nsContainerFrame::LengthOf(k2),
1143 "child counts don't match");
1150 NS_ASSERTION(nsnull == k2, "child lists are different");
1153 NS_ASSERTION(nsnull != k2, "child lists are different");
1155 // Verify that the frames are the same size
1159 ShowDiffs(k1, k2, r1, r2);
1162 // Make sure either both have views or neither have views; if they
1163 // do have views, make sure the views are the same size. If the
1164 // views have widgets, make sure they both do or neither does. If
1165 // they do, make sure the widgets are the same size.
1169 NS_ASSERTION(nsnull != v2, "child views are not matched");
1172 NS_ASSERTION(r1 == r2, "child views are different sizes");
1177 NS_ASSERTION(nsnull != w2, "child widgets are not matched");
1180 NS_ASSERTION(r1 == r2, "child widgets are different sizes");
1183 NS_ASSERTION(nsnull == w2, "child widgets are not matched");
1187 NS_ASSERTION(nsnull == v2, "child views are not matched");
1190 // Compare the sub-trees too
1191 CompareTrees(k1, k2);
1194 // Advance to next sibling
1195 k1->GetNextSibling(k1);
1196 k2->GetNextSibling(k2);
1200 // XXX: copy of nsWebWidget's ua.css loading code!!!
1201 #define UA_CSS_URL "resource:/res/ua.css"
1203 static nsIStyleSheet* gUAStyleSheet;
1208 nsresult rv = NS_OK;
1210 if (nsnull == gUAStyleSheet) { // snarf one
1212 rv = NS_NewURL(&uaURL, nsnull, UA_CSS_URL); // XXX this bites, fix it
1214 // Get an input stream from the url
1216 nsIInputStream* in = uaURL->Open(&ec);
1218 // Translate the input using the argument character set id into unicode
1219 nsIUnicharInputStream* uin;
1220 rv = NS_NewConverterStream(&uin, nsnull, in);
1222 // Create parser and set it up to process the input file
1224 rv = NS_NewCSSParser(&css);
1226 // Parse the input and produce a style set
1227 // XXX note: we are ignoring rv until the error code stuff in the
1228 // input routines is converted to use nsresult's
1229 css->Parse(uin, uaURL, gUAStyleSheet);
1237 // printf("open of %s failed: error=%x\n", UA_CSS_URL, ec);
1238 rv = NS_ERROR_ILLEGAL_VALUE; // XXX need a better error code here
1248 CreateStyleSet(nsIDocument* aDocument, nsIStyleSet** aStyleSet)
1250 nsresult rv = InitUAStyleSheet();
1252 NS_WARNING("unable to load UA style sheet");
1255 rv = NS_NewStyleSet(aStyleSet);
1257 PRInt32 index = aDocument->GetNumberOfStyleSheets();
1258 while (0 < index--) {
1259 // NOTE: turn the order around for the set
1260 nsIStyleSheet* sheet = aDocument->GetStyleSheetAt(index);
1261 (*aStyleSet)->AppendDocStyleSheet(sheet);
1264 // XXX this is just wrong, the UA style sheet should be owned by the UA
1265 // for that matter, the style set should be created by the UA too
1266 if (nsnull != gUAStyleSheet) {
1267 (*aStyleSet)->AppendBackstopStyleSheet(gUAStyleSheet);
1273 // After an incremental reflow, we verify the correctness by doing a
1274 // full reflow into a fresh frame tree.
1276 PresShell::VerifyIncrementalReflow()
1278 // All the stuff we are creating that needs releasing
1285 // Create a presentation context to view the new frame tree
1287 if (mPresContext->IsPaginated()) {
1288 rv = NS_NewPrintPreviewContext(&cx);
1291 rv = NS_NewGalleyContext(&cx);
1293 NS_ASSERTION(NS_OK == rv, "failed to create presentation context");
1294 nsIDeviceContext* dc = mPresContext->GetDeviceContext();
1296 mPresContext->GetPrefs(prefs);
1297 cx->Init(dc, prefs);
1298 NS_IF_RELEASE(prefs);
1300 rv = CreateStyleSet(mDocument, &ss);
1301 NS_ASSERTION(NS_OK == rv, "failed to create style set");
1303 // Get our scrolling preference
1304 nsScrollPreference scrolling;
1306 mViewManager->GetRootView(rootView);
1307 nsIScrollableView* scrollView;
1308 rv = rootView->QueryInterface(kScrollViewIID, (void**)&scrollView);
1310 scrollView->GetScrollPreference(scrolling);
1312 nsIWidget* rootWidget;
1313 rootView->GetWidget(rootWidget);
1314 void* nativeParentWidget = rootWidget->GetNativeData(NS_NATIVE_WIDGET);
1316 // Create a new view manager.
1317 rv = nsRepository::CreateInstance(kViewManagerCID, nsnull, kIViewManagerIID,
1319 if ((NS_OK != rv) || (NS_OK != vm->Init(dc))) {
1320 NS_ASSERTION(NS_OK == rv, "failed to create view manager");
1325 vm->SetViewObserver((nsIViewObserver *)this);
1327 // Create a child window of the parent that is our "root view/window"
1330 mPresContext->GetVisibleArea(tbounds);
1331 // tbounds *= mPresContext->GetPixelsToTwips();
1332 rv = nsRepository::CreateInstance(kScrollingViewCID, nsnull, kIViewIID,
1334 if ((NS_OK != rv) || (NS_OK != view->Init(vm, tbounds, nsnull))) {
1335 NS_ASSERTION(NS_OK == rv, "failed to create scroll view");
1338 //now create the widget for the view
1339 rv = view->CreateWidget(kWidgetCID, nsnull, nativeParentWidget);
1341 NS_ASSERTION(NS_OK == rv, "failed to create scroll view widget");
1344 rv = view->QueryInterface(kScrollViewIID, (void**)&scrollView);
1346 scrollView->CreateScrollControls(nativeParentWidget);
1347 scrollView->SetScrollPreference(scrolling);
1350 NS_ASSERTION(0, "invalid scrolling view");
1353 // Setup hierarchical relationship in view manager
1354 vm->SetRootView(view);
1356 // Make the new presentation context the same size as our
1357 // presentation context.
1359 mPresContext->GetVisibleArea(r);
1360 cx->SetVisibleArea(r);
1362 // Create a new presentation shell to view the document
1363 rv = mDocument->CreateShell(cx, vm, ss, &sh);
1364 NS_ASSERTION(NS_OK == rv, "failed to create presentation shell");
1365 sh->ResizeReflow(r.width, r.height);
1367 // Now that the document has been reflowed, use its frame tree to
1368 // compare against our frame tree.
1369 CompareTrees(GetRootFrame(), sh->GetRootFrame());