зеркало из https://github.com/mozilla/gecko-dev.git
290 строки
7.2 KiB
C++
290 строки
7.2 KiB
C++
/* -*- 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 "nsLineBox.h"
|
|
#include "nsISpaceManager.h"
|
|
#include "nsIStyleContext.h"
|
|
#include "nsLineLayout.h"
|
|
#include "prprf.h"
|
|
|
|
nsLineBox::nsLineBox(nsIFrame* aFrame, PRInt32 aCount, PRUint16 flags)
|
|
{
|
|
mFirstChild = aFrame;
|
|
mChildCount = aCount;
|
|
mState = LINE_IS_DIRTY | LINE_NEED_DID_REFLOW | flags;
|
|
mFloaters = nsnull;
|
|
mNext = nsnull;
|
|
mBounds.SetRect(0,0,0,0);
|
|
mCombinedArea.SetRect(0,0,0,0);
|
|
mCarriedOutTopMargin = 0;
|
|
mCarriedOutBottomMargin = 0;
|
|
mBreakType = NS_STYLE_CLEAR_NONE;
|
|
}
|
|
|
|
nsLineBox::~nsLineBox()
|
|
{
|
|
if (nsnull != mFloaters) {
|
|
delete mFloaters;
|
|
}
|
|
}
|
|
|
|
static void
|
|
ListFloaters(FILE* out, PRInt32 aIndent, nsVoidArray* aFloaters)
|
|
{
|
|
PRInt32 j, i, n = aFloaters->Count();
|
|
for (i = 0; i < n; i++) {
|
|
for (j = aIndent; --j >= 0; ) fputs(" ", out);
|
|
nsPlaceholderFrame* ph = (nsPlaceholderFrame*) aFloaters->ElementAt(i);
|
|
if (nsnull != ph) {
|
|
fprintf(out, "placeholder@%p\n", ph);
|
|
nsIFrame* frame = ph->GetAnchoredItem();
|
|
if (nsnull != frame) {
|
|
frame->List(out, aIndent + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
char*
|
|
nsLineBox::StateToString(char* aBuf, PRInt32 aBufSize) const
|
|
{
|
|
PR_snprintf(aBuf, aBufSize, "%s,%s[0x%x]",
|
|
(mState & LINE_IS_DIRTY) ? "dirty" : "clean",
|
|
(mState & LINE_IS_BLOCK) ? "block" : "inline",
|
|
mState);
|
|
return aBuf;
|
|
}
|
|
|
|
void
|
|
nsLineBox::List(FILE* out, PRInt32 aIndent) const
|
|
{
|
|
PRInt32 i;
|
|
|
|
for (i = aIndent; --i >= 0; ) fputs(" ", out);
|
|
char cbuf[100];
|
|
fprintf(out, "line %p: count=%d state=%s ",
|
|
this, ChildCount(), StateToString(cbuf, sizeof(cbuf)));
|
|
if (0 != mCarriedOutTopMargin) {
|
|
fprintf(out, "tm=%d ", mCarriedOutTopMargin);
|
|
}
|
|
if (0 != mCarriedOutBottomMargin) {
|
|
fprintf(out, "bm=%d ", mCarriedOutBottomMargin);
|
|
}
|
|
out << mBounds;
|
|
fprintf(out, " ca=");
|
|
out << mCombinedArea;
|
|
fprintf(out, " <\n");
|
|
|
|
nsIFrame* frame = mFirstChild;
|
|
PRInt32 n = ChildCount();
|
|
while (--n >= 0) {
|
|
frame->List(out, aIndent + 1);
|
|
frame->GetNextSibling(&frame);
|
|
}
|
|
|
|
for (i = aIndent; --i >= 0; ) fputs(" ", out);
|
|
if (nsnull != mFloaters) {
|
|
fputs("> floaters <\n", out);
|
|
ListFloaters(out, aIndent + 1, mFloaters);
|
|
for (i = aIndent; --i >= 0; ) fputs(" ", out);
|
|
}
|
|
fputs(">\n", out);
|
|
}
|
|
|
|
nsIFrame*
|
|
nsLineBox::LastChild() const
|
|
{
|
|
nsIFrame* frame = mFirstChild;
|
|
PRInt32 n = ChildCount() - 1;
|
|
while (--n >= 0) {
|
|
frame->GetNextSibling(&frame);
|
|
}
|
|
return frame;
|
|
}
|
|
|
|
PRBool
|
|
nsLineBox::IsLastChild(nsIFrame* aFrame) const
|
|
{
|
|
nsIFrame* lastFrame = LastChild();
|
|
return aFrame == lastFrame;
|
|
}
|
|
|
|
PRBool
|
|
nsLineBox::Contains(nsIFrame* aFrame) const
|
|
{
|
|
PRInt32 n = ChildCount();
|
|
nsIFrame* frame = mFirstChild;
|
|
while (--n >= 0) {
|
|
if (frame == aFrame) {
|
|
return PR_TRUE;
|
|
}
|
|
frame->GetNextSibling(&frame);
|
|
}
|
|
return PR_FALSE;
|
|
}
|
|
|
|
#if 0
|
|
static PRInt32
|
|
LengthOf(nsIFrame* aFrame)
|
|
{
|
|
PRInt32 result = 0;
|
|
while (nsnull != aFrame) {
|
|
result++;
|
|
aFrame->GetNextSibling(aFrame);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void
|
|
nsLineBox::Verify()
|
|
{
|
|
nsIFrame* lastFrame = LastChild();
|
|
if (nsnull != lastFrame) {
|
|
nsIFrame* nextInFlow;
|
|
lastFrame->GetNextInFlow(nextInFlow);
|
|
if (nsnull != mNext) {
|
|
nsIFrame* nextSibling;
|
|
lastFrame->GetNextSibling(nextSibling);
|
|
NS_ASSERTION(mNext->mFirstChild == nextSibling, "bad line list");
|
|
}
|
|
}
|
|
PRInt32 len = LengthOf(mFirstChild);
|
|
NS_ASSERTION(len >= ChildCount(), "bad mChildCount");
|
|
}
|
|
|
|
static void
|
|
VerifyLines(nsLineBox* aLine)
|
|
{
|
|
while (nsnull != aLine) {
|
|
aLine->Verify();
|
|
aLine = aLine->mNext;
|
|
}
|
|
}
|
|
|
|
static void
|
|
VerifyChildCount(nsLineBox* aLines, PRBool aEmptyOK = PR_FALSE)
|
|
{
|
|
if (nsnull != aLines) {
|
|
PRInt32 childCount = LengthOf(aLines->mFirstChild);
|
|
PRInt32 sum = 0;
|
|
nsLineBox* line = aLines;
|
|
while (nsnull != line) {
|
|
if (!aEmptyOK) {
|
|
NS_ASSERTION(0 != line->ChildCount(), "empty line left in line list");
|
|
}
|
|
sum += line->ChildCount();
|
|
line = line->mNext;
|
|
}
|
|
if (sum != childCount) {
|
|
printf("Bad sibling list/line mChildCount's\n");
|
|
nsLineBox* line = aLines;
|
|
while (nsnull != line) {
|
|
line->List(stdout, 1);
|
|
if (nsnull != line->mNext) {
|
|
nsIFrame* lastFrame = line->LastChild();
|
|
if (nsnull != lastFrame) {
|
|
nsIFrame* nextSibling;
|
|
lastFrame->GetNextSibling(nextSibling);
|
|
if (line->mNext->mFirstChild != nextSibling) {
|
|
printf(" [list broken: nextSibling=%p mNext->mFirstChild=%p]\n",
|
|
nextSibling, line->mNext->mFirstChild);
|
|
}
|
|
}
|
|
}
|
|
line = line->mNext;
|
|
}
|
|
NS_ASSERTION(sum == childCount, "bad sibling list/line mChildCount's");
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void
|
|
nsLineBox::DeleteLineList(nsIPresContext& aPresContext, nsLineBox* aLine)
|
|
{
|
|
if (nsnull != aLine) {
|
|
// Delete our child frames before doing anything else. In particular
|
|
// we do all of this before our base class releases it's hold on the
|
|
// view.
|
|
for (nsIFrame* child = aLine->mFirstChild; child; ) {
|
|
nsIFrame* nextChild;
|
|
child->GetNextSibling(&nextChild);
|
|
child->DeleteFrame(aPresContext);
|
|
child = nextChild;
|
|
}
|
|
|
|
while (nsnull != aLine) {
|
|
nsLineBox* next = aLine->mNext;
|
|
delete aLine;
|
|
aLine = next;
|
|
}
|
|
}
|
|
}
|
|
|
|
nsLineBox*
|
|
nsLineBox::LastLine(nsLineBox* aLine)
|
|
{
|
|
if (nsnull != aLine) {
|
|
while (nsnull != aLine->mNext) {
|
|
aLine = aLine->mNext;
|
|
}
|
|
}
|
|
return aLine;
|
|
}
|
|
|
|
nsLineBox*
|
|
nsLineBox::FindLineContaining(nsLineBox* aLine, nsIFrame* aFrame)
|
|
{
|
|
while (nsnull != aLine) {
|
|
if (aLine->Contains(aFrame)) {
|
|
return aLine;
|
|
}
|
|
aLine = aLine->mNext;
|
|
}
|
|
return nsnull;
|
|
}
|
|
|
|
void
|
|
nsLineBox::UnplaceFloaters(nsISpaceManager* aSpaceManager)
|
|
{
|
|
if (nsnull != mFloaters) {
|
|
PRInt32 i, n = mFloaters->Count();
|
|
for (i = 0; i < n; i++) {
|
|
nsPlaceholderFrame* pf = (nsPlaceholderFrame*) mFloaters->ElementAt(i);
|
|
nsIFrame* floater = pf->GetAnchoredItem();
|
|
aSpaceManager->RemoveRegion(floater);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef NS_DEBUG
|
|
PRBool
|
|
nsLineBox::CheckIsBlock() const
|
|
{
|
|
nsIFrame* frame = mFirstChild;
|
|
const nsStyleDisplay* display;
|
|
frame->GetStyleData(eStyleStruct_Display,
|
|
(const nsStyleStruct*&) display);
|
|
const nsStylePosition* position;
|
|
frame->GetStyleData(eStyleStruct_Position,
|
|
(const nsStyleStruct*&) position);
|
|
PRBool isBlock = nsLineLayout::TreatFrameAsBlock(display, position);
|
|
return isBlock == IsBlock();
|
|
}
|
|
#endif
|