From 4b92814e1e06e3124c6a0e5c18263bbca5f2b39b Mon Sep 17 00:00:00 2001 From: "kipp%netscape.com" Date: Tue, 27 Apr 1999 22:05:02 +0000 Subject: [PATCH] new git-svn-id: svn://10.0.0.236/trunk@29535 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/layout/generic/nsFirstLetterFrame.cpp | 281 ++++++++++++++++++ .../html/base/src/nsFirstLetterFrame.cpp | 281 ++++++++++++++++++ 2 files changed, 562 insertions(+) create mode 100644 mozilla/layout/generic/nsFirstLetterFrame.cpp create mode 100644 mozilla/layout/html/base/src/nsFirstLetterFrame.cpp diff --git a/mozilla/layout/generic/nsFirstLetterFrame.cpp b/mozilla/layout/generic/nsFirstLetterFrame.cpp new file mode 100644 index 00000000000..fb560b87d8d --- /dev/null +++ b/mozilla/layout/generic/nsFirstLetterFrame.cpp @@ -0,0 +1,281 @@ +/* -*- 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 "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/NPL/ + * + * 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 Communicator client code. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 + * Netscape Communications Corporation. All Rights Reserved. + */ +#include "nsHTMLContainerFrame.h" +#include "nsIPresContext.h" +#include "nsIStyleContext.h" +#include "nsLineLayout.h" +#include "nsHTMLAtoms.h" +#include "nsHTMLIIDs.h" +#include "nsLayoutAtoms.h" + +#define nsFirstLetterFrameSuper nsHTMLContainerFrame + +class nsFirstLetterFrame : public nsFirstLetterFrameSuper { +public: + nsFirstLetterFrame(); + + NS_IMETHOD Init(nsIPresContext& aPresContext, + nsIContent* aContent, + nsIFrame* aParent, + nsIStyleContext* aContext, + nsIFrame* aPrevInFlow); + NS_IMETHOD SetInitialChildList(nsIPresContext& aPresContext, + nsIAtom* aListName, + nsIFrame* aChildList); + NS_IMETHOD GetFrameName(nsString& aResult) const; + NS_IMETHOD GetFrameType(nsIAtom** aType) const; + NS_IMETHOD Reflow(nsIPresContext& aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); + NS_IMETHOD FindTextRuns(nsLineLayout& aLineLayout); + +protected: + virtual PRIntn GetSkipSides() const; + + void DrainOverflowFrames(nsIPresContext* aPresContext); +}; + +nsresult +NS_NewFirstLetterFrame(nsIFrame** aNewFrame) +{ + NS_PRECONDITION(nsnull != aNewFrame, "null ptr"); + if (nsnull == aNewFrame) { + return NS_ERROR_NULL_POINTER; + } + nsFirstLetterFrame* it = new nsFirstLetterFrame; + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aNewFrame = it; + return NS_OK; +} + +nsFirstLetterFrame::nsFirstLetterFrame() +{ +} + +NS_IMETHODIMP +nsFirstLetterFrame::GetFrameName(nsString& aResult) const +{ + return MakeFrameName("Letter", aResult); +} + +NS_IMETHODIMP +nsFirstLetterFrame::GetFrameType(nsIAtom** aType) const +{ + NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer"); + *aType = nsLayoutAtoms::letterFrame; + NS_ADDREF(*aType); + return NS_OK; +} + +PRIntn +nsFirstLetterFrame::GetSkipSides() const +{ + return 0; +} + +NS_IMETHODIMP +nsFirstLetterFrame::Init(nsIPresContext& aPresContext, + nsIContent* aContent, + nsIFrame* aParent, + nsIStyleContext* aContext, + nsIFrame* aPrevInFlow) +{ + nsresult rv; + nsIStyleContext* newSC = nsnull; + if (aPrevInFlow) { + // Get proper style context for ourselves + nsIStyleContext* parentStyleContext; + parentStyleContext = aContext->GetParent(); + if (parentStyleContext) { + nsIAtom* atom = aPrevInFlow + ? nsHTMLAtoms::mozLetterFrame + : nsHTMLAtoms::firstLetterPseudo; + rv = aPresContext.ResolvePseudoStyleContextFor(aContent, atom, + parentStyleContext, + PR_FALSE, &newSC); + NS_RELEASE(parentStyleContext); + if (NS_FAILED(rv)) { + return rv; + } + + if (nsnull != newSC) { + if (newSC == aContext) { + NS_RELEASE(newSC); + } + else { + aContext = newSC; + } + } + } + } + rv = nsFirstLetterFrameSuper::Init(aPresContext, aContent, aParent, + aContext, aPrevInFlow); + NS_IF_RELEASE(newSC); + return rv; +} + +NS_IMETHODIMP +nsFirstLetterFrame::SetInitialChildList(nsIPresContext& aPresContext, + nsIAtom* aListName, + nsIFrame* aChildList) +{ + mFrames.SetFrames(aChildList); + aChildList->ReResolveStyleContext(&aPresContext, mStyleContext, + NS_STYLE_HINT_REFLOW, + nsnull, nsnull); + return NS_OK; +} + +NS_IMETHODIMP +nsFirstLetterFrame::FindTextRuns(nsLineLayout& aLineLayout) +{ + nsIFrame* frame = mFrames.FirstChild(); + while (nsnull != frame) { + nsIHTMLReflow* ihr; + nsresult rv = frame->QueryInterface(kIHTMLReflowIID, (void**)&ihr); + if (NS_SUCCEEDED(rv)) { + ihr->FindTextRuns(aLineLayout); + } + frame->GetNextSibling(&frame); + } + return NS_OK; +} + +NS_IMETHODIMP +nsFirstLetterFrame::Reflow(nsIPresContext& aPresContext, + nsHTMLReflowMetrics& aMetrics, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aReflowStatus) +{ + // Grab overflow list + DrainOverflowFrames(&aPresContext); + + nsIFrame* kid = mFrames.FirstChild(); + nsIHTMLReflow* htmlReflow; + nsresult rv = kid->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow); + if (NS_FAILED(rv)) { + return rv; + } + + // Setup reflow state for our child + nsSize availSize(aReflowState.availableWidth, aReflowState.availableHeight); + const nsMargin& bp = aReflowState.mComputedBorderPadding; + nscoord lr = bp.left + bp.right; + nscoord tb = bp.top + bp.bottom; + if (NS_UNCONSTRAINEDSIZE != availSize.width) { + availSize.width -= lr; + } + if (NS_UNCONSTRAINEDSIZE != availSize.height) { + availSize.width -= tb; + } + + // Reflow the child + nsHTMLReflowState rs(aPresContext, aReflowState, kid, availSize); + htmlReflow->WillReflow(aPresContext); + if (!rs.lineLayout) { + // When there is no lineLayout provided, we provide our own. The + // only time that the first-letter-frame is not reflowing in a + // line context is when its floating. + nsLineLayout ll(aPresContext, nsnull, &aReflowState, + nsnull != aMetrics.maxElementSize); + ll.BeginLineReflow(0, 0, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE, + PR_FALSE, PR_TRUE); + rs.lineLayout = ≪ + ll.SetFirstLetterStyleOK(PR_TRUE); + htmlReflow->Reflow(aPresContext, aMetrics, rs, aReflowStatus); + ll.EndLineReflow(); + } + else { + htmlReflow->Reflow(aPresContext, aMetrics, rs, aReflowStatus); + } + + // Place and size the child and update the output metrics + kid->MoveTo(bp.left, bp.top); + kid->SizeTo(aMetrics.width, aMetrics.height); + aMetrics.width += lr; + aMetrics.height += tb; + if (aMetrics.maxElementSize) { + aMetrics.maxElementSize->width += lr; + aMetrics.maxElementSize->height += tb; + } + + // Create a continuation or remove existing continuations based on + // the reflow completion status. + if (NS_FRAME_IS_COMPLETE(aReflowStatus)) { + nsIFrame* kidNextInFlow; + kid->GetNextInFlow(&kidNextInFlow); + if (nsnull != kidNextInFlow) { + // Remove all of the childs next-in-flows + DeleteChildsNextInFlow(aPresContext, kid); + } + } + else { + // Create a continuation for the child frame if it doesn't already + // have one. + nsIFrame* nextInFlow; + rv = CreateNextInFlow(aPresContext, this, kid, nextInFlow); + if (NS_FAILED(rv)) { + return rv; + } + + // And then push it to our overflow list + if (nextInFlow) { + kid->SetNextSibling(nsnull); + mOverflowFrames.SetFrames(nextInFlow); + } + } + + return rv; +} + +void +nsFirstLetterFrame::DrainOverflowFrames(nsIPresContext* aPresContext) +{ + // Check for an overflow list with our prev-in-flow + nsFirstLetterFrame* prevInFlow = (nsFirstLetterFrame*)mPrevInFlow; + if (nsnull != prevInFlow) { + if (prevInFlow->mOverflowFrames.NotEmpty()) { + NS_ASSERTION(mFrames.IsEmpty(), "bad overflow list"); + + // When pushing and pulling frames we need to check for whether any + // views need to be reparented. + nsIFrame* f = prevInFlow->mOverflowFrames.FirstChild(); + while (f) { + nsHTMLContainerFrame::ReparentFrameView(f, prevInFlow, this); + f->GetNextSibling(&f); + } + mFrames.InsertFrames(this, nsnull, prevInFlow->mOverflowFrames); + } + } + + // It's also possible that we have an overflow list for ourselves + if (mOverflowFrames.NotEmpty()) { + NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames"); + mFrames.AppendFrames(nsnull, mOverflowFrames); + } + + // Now repair our first frames style context + nsIFrame* kid = mFrames.FirstChild(); + kid->ReResolveStyleContext(aPresContext, mStyleContext, + NS_STYLE_HINT_REFLOW, + nsnull, nsnull); +} diff --git a/mozilla/layout/html/base/src/nsFirstLetterFrame.cpp b/mozilla/layout/html/base/src/nsFirstLetterFrame.cpp new file mode 100644 index 00000000000..fb560b87d8d --- /dev/null +++ b/mozilla/layout/html/base/src/nsFirstLetterFrame.cpp @@ -0,0 +1,281 @@ +/* -*- 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 "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/NPL/ + * + * 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 Communicator client code. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 + * Netscape Communications Corporation. All Rights Reserved. + */ +#include "nsHTMLContainerFrame.h" +#include "nsIPresContext.h" +#include "nsIStyleContext.h" +#include "nsLineLayout.h" +#include "nsHTMLAtoms.h" +#include "nsHTMLIIDs.h" +#include "nsLayoutAtoms.h" + +#define nsFirstLetterFrameSuper nsHTMLContainerFrame + +class nsFirstLetterFrame : public nsFirstLetterFrameSuper { +public: + nsFirstLetterFrame(); + + NS_IMETHOD Init(nsIPresContext& aPresContext, + nsIContent* aContent, + nsIFrame* aParent, + nsIStyleContext* aContext, + nsIFrame* aPrevInFlow); + NS_IMETHOD SetInitialChildList(nsIPresContext& aPresContext, + nsIAtom* aListName, + nsIFrame* aChildList); + NS_IMETHOD GetFrameName(nsString& aResult) const; + NS_IMETHOD GetFrameType(nsIAtom** aType) const; + NS_IMETHOD Reflow(nsIPresContext& aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); + NS_IMETHOD FindTextRuns(nsLineLayout& aLineLayout); + +protected: + virtual PRIntn GetSkipSides() const; + + void DrainOverflowFrames(nsIPresContext* aPresContext); +}; + +nsresult +NS_NewFirstLetterFrame(nsIFrame** aNewFrame) +{ + NS_PRECONDITION(nsnull != aNewFrame, "null ptr"); + if (nsnull == aNewFrame) { + return NS_ERROR_NULL_POINTER; + } + nsFirstLetterFrame* it = new nsFirstLetterFrame; + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aNewFrame = it; + return NS_OK; +} + +nsFirstLetterFrame::nsFirstLetterFrame() +{ +} + +NS_IMETHODIMP +nsFirstLetterFrame::GetFrameName(nsString& aResult) const +{ + return MakeFrameName("Letter", aResult); +} + +NS_IMETHODIMP +nsFirstLetterFrame::GetFrameType(nsIAtom** aType) const +{ + NS_PRECONDITION(nsnull != aType, "null OUT parameter pointer"); + *aType = nsLayoutAtoms::letterFrame; + NS_ADDREF(*aType); + return NS_OK; +} + +PRIntn +nsFirstLetterFrame::GetSkipSides() const +{ + return 0; +} + +NS_IMETHODIMP +nsFirstLetterFrame::Init(nsIPresContext& aPresContext, + nsIContent* aContent, + nsIFrame* aParent, + nsIStyleContext* aContext, + nsIFrame* aPrevInFlow) +{ + nsresult rv; + nsIStyleContext* newSC = nsnull; + if (aPrevInFlow) { + // Get proper style context for ourselves + nsIStyleContext* parentStyleContext; + parentStyleContext = aContext->GetParent(); + if (parentStyleContext) { + nsIAtom* atom = aPrevInFlow + ? nsHTMLAtoms::mozLetterFrame + : nsHTMLAtoms::firstLetterPseudo; + rv = aPresContext.ResolvePseudoStyleContextFor(aContent, atom, + parentStyleContext, + PR_FALSE, &newSC); + NS_RELEASE(parentStyleContext); + if (NS_FAILED(rv)) { + return rv; + } + + if (nsnull != newSC) { + if (newSC == aContext) { + NS_RELEASE(newSC); + } + else { + aContext = newSC; + } + } + } + } + rv = nsFirstLetterFrameSuper::Init(aPresContext, aContent, aParent, + aContext, aPrevInFlow); + NS_IF_RELEASE(newSC); + return rv; +} + +NS_IMETHODIMP +nsFirstLetterFrame::SetInitialChildList(nsIPresContext& aPresContext, + nsIAtom* aListName, + nsIFrame* aChildList) +{ + mFrames.SetFrames(aChildList); + aChildList->ReResolveStyleContext(&aPresContext, mStyleContext, + NS_STYLE_HINT_REFLOW, + nsnull, nsnull); + return NS_OK; +} + +NS_IMETHODIMP +nsFirstLetterFrame::FindTextRuns(nsLineLayout& aLineLayout) +{ + nsIFrame* frame = mFrames.FirstChild(); + while (nsnull != frame) { + nsIHTMLReflow* ihr; + nsresult rv = frame->QueryInterface(kIHTMLReflowIID, (void**)&ihr); + if (NS_SUCCEEDED(rv)) { + ihr->FindTextRuns(aLineLayout); + } + frame->GetNextSibling(&frame); + } + return NS_OK; +} + +NS_IMETHODIMP +nsFirstLetterFrame::Reflow(nsIPresContext& aPresContext, + nsHTMLReflowMetrics& aMetrics, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aReflowStatus) +{ + // Grab overflow list + DrainOverflowFrames(&aPresContext); + + nsIFrame* kid = mFrames.FirstChild(); + nsIHTMLReflow* htmlReflow; + nsresult rv = kid->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow); + if (NS_FAILED(rv)) { + return rv; + } + + // Setup reflow state for our child + nsSize availSize(aReflowState.availableWidth, aReflowState.availableHeight); + const nsMargin& bp = aReflowState.mComputedBorderPadding; + nscoord lr = bp.left + bp.right; + nscoord tb = bp.top + bp.bottom; + if (NS_UNCONSTRAINEDSIZE != availSize.width) { + availSize.width -= lr; + } + if (NS_UNCONSTRAINEDSIZE != availSize.height) { + availSize.width -= tb; + } + + // Reflow the child + nsHTMLReflowState rs(aPresContext, aReflowState, kid, availSize); + htmlReflow->WillReflow(aPresContext); + if (!rs.lineLayout) { + // When there is no lineLayout provided, we provide our own. The + // only time that the first-letter-frame is not reflowing in a + // line context is when its floating. + nsLineLayout ll(aPresContext, nsnull, &aReflowState, + nsnull != aMetrics.maxElementSize); + ll.BeginLineReflow(0, 0, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE, + PR_FALSE, PR_TRUE); + rs.lineLayout = ≪ + ll.SetFirstLetterStyleOK(PR_TRUE); + htmlReflow->Reflow(aPresContext, aMetrics, rs, aReflowStatus); + ll.EndLineReflow(); + } + else { + htmlReflow->Reflow(aPresContext, aMetrics, rs, aReflowStatus); + } + + // Place and size the child and update the output metrics + kid->MoveTo(bp.left, bp.top); + kid->SizeTo(aMetrics.width, aMetrics.height); + aMetrics.width += lr; + aMetrics.height += tb; + if (aMetrics.maxElementSize) { + aMetrics.maxElementSize->width += lr; + aMetrics.maxElementSize->height += tb; + } + + // Create a continuation or remove existing continuations based on + // the reflow completion status. + if (NS_FRAME_IS_COMPLETE(aReflowStatus)) { + nsIFrame* kidNextInFlow; + kid->GetNextInFlow(&kidNextInFlow); + if (nsnull != kidNextInFlow) { + // Remove all of the childs next-in-flows + DeleteChildsNextInFlow(aPresContext, kid); + } + } + else { + // Create a continuation for the child frame if it doesn't already + // have one. + nsIFrame* nextInFlow; + rv = CreateNextInFlow(aPresContext, this, kid, nextInFlow); + if (NS_FAILED(rv)) { + return rv; + } + + // And then push it to our overflow list + if (nextInFlow) { + kid->SetNextSibling(nsnull); + mOverflowFrames.SetFrames(nextInFlow); + } + } + + return rv; +} + +void +nsFirstLetterFrame::DrainOverflowFrames(nsIPresContext* aPresContext) +{ + // Check for an overflow list with our prev-in-flow + nsFirstLetterFrame* prevInFlow = (nsFirstLetterFrame*)mPrevInFlow; + if (nsnull != prevInFlow) { + if (prevInFlow->mOverflowFrames.NotEmpty()) { + NS_ASSERTION(mFrames.IsEmpty(), "bad overflow list"); + + // When pushing and pulling frames we need to check for whether any + // views need to be reparented. + nsIFrame* f = prevInFlow->mOverflowFrames.FirstChild(); + while (f) { + nsHTMLContainerFrame::ReparentFrameView(f, prevInFlow, this); + f->GetNextSibling(&f); + } + mFrames.InsertFrames(this, nsnull, prevInFlow->mOverflowFrames); + } + } + + // It's also possible that we have an overflow list for ourselves + if (mOverflowFrames.NotEmpty()) { + NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames"); + mFrames.AppendFrames(nsnull, mOverflowFrames); + } + + // Now repair our first frames style context + nsIFrame* kid = mFrames.FirstChild(); + kid->ReResolveStyleContext(aPresContext, mStyleContext, + NS_STYLE_HINT_REFLOW, + nsnull, nsnull); +}