/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #include "nsHTMLReflowCommand.h" #include "nsIFrame.h" #include "nsIHTMLReflow.h" #include "nsIPresContext.h" #include "nsIPresShell.h" #include "nsIContent.h" #include "nsIStyleContext.h" #include "nsStyleConsts.h" #include "nsIFloaterContainer.h" #include "nsHTMLIIDs.h" static NS_DEFINE_IID(kIReflowCommandIID, NS_IREFLOWCOMMAND_IID); nsresult NS_NewHTMLReflowCommand(nsIReflowCommand** aInstancePtrResult, nsIFrame* aTargetFrame, nsIReflowCommand::ReflowType aReflowType, nsIFrame* aChildFrame) { NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); if (nsnull == aInstancePtrResult) { return NS_ERROR_NULL_POINTER; } nsHTMLReflowCommand* cmd = new nsHTMLReflowCommand(aTargetFrame, aReflowType, aChildFrame); if (nsnull == cmd) { return NS_ERROR_OUT_OF_MEMORY; } return cmd->QueryInterface(kIReflowCommandIID, (void**)aInstancePtrResult); } nsresult NS_NewHTMLReflowCommand(nsIReflowCommand** aInstancePtrResult, nsIFrame* aTargetFrame, nsIFrame* aChildFrame, nsIFrame* aPrevSiblingFrame) { NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); if (nsnull == aInstancePtrResult) { return NS_ERROR_NULL_POINTER; } nsHTMLReflowCommand* cmd = new nsHTMLReflowCommand(aTargetFrame, aChildFrame, aPrevSiblingFrame); if (nsnull == cmd) { return NS_ERROR_OUT_OF_MEMORY; } return cmd->QueryInterface(kIReflowCommandIID, (void**)aInstancePtrResult); } // Construct a reflow command given a target frame, reflow command type, // and optional child frame nsHTMLReflowCommand::nsHTMLReflowCommand(nsIFrame* aTargetFrame, ReflowType aReflowType, nsIFrame* aChildFrame) : mType(aReflowType), mTargetFrame(aTargetFrame), mChildFrame(aChildFrame), mPrevSiblingFrame(nsnull) { NS_PRECONDITION(mTargetFrame != nsnull, "null target frame"); NS_INIT_REFCNT(); } nsHTMLReflowCommand::nsHTMLReflowCommand(nsIFrame* aTargetFrame, nsIFrame* aChildFrame, nsIFrame* aPrevSiblingFrame) : mType(FrameInserted), mTargetFrame(aTargetFrame), mChildFrame(aChildFrame), mPrevSiblingFrame(aPrevSiblingFrame) { NS_PRECONDITION(mTargetFrame != nsnull, "null target frame"); NS_INIT_REFCNT(); } nsHTMLReflowCommand::~nsHTMLReflowCommand() { } NS_IMPL_ISUPPORTS(nsHTMLReflowCommand, kIReflowCommandIID); nsIFrame* nsHTMLReflowCommand::GetContainingBlock(nsIFrame* aFloater) { nsIFrame* containingBlock = nsnull; nsIFloaterContainer* container = nsnull; for (aFloater->GetContentParent(containingBlock); nsnull != containingBlock; containingBlock->GetContentParent(containingBlock)) { if (NS_OK == containingBlock->QueryInterface(kIFloaterContainerIID, (void**)&container)) { break; } } return containingBlock; } void nsHTMLReflowCommand::BuildPath() { mPath.Clear(); // Floating frames are handled differently. The path goes from the target // frame to the containing block, and then up the hierarchy nsStyleDisplay* display; mTargetFrame->GetStyleData(eStyleStruct_Display, (nsStyleStruct*&)display); if (NS_STYLE_FLOAT_NONE != display->mFloats) { mPath.AppendElement((void*)mTargetFrame); for (nsIFrame* f = GetContainingBlock(mTargetFrame); nsnull != f; f->GetGeometricParent(f)) { mPath.AppendElement((void*)f); } } else { for (nsIFrame* f = mTargetFrame; nsnull != f; f->GetGeometricParent(f)) { mPath.AppendElement((void*)f); } } } NS_IMETHODIMP nsHTMLReflowCommand::Dispatch(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsSize& aMaxSize, nsIRenderingContext& aRendContext) { // Build the path from the target frame (index 0) to the root frame BuildPath(); // Send an incremental reflow notification to the root frame nsIFrame* root = (nsIFrame*)mPath[mPath.Count() - 1]; #ifdef NS_DEBUG nsIPresShell* shell = aPresContext.GetShell(); if (nsnull != shell) { NS_ASSERTION(shell->GetRootFrame() == root, "bad root frame"); NS_RELEASE(shell); } #endif if (nsnull != root) { mPath.RemoveElementAt(mPath.Count() - 1); nsHTMLReflowState reflowState(aPresContext, root, *this, aMaxSize, &aRendContext); nsIHTMLReflow* htmlReflow; nsReflowStatus status; if (NS_OK == root->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) { htmlReflow->Reflow(aPresContext, aDesiredSize, reflowState, status); } } return NS_OK; } NS_IMETHODIMP nsHTMLReflowCommand::GetNext(nsIFrame*& aNextFrame) { PRInt32 count = mPath.Count(); aNextFrame = nsnull; if (count > 0) { aNextFrame = (nsIFrame*)mPath[count - 1]; mPath.RemoveElementAt(count - 1); } return NS_OK; } NS_IMETHODIMP nsHTMLReflowCommand::GetTarget(nsIFrame*& aTargetFrame) const { aTargetFrame = mTargetFrame; return NS_OK; } NS_IMETHODIMP nsHTMLReflowCommand::SetTarget(nsIFrame* aTargetFrame) { mTargetFrame = aTargetFrame; return NS_OK; } NS_IMETHODIMP nsHTMLReflowCommand::GetType(ReflowType& aReflowType) const { aReflowType = mType; return NS_OK; } NS_IMETHODIMP nsHTMLReflowCommand::GetChildFrame(nsIFrame*& aChildFrame) const { aChildFrame = mChildFrame; return NS_OK; } NS_IMETHODIMP nsHTMLReflowCommand::GetPrevSiblingFrame(nsIFrame*& aSiblingFrame) const { aSiblingFrame = mPrevSiblingFrame; return NS_OK; }